blob: e75bcc59e483ffc20972a5013b21e44ba8ac2df5 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08002 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/* Include Files */
29
Archana Ramachandran3abc3912016-04-29 17:01:32 -070030/* denote that this file does not allow legacy hddLog */
31#define HDD_DISALLOW_LEGACY_HDDLOG 1
32
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080033#include <wlan_hdd_includes.h>
34#include <wlan_hdd_wowl.h>
35#include "wlan_hdd_trace.h"
36#include "wlan_hdd_ioctl.h"
37#include "wlan_hdd_power.h"
38#include "wlan_hdd_driver_ops.h"
39#include "cds_concurrency.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053040#include "wlan_hdd_hostapd.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080041
42#include "wlan_hdd_p2p.h"
43#include <linux/ctype.h>
44#include "wma.h"
45#include "wlan_hdd_napi.h"
46
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080047#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080048#include <sme_api.h>
49#include <sir_api.h>
50#endif
51#include "hif.h"
52
53#if defined(LINUX_QCMBR)
54#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
55#endif
56
57/*
58 * Size of Driver command strings from upper layer
59 */
60#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
61#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
62
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080063/*
64 * Ibss prop IE from command will be of size:
65 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
66 * OUI_DATA should be at least 3 bytes long
67 */
68#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080070#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071#define TID_MIN_VALUE 0
72#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080073#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080074
75/*
76 * Maximum buffer size used for returning the data back to user space
77 */
78#define WLAN_MAX_BUF_SIZE 1024
79#define WLAN_PRIV_DATA_MAX_LEN 8192
80
81/*
82 * Driver miracast parameters 0-Disabled
83 * 1-Source, 2-Sink
84 */
85#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
86#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
87
88/*
89 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
90 * we will split the printing.
91 */
92#define NUM_OF_STA_DATA_TO_PRINT 16
93
94/*
95 * Android DRIVER command structures
96 */
97struct android_wifi_reassoc_params {
98 unsigned char bssid[18];
99 int channel;
100};
101
102#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
103struct android_wifi_af_params {
104 unsigned char bssid[18];
105 int channel;
106 int dwell_time;
107 int len;
108 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
109};
110
111/*
112 * Define HDD driver command handling entry, each contains a command
113 * string and the handler.
114 */
115typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
116 hdd_context_t *hdd_ctx,
117 uint8_t *cmd,
118 uint8_t cmd_name_len,
119 hdd_priv_data_t *priv_data);
120
121typedef struct {
122 const char *cmd;
123 hdd_drv_cmd_handler_t handler;
124} hdd_drv_cmd_t;
125
126#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
127#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
128#define WLAN_HDD_MAX_TCP_PORT 65535
129#endif
130
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800131static uint16_t cesium_pid;
132extern struct sock *cesium_nl_srv_sock;
133
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800134#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800135static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
136 const uint32_t staId, void *context)
137{
138 struct statsContext *stats_context = NULL;
139 hdd_adapter_t *adapter = NULL;
140
141 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700142 hdd_err("Bad param, context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143 return;
144 }
145
146 /*
147 * there is a race condition that exists between this callback
148 * function and the caller since the caller could time out either
149 * before or while this code is executing. we use a spinlock to
150 * serialize these actions
151 */
152 spin_lock(&hdd_context_lock);
153
154 stats_context = context;
155 adapter = stats_context->pAdapter;
156 if ((NULL == adapter) ||
157 (STATS_CONTEXT_MAGIC != stats_context->magic)) {
158 /*
159 * the caller presumably timed out so there is
160 * nothing we can do
161 */
162 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700163 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
164 adapter, stats_context->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165 return;
166 }
167
168 /* context is valid so caller is still waiting */
169
170 /* paranoia: invalidate the magic */
171 stats_context->magic = 0;
172
173 /* copy over the tsm stats */
174 adapter->tsmStats.UplinkPktQueueDly = tsm_metrics.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530175 qdf_mem_copy(adapter->tsmStats.UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176 tsm_metrics.UplinkPktQueueDlyHist,
177 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
178 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist[0]));
179 adapter->tsmStats.UplinkPktTxDly = tsm_metrics.UplinkPktTxDly;
180 adapter->tsmStats.UplinkPktLoss = tsm_metrics.UplinkPktLoss;
181 adapter->tsmStats.UplinkPktCount = tsm_metrics.UplinkPktCount;
182 adapter->tsmStats.RoamingCount = tsm_metrics.RoamingCount;
183 adapter->tsmStats.RoamingDly = tsm_metrics.RoamingDly;
184
185 /* notify the caller */
186 complete(&stats_context->completion);
187
188 /* serialization is complete */
189 spin_unlock(&hdd_context_lock);
190}
191
192static
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530193QDF_STATUS hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194 const uint8_t tid,
195 tAniTrafStrmMetrics *tsm_metrics)
196{
197 hdd_station_ctx_t *hdd_sta_ctx = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530198 QDF_STATUS hstatus;
199 QDF_STATUS vstatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800200 unsigned long rc;
201 struct statsContext context;
202 hdd_context_t *hdd_ctx = NULL;
203
204 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700205 hdd_err("adapter is NULL");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530206 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 }
208
209 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
210 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
211
212 /* we are connected prepare our callback context */
213 init_completion(&context.completion);
214 context.pAdapter = adapter;
215 context.magic = STATS_CONTEXT_MAGIC;
216
217 /* query tsm stats */
218 hstatus = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
219 hdd_sta_ctx->conn_info.staId[0],
220 hdd_sta_ctx->conn_info.bssId,
221 &context, hdd_ctx->pcds_context, tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530222 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700223 hdd_err("Unable to retrieve statistics");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530224 vstatus = QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800225 } else {
226 /* request was sent -- wait for the response */
227 rc = wait_for_completion_timeout(&context.completion,
228 msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
229 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700230 hdd_err("SME timed out while retrieving statistics");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530231 vstatus = QDF_STATUS_E_TIMEOUT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 }
233 }
234
235 /*
236 * either we never sent a request, we sent a request and received a
237 * response or we sent a request and timed out. if we never sent a
238 * request or if we sent a request and got a response, we want to
239 * clear the magic out of paranoia. if we timed out there is a
240 * race condition such that the callback function could be
241 * executing at the same time we are. of primary concern is if the
242 * callback function had already verified the "magic" but had not
243 * yet set the completion variable when a timeout occurred. we
244 * serialize these activities by invalidating the magic while
245 * holding a shared spinlock which will cause us to block if the
246 * callback is currently executing
247 */
248 spin_lock(&hdd_context_lock);
249 context.magic = 0;
250 spin_unlock(&hdd_context_lock);
251
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530252 if (QDF_STATUS_SUCCESS == vstatus) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800253 tsm_metrics->UplinkPktQueueDly =
254 adapter->tsmStats.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530255 qdf_mem_copy(tsm_metrics->UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256 adapter->tsmStats.UplinkPktQueueDlyHist,
257 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
258 sizeof(adapter->tsmStats.
259 UplinkPktQueueDlyHist[0]));
260 tsm_metrics->UplinkPktTxDly = adapter->tsmStats.UplinkPktTxDly;
261 tsm_metrics->UplinkPktLoss = adapter->tsmStats.UplinkPktLoss;
262 tsm_metrics->UplinkPktCount = adapter->tsmStats.UplinkPktCount;
263 tsm_metrics->RoamingCount = adapter->tsmStats.RoamingCount;
264 tsm_metrics->RoamingDly = adapter->tsmStats.RoamingDly;
265 }
266 return vstatus;
267}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800268#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800269
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800270/* Function header is left blank intentionally */
271static int hdd_parse_setrmcenable_command(uint8_t *pValue,
272 uint8_t *pRmcEnable)
273{
274 uint8_t *inPtr = pValue;
275 int tempInt;
276 int v = 0;
277 char buf[32];
278 *pRmcEnable = 0;
279
280 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
281
282 if (NULL == inPtr) {
283 return 0;
284 }
285
286 else if (SPACE_ASCII_VALUE != *inPtr) {
287 return 0;
288 }
289
290 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
291 inPtr++;
292
293 if ('\0' == *inPtr) {
294 return 0;
295 }
296
297 sscanf(inPtr, "%32s ", buf);
298 v = kstrtos32(buf, 10, &tempInt);
299 if (v < 0) {
300 return -EINVAL;
301 }
302
303 *pRmcEnable = tempInt;
304
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700305 hdd_info("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800306
307 return 0;
308}
309
310/* Function header is left blank intentionally */
311static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
312 uint32_t *pActionPeriod)
313{
314 uint8_t *inPtr = pValue;
315 int tempInt;
316 int v = 0;
317 char buf[32];
318 *pActionPeriod = 0;
319
320 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
321
322 if (NULL == inPtr) {
323 return -EINVAL;
324 }
325
326 else if (SPACE_ASCII_VALUE != *inPtr) {
327 return -EINVAL;
328 }
329
330 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
331 inPtr++;
332
333 if ('\0' == *inPtr) {
334 return 0;
335 }
336
337 sscanf(inPtr, "%32s ", buf);
338 v = kstrtos32(buf, 10, &tempInt);
339 if (v < 0) {
340 return -EINVAL;
341 }
342
343 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
344 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) {
345 return -EINVAL;
346 }
347
348 *pActionPeriod = tempInt;
349
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700350 hdd_info("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800351
352 return 0;
353}
354
355/* Function header is left blank intentionally */
356static int hdd_parse_setrmcrate_command(uint8_t *pValue,
357 uint32_t *pRate,
358 tTxrateinfoflags *pTxFlags)
359{
360 uint8_t *inPtr = pValue;
361 int tempInt;
362 int v = 0;
363 char buf[32];
364 *pRate = 0;
365 *pTxFlags = 0;
366
367 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
368
369 if (NULL == inPtr) {
370 return -EINVAL;
371 }
372
373 else if (SPACE_ASCII_VALUE != *inPtr) {
374 return -EINVAL;
375 }
376
377 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
378 inPtr++;
379
380 if ('\0' == *inPtr) {
381 return 0;
382 }
383
384 sscanf(inPtr, "%32s ", buf);
385 v = kstrtos32(buf, 10, &tempInt);
386 if (v < 0) {
387 return -EINVAL;
388 }
389
390 switch (tempInt) {
391 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700392 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800393 return -EINVAL;
394 case 0:
395 case 6:
396 case 9:
397 case 12:
398 case 18:
399 case 24:
400 case 36:
401 case 48:
402 case 54:
403 *pTxFlags = eHAL_TX_RATE_LEGACY;
404 *pRate = tempInt * 10;
405 break;
406 case 65:
407 *pTxFlags = eHAL_TX_RATE_HT20;
408 *pRate = tempInt * 10;
409 break;
410 case 72:
411 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
412 *pRate = 722;
413 break;
414 }
415
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700416 hdd_info("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800417
418 return 0;
419}
420
421/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700422 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
423 * @UserData: Adapter private data
424 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800425 *
426 * This is an asynchronous callback function from SME when the peer info
427 * is received
428 *
429 * Return: 0 for success non-zero for failure
430 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700431void
432hdd_get_ibss_peer_info_cb(void *pUserData,
433 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800434{
435 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800436 hdd_station_ctx_t *pStaCtx;
437 uint8_t i;
438
439 /* Sanity check */
440 if ((NULL == adapter) ||
441 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700442 hdd_alert("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800443 return;
444 }
445
446 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
447 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700448 /* validate number of peers */
449 if (pPeerInfo->numPeers < SIR_MAX_NUM_STA_IN_IBSS) {
450 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
451 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800452
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700453 for (i = 0; i < pPeerInfo->numPeers; i++) {
454 pStaCtx->ibss_peer_info.peerInfoParams[i] =
455 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800456 }
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700457 hdd_info("Peer Info copied in HDD");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800458 } else {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700459 hdd_info("Number of peers %d returned is more than limit %d",
460 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800461 }
462 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700463 hdd_info("peerInfo returned is NULL");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800464 }
465
466 complete(&adapter->ibss_peer_info_comp);
467}
468
469/**
470 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
471 * @adapter: Adapter context
472 *
473 * Request function to get IBSS peer info from lower layers
474 *
475 * Return: 0 for success non-zero for failure
476 */
477static
478QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
479{
480 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
481 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
482 unsigned long rc;
483
484 INIT_COMPLETION(adapter->ibss_peer_info_comp);
485
486 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700487 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800488 true, 0xFF);
489
490 if (QDF_STATUS_SUCCESS == retStatus) {
491 rc = wait_for_completion_timeout
492 (&adapter->ibss_peer_info_comp,
493 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
494
495 /* status will be 0 if timed out */
496 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700497 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800498 retStatus = QDF_STATUS_E_FAILURE;
499 return retStatus;
500 }
501 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700502 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800503 }
504
505 return retStatus;
506}
507
508/**
509 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
510 * @adapter: Adapter context
511 * @staIdx: Sta index for which the peer info is requested
512 *
513 * Request function to get IBSS peer info from lower layers
514 *
515 * Return: 0 for success non-zero for failure
516 */
517static QDF_STATUS
518hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
519{
520 unsigned long rc;
521 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
522 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
523
524 INIT_COMPLETION(adapter->ibss_peer_info_comp);
525
526 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700527 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800528 false, staIdx);
529
530 if (QDF_STATUS_SUCCESS == retStatus) {
531 rc = wait_for_completion_timeout(
532 &adapter->ibss_peer_info_comp,
533 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
534
535 /* status = 0 on timeout */
536 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700537 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800538 retStatus = QDF_STATUS_E_FAILURE;
539 return retStatus;
540 }
541 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700542 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800543 }
544
545 return retStatus;
546}
547
548/* Function header is left blank intentionally */
549QDF_STATUS
550hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
551{
552 uint8_t *inPtr = pValue;
553 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
554
555 if (NULL == inPtr) {
556 return QDF_STATUS_E_FAILURE;;
557 }
558
559 else if (SPACE_ASCII_VALUE != *inPtr) {
560 return QDF_STATUS_E_FAILURE;;
561 }
562
563 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
564 inPtr++;
565
566 if ('\0' == *inPtr) {
567 return QDF_STATUS_E_FAILURE;;
568 }
569
570 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
571 inPtr[11] != ':' || inPtr[14] != ':') {
572 return QDF_STATUS_E_FAILURE;;
573 }
574 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
575 (unsigned int *)&pPeerMacAddr->bytes[0],
576 (unsigned int *)&pPeerMacAddr->bytes[1],
577 (unsigned int *)&pPeerMacAddr->bytes[2],
578 (unsigned int *)&pPeerMacAddr->bytes[3],
579 (unsigned int *)&pPeerMacAddr->bytes[4],
580 (unsigned int *)&pPeerMacAddr->bytes[5]);
581
582 return QDF_STATUS_SUCCESS;
583}
584
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800585static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
586{
587 eCsrBand band = -1;
588 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
589 switch (band) {
590 case eCSR_BAND_ALL:
591 *pBand = WLAN_HDD_UI_BAND_AUTO;
592 break;
593
594 case eCSR_BAND_24:
595 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
596 break;
597
598 case eCSR_BAND_5G:
599 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
600 break;
601
602 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700603 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800604 *pBand = -1;
605 break;
606 }
607}
608
609/**
610 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
611 * @data: input data
612 * @target_ap_bssid: pointer to bssid (output parameter)
613 * @channel: pointer to channel (output parameter)
614 *
615 * Return: 0 if parsing is successful; -EINVAL otherwise
616 */
617static int _hdd_parse_bssid_and_chan(const uint8_t **data,
618 uint8_t *bssid,
619 uint8_t *channel)
620{
621 const uint8_t *in_ptr;
622 int v = 0;
623 int temp_int;
624 uint8_t temp_buf[32];
625
626 /* 12 hexa decimal digits, 5 ':' and '\0' */
627 uint8_t mac_addr[18];
628
629 if (!data || !*data)
630 return -EINVAL;
631
632 in_ptr = *data;
633
634 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
635 /* no argument after the command */
636 if (NULL == in_ptr)
637 goto error;
638 /* no space after the command */
639 else if (SPACE_ASCII_VALUE != *in_ptr)
640 goto error;
641
642 /* remove empty spaces */
643 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
644 in_ptr++;
645
646 /* no argument followed by spaces */
647 if ('\0' == *in_ptr)
648 goto error;
649
650 v = sscanf(in_ptr, "%17s", mac_addr);
651 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700652 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
653 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800654 goto error;
655 }
656
657 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
658 hex_to_bin(mac_addr[1]);
659 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
660 hex_to_bin(mac_addr[4]);
661 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
662 hex_to_bin(mac_addr[7]);
663 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
664 hex_to_bin(mac_addr[10]);
665 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
666 hex_to_bin(mac_addr[13]);
667 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
668 hex_to_bin(mac_addr[16]);
669
670 /* point to the next argument */
671 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
672 /* no argument after the command */
673 if (NULL == in_ptr)
674 goto error;
675
676 /* remove empty spaces */
677 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
678 in_ptr++;
679
680 /* no argument followed by spaces */
681 if ('\0' == *in_ptr)
682 goto error;
683
684 /* get the next argument ie the channel number */
685 v = sscanf(in_ptr, "%31s ", temp_buf);
686 if (1 != v)
687 goto error;
688
689 v = kstrtos32(temp_buf, 10, &temp_int);
690 if ((v < 0) || (temp_int < 0) ||
691 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
692 return -EINVAL;
693
694 *channel = temp_int;
695 *data = in_ptr;
696 return 0;
697error:
698 *data = in_ptr;
699 return -EINVAL;
700}
701
702/**
703 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
704 * @pValue: Pointer to input data
705 * @pTargetApBssid: Pointer to target Ap bssid
706 * @pChannel: Pointer to the Target AP channel
707 * @pDwellTime: Pointer to the time to stay off-channel
708 * after transmitting action frame
709 * @pBuf: Pointer to data
710 * @pBufLen: Pointer to data length
711 *
712 * This function parses the send action frame data passed in the format
713 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
714 *
715 * Return: 0 for success non-zero for failure
716 */
717static int
718hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
719 uint8_t *pTargetApBssid,
720 uint8_t *pChannel, uint8_t *pDwellTime,
721 uint8_t **pBuf, uint8_t *pBufLen)
722{
723 const uint8_t *inPtr = pValue;
724 const uint8_t *dataEnd;
725 int tempInt;
726 int j = 0;
727 int i = 0;
728 int v = 0;
729 uint8_t tempBuf[32];
730 uint8_t tempByte = 0;
731
732 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
733 return -EINVAL;
734
735 /* point to the next argument */
736 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
737 /* no argument after the command */
738 if (NULL == inPtr)
739 return -EINVAL;
740 /* removing empty spaces */
741 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
742 inPtr++;
743
744 /* no argument followed by spaces */
745 if ('\0' == *inPtr) {
746 return -EINVAL;
747 }
748
749 /* getting the next argument ie the dwell time */
750 v = sscanf(inPtr, "%31s ", tempBuf);
751 if (1 != v)
752 return -EINVAL;
753
754 v = kstrtos32(tempBuf, 10, &tempInt);
755 if (v < 0 || tempInt < 0)
756 return -EINVAL;
757
758 *pDwellTime = tempInt;
759
760 /* point to the next argument */
761 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
762 /* no argument after the command */
763 if (NULL == inPtr)
764 return -EINVAL;
765 /* removing empty spaces */
766 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
767 inPtr++;
768
769 /* no argument followed by spaces */
770 if ('\0' == *inPtr) {
771 return -EINVAL;
772 }
773
774 /* find the length of data */
775 dataEnd = inPtr;
776 while (('\0' != *dataEnd)) {
777 dataEnd++;
778 }
779 *pBufLen = dataEnd - inPtr;
780 if (*pBufLen <= 0)
781 return -EINVAL;
782
783 /*
784 * Allocate the number of bytes based on the number of input characters
785 * whether it is even or odd.
786 * if the number of input characters are even, then we need N/2 byte.
787 * if the number of input characters are odd, then we need do (N+1)/2
788 * to compensate rounding off.
789 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
790 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
791 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530792 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700794 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800795 return -ENOMEM;
796 }
797
798 /* the buffer received from the upper layer is character buffer,
799 * we need to prepare the buffer taking 2 characters in to a U8 hex
800 * decimal number for example 7f0000f0...form a buffer to contain 7f
801 * in 0th location, 00 in 1st and f0 in 3rd location
802 */
803 for (i = 0, j = 0; j < *pBufLen; j += 2) {
804 if (j + 1 == *pBufLen) {
805 tempByte = hex_to_bin(inPtr[j]);
806 } else {
807 tempByte =
808 (hex_to_bin(inPtr[j]) << 4) |
809 (hex_to_bin(inPtr[j + 1]));
810 }
811 (*pBuf)[i++] = tempByte;
812 }
813 *pBufLen = i;
814 return 0;
815}
816
817/**
818 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
819 * @pValue: Pointer to input data (its a NULL terminated string)
820 * @pTargetApBssid: Pointer to target Ap bssid
821 * @pChannel: Pointer to the Target AP channel
822 *
823 * This function parses the reasoc command data passed in the format
824 * REASSOC<space><bssid><space><channel>
825 *
826 * Return: 0 for success non-zero for failure
827 */
828static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
829 uint8_t *pTargetApBssid,
830 uint8_t *pChannel)
831{
832 const uint8_t *inPtr = pValue;
833
834 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
835 return -EINVAL;
836
837 return 0;
838}
839
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840/**
841 * hdd_reassoc() - perform a userspace-directed reassoc
842 * @adapter: Adapter upon which the command was received
843 * @bssid: BSSID with which to reassociate
844 * @channel: channel upon which to reassociate
845 *
846 * This function performs a userspace-directed reassoc operation
847 *
848 * Return: 0 for success non-zero for failure
849 */
850static int
851hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
852 const uint8_t channel)
853{
854 hdd_station_ctx_t *pHddStaCtx;
855 int ret = 0;
856
Krunal Sonibe766b02016-03-10 13:00:44 -0800857 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800858 hdd_warn("Unsupported in mode %s(%d)",
859 hdd_device_mode_to_string(adapter->device_mode),
860 adapter->device_mode);
861 return -EINVAL;
862 }
863
864 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
865
866 /* if not associated, no need to proceed with reassoc */
867 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700868 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800869 ret = -EINVAL;
870 goto exit;
871 }
872
873 /*
874 * if the target bssid is same as currently associated AP,
875 * then no need to proceed with reassoc
876 */
877 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530878 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700879 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800880 ret = -EINVAL;
881 goto exit;
882 }
883
884 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530885 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800886 wlan_hdd_validate_operation_channel(adapter, channel)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700887 hdd_err("Invalid Channel %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 ret = -EINVAL;
889 goto exit;
890 }
891
892 /* Proceed with reassoc */
893 {
894 tCsrHandoffRequest handoffInfo;
895 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
896
897 handoffInfo.channel = channel;
898 handoffInfo.src = REASSOC;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530899 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800900 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
901 &handoffInfo);
902 }
903exit:
904 return ret;
905}
906
907/**
908 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
909 * @adapter: Adapter upon which the command was received
910 * @command: ASCII text command that was received
911 *
912 * This function parses the v1 REASSOC command with the format
913 *
914 * REASSOC xx:xx:xx:xx:xx:xx CH
915 *
916 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
917 * BSSID and CH is the ASCII representation of the channel. For
918 * example
919 *
920 * REASSOC 00:0a:0b:11:22:33 48
921 *
922 * Return: 0 for success non-zero for failure
923 */
924static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
925{
926 uint8_t channel = 0;
927 tSirMacAddr bssid;
928 int ret;
929
930 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
931 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700932 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933 } else {
934 ret = hdd_reassoc(adapter, bssid, channel);
935 }
936 return ret;
937}
938
939/**
940 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
941 * @adapter: Adapter upon which the command was received
942 * @command: Command that was received, ASCII command
943 * followed by binary data
944 *
945 * This function parses the v2 REASSOC command with the format
946 *
947 * REASSOC <android_wifi_reassoc_params>
948 *
949 * Return: 0 for success non-zero for failure
950 */
951static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
952{
953 struct android_wifi_reassoc_params params;
954 tSirMacAddr bssid;
955 int ret;
956
957 /* The params are located after "REASSOC " */
958 memcpy(&params, command + 8, sizeof(params));
959
960 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700961 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962 ret = -EINVAL;
963 } else {
964 ret = hdd_reassoc(adapter, bssid, params.channel);
965 }
966 return ret;
967}
968
969/**
970 * hdd_parse_reassoc() - parse the REASSOC command
971 * @adapter: Adapter upon which the command was received
972 * @command: Command that was received
973 *
974 * There are two different versions of the REASSOC command. Version 1
975 * of the command contains a parameter list that is ASCII characters
976 * whereas version 2 contains a combination of ASCII and binary
977 * payload. Determine if a version 1 or a version 2 command is being
978 * parsed by examining the parameters, and then dispatch the parser
979 * that is appropriate for the command.
980 *
981 * Return: 0 for success non-zero for failure
982 */
983static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
984{
985 int ret;
986
987 /* both versions start with "REASSOC "
988 * v1 has a bssid and channel # as an ASCII string
989 * REASSOC xx:xx:xx:xx:xx:xx CH
990 * v2 has a C struct
991 * REASSOC <binary c struct>
992 *
993 * The first field in the v2 struct is also the bssid in ASCII.
994 * But in the case of a v2 message the BSSID is NUL-terminated.
995 * Hence we can peek at that offset to see if this is V1 or V2
996 * REASSOC xx:xx:xx:xx:xx:xx*
997 * 1111111111222222
998 * 01234567890123456789012345
999 */
1000 if (command[25]) {
1001 ret = hdd_parse_reassoc_v1(adapter, command);
1002 } else {
1003 ret = hdd_parse_reassoc_v2(adapter, command);
1004 }
1005
1006 return ret;
1007}
1008
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001009/**
1010 * hdd_sendactionframe() - send a userspace-supplied action frame
1011 * @adapter: Adapter upon which the command was received
1012 * @bssid: BSSID target of the action frame
1013 * @channel: Channel upon which to send the frame
1014 * @dwell_time: Amount of time to dwell when the frame is sent
1015 * @payload_len:Length of the payload
1016 * @payload: Payload of the frame
1017 *
1018 * This function sends a userspace-supplied action frame
1019 *
1020 * Return: 0 for success non-zero for failure
1021 */
1022static int
1023hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1024 const uint8_t channel, const uint8_t dwell_time,
1025 const uint8_t payload_len, const uint8_t *payload)
1026{
1027 struct ieee80211_channel chan;
1028 uint8_t frame_len;
1029 uint8_t *frame;
1030 struct ieee80211_hdr_3addr *hdr;
1031 u64 cookie;
1032 hdd_station_ctx_t *pHddStaCtx;
1033 hdd_context_t *hdd_ctx;
1034 int ret = 0;
1035 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1036 (tpSirMacVendorSpecificFrameHdr) payload;
1037#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1038 struct cfg80211_mgmt_tx_params params;
1039#endif
1040
Krunal Sonibe766b02016-03-10 13:00:44 -08001041 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042 hdd_warn("Unsupported in mode %s(%d)",
1043 hdd_device_mode_to_string(adapter->device_mode),
1044 adapter->device_mode);
1045 return -EINVAL;
1046 }
1047
1048 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1049 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1050
1051 /* if not associated, no need to send action frame */
1052 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001053 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054 ret = -EINVAL;
1055 goto exit;
1056 }
1057
1058 /*
1059 * if the target bssid is different from currently associated AP,
1060 * then no need to send action frame
1061 */
1062 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301063 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001064 hdd_info("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 ret = -EINVAL;
1066 goto exit;
1067 }
1068
1069 chan.center_freq = sme_chn_to_freq(channel);
1070 /* Check if it is specific action frame */
1071 if (pVendorSpecific->category ==
1072 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1073 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301074 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001075 /*
1076 * if the channel number is different from operating
1077 * channel then no need to send action frame
1078 */
1079 if (channel != 0) {
1080 if (channel !=
1081 pHddStaCtx->conn_info.operationChannel) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001082 hdd_info("channel(%d) is different from operating channel(%d)",
1083 channel,
1084 pHddStaCtx->conn_info.
1085 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001086 ret = -EINVAL;
1087 goto exit;
1088 }
1089 /*
1090 * If channel number is specified and same
1091 * as home channel, ensure that action frame
1092 * is sent immediately by cancelling
1093 * roaming scans. Otherwise large dwell times
1094 * may cause long delays in sending action
1095 * frames.
1096 */
1097 sme_abort_roam_scan(hdd_ctx->hHal,
1098 adapter->sessionId);
1099 } else {
1100 /*
1101 * 0 is accepted as current home channel,
1102 * delayed transmission of action frame is ok.
1103 */
1104 chan.center_freq =
1105 sme_chn_to_freq(pHddStaCtx->conn_info.
1106 operationChannel);
1107 }
1108 }
1109 }
1110 if (chan.center_freq == 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001111 hdd_err("Invalid channel number %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001112 ret = -EINVAL;
1113 goto exit;
1114 }
1115
1116 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301117 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001119 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001120 ret = -ENOMEM;
1121 goto exit;
1122 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301123 qdf_mem_zero(frame, frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001124
1125 hdr = (struct ieee80211_hdr_3addr *)frame;
1126 hdr->frame_control =
1127 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301128 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1129 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301130 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301131 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1132 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133
1134#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1135 params.chan = &chan;
1136 params.offchan = 0;
1137 params.wait = dwell_time;
1138 params.buf = frame;
1139 params.len = frame_len;
1140 params.no_cck = 1;
1141 params.dont_wait_for_ack = 1;
1142 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1143#else
1144 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001146 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001147
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148 dwell_time, frame, frame_len, 1, 1, &cookie);
1149#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1150
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301151 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001152exit:
1153 return ret;
1154}
1155
1156/**
1157 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1158 * SENDACTIONFRAME command
1159 * @adapter: Adapter upon which the command was received
1160 * @command: ASCII text command that was received
1161 *
1162 * This function parses the v1 SENDACTIONFRAME command with the format
1163 *
1164 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1165 *
1166 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1167 * BSSID, CH is the ASCII representation of the channel, DW is the
1168 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1169 * payload. For example
1170 *
1171 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1172 *
1173 * Return: 0 for success non-zero for failure
1174 */
1175static int
1176hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1177{
1178 uint8_t channel = 0;
1179 uint8_t dwell_time = 0;
1180 uint8_t payload_len = 0;
1181 uint8_t *payload = NULL;
1182 tSirMacAddr bssid;
1183 int ret;
1184
1185 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1186 &dwell_time, &payload,
1187 &payload_len);
1188 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001189 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190 } else {
1191 ret = hdd_sendactionframe(adapter, bssid, channel,
1192 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301193 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001194 }
1195
1196 return ret;
1197}
1198
1199/**
1200 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1201 * SENDACTIONFRAME command
1202 * @adapter: Adapter upon which the command was received
1203 * @command: Command that was received, ASCII command
1204 * followed by binary data
1205 *
1206 * This function parses the v2 SENDACTIONFRAME command with the format
1207 *
1208 * SENDACTIONFRAME <android_wifi_af_params>
1209 *
1210 * Return: 0 for success non-zero for failure
1211 */
1212static int
1213hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter, const char *command)
1214{
1215 struct android_wifi_af_params *params;
1216 tSirMacAddr bssid;
1217 int ret;
1218
1219 /* params are large so keep off the stack */
1220 params = kmalloc(sizeof(*params), GFP_KERNEL);
1221 if (!params)
1222 return -ENOMEM;
1223
1224 /* The params are located after "SENDACTIONFRAME " */
1225 memcpy(params, command + 16, sizeof(*params));
1226
1227 if (!mac_pton(params->bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001228 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 ret = -EINVAL;
1230 } else {
1231 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1232 params->dwell_time, params->len,
1233 params->data);
1234 }
1235 kfree(params);
1236 return ret;
1237}
1238
1239/**
1240 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1241 * @adapter: Adapter upon which the command was received
1242 * @command: Command that was received
1243 *
1244 * There are two different versions of the SENDACTIONFRAME command.
1245 * Version 1 of the command contains a parameter list that is ASCII
1246 * characters whereas version 2 contains a combination of ASCII and
1247 * binary payload. Determine if a version 1 or a version 2 command is
1248 * being parsed by examining the parameters, and then dispatch the
1249 * parser that is appropriate for the version of the command.
1250 *
1251 * Return: 0 for success non-zero for failure
1252 */
1253static int
1254hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command)
1255{
1256 int ret;
1257
1258 /*
1259 * both versions start with "SENDACTIONFRAME "
1260 * v1 has a bssid and other parameters as an ASCII string
1261 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1262 * v2 has a C struct
1263 * SENDACTIONFRAME <binary c struct>
1264 *
1265 * The first field in the v2 struct is also the bssid in ASCII.
1266 * But in the case of a v2 message the BSSID is NUL-terminated.
1267 * Hence we can peek at that offset to see if this is V1 or V2
1268 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1269 * 111111111122222222223333
1270 * 0123456789012345678901234567890123
1271 */
1272 if (command[33]) {
1273 ret = hdd_parse_sendactionframe_v1(adapter, command);
1274 } else {
1275 ret = hdd_parse_sendactionframe_v2(adapter, command);
1276 }
1277
1278 return ret;
1279}
1280
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001281/**
1282 * hdd_parse_channellist() - HDD Parse channel list
1283 * @pValue: Pointer to input channel list
1284 * @ChannelList: Pointer to local output array to record
1285 * channel list
1286 * @pNumChannels: Pointer to number of roam scan channels
1287 *
1288 * This function parses the channel list passed in the format
1289 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1290 * if the Number of channels (N) does not match with the actual number
1291 * of channels passed then take the minimum of N and count of
1292 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1293 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1294 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1295 * removing duplicate channels from the list
1296 *
1297 * Return: 0 for success non-zero for failure
1298 */
1299static int
1300hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1301 uint8_t *pNumChannels)
1302{
1303 const uint8_t *inPtr = pValue;
1304 int tempInt;
1305 int j = 0;
1306 int v = 0;
1307 char buf[32];
1308
1309 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1310 /* no argument after the command */
1311 if (NULL == inPtr) {
1312 return -EINVAL;
1313 }
1314
1315 /* no space after the command */
1316 else if (SPACE_ASCII_VALUE != *inPtr) {
1317 return -EINVAL;
1318 }
1319
1320 /* remove empty spaces */
1321 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1322 inPtr++;
1323
1324 /* no argument followed by spaces */
1325 if ('\0' == *inPtr) {
1326 return -EINVAL;
1327 }
1328
1329 /* get the first argument ie the number of channels */
1330 v = sscanf(inPtr, "%31s ", buf);
1331 if (1 != v)
1332 return -EINVAL;
1333
1334 v = kstrtos32(buf, 10, &tempInt);
1335 if ((v < 0) ||
1336 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1337 return -EINVAL;
1338 }
1339
1340 *pNumChannels = tempInt;
1341
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001342 hdd_info("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001343
1344 for (j = 0; j < (*pNumChannels); j++) {
1345 /*
1346 * inPtr pointing to the beginning of first space after number
1347 * of channels
1348 */
1349 inPtr = strpbrk(inPtr, " ");
1350 /* no channel list after the number of channels argument */
1351 if (NULL == inPtr) {
1352 if (0 != j) {
1353 *pNumChannels = j;
1354 return 0;
1355 } else {
1356 return -EINVAL;
1357 }
1358 }
1359
1360 /* remove empty space */
1361 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1362 inPtr++;
1363
1364 /*
1365 * no channel list after the number of channels
1366 * argument and spaces
1367 */
1368 if ('\0' == *inPtr) {
1369 if (0 != j) {
1370 *pNumChannels = j;
1371 return 0;
1372 } else {
1373 return -EINVAL;
1374 }
1375 }
1376
1377 v = sscanf(inPtr, "%31s ", buf);
1378 if (1 != v)
1379 return -EINVAL;
1380
1381 v = kstrtos32(buf, 10, &tempInt);
1382 if ((v < 0) ||
1383 (tempInt <= 0) ||
1384 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1385 return -EINVAL;
1386 }
1387 pChannelList[j] = tempInt;
1388
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001389 hdd_info("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001390 pChannelList[j]);
1391 }
1392
1393 return 0;
1394}
1395
1396/**
1397 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1398 * SETROAMSCANCHANNELS command
1399 * @adapter: Adapter upon which the command was received
1400 * @command: ASCII text command that was received
1401 *
1402 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1403 *
1404 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1405 *
1406 * Where "N" is the ASCII representation of the number of channels and
1407 * C1 thru Cn is the ASCII representation of the channels. For example
1408 *
1409 * SETROAMSCANCHANNELS 4 36 40 44 48
1410 *
1411 * Return: 0 for success non-zero for failure
1412 */
1413static int
1414hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1415 const char *command)
1416{
1417 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1418 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301419 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001420 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1421 int ret;
1422
1423 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1424 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001425 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426 goto exit;
1427 }
1428
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301429 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001430 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1431 adapter->sessionId, num_chan));
1432
1433 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001434 hdd_err("number of channels (%d) supported exceeded max (%d)",
1435 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436 ret = -EINVAL;
1437 goto exit;
1438 }
1439
1440 status =
1441 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1442 adapter->sessionId,
1443 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301444 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001445 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446 ret = -EINVAL;
1447 goto exit;
1448 }
1449exit:
1450 return ret;
1451}
1452
1453/**
1454 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1455 * SETROAMSCANCHANNELS command
1456 * @adapter: Adapter upon which the command was received
1457 * @command: Command that was received, ASCII command
1458 * followed by binary data
1459 *
1460 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1461 *
1462 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1463 *
1464 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1465 * what follows the space is an array of u08 parameters. For example
1466 *
1467 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1468 *
1469 * Return: 0 for success non-zero for failure
1470 */
1471static int
1472hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1473 const char *command)
1474{
1475 const uint8_t *value;
1476 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1477 uint8_t channel;
1478 uint8_t num_chan;
1479 int i;
1480 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301481 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001482 int ret = 0;
1483
1484 /* array of values begins after "SETROAMSCANCHANNELS " */
1485 value = command + 20;
1486
1487 num_chan = *value++;
1488 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001489 hdd_err("number of channels (%d) supported exceeded max (%d)",
1490 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001491 ret = -EINVAL;
1492 goto exit;
1493 }
1494
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301495 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1497 adapter->sessionId, num_chan));
1498
1499 for (i = 0; i < num_chan; i++) {
1500 channel = *value++;
1501 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001502 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001503 i, channel);
1504 ret = -EINVAL;
1505 goto exit;
1506 }
1507 channel_list[i] = channel;
1508 }
1509 status =
1510 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1511 adapter->sessionId,
1512 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301513 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001514 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001515 ret = -EINVAL;
1516 goto exit;
1517 }
1518exit:
1519 return ret;
1520}
1521
1522/**
1523 * hdd_parse_set_roam_scan_channels() - parse the
1524 * SETROAMSCANCHANNELS command
1525 * @adapter: Adapter upon which the command was received
1526 * @command: Command that was received
1527 *
1528 * There are two different versions of the SETROAMSCANCHANNELS command.
1529 * Version 1 of the command contains a parameter list that is ASCII
1530 * characters whereas version 2 contains a binary payload. Determine
1531 * if a version 1 or a version 2 command is being parsed by examining
1532 * the parameters, and then dispatch the parser that is appropriate for
1533 * the command.
1534 *
1535 * Return: 0 for success non-zero for failure
1536 */
1537static int
1538hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1539{
1540 const char *cursor;
1541 char ch;
1542 bool v1;
1543 int ret;
1544
1545 /* start after "SETROAMSCANCHANNELS " */
1546 cursor = command + 20;
1547
1548 /* assume we have a version 1 command until proven otherwise */
1549 v1 = true;
1550
1551 /* v1 params will only contain ASCII digits and space */
1552 while ((ch = *cursor++) && v1) {
1553 if (!(isdigit(ch) || isspace(ch))) {
1554 v1 = false;
1555 }
1556 }
1557 if (v1) {
1558 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1559 } else {
1560 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1561 }
1562
1563 return ret;
1564}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001565
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001566#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001567/**
1568 * hdd_parse_plm_cmd() - HDD Parse Plm command
1569 * @pValue: Pointer to input data
1570 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1571 *
1572 * This function parses the plm command passed in the format
1573 * CCXPLMREQ<space><enable><space><dialog_token><space>
1574 * <meas_token><space><num_of_bursts><space><burst_int><space>
1575 * <measu duration><space><burst_len><space><desired_tx_pwr>
1576 * <space><multcast_addr><space><number_of_channels>
1577 * <space><channel_numbers>
1578 *
1579 * Return: 0 for success non-zero for failure
1580 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301581QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001582{
1583 uint8_t *cmdPtr = NULL;
1584 int count, content = 0, ret = 0;
1585 char buf[32];
1586
1587 /* move to argument list */
1588 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1589 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301590 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001591
1592 /* no space after the command */
1593 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301594 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001595
1596 /* remove empty spaces */
1597 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1598 cmdPtr++;
1599
1600 /* START/STOP PLM req */
1601 ret = sscanf(cmdPtr, "%31s ", buf);
1602 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301603 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001604
1605 ret = kstrtos32(buf, 10, &content);
1606 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301607 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608
1609 pPlmRequest->enable = content;
1610 cmdPtr = strpbrk(cmdPtr, " ");
1611
1612 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301613 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614
1615 /* remove empty spaces */
1616 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1617 cmdPtr++;
1618
1619 /* Dialog token of radio meas req containing meas reqIE */
1620 ret = sscanf(cmdPtr, "%31s ", buf);
1621 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301622 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001623
1624 ret = kstrtos32(buf, 10, &content);
1625 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301626 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001627
1628 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001629 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001630 cmdPtr = strpbrk(cmdPtr, " ");
1631
1632 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301633 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634
1635 /* remove empty spaces */
1636 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1637 cmdPtr++;
1638
1639 /* measurement token of meas req IE */
1640 ret = sscanf(cmdPtr, "%31s ", buf);
1641 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301642 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001643
1644 ret = kstrtos32(buf, 10, &content);
1645 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301646 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647
1648 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001649 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001650
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001651 hdd_err("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001652 if (pPlmRequest->enable) {
1653
1654 cmdPtr = strpbrk(cmdPtr, " ");
1655
1656 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301657 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658
1659 /* remove empty spaces */
1660 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1661 cmdPtr++;
1662
1663 /* total number of bursts after which STA stops sending */
1664 ret = sscanf(cmdPtr, "%31s ", buf);
1665 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301666 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001667
1668 ret = kstrtos32(buf, 10, &content);
1669 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301670 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001671
1672 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301673 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001674
1675 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001676 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001677 cmdPtr = strpbrk(cmdPtr, " ");
1678
1679 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301680 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001681
1682 /* remove empty spaces */
1683 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1684 cmdPtr++;
1685
1686 /* burst interval in seconds */
1687 ret = sscanf(cmdPtr, "%31s ", buf);
1688 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301689 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001690
1691 ret = kstrtos32(buf, 10, &content);
1692 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301693 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694
1695 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301696 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697
1698 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001699 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700 cmdPtr = strpbrk(cmdPtr, " ");
1701
1702 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301703 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001704
1705 /* remove empty spaces */
1706 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1707 cmdPtr++;
1708
1709 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1710 ret = sscanf(cmdPtr, "%31s ", buf);
1711 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301712 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001713
1714 ret = kstrtos32(buf, 10, &content);
1715 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301716 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001717
1718 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301719 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720
1721 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001722 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001723 cmdPtr = strpbrk(cmdPtr, " ");
1724
1725 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301726 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001727
1728 /* remove empty spaces */
1729 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1730 cmdPtr++;
1731
1732 /* burst length of PLM bursts */
1733 ret = sscanf(cmdPtr, "%31s ", buf);
1734 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301735 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736
1737 ret = kstrtos32(buf, 10, &content);
1738 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301739 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740
1741 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301742 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001743
1744 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001745 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001746 cmdPtr = strpbrk(cmdPtr, " ");
1747
1748 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301749 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001750
1751 /* remove empty spaces */
1752 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1753 cmdPtr++;
1754
1755 /* desired tx power for transmission of PLM bursts */
1756 ret = sscanf(cmdPtr, "%31s ", buf);
1757 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301758 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001759
1760 ret = kstrtos32(buf, 10, &content);
1761 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301762 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763
1764 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301765 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766
1767 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001768 hdd_debug("desiredTxPwr %d",
1769 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770
Anurag Chouhan6d760662016-02-20 16:05:43 +05301771 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001772 cmdPtr = strpbrk(cmdPtr, " ");
1773
1774 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301775 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001776
1777 /* remove empty spaces */
1778 while ((SPACE_ASCII_VALUE == *cmdPtr)
1779 && ('\0' != *cmdPtr))
1780 cmdPtr++;
1781
1782 ret = sscanf(cmdPtr, "%31s ", buf);
1783 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301784 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001785
1786 ret = kstrtos32(buf, 16, &content);
1787 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301788 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001790 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001791 }
1792
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001793 hdd_debug("MC addr " MAC_ADDRESS_STR,
1794 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001795
1796 cmdPtr = strpbrk(cmdPtr, " ");
1797
1798 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301799 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001800
1801 /* remove empty spaces */
1802 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1803 cmdPtr++;
1804
1805 /* number of channels */
1806 ret = sscanf(cmdPtr, "%31s ", buf);
1807 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301808 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001809
1810 ret = kstrtos32(buf, 10, &content);
1811 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301812 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001813
1814 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301815 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001816
1817 pPlmRequest->plmNumCh = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001818 hdd_debug("numch %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001819
1820 /* Channel numbers */
1821 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1822 cmdPtr = strpbrk(cmdPtr, " ");
1823
1824 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301825 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001826
1827 /* remove empty spaces */
1828 while ((SPACE_ASCII_VALUE == *cmdPtr)
1829 && ('\0' != *cmdPtr))
1830 cmdPtr++;
1831
1832 ret = sscanf(cmdPtr, "%31s ", buf);
1833 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301834 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835
1836 ret = kstrtos32(buf, 10, &content);
1837 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301838 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839
1840 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301841 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001842
1843 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001844 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001845 }
1846 }
1847 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301848 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001849}
1850#endif
1851
1852#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1853static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1854{
1855 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1856 int rc;
1857
1858 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301859 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001861 hdd_ctx->ext_wow_should_suspend = is_success;
1862 complete(&hdd_ctx->ready_to_extwow);
1863}
1864
1865static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1866 tpSirExtWoWParams arg_params)
1867{
1868 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301869 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1871 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1872 int rc;
1873
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301874 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001875
1876 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1877
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301878 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001879 &wlan_hdd_ready_to_extwow,
1880 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301881 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001882 hdd_err("sme_configure_ext_wow returned failure %d",
1883 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001884 return -EPERM;
1885 }
1886
1887 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1888 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1889 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001890 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891 return -EPERM;
1892 }
1893
1894 if (hdd_ctx->ext_wow_should_suspend) {
1895 if (hdd_ctx->config->extWowGotoSuspend) {
1896 pm_message_t state;
1897
1898 state.event = PM_EVENT_SUSPEND;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001899 hdd_info("Received ready to ExtWoW. Going to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900
1901 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1902 if (rc < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001903 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1904 rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001905 return rc;
1906 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301907 qdf_ret_status = wlan_hdd_bus_suspend(state);
1908 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001909 hdd_err("wlan_hdd_suspend failed, status = %d",
1910 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1912 return -EPERM;
1913 }
1914 }
1915 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001916 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001917 return -EPERM;
1918 }
1919
1920 return 0;
1921}
1922
1923static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1924 int value)
1925{
1926 tSirExtWoWParams params;
1927 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1928 int rc;
1929
1930 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301931 if (rc)
1932 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933
1934 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1935 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001936 hdd_err("Invalid type");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937 return -EINVAL;
1938 }
1939
1940 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1941 hdd_ctx->is_extwow_app_type1_param_set)
1942 params.type = value;
1943 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1944 hdd_ctx->is_extwow_app_type2_param_set)
1945 params.type = value;
1946 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1947 hdd_ctx->is_extwow_app_type1_param_set &&
1948 hdd_ctx->is_extwow_app_type2_param_set)
1949 params.type = value;
1950 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001951 hdd_err("Set app params before enable it value %d",
1952 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953 return -EINVAL;
1954 }
1955
1956 params.vdev_id = vdev_id;
1957 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1958 (hdd_ctx->config->extWowApp2WakeupPinNumber
1959 << 8);
1960
1961 return hdd_enable_ext_wow(adapter, &params);
1962}
1963
1964static int hdd_set_app_type1_params(tHalHandle hHal,
1965 tpSirAppType1Params arg_params)
1966{
1967 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301968 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001969
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301970 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001971
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301972 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1973 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001974 hdd_err("sme_configure_app_type1_params returned failure %d",
1975 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001976 return -EPERM;
1977 }
1978
1979 return 0;
1980}
1981
1982static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
1983 char *arg, int len)
1984{
1985 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1986 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1987 char id[20], password[20];
1988 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001989 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001990
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 (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001996 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001997 return -EINVAL;
1998 }
1999
2000 memset(&params, 0, sizeof(tSirAppType1Params));
2001 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302002 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003
2004 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302005 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302007 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002008
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002009 hdd_info("%d %pM %.8s %u %.16s %u",
2010 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 params.identification_id, params.id_length,
2012 params.password, params.pass_length);
2013
2014 return hdd_set_app_type1_params(hHal, &params);
2015}
2016
2017static int hdd_set_app_type2_params(tHalHandle hHal,
2018 tpSirAppType2Params arg_params)
2019{
2020 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302021 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002022
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302023 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302025 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2026 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002027 hdd_err("sme_configure_app_type2_params returned failure %d",
2028 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029 return -EPERM;
2030 }
2031
2032 return 0;
2033}
2034
2035static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2036 char *arg, int len)
2037{
2038 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2039 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2040 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302041 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042 tSirAppType2Params params;
2043 int ret;
2044
2045 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302046 if (ret)
2047 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048
2049 memset(&params, 0, sizeof(tSirAppType2Params));
2050
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302051 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 -08002052 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2053 (unsigned int *)&params.ip_device_ip,
2054 (unsigned int *)&params.ip_server_ip,
2055 (unsigned int *)&params.tcp_seq,
2056 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302057 (uint16_t *)&params.tcp_src_port,
2058 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002059 (unsigned int *)&params.keepalive_init,
2060 (unsigned int *)&params.keepalive_min,
2061 (unsigned int *)&params.keepalive_max,
2062 (unsigned int *)&params.keepalive_inc,
2063 (unsigned int *)&params.tcp_tx_timeout_val,
2064 (unsigned int *)&params.tcp_rx_timeout_val);
2065
2066 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002067 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068 return -EINVAL;
2069 }
2070
2071 if (6 !=
2072 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2073 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2074 &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002075 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 return -EINVAL;
2077 }
2078
2079 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2080 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002081 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002082 return -EINVAL;
2083 }
2084
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302085 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302086 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087
2088 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302089 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002090
2091 params.vdev_id = adapter->sessionId;
2092 params.tcp_src_port = (params.tcp_src_port != 0) ?
2093 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2094 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2095 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2096 params.keepalive_init = (params.keepalive_init != 0) ?
2097 params.keepalive_init : hdd_ctx->config->
2098 extWowApp2KAInitPingInterval;
2099 params.keepalive_min =
2100 (params.keepalive_min != 0) ?
2101 params.keepalive_min :
2102 hdd_ctx->config->extWowApp2KAMinPingInterval;
2103 params.keepalive_max =
2104 (params.keepalive_max != 0) ?
2105 params.keepalive_max :
2106 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2107 params.keepalive_inc =
2108 (params.keepalive_inc != 0) ?
2109 params.keepalive_inc :
2110 hdd_ctx->config->extWowApp2KAIncPingInterval;
2111 params.tcp_tx_timeout_val =
2112 (params.tcp_tx_timeout_val != 0) ?
2113 params.tcp_tx_timeout_val :
2114 hdd_ctx->config->extWowApp2TcpTxTimeout;
2115 params.tcp_rx_timeout_val =
2116 (params.tcp_rx_timeout_val != 0) ?
2117 params.tcp_rx_timeout_val :
2118 hdd_ctx->config->extWowApp2TcpRxTimeout;
2119
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002120 hdd_info("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2121 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002122 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2123 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2124 params.keepalive_init, params.keepalive_min,
2125 params.keepalive_max, params.keepalive_inc,
2126 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2127
2128 return hdd_set_app_type2_params(hHal, &params);
2129}
2130#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2131
2132/**
2133 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2134 * @pValue: Pointer to MAXTXPOWER command
2135 * @pDbm: Pointer to tx power
2136 *
2137 * This function parses the MAXTXPOWER command passed in the format
2138 * MAXTXPOWER<space>X(Tx power in dbm)
2139 *
2140 * For example input commands:
2141 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2142 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2143 *
2144 * Return: 0 for success non-zero for failure
2145 */
2146static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2147{
2148 uint8_t *inPtr = pValue;
2149 int tempInt;
2150 int v = 0;
2151 *pTxPower = 0;
2152
2153 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2154 /* no argument after the command */
2155 if (NULL == inPtr) {
2156 return -EINVAL;
2157 }
2158
2159 /* no space after the command */
2160 else if (SPACE_ASCII_VALUE != *inPtr) {
2161 return -EINVAL;
2162 }
2163
2164 /* remove empty spaces */
2165 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2166 inPtr++;
2167
2168 /* no argument followed by spaces */
2169 if ('\0' == *inPtr) {
2170 return 0;
2171 }
2172
2173 v = kstrtos32(inPtr, 10, &tempInt);
2174
2175 /* Range checking for passed parameter */
2176 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2177 return -EINVAL;
2178 }
2179
2180 *pTxPower = tempInt;
2181
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002182 hdd_info("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002183
2184 return 0;
2185} /* End of hdd_parse_setmaxtxpower_command */
2186
2187static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2188 char *extra, uint8_t n, uint8_t *len)
2189{
2190 int ret = 0;
2191
2192 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002193 hdd_err("argument passed for GETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 ret = -EINVAL;
2195 return ret;
2196 }
2197
2198 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2199 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2200 (int)pCfg->nActiveMaxChnTime);
2201 return ret;
2202 } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
2203 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2204 (int)pCfg->nActiveMinChnTime);
2205 return ret;
2206 } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
2207 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2208 (int)pCfg->nPassiveMaxChnTime);
2209 return ret;
2210 } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
2211 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2212 (int)pCfg->nPassiveMinChnTime);
2213 return ret;
2214 } else if (strncmp(command, "GETDWELLTIME", 12) == 0) {
2215 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2216 (int)pCfg->nActiveMaxChnTime);
2217 return ret;
2218 } else {
2219 ret = -EINVAL;
2220 }
2221
2222 return ret;
2223}
2224
2225static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2226{
2227 tHalHandle hHal;
2228 struct hdd_config *pCfg;
2229 uint8_t *value = command;
2230 tSmeConfigParams smeConfig;
2231 int val = 0, temp = 0;
2232
2233 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2234 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2235 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002236 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002237 return -EINVAL;
2238 }
2239
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302240 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002241 sme_get_config_param(hHal, &smeConfig);
2242
2243 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2244 value = value + 24;
2245 temp = kstrtou32(value, 10, &val);
2246 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2247 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002248 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002249 return -EFAULT;
2250 }
2251 pCfg->nActiveMaxChnTime = val;
2252 smeConfig.csrConfig.nActiveMaxChnTime = val;
2253 sme_update_config(hHal, &smeConfig);
2254 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2255 value = value + 24;
2256 temp = kstrtou32(value, 10, &val);
2257 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2258 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002259 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002260 return -EFAULT;
2261 }
2262 pCfg->nActiveMinChnTime = val;
2263 smeConfig.csrConfig.nActiveMinChnTime = val;
2264 sme_update_config(hHal, &smeConfig);
2265 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2266 value = value + 25;
2267 temp = kstrtou32(value, 10, &val);
2268 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2269 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002270 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002271 return -EFAULT;
2272 }
2273 pCfg->nPassiveMaxChnTime = val;
2274 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2275 sme_update_config(hHal, &smeConfig);
2276 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2277 value = value + 25;
2278 temp = kstrtou32(value, 10, &val);
2279 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2280 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002281 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002282 return -EFAULT;
2283 }
2284 pCfg->nPassiveMinChnTime = val;
2285 smeConfig.csrConfig.nPassiveMinChnTime = val;
2286 sme_update_config(hHal, &smeConfig);
2287 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2288 value = value + 13;
2289 temp = kstrtou32(value, 10, &val);
2290 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2291 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002292 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002293 return -EFAULT;
2294 }
2295 pCfg->nActiveMaxChnTime = val;
2296 smeConfig.csrConfig.nActiveMaxChnTime = val;
2297 sme_update_config(hHal, &smeConfig);
2298 } else {
2299 return -EINVAL;
2300 }
2301
2302 return 0;
2303}
2304
2305static void hdd_get_link_status_cb(uint8_t status, void *context)
2306{
2307 struct statsContext *pLinkContext;
2308 hdd_adapter_t *adapter;
2309
2310 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002311 hdd_err("Bad context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002312 return;
2313 }
2314
2315 pLinkContext = context;
2316 adapter = pLinkContext->pAdapter;
2317
2318 spin_lock(&hdd_context_lock);
2319
2320 if ((NULL == adapter) ||
2321 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2322 /*
2323 * the caller presumably timed out so there is
2324 * nothing we can do
2325 */
2326 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002327 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
2328 adapter, pLinkContext->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329 return;
2330 }
2331
2332 /* context is valid so caller is still waiting */
2333
2334 /* paranoia: invalidate the magic */
2335 pLinkContext->magic = 0;
2336
2337 /* copy over the status */
2338 adapter->linkStatus = status;
2339
2340 /* notify the caller */
2341 complete(&pLinkContext->completion);
2342
2343 /* serialization is complete */
2344 spin_unlock(&hdd_context_lock);
2345}
2346
2347/**
2348 * wlan_hdd_get_link_status() - get link status
2349 * @pAdapter: pointer to the adapter
2350 *
2351 * This function sends a request to query the link status and waits
2352 * on a timer to invoke the callback. if the callback is invoked then
2353 * latest link status shall be returned or otherwise cached value
2354 * will be returned.
2355 *
2356 * Return: On success, link status shall be returned.
2357 * On error or not associated, link status 0 will be returned.
2358 */
2359static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2360{
2361
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002362 hdd_station_ctx_t *pHddStaCtx =
2363 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2364 struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302365 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002366 unsigned long rc;
2367
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002368 if (cds_is_driver_recovering()) {
2369 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2370 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002371 return 0;
2372 }
2373
Krunal Sonibe766b02016-03-10 13:00:44 -08002374 if ((QDF_STA_MODE != adapter->device_mode) &&
2375 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002376 hdd_warn("Unsupported in mode %s(%d)",
2377 hdd_device_mode_to_string(adapter->device_mode),
2378 adapter->device_mode);
2379 return 0;
2380 }
2381
2382 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2383 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2384 /* If not associated, then expected link status return
2385 * value is 0
2386 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002387 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002388 return 0;
2389 }
2390
2391 init_completion(&context.completion);
2392 context.pAdapter = adapter;
2393 context.magic = LINK_STATUS_MAGIC;
2394 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2395 hdd_get_link_status_cb,
2396 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302397 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002398 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002399 /* return a cached value */
2400 } else {
2401 /* request is sent -- wait for the response */
2402 rc = wait_for_completion_timeout(&context.completion,
2403 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2404 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002405 hdd_err("SME timed out while retrieving link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002406 }
2407
2408 spin_lock(&hdd_context_lock);
2409 context.magic = 0;
2410 spin_unlock(&hdd_context_lock);
2411
2412 /* either callback updated adapter stats or it has cached data */
2413 return adapter->linkStatus;
2414}
2415
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002416static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2417{
2418 int payload_len;
2419 struct sk_buff *skb;
2420 struct nlmsghdr *nlh;
2421 uint8_t *data;
2422
2423 payload_len = ETH_ALEN;
2424
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002425 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002426 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002427 return;
2428 }
2429
2430 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2431 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002432 hdd_err("nlmsg_new() failed for msg size[%d]",
2433 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002434 return;
2435 }
2436
2437 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2438
2439 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002440 hdd_err("nlmsg_put() failed for msg size[%d]",
2441 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002442
2443 kfree_skb(skb);
2444 return;
2445 }
2446
2447 data = nlmsg_data(nlh);
2448 memcpy(data, MacAddr, ETH_ALEN);
2449
2450 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002451 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2452 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002453 }
2454
2455 return;
2456}
2457
2458
2459/**
2460 * hdd_ParseuserParams - return a pointer to the next argument
2461 * @pValue: Input argument string
2462 * @ppArg: Output pointer to the next argument
2463 *
2464 * This function parses argument stream and finds the pointer
2465 * to the next argument
2466 *
2467 * Return: 0 if the next argument found; -EINVAL otherwise
2468 */
2469static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2470{
2471 uint8_t *pVal;
2472
2473 pVal = strnchr(pValue, strlen(pValue), ' ');
2474
2475 if (NULL == pVal) {
2476 /* no argument remains */
2477 return -EINVAL;
2478 } else if (SPACE_ASCII_VALUE != *pVal) {
2479 /* no space after the current argument */
2480 return -EINVAL;
2481 }
2482
2483 pVal++;
2484
2485 /* remove empty spaces */
2486 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2487 pVal++;
2488 }
2489
2490 /* no argument followed by spaces */
2491 if ('\0' == *pVal) {
2492 return -EINVAL;
2493 }
2494
2495 *ppArg = pVal;
2496
2497 return 0;
2498}
2499
2500/**
2501 * hdd_parse_ibsstx_fail_event_params - Parse params
2502 * for SETIBSSTXFAILEVENT
2503 * @pValue: Input ibss tx fail event argument
2504 * @tx_fail_count: (Output parameter) Tx fail counter
2505 * @pid: (Output parameter) PID
2506 *
2507 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2508 */
2509static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2510 uint8_t *tx_fail_count,
2511 uint16_t *pid)
2512{
2513 uint8_t *param = NULL;
2514 int ret;
2515
2516 ret = hdd_parse_user_params(pValue, &param);
2517
2518 if (0 == ret && NULL != param) {
2519 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2520 ret = -EINVAL;
2521 goto done;
2522 }
2523 } else {
2524 goto done;
2525 }
2526
2527 if (0 == *tx_fail_count) {
2528 *pid = 0;
2529 goto done;
2530 }
2531
2532 pValue = param;
2533 pValue++;
2534
2535 ret = hdd_parse_user_params(pValue, &param);
2536
2537 if (0 == ret) {
2538 if (1 != sscanf(param, "%hu", pid)) {
2539 ret = -EINVAL;
2540 goto done;
2541 }
2542 } else {
2543 goto done;
2544 }
2545
2546done:
2547 return ret;
2548}
2549
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002550#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002551/**
2552 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2553 * @pValue: Pointer to data
2554 * @pEseBcnReq: Output pointer to store parsed ie information
2555 *
2556 * This function parses the ese beacon request passed in the format
2557 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2558 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2559 * <space>Scan Mode N<space>Meas Duration N
2560 *
2561 * If the Number of bcn req fields (N) does not match with the
2562 * actual number of fields passed then take N.
2563 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2564 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2565 * This function does not take care of removing duplicate channels from the
2566 * list
2567 *
2568 * Return: 0 for success non-zero for failure
2569 */
2570static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2571 tCsrEseBeaconReq *pEseBcnReq)
2572{
2573 uint8_t *inPtr = pValue;
2574 int tempInt = 0;
2575 int j = 0, i = 0, v = 0;
2576 char buf[32];
2577
2578 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2579 /* no argument after the command */
2580 if (NULL == inPtr) {
2581 return -EINVAL;
2582 }
2583 /* no space after the command */
2584 else if (SPACE_ASCII_VALUE != *inPtr) {
2585 return -EINVAL;
2586 }
2587
2588 /* remove empty spaces */
2589 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2590 inPtr++;
2591
2592 /* no argument followed by spaces */
2593 if ('\0' == *inPtr)
2594 return -EINVAL;
2595
2596 /* get the first argument ie measurement token */
2597 v = sscanf(inPtr, "%31s ", buf);
2598 if (1 != v)
2599 return -EINVAL;
2600
2601 v = kstrtos32(buf, 10, &tempInt);
2602 if (v < 0)
2603 return -EINVAL;
2604
2605 pEseBcnReq->numBcnReqIe = tempInt;
2606
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002607 hdd_info("Number of Bcn Req Ie fields(%d)",
2608 pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002609
2610 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2611 for (i = 0; i < 4; i++) {
2612 /*
2613 * inPtr pointing to the beginning of 1st space
2614 * after number of ie fields
2615 */
2616 inPtr = strpbrk(inPtr, " ");
2617 /* no ie data after the number of ie fields argument */
2618 if (NULL == inPtr)
2619 return -EINVAL;
2620
2621 /* remove empty space */
2622 while ((SPACE_ASCII_VALUE == *inPtr)
2623 && ('\0' != *inPtr))
2624 inPtr++;
2625
2626 /*
2627 * no ie data after the number of ie fields
2628 * argument and spaces
2629 */
2630 if ('\0' == *inPtr)
2631 return -EINVAL;
2632
2633 v = sscanf(inPtr, "%31s ", buf);
2634 if (1 != v)
2635 return -EINVAL;
2636
2637 v = kstrtos32(buf, 10, &tempInt);
2638 if (v < 0)
2639 return -EINVAL;
2640
2641 switch (i) {
2642 case 0: /* Measurement token */
2643 if (tempInt <= 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002644 hdd_err("Invalid Measurement Token(%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002645 tempInt);
2646 return -EINVAL;
2647 }
2648 pEseBcnReq->bcnReq[j].measurementToken =
2649 tempInt;
2650 break;
2651
2652 case 1: /* Channel number */
2653 if ((tempInt <= 0) ||
2654 (tempInt >
2655 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002656 hdd_err("Invalid Channel Number(%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002657 tempInt);
2658 return -EINVAL;
2659 }
2660 pEseBcnReq->bcnReq[j].channel = tempInt;
2661 break;
2662
2663 case 2: /* Scan mode */
2664 if ((tempInt < eSIR_PASSIVE_SCAN)
2665 || (tempInt > eSIR_BEACON_TABLE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002666 hdd_err("Invalid Scan Mode(%d) Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002667 tempInt);
2668 return -EINVAL;
2669 }
2670 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2671 break;
2672
2673 case 3: /* Measurement duration */
2674 if (((tempInt <= 0)
2675 && (pEseBcnReq->bcnReq[j].scanMode !=
2676 eSIR_BEACON_TABLE)) ||
2677 ((tempInt < 0) &&
2678 (pEseBcnReq->bcnReq[j].scanMode ==
2679 eSIR_BEACON_TABLE))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002680 hdd_err("Invalid Measurement Duration(%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002681 tempInt);
2682 return -EINVAL;
2683 }
2684 pEseBcnReq->bcnReq[j].measurementDuration =
2685 tempInt;
2686 break;
2687 }
2688 }
2689 }
2690
2691 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002692 hdd_info("Index(%d) Measurement Token(%u) Channel(%u) Scan Mode(%u) Measurement Duration(%u)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002693 j,
2694 pEseBcnReq->bcnReq[j].measurementToken,
2695 pEseBcnReq->bcnReq[j].channel,
2696 pEseBcnReq->bcnReq[j].scanMode,
2697 pEseBcnReq->bcnReq[j].measurementDuration);
2698 }
2699
2700 return 0;
2701}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002702
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002703/**
2704 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2705 * @pValue: Pointer to input data
2706 * @pCckmIe: Pointer to output cckm Ie
2707 * @pCckmIeLen: Pointer to output cckm ie length
2708 *
2709 * This function parses the SETCCKM IE command
2710 * SETCCKMIE<space><ie data>
2711 *
2712 * Return: 0 for success non-zero for failure
2713 */
2714static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2715 uint8_t *pCckmIeLen)
2716{
2717 uint8_t *inPtr = pValue;
2718 uint8_t *dataEnd;
2719 int j = 0;
2720 int i = 0;
2721 uint8_t tempByte = 0;
2722 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2723 /* no argument after the command */
2724 if (NULL == inPtr) {
2725 return -EINVAL;
2726 }
2727 /* no space after the command */
2728 else if (SPACE_ASCII_VALUE != *inPtr) {
2729 return -EINVAL;
2730 }
2731 /* remove empty spaces */
2732 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2733 inPtr++;
2734 /* no argument followed by spaces */
2735 if ('\0' == *inPtr) {
2736 return -EINVAL;
2737 }
2738 /* find the length of data */
2739 dataEnd = inPtr;
2740 while (('\0' != *dataEnd)) {
2741 dataEnd++;
2742 ++(*pCckmIeLen);
2743 }
2744 if (*pCckmIeLen <= 0)
2745 return -EINVAL;
2746 /*
2747 * Allocate the number of bytes based on the number of input characters
2748 * whether it is even or odd.
2749 * if the number of input characters are even, then we need N / 2 byte.
2750 * if the number of input characters are odd, then we need do
2751 * (N + 1) / 2 to compensate rounding off.
2752 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2753 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2754 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302755 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002756 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002757 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002758 return -ENOMEM;
2759 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302760 qdf_mem_zero(*pCckmIe, (*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002761 /*
2762 * the buffer received from the upper layer is character buffer,
2763 * we need to prepare the buffer taking 2 characters in to a U8 hex
2764 * decimal number for example 7f0000f0...form a buffer to contain
2765 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2766 */
2767 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2768 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2769 (hex_to_bin(inPtr[j + 1]));
2770 (*pCckmIe)[i++] = tempByte;
2771 }
2772 *pCckmIeLen = i;
2773 return 0;
2774}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002775#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002776
2777int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2778{
2779 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302780 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002781 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2782 struct hdd_config *pConfig = NULL;
2783
2784 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002785 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002786 return -EINVAL;
2787 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002788 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2789 (QDF_SAP_MODE != pAdapter->device_mode) &&
2790 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002791 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2792 hdd_device_mode_to_string(pAdapter->device_mode),
2793 pAdapter->device_mode);
2794 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002795 return -EINVAL;
2796 }
2797 pConfig = pHddCtx->config;
2798 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2799 rateUpdate.dev_mode = pAdapter->device_mode;
2800 rateUpdate.mcastDataRate24GHz = targetRate;
2801 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2802 rateUpdate.mcastDataRate5GHz = targetRate;
2803 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302804 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002805 hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
2806 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2807 hdd_device_mode_to_string(pAdapter->device_mode),
2808 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002809 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302810 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002811 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002812 return -EFAULT;
2813 }
2814 return 0;
2815}
2816
2817static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2818 hdd_context_t *hdd_ctx,
2819 uint8_t *command,
2820 uint8_t command_len,
2821 hdd_priv_data_t *priv_data)
2822{
2823 int ret = 0;
2824
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302825 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002826 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2827 adapter->sessionId,
2828 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2829 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2830 + 3) << 16 | *(hdd_ctx->
2831 p2pDeviceAddress.bytes + 4) << 8 |
2832 *(hdd_ctx->p2pDeviceAddress.bytes +
2833 5))));
2834
2835 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2836 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002837 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002838 ret = -EFAULT;
2839 }
2840
2841 return ret;
2842}
2843
2844/**
2845 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2846 * @adapter: Adapter on which the command was received
2847 * @hdd_ctx: HDD global context
2848 * @command: Entire driver command received from userspace
2849 * @command_len: Length of @command
2850 * @priv_data: Pointer to ioctl private data structure
2851 *
2852 * This is a trivial command hander function which simply forwards the
2853 * command to the actual command processor within the P2P module.
2854 *
2855 * Return: 0 on success, non-zero on failure
2856 */
2857static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2858 hdd_context_t *hdd_ctx,
2859 uint8_t *command,
2860 uint8_t command_len,
2861 hdd_priv_data_t *priv_data)
2862{
2863 return hdd_set_p2p_noa(adapter->dev, command);
2864}
2865
2866/**
2867 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2868 * @adapter: Adapter on which the command was received
2869 * @hdd_ctx: HDD global context
2870 * @command: Entire driver command received from userspace
2871 * @command_len: Length of @command
2872 * @priv_data: Pointer to ioctl private data structure
2873 *
2874 * This is a trivial command hander function which simply forwards the
2875 * command to the actual command processor within the P2P module.
2876 *
2877 * Return: 0 on success, non-zero on failure
2878 */
2879static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2880 hdd_context_t *hdd_ctx,
2881 uint8_t *command,
2882 uint8_t command_len,
2883 hdd_priv_data_t *priv_data)
2884{
2885 return hdd_set_p2p_opps(adapter->dev, command);
2886}
2887
2888static int drv_cmd_set_band(hdd_adapter_t *adapter,
2889 hdd_context_t *hdd_ctx,
2890 uint8_t *command,
2891 uint8_t command_len,
2892 hdd_priv_data_t *priv_data)
2893{
2894 int ret = 0;
2895
2896 uint8_t *ptr = command;
2897
2898 /* Change band request received */
2899
2900 /*
2901 * First 8 bytes will have "SETBAND " and
2902 * 9 byte will have band setting value
2903 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002904 hdd_info("SetBandCommand Info comm %s UL %d, TL %d",
2905 command, priv_data->used_len,
2906 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002907
2908 /* Change band request received */
2909 ret = hdd_set_band_helper(adapter->dev, ptr);
2910
2911 return ret;
2912}
2913
2914static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2915 hdd_context_t *hdd_ctx,
2916 uint8_t *command,
2917 uint8_t command_len,
2918 hdd_priv_data_t *priv_data)
2919{
2920 return hdd_wmmps_helper(adapter, command);
2921}
2922
2923static int drv_cmd_country(hdd_adapter_t *adapter,
2924 hdd_context_t *hdd_ctx,
2925 uint8_t *command,
2926 uint8_t command_len,
2927 hdd_priv_data_t *priv_data)
2928{
2929 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302930 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002931 unsigned long rc;
2932 char *country_code;
2933
2934 country_code = command + 8;
2935
2936 INIT_COMPLETION(adapter->change_country_code);
2937
2938 status = sme_change_country_code(hdd_ctx->hHal,
2939 wlan_hdd_change_country_code_callback,
2940 country_code,
2941 adapter,
2942 hdd_ctx->pcds_context,
2943 eSIR_TRUE,
2944 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302945 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002946 rc = wait_for_completion_timeout(
2947 &adapter->change_country_code,
2948 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
2949 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002950 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002951 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002952 hdd_err("SME Change Country code fail, status %d",
2953 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002954 ret = -EINVAL;
2955 }
2956
2957 return ret;
2958}
2959
2960static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
2961 hdd_context_t *hdd_ctx,
2962 uint8_t *command,
2963 uint8_t command_len,
2964 hdd_priv_data_t *priv_data)
2965{
2966 int ret = 0;
2967 uint8_t *value = command;
2968 int8_t rssi = 0;
2969 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302970 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002971
2972 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2973 value = value + command_len + 1;
2974
2975 /* Convert the value from ascii to integer */
2976 ret = kstrtos8(value, 10, &rssi);
2977 if (ret < 0) {
2978 /*
2979 * If the input value is greater than max value of datatype,
2980 * then also kstrtou8 fails
2981 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002982 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2983 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2984 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002985 ret = -EINVAL;
2986 goto exit;
2987 }
2988
2989 lookUpThreshold = abs(rssi);
2990
2991 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
2992 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002993 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002994 lookUpThreshold,
2995 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2996 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
2997 ret = -EINVAL;
2998 goto exit;
2999 }
3000
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303001 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003002 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3003 adapter->sessionId, lookUpThreshold));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003004 hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003005 lookUpThreshold);
3006
3007 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3008 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3009 adapter->sessionId,
3010 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303011 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003012 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003013 ret = -EPERM;
3014 goto exit;
3015 }
3016
3017exit:
3018 return ret;
3019}
3020
3021static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3022 hdd_context_t *hdd_ctx,
3023 uint8_t *command,
3024 uint8_t command_len,
3025 hdd_priv_data_t *priv_data)
3026{
3027 int ret = 0;
3028 uint8_t lookUpThreshold =
3029 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3030 int rssi = (-1) * lookUpThreshold;
3031 char extra[32];
3032 uint8_t len = 0;
3033
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303034 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003035 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3036 adapter->sessionId, lookUpThreshold));
3037
3038 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303039 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003040 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003041 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003042 ret = -EFAULT;
3043 }
3044
3045 return ret;
3046}
3047
3048static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3049 hdd_context_t *hdd_ctx,
3050 uint8_t *command,
3051 uint8_t command_len,
3052 hdd_priv_data_t *priv_data)
3053{
3054 int ret = 0;
3055 uint8_t *value = command;
3056 uint8_t roamScanPeriod = 0;
3057 uint16_t neighborEmptyScanRefreshPeriod =
3058 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3059
3060 /* input refresh period is in terms of seconds */
3061
3062 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3063 value = value + command_len + 1;
3064
3065 /* Convert the value from ascii to integer */
3066 ret = kstrtou8(value, 10, &roamScanPeriod);
3067 if (ret < 0) {
3068 /*
3069 * If the input value is greater than max value of datatype,
3070 * then also kstrtou8 fails
3071 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003072 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3073 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3074 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003075 ret = -EINVAL;
3076 goto exit;
3077 }
3078
3079 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3080 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003081 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3082 roamScanPeriod,
3083 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3084 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003085 ret = -EINVAL;
3086 goto exit;
3087 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303088 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003089 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3090 adapter->sessionId, roamScanPeriod));
3091 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3092
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003093 hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003094 roamScanPeriod);
3095
3096 hdd_ctx->config->nEmptyScanRefreshPeriod =
3097 neighborEmptyScanRefreshPeriod;
3098 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3099 adapter->sessionId,
3100 neighborEmptyScanRefreshPeriod);
3101
3102exit:
3103 return ret;
3104}
3105
3106static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3107 hdd_context_t *hdd_ctx,
3108 uint8_t *command,
3109 uint8_t command_len,
3110 hdd_priv_data_t *priv_data)
3111{
3112 int ret = 0;
3113 uint16_t nEmptyScanRefreshPeriod =
3114 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3115 char extra[32];
3116 uint8_t len = 0;
3117
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303118 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003119 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3120 adapter->sessionId,
3121 nEmptyScanRefreshPeriod));
3122 len = scnprintf(extra, sizeof(extra), "%s %d",
3123 "GETROAMSCANPERIOD",
3124 (nEmptyScanRefreshPeriod / 1000));
3125 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303126 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003127 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003128 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003129 ret = -EFAULT;
3130 }
3131
3132 return ret;
3133}
3134
3135static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3136 hdd_context_t *hdd_ctx,
3137 uint8_t *command,
3138 uint8_t command_len,
3139 hdd_priv_data_t *priv_data)
3140{
3141 int ret = 0;
3142 uint8_t *value = command;
3143 uint8_t roamScanRefreshPeriod = 0;
3144 uint16_t neighborScanRefreshPeriod =
3145 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3146
3147 /* input refresh period is in terms of seconds */
3148 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3149 value = value + command_len + 1;
3150
3151 /* Convert the value from ascii to integer */
3152 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3153 if (ret < 0) {
3154 /*
3155 * If the input value is greater than max value of datatype,
3156 * then also kstrtou8 fails
3157 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003158 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3159 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3160 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003161 ret = -EINVAL;
3162 goto exit;
3163 }
3164
3165 if ((roamScanRefreshPeriod <
3166 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3167 || (roamScanRefreshPeriod >
3168 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003169 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3170 roamScanRefreshPeriod,
3171 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3172 / 1000),
3173 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3174 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003175 ret = -EINVAL;
3176 goto exit;
3177 }
3178 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3179
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003180 hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003181 roamScanRefreshPeriod);
3182
3183 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3184 neighborScanRefreshPeriod;
3185 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3186 adapter->sessionId,
3187 neighborScanRefreshPeriod);
3188
3189exit:
3190 return ret;
3191}
3192
3193static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3194 hdd_context_t *hdd_ctx,
3195 uint8_t *command,
3196 uint8_t command_len,
3197 hdd_priv_data_t *priv_data)
3198{
3199 int ret = 0;
3200 uint16_t value =
3201 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3202 char extra[32];
3203 uint8_t len = 0;
3204
3205 len = scnprintf(extra, sizeof(extra), "%s %d",
3206 "GETROAMSCANREFRESHPERIOD",
3207 (value / 1000));
3208 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303209 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003210 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003211 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003212 ret = -EFAULT;
3213 }
3214
3215 return ret;
3216}
3217
3218static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3219 hdd_context_t *hdd_ctx,
3220 uint8_t *command,
3221 uint8_t command_len,
3222 hdd_priv_data_t *priv_data)
3223{
3224 int ret = 0;
3225 uint8_t *value = command;
3226 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3227
3228 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3229 value = value + SIZE_OF_SETROAMMODE + 1;
3230
3231 /* Convert the value from ascii to integer */
3232 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3233 if (ret < 0) {
3234 /*
3235 * If the input value is greater than max value of datatype,
3236 * then also kstrtou8 fails
3237 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003238 hdd_err("kstrtou8 failed range [%d - %d]",
3239 CFG_LFR_FEATURE_ENABLED_MIN,
3240 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003241 ret = -EINVAL;
3242 goto exit;
3243 }
3244 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3245 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003246 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3247 roamMode,
3248 CFG_LFR_FEATURE_ENABLED_MIN,
3249 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003250 ret = -EINVAL;
3251 goto exit;
3252 }
3253
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003254 hdd_debug("Received Command to Set Roam Mode = %d",
3255 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003256 /*
3257 * Note that
3258 * SETROAMMODE 0 is to enable LFR while
3259 * SETROAMMODE 1 is to disable LFR, but
3260 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3261 * enable/disable. So, we have to invert the value
3262 * to call sme_update_is_fast_roam_ini_feature_enabled.
3263 */
3264 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3265 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3266 else
3267 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3268
3269 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3270 if (roamMode) {
3271 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3272 sme_update_roam_scan_offload_enabled(
3273 (tHalHandle)(hdd_ctx->hHal),
3274 hdd_ctx->config->isRoamOffloadScanEnabled);
3275 sme_update_is_fast_roam_ini_feature_enabled(
3276 hdd_ctx->hHal,
3277 adapter->sessionId,
3278 roamMode);
3279 } else {
3280 sme_update_is_fast_roam_ini_feature_enabled(
3281 hdd_ctx->hHal,
3282 adapter->sessionId,
3283 roamMode);
3284 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3285 sme_update_roam_scan_offload_enabled(
3286 (tHalHandle)(hdd_ctx->hHal),
3287 hdd_ctx->config->isRoamOffloadScanEnabled);
3288 }
3289
3290
3291exit:
3292 return ret;
3293}
3294
3295static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3296 hdd_context_t *hdd_ctx,
3297 uint8_t *command,
3298 uint8_t command_len,
3299 hdd_priv_data_t *priv_data)
3300{
3301 int ret = 0;
3302 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3303 char extra[32];
3304 uint8_t len = 0;
3305
3306 /*
3307 * roamMode value shall be inverted because the sementics is different.
3308 */
3309 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3310 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3311 else
3312 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3313
3314 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303315 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003316 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003317 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003318 ret = -EFAULT;
3319 }
3320
3321 return ret;
3322}
3323
3324static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3325 hdd_context_t *hdd_ctx,
3326 uint8_t *command,
3327 uint8_t command_len,
3328 hdd_priv_data_t *priv_data)
3329{
3330 int ret = 0;
3331 uint8_t *value = command;
3332 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3333
3334 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3335 value = value + command_len + 1;
3336
3337 /* Convert the value from ascii to integer */
3338 ret = kstrtou8(value, 10, &roamRssiDiff);
3339 if (ret < 0) {
3340 /*
3341 * If the input value is greater than max value of datatype,
3342 * then also kstrtou8 fails
3343 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003344 hdd_err("kstrtou8 failed range [%d - %d]",
3345 CFG_ROAM_RSSI_DIFF_MIN,
3346 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003347 ret = -EINVAL;
3348 goto exit;
3349 }
3350
3351 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3352 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003353 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3354 roamRssiDiff,
3355 CFG_ROAM_RSSI_DIFF_MIN,
3356 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003357 ret = -EINVAL;
3358 goto exit;
3359 }
3360
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003361 hdd_info("Received Command to Set roam rssi diff = %d",
3362 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003363
3364 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3365 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3366 adapter->sessionId,
3367 roamRssiDiff);
3368
3369exit:
3370 return ret;
3371}
3372
3373static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3374 hdd_context_t *hdd_ctx,
3375 uint8_t *command,
3376 uint8_t command_len,
3377 hdd_priv_data_t *priv_data)
3378{
3379 int ret = 0;
3380 uint8_t roamRssiDiff =
3381 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3382 char extra[32];
3383 uint8_t len = 0;
3384
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303385 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003386 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3387 adapter->sessionId, roamRssiDiff));
3388
3389 len = scnprintf(extra, sizeof(extra), "%s %d",
3390 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303391 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003392
3393 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003394 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003395 ret = -EFAULT;
3396 }
3397
3398 return ret;
3399}
3400
3401static int drv_cmd_get_band(hdd_adapter_t *adapter,
3402 hdd_context_t *hdd_ctx,
3403 uint8_t *command,
3404 uint8_t command_len,
3405 hdd_priv_data_t *priv_data)
3406{
3407 int ret = 0;
3408 int band = -1;
3409 char extra[32];
3410 uint8_t len = 0;
3411
3412 hdd_get_band_helper(hdd_ctx, &band);
3413
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303414 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003415 TRACE_CODE_HDD_GETBAND_IOCTL,
3416 adapter->sessionId, band));
3417
3418 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303419 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003420
3421 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003422 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423 ret = -EFAULT;
3424 }
3425
3426 return ret;
3427}
3428
3429static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3430 hdd_context_t *hdd_ctx,
3431 uint8_t *command,
3432 uint8_t command_len,
3433 hdd_priv_data_t *priv_data)
3434{
3435 return hdd_parse_set_roam_scan_channels(adapter, command);
3436}
3437
3438static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3439 hdd_context_t *hdd_ctx,
3440 uint8_t *command,
3441 uint8_t command_len,
3442 hdd_priv_data_t *priv_data)
3443{
3444 int ret = 0;
3445 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3446 uint8_t numChannels = 0;
3447 uint8_t j = 0;
3448 char extra[128] = { 0 };
3449 int len;
3450
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303451 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3453 ChannelList,
3454 &numChannels,
3455 adapter->sessionId)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003456 hdd_alert("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457 ret = -EFAULT;
3458 goto exit;
3459 }
3460
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303461 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003462 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3463 adapter->sessionId, numChannels));
3464 /*
3465 * output channel list is of the format
3466 * [Number of roam scan channels][Channel1][Channel2]...
3467 * copy the number of channels in the 0th index
3468 */
3469 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3470 numChannels);
3471 for (j = 0; (j < numChannels); j++)
3472 len += scnprintf(extra + len, sizeof(extra) - len,
3473 " %d", ChannelList[j]);
3474
Anurag Chouhan6d760662016-02-20 16:05:43 +05303475 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003476 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003477 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003478 ret = -EFAULT;
3479 goto exit;
3480 }
3481
3482exit:
3483 return ret;
3484}
3485
3486static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3487 hdd_context_t *hdd_ctx,
3488 uint8_t *command,
3489 uint8_t command_len,
3490 hdd_priv_data_t *priv_data)
3491{
3492 int ret = 0;
3493 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3494 char extra[32];
3495 uint8_t len = 0;
3496
3497 /*
3498 * Check if the features OKC/ESE/11R are supported simultaneously,
3499 * then this operation is not permitted (return FAILURE)
3500 */
3501 if (eseMode &&
3502 hdd_is_okc_mode_enabled(hdd_ctx) &&
3503 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003504 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003505 ret = -EPERM;
3506 goto exit;
3507 }
3508
3509 len = scnprintf(extra, sizeof(extra), "%s %d",
3510 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303511 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003512 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003513 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003514 ret = -EFAULT;
3515 goto exit;
3516 }
3517
3518exit:
3519 return ret;
3520}
3521
3522static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3523 hdd_context_t *hdd_ctx,
3524 uint8_t *command,
3525 uint8_t command_len,
3526 hdd_priv_data_t *priv_data)
3527{
3528 int ret = 0;
3529 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3530 char extra[32];
3531 uint8_t len = 0;
3532
3533 /*
3534 * Check if the features OKC/ESE/11R are supported simultaneously,
3535 * then this operation is not permitted (return FAILURE)
3536 */
3537 if (okcMode &&
3538 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3539 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003540 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003541 ret = -EPERM;
3542 goto exit;
3543 }
3544
3545 len = scnprintf(extra, sizeof(extra), "%s %d",
3546 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303547 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003548
3549 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003550 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003551 ret = -EFAULT;
3552 goto exit;
3553 }
3554
3555exit:
3556 return ret;
3557}
3558
3559static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3560 hdd_context_t *hdd_ctx,
3561 uint8_t *command,
3562 uint8_t command_len,
3563 hdd_priv_data_t *priv_data)
3564{
3565 int ret = 0;
3566 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3567 char extra[32];
3568 uint8_t len = 0;
3569
3570 len = scnprintf(extra, sizeof(extra), "%s %d",
3571 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303572 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003573
3574 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003575 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003576 ret = -EFAULT;
3577 }
3578
3579 return ret;
3580}
3581
3582static int drv_cmd_get_fast_transition(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 ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3590 char extra[32];
3591 uint8_t len = 0;
3592
3593 len = scnprintf(extra, sizeof(extra), "%s %d",
3594 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303595 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003596
3597 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003598 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003599 ret = -EFAULT;
3600 }
3601
3602 return ret;
3603}
3604
3605static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3606 hdd_context_t *hdd_ctx,
3607 uint8_t *command,
3608 uint8_t command_len,
3609 hdd_priv_data_t *priv_data)
3610{
3611 int ret = 0;
3612 uint8_t *value = command;
3613 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3614
3615 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3616 value = value + command_len + 1;
3617
3618 /* Convert the value from ascii to integer */
3619 ret = kstrtou8(value, 10, &minTime);
3620 if (ret < 0) {
3621 /*
3622 * If the input value is greater than max value of datatype,
3623 * then also kstrtou8 fails
3624 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003625 hdd_err("kstrtou8 failed range [%d - %d]",
3626 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3627 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003628 ret = -EINVAL;
3629 goto exit;
3630 }
3631
3632 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3633 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003634 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3635 minTime,
3636 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3637 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638 ret = -EINVAL;
3639 goto exit;
3640 }
3641
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303642 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003643 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3644 adapter->sessionId, minTime));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003645 hdd_info("Received Command to change channel min time = %d",
3646 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003647
3648 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3649 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3650 minTime,
3651 adapter->sessionId);
3652
3653exit:
3654 return ret;
3655}
3656
3657static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3658 hdd_context_t *hdd_ctx,
3659 uint8_t *command,
3660 uint8_t command_len,
3661 hdd_priv_data_t *priv_data)
3662{
3663 return hdd_parse_sendactionframe(adapter, command);
3664}
3665
3666static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3667 hdd_context_t *hdd_ctx,
3668 uint8_t *command,
3669 uint8_t command_len,
3670 hdd_priv_data_t *priv_data)
3671{
3672 int ret = 0;
3673 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3674 adapter->sessionId);
3675 char extra[32];
3676 uint8_t len = 0;
3677
3678 /* value is interms of msec */
3679 len = scnprintf(extra, sizeof(extra), "%s %d",
3680 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303681 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003682
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303683 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3685 adapter->sessionId, val));
3686
3687 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003688 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003689 ret = -EFAULT;
3690 }
3691
3692 return ret;
3693}
3694
3695static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3696 hdd_context_t *hdd_ctx,
3697 uint8_t *command,
3698 uint8_t command_len,
3699 hdd_priv_data_t *priv_data)
3700{
3701 int ret = 0;
3702 uint8_t *value = command;
3703 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3704
3705 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3706 value = value + command_len + 1;
3707
3708 /* Convert the value from ascii to integer */
3709 ret = kstrtou16(value, 10, &maxTime);
3710 if (ret < 0) {
3711 /*
3712 * If the input value is greater than max value of datatype,
3713 * then also kstrtou8 fails
3714 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003715 hdd_err("kstrtou16 failed range [%d - %d]",
3716 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3717 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003718 ret = -EINVAL;
3719 goto exit;
3720 }
3721
3722 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3723 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003724 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3725 maxTime,
3726 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3727 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003728 ret = -EINVAL;
3729 goto exit;
3730 }
3731
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003732 hdd_info("Received Command to change channel max time = %d",
3733 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003734
3735 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3736 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3737 adapter->sessionId,
3738 maxTime);
3739
3740exit:
3741 return ret;
3742}
3743
3744static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3745 hdd_context_t *hdd_ctx,
3746 uint8_t *command,
3747 uint8_t command_len,
3748 hdd_priv_data_t *priv_data)
3749{
3750 int ret = 0;
3751 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3752 adapter->sessionId);
3753 char extra[32];
3754 uint8_t len = 0;
3755
3756 /* value is interms of msec */
3757 len = scnprintf(extra, sizeof(extra), "%s %d",
3758 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303759 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003760
3761 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003762 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003763 ret = -EFAULT;
3764 }
3765
3766 return ret;
3767}
3768
3769static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3770 hdd_context_t *hdd_ctx,
3771 uint8_t *command,
3772 uint8_t command_len,
3773 hdd_priv_data_t *priv_data)
3774{
3775 int ret = 0;
3776 uint8_t *value = command;
3777 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3778
3779 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3780 value = value + command_len + 1;
3781
3782 /* Convert the value from ascii to integer */
3783 ret = kstrtou16(value, 10, &val);
3784 if (ret < 0) {
3785 /*
3786 * If the input value is greater than max value of datatype,
3787 * then also kstrtou8 fails
3788 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003789 hdd_err("kstrtou16 failed range [%d - %d]",
3790 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3791 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003792 ret = -EINVAL;
3793 goto exit;
3794 }
3795
3796 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3797 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003798 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3799 val,
3800 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3801 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003802 ret = -EINVAL;
3803 goto exit;
3804 }
3805
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003806 hdd_info("Received Command to change scan home time = %d",
3807 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003808
3809 hdd_ctx->config->nNeighborScanPeriod = val;
3810 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3811 adapter->sessionId, val);
3812
3813exit:
3814 return ret;
3815}
3816
3817static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3818 hdd_context_t *hdd_ctx,
3819 uint8_t *command,
3820 uint8_t command_len,
3821 hdd_priv_data_t *priv_data)
3822{
3823 int ret = 0;
3824 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3825 adapter->
3826 sessionId);
3827 char extra[32];
3828 uint8_t len = 0;
3829
3830 /* value is interms of msec */
3831 len = scnprintf(extra, sizeof(extra), "%s %d",
3832 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303833 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003834
3835 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003836 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003837 ret = -EFAULT;
3838 }
3839
3840 return ret;
3841}
3842
3843static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3844 hdd_context_t *hdd_ctx,
3845 uint8_t *command,
3846 uint8_t command_len,
3847 hdd_priv_data_t *priv_data)
3848{
3849 int ret = 0;
3850 uint8_t *value = command;
3851 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3852
3853 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3854 value = value + command_len + 1;
3855
3856 /* Convert the value from ascii to integer */
3857 ret = kstrtou8(value, 10, &val);
3858 if (ret < 0) {
3859 /*
3860 * If the input value is greater than max value of datatype,
3861 * then also kstrtou8 fails
3862 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003863 hdd_err("kstrtou8 failed range [%d - %d]",
3864 CFG_ROAM_INTRA_BAND_MIN,
3865 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003866 ret = -EINVAL;
3867 goto exit;
3868 }
3869
3870 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3871 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003872 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3873 val,
3874 CFG_ROAM_INTRA_BAND_MIN,
3875 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003876 ret = -EINVAL;
3877 goto exit;
3878 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003879 hdd_info("Received Command to change intra band = %d",
3880 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003881
3882 hdd_ctx->config->nRoamIntraBand = val;
3883 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3884
3885exit:
3886 return ret;
3887}
3888
3889static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3890 hdd_context_t *hdd_ctx,
3891 uint8_t *command,
3892 uint8_t command_len,
3893 hdd_priv_data_t *priv_data)
3894{
3895 int ret = 0;
3896 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3897 char extra[32];
3898 uint8_t len = 0;
3899
3900 /* value is interms of msec */
3901 len = scnprintf(extra, sizeof(extra), "%s %d",
3902 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303903 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003904 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003905 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003906 ret = -EFAULT;
3907 }
3908
3909 return ret;
3910}
3911
3912static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3913 hdd_context_t *hdd_ctx,
3914 uint8_t *command,
3915 uint8_t command_len,
3916 hdd_priv_data_t *priv_data)
3917{
3918 int ret = 0;
3919 uint8_t *value = command;
3920 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3921
3922 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3923 value = value + command_len + 1;
3924
3925 /* Convert the value from ascii to integer */
3926 ret = kstrtou8(value, 10, &nProbes);
3927 if (ret < 0) {
3928 /*
3929 * If the input value is greater than max value of datatype,
3930 * then also kstrtou8 fails
3931 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003932 hdd_err("kstrtou8 failed range [%d - %d]",
3933 CFG_ROAM_SCAN_N_PROBES_MIN,
3934 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003935 ret = -EINVAL;
3936 goto exit;
3937 }
3938
3939 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3940 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003941 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3942 nProbes,
3943 CFG_ROAM_SCAN_N_PROBES_MIN,
3944 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003945 ret = -EINVAL;
3946 goto exit;
3947 }
3948
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003949 hdd_info("Received Command to Set nProbes = %d",
3950 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003951
3952 hdd_ctx->config->nProbes = nProbes;
3953 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3954 adapter->sessionId, nProbes);
3955
3956exit:
3957 return ret;
3958}
3959
3960static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3961 hdd_context_t *hdd_ctx,
3962 uint8_t *command,
3963 uint8_t command_len,
3964 hdd_priv_data_t *priv_data)
3965{
3966 int ret = 0;
3967 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3968 char extra[32];
3969 uint8_t len = 0;
3970
3971 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303972 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003973 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003974 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003975 ret = -EFAULT;
3976 }
3977
3978 return ret;
3979}
3980
3981static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
3982 hdd_context_t *hdd_ctx,
3983 uint8_t *command,
3984 uint8_t command_len,
3985 hdd_priv_data_t *priv_data)
3986{
3987 int ret = 0;
3988 uint8_t *value = command;
3989 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3990
3991 /* input value is in units of msec */
3992
3993 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3994 value = value + command_len + 1;
3995
3996 /* Convert the value from ascii to integer */
3997 ret = kstrtou16(value, 10, &homeAwayTime);
3998 if (ret < 0) {
3999 /*
4000 * If the input value is greater than max value of datatype,
4001 * then also kstrtou8 fails
4002 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004003 hdd_err("kstrtou8 failed range [%d - %d]",
4004 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4005 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004006 ret = -EINVAL;
4007 goto exit;
4008 }
4009
4010 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4011 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004012 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004013 homeAwayTime,
4014 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4015 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4016 ret = -EINVAL;
4017 goto exit;
4018 }
4019
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004020 hdd_info("Received Command to Set scan away time = %d",
4021 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004022
4023 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4024 homeAwayTime) {
4025 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4026 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4027 adapter->sessionId,
4028 homeAwayTime,
4029 true);
4030 }
4031
4032exit:
4033 return ret;
4034}
4035
4036static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4037 hdd_context_t *hdd_ctx,
4038 uint8_t *command,
4039 uint8_t command_len,
4040 hdd_priv_data_t *priv_data)
4041{
4042 int ret = 0;
4043 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4044 char extra[32];
4045 uint8_t len = 0;
4046
4047 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304048 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004049
4050 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004051 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004052 ret = -EFAULT;
4053 }
4054
4055 return ret;
4056}
4057
4058static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4059 hdd_context_t *hdd_ctx,
4060 uint8_t *command,
4061 uint8_t command_len,
4062 hdd_priv_data_t *priv_data)
4063{
4064 return hdd_parse_reassoc(adapter, command);
4065}
4066
4067static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4068 hdd_context_t *hdd_ctx,
4069 uint8_t *command,
4070 uint8_t command_len,
4071 hdd_priv_data_t *priv_data)
4072{
4073 int ret = 0;
4074 uint8_t *value = command;
4075 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4076
4077 /* Move pointer to ahead of SETWESMODE<delimiter> */
4078 value = value + command_len + 1;
4079
4080 /* Convert the value from ascii to integer */
4081 ret = kstrtou8(value, 10, &wesMode);
4082 if (ret < 0) {
4083 /*
4084 * If the input value is greater than max value of datatype,
4085 * then also kstrtou8 fails
4086 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004087 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004088 CFG_ENABLE_WES_MODE_NAME_MIN,
4089 CFG_ENABLE_WES_MODE_NAME_MAX);
4090 ret = -EINVAL;
4091 goto exit;
4092 }
4093
4094 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4095 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004096 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004097 wesMode,
4098 CFG_ENABLE_WES_MODE_NAME_MIN,
4099 CFG_ENABLE_WES_MODE_NAME_MAX);
4100 ret = -EINVAL;
4101 goto exit;
4102 }
4103
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004104 hdd_info("Received Command to Set WES Mode rssi diff = %d",
4105 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004106
4107 hdd_ctx->config->isWESModeEnabled = wesMode;
4108 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4109
4110exit:
4111 return ret;
4112}
4113
4114static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4115 hdd_context_t *hdd_ctx,
4116 uint8_t *command,
4117 uint8_t command_len,
4118 hdd_priv_data_t *priv_data)
4119{
4120 int ret = 0;
4121 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4122 char extra[32];
4123 uint8_t len = 0;
4124
4125 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304126 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004127 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004128 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004129 ret = -EFAULT;
4130 }
4131
4132 return ret;
4133}
4134
4135static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4136 hdd_context_t *hdd_ctx,
4137 uint8_t *command,
4138 uint8_t command_len,
4139 hdd_priv_data_t *priv_data)
4140{
4141 int ret = 0;
4142 uint8_t *value = command;
4143 uint8_t nOpportunisticThresholdDiff =
4144 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4145
4146 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4147 value = value + command_len + 1;
4148
4149 /* Convert the value from ascii to integer */
4150 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4151 if (ret < 0) {
4152 /*
4153 * If the input value is greater than max value of datatype,
4154 * then also kstrtou8 fails
4155 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004156 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004157 ret = -EINVAL;
4158 goto exit;
4159 }
4160
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004161 hdd_info("Received Command to Set Opportunistic Threshold diff = %d",
4162 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004163
4164 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4165 adapter->sessionId,
4166 nOpportunisticThresholdDiff);
4167
4168exit:
4169 return ret;
4170}
4171
4172static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4173 hdd_context_t *hdd_ctx,
4174 uint8_t *command,
4175 uint8_t command_len,
4176 hdd_priv_data_t *priv_data)
4177{
4178 int ret = 0;
4179 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4180 hdd_ctx->hHal);
4181 char extra[32];
4182 uint8_t len = 0;
4183
4184 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304185 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004186 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004187 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004188 ret = -EFAULT;
4189 }
4190
4191 return ret;
4192}
4193
4194static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4195 hdd_context_t *hdd_ctx,
4196 uint8_t *command,
4197 uint8_t command_len,
4198 hdd_priv_data_t *priv_data)
4199{
4200 int ret = 0;
4201 uint8_t *value = command;
4202 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4203
4204 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4205 value = value + command_len + 1;
4206
4207 /* Convert the value from ascii to integer */
4208 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4209 if (ret < 0) {
4210 /*
4211 * If the input value is greater than max value of datatype,
4212 * then also kstrtou8 fails
4213 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004214 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004215 ret = -EINVAL;
4216 goto exit;
4217 }
4218
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004219 hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d",
4220 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004221
4222 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4223 adapter->sessionId,
4224 nRoamRescanRssiDiff);
4225
4226exit:
4227 return ret;
4228}
4229
4230static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4231 hdd_context_t *hdd_ctx,
4232 uint8_t *command,
4233 uint8_t command_len,
4234 hdd_priv_data_t *priv_data)
4235{
4236 int ret = 0;
4237 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4238 char extra[32];
4239 uint8_t len = 0;
4240
4241 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304242 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004243 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004244 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004245 ret = -EFAULT;
4246 }
4247
4248 return ret;
4249}
4250
4251static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4252 hdd_context_t *hdd_ctx,
4253 uint8_t *command,
4254 uint8_t command_len,
4255 hdd_priv_data_t *priv_data)
4256{
4257 int ret = 0;
4258 uint8_t *value = command;
4259 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4260
4261 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4262 value = value + command_len + 1;
4263
4264 /* Convert the value from ascii to integer */
4265 ret = kstrtou8(value, 10, &lfrMode);
4266 if (ret < 0) {
4267 /*
4268 * If the input value is greater than max value of datatype,
4269 * then also kstrtou8 fails
4270 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004271 hdd_err("kstrtou8 failed range [%d - %d]",
4272 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004273 CFG_LFR_FEATURE_ENABLED_MAX);
4274 ret = -EINVAL;
4275 goto exit;
4276 }
4277
4278 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4279 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004280 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004281 lfrMode,
4282 CFG_LFR_FEATURE_ENABLED_MIN,
4283 CFG_LFR_FEATURE_ENABLED_MAX);
4284 ret = -EINVAL;
4285 goto exit;
4286 }
4287
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004288 hdd_info("Received Command to change lfr mode = %d",
4289 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004290
4291 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4292 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4293 adapter->
4294 sessionId,
4295 lfrMode);
4296
4297exit:
4298 return ret;
4299}
4300
4301static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4302 hdd_context_t *hdd_ctx,
4303 uint8_t *command,
4304 uint8_t command_len,
4305 hdd_priv_data_t *priv_data)
4306{
4307 int ret = 0;
4308 uint8_t *value = command;
4309 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4310
4311 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4312 value = value + command_len + 1;
4313
4314 /* Convert the value from ascii to integer */
4315 ret = kstrtou8(value, 10, &ft);
4316 if (ret < 0) {
4317 /*
4318 * If the input value is greater than max value of datatype,
4319 * then also kstrtou8 fails
4320 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004321 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004322 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4323 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4324 ret = -EINVAL;
4325 goto exit;
4326 }
4327
4328 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4329 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004330 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004331 ft,
4332 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4333 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4334 ret = -EINVAL;
4335 goto exit;
4336 }
4337
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004338 hdd_info("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004339
4340 hdd_ctx->config->isFastTransitionEnabled = ft;
4341 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4342
4343exit:
4344 return ret;
4345}
4346
4347#ifdef WLAN_FEATURE_ROAM_OFFLOAD
4348static void hdd_wma_send_fastreassoc_cmd(int sessionId, tSirMacAddr bssid,
4349 int channel)
4350{
4351 struct wma_roam_invoke_cmd *fastreassoc;
4352 cds_msg_t msg = {0};
4353
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304354 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355 if (NULL == fastreassoc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004356 hdd_err("qdf_mem_malloc failed for fastreassoc");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004357 return;
4358 }
4359 fastreassoc->vdev_id = sessionId;
4360 fastreassoc->channel = channel;
4361 fastreassoc->bssid[0] = bssid[0];
4362 fastreassoc->bssid[1] = bssid[1];
4363 fastreassoc->bssid[2] = bssid[2];
4364 fastreassoc->bssid[3] = bssid[3];
4365 fastreassoc->bssid[4] = bssid[4];
4366 fastreassoc->bssid[5] = bssid[5];
4367
4368 msg.type = SIR_HAL_ROAM_INVOKE;
4369 msg.reserved = 0;
4370 msg.bodyptr = fastreassoc;
Anurag Chouhan6d760662016-02-20 16:05:43 +05304371 if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004372 &msg)) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304373 qdf_mem_free(fastreassoc);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004374 hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004375 }
4376}
Varun Reddy Yeturubbbbe232016-02-29 14:01:57 -08004377#else
4378static inline void hdd_wma_send_fastreassoc_cmd(int sessionId,
4379 tSirMacAddr bssid, int channel)
4380{}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004381#endif
4382static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4383 hdd_context_t *hdd_ctx,
4384 uint8_t *command,
4385 uint8_t command_len,
4386 hdd_priv_data_t *priv_data)
4387{
4388 int ret = 0;
4389 uint8_t *value = command;
4390 uint8_t channel = 0;
4391 tSirMacAddr targetApBssid;
4392 uint32_t roamId = 0;
4393 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004394 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004395 hdd_station_ctx_t *pHddStaCtx;
4396
Krunal Sonibe766b02016-03-10 13:00:44 -08004397 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004398 hdd_warn("Unsupported in mode %s(%d)",
4399 hdd_device_mode_to_string(adapter->device_mode),
4400 adapter->device_mode);
4401 return -EINVAL;
4402 }
4403
4404 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4405
4406 /* if not associated, no need to proceed with reassoc */
4407 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004408 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004409 ret = -EINVAL;
4410 goto exit;
4411 }
4412
4413 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4414 &channel);
4415 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004416 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417 goto exit;
4418 }
4419
4420 /*
4421 * if the target bssid is same as currently associated AP,
4422 * issue reassoc to same AP
4423 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304424 if (true != qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004425 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304426 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 /* Reassoc to same AP, only supported for Open Security*/
4428 if ((pHddStaCtx->conn_info.ucEncryptionType ||
4429 pHddStaCtx->conn_info.mcEncryptionType)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004430 hdd_err("Reassoc to same AP, only supported for Open Security");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431 return -ENOTSUPP;
4432 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004433 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004434 sme_get_modify_profile_fields(hdd_ctx->hHal, adapter->sessionId,
4435 &modProfileFields);
4436 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4437 NULL, modProfileFields, &roamId, 1);
4438 return 0;
4439 }
4440
4441 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304442 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443 wlan_hdd_validate_operation_channel(adapter, channel)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004444 hdd_err("Invalid Channel [%d]", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004445 return -EINVAL;
4446 }
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004447 if (roaming_offload_enabled(hdd_ctx)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004448 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4449 targetApBssid, (int)channel);
4450 goto exit;
4451 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004452 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004453 handoffInfo.channel = channel;
4454 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004455 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004456 sizeof(tSirMacAddr));
4457 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4458 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004459exit:
4460 return ret;
4461}
4462
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004463static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4464 hdd_context_t *hdd_ctx,
4465 uint8_t *command,
4466 uint8_t command_len,
4467 hdd_priv_data_t *priv_data)
4468{
4469 int ret = 0;
4470 uint8_t *value = command;
4471 uint8_t roamScanControl = 0;
4472
4473 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4474 value = value + command_len + 1;
4475
4476 /* Convert the value from ascii to integer */
4477 ret = kstrtou8(value, 10, &roamScanControl);
4478 if (ret < 0) {
4479 /*
4480 * If the input value is greater than max value of datatype,
4481 * then also kstrtou8 fails
4482 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004483 hdd_err("kstrtou8 failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484 ret = -EINVAL;
4485 goto exit;
4486 }
4487
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004488 hdd_info("Received Command to Set roam scan control = %d",
4489 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004490
4491 if (0 != roamScanControl) {
4492 ret = 0; /* return success but ignore param value "true" */
4493 goto exit;
4494 }
4495
4496 sme_set_roam_scan_control(hdd_ctx->hHal,
4497 adapter->sessionId,
4498 roamScanControl);
4499
4500exit:
4501 return ret;
4502}
4503
4504static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4505 hdd_context_t *hdd_ctx,
4506 uint8_t *command,
4507 uint8_t command_len,
4508 hdd_priv_data_t *priv_data)
4509{
4510 int ret = 0;
4511 uint8_t *value = command;
4512 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4513
4514 /*
4515 * Check if the features OKC/ESE/11R are supported simultaneously,
4516 * then this operation is not permitted (return FAILURE)
4517 */
4518 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4519 hdd_is_okc_mode_enabled(hdd_ctx) &&
4520 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004521 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004522 ret = -EPERM;
4523 goto exit;
4524 }
4525
4526 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4527 value = value + command_len + 1;
4528
4529 /* Convert the value from ascii to integer */
4530 ret = kstrtou8(value, 10, &okcMode);
4531 if (ret < 0) {
4532 /*
4533 * If the input value is greater than max value of datatype,
4534 * then also kstrtou8 fails
4535 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004536 hdd_err("kstrtou8 failed range [%d - %d]",
4537 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004538 CFG_OKC_FEATURE_ENABLED_MAX);
4539 ret = -EINVAL;
4540 goto exit;
4541 }
4542
4543 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4544 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004545 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004546 okcMode,
4547 CFG_OKC_FEATURE_ENABLED_MIN,
4548 CFG_OKC_FEATURE_ENABLED_MAX);
4549 ret = -EINVAL;
4550 goto exit;
4551 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004552 hdd_info("Received Command to change okc mode = %d",
4553 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004554
4555 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4556
4557exit:
4558 return ret;
4559}
4560
4561static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4562 hdd_context_t *hdd_ctx,
4563 uint8_t *command,
4564 uint8_t command_len,
4565 hdd_priv_data_t *priv_data)
4566{
4567 int ret = 0;
4568 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4569 char extra[32];
4570 uint8_t len = 0;
4571
4572 len = scnprintf(extra, sizeof(extra), "%s %d",
4573 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304574 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004575 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004576 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004577 ret = -EFAULT;
4578 }
4579
4580 return ret;
4581}
4582
4583static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4584 hdd_context_t *hdd_ctx,
4585 uint8_t *command,
4586 uint8_t command_len,
4587 hdd_priv_data_t *priv_data)
4588{
4589 int ret = 0;
4590 char *bcMode;
4591
4592 bcMode = command + 11;
4593 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004594 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004595 hdd_ctx->btCoexModeSet = true;
4596 ret = wlan_hdd_scan_abort(adapter);
4597 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004598 hdd_err("Failed to abort existing scan status: %d",
4599 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004600 }
4601 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004602 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004603 hdd_ctx->btCoexModeSet = false;
4604 }
4605
4606 return ret;
4607}
4608
4609static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4610 hdd_context_t *hdd_ctx,
4611 uint8_t *command,
4612 uint8_t command_len,
4613 hdd_priv_data_t *priv_data)
4614{
4615 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4616 return 0;
4617}
4618
4619static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4620 hdd_context_t *hdd_ctx,
4621 uint8_t *command,
4622 uint8_t command_len,
4623 hdd_priv_data_t *priv_data)
4624{
4625 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4626 return 0;
4627}
4628
4629static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4630 hdd_context_t *hdd_ctx,
4631 uint8_t *command,
4632 uint8_t command_len,
4633 hdd_priv_data_t *priv_data)
4634{
4635 int ret = 0;
4636 struct hdd_config *pCfg =
4637 (WLAN_HDD_GET_CTX(adapter))->config;
4638 char extra[32];
4639 uint8_t len = 0;
4640
4641 memset(extra, 0, sizeof(extra));
4642 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304643 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004645 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004646 ret = -EFAULT;
4647 goto exit;
4648 }
4649 ret = len;
4650exit:
4651 return ret;
4652}
4653
4654static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4655 hdd_context_t *hdd_ctx,
4656 uint8_t *command,
4657 uint8_t command_len,
4658 hdd_priv_data_t *priv_data)
4659{
4660 return hdd_set_dwell_time(adapter, command);
4661}
4662
4663static int drv_cmd_miracast(hdd_adapter_t *adapter,
4664 hdd_context_t *hdd_ctx,
4665 uint8_t *command,
4666 uint8_t command_len,
4667 hdd_priv_data_t *priv_data)
4668{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304669 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004670 int ret = 0;
4671 tHalHandle hHal;
4672 uint8_t filterType = 0;
4673 hdd_context_t *pHddCtx = NULL;
4674 uint8_t *value;
4675
4676 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304677 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004678 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004679
4680 hHal = pHddCtx->hHal;
4681 value = command + 9;
4682
4683 /* Convert the value from ascii to integer */
4684 ret = kstrtou8(value, 10, &filterType);
4685 if (ret < 0) {
4686 /*
4687 * If the input value is greater than max value of datatype,
4688 * then also kstrtou8 fails
4689 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004690 hdd_err("kstrtou8 failed range ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004691 ret = -EINVAL;
4692 goto exit;
4693 }
4694 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4695 || (filterType >
4696 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004697 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004698 ret = -EINVAL;
4699 goto exit;
4700 }
4701 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4702 pHddCtx->miracast_value = filterType;
4703
4704 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304705 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004706 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707 return -EBUSY;
4708 }
4709
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004710 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004711 return cds_set_mas(adapter, filterType);
4712
4713exit:
4714 return ret;
4715}
4716
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004717/* Function header is left blank intentionally */
4718static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4719 int32_t *oui_length, int32_t limit)
4720{
4721 uint8_t len;
4722 uint8_t data;
4723
4724 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4725 command++;
4726 limit--;
4727 }
4728
4729 len = 2;
4730
4731 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4732 (limit > 1)) {
4733 sscanf(command, "%02x", (unsigned int *)&data);
4734 ie[len++] = data;
4735 command += 2;
4736 limit -= 2;
4737 }
4738
4739 *oui_length = len - 2;
4740
4741 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4742 command++;
4743 limit--;
4744 }
4745
4746 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4747 (limit > 1)) {
4748 sscanf(command, "%02x", (unsigned int *)&data);
4749 ie[len++] = data;
4750 command += 2;
4751 limit -= 2;
4752 }
4753
4754 ie[0] = IE_EID_VENDOR;
4755 ie[1] = len - 2;
4756
4757 return len;
4758}
4759
4760/**
4761 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4762 * @adapter: Pointer to adapter
4763 * @hdd_ctx: Pointer to HDD context
4764 * @command: Pointer to command string
4765 * @command_len : Command length
4766 * @priv_data : Pointer to priv data
4767 *
4768 * Return:
4769 * int status code
4770 */
4771static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4772 hdd_context_t *hdd_ctx,
4773 uint8_t *command,
4774 uint8_t command_len,
4775 hdd_priv_data_t *priv_data)
4776{
4777 int i = 0;
4778 int status;
4779 int ret = 0;
4780 uint8_t *ibss_ie;
4781 int32_t oui_length = 0;
4782 uint32_t ibss_ie_length;
4783 uint8_t *value = command;
4784 tSirModifyIE ibssModifyIE;
4785 tCsrRoamProfile *pRoamProfile;
4786 hdd_wext_state_t *pWextState;
4787
4788
Krunal Sonibe766b02016-03-10 13:00:44 -08004789 if (QDF_IBSS_MODE != adapter->device_mode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004790 hdd_info("Device_mode %s(%d) not IBSS",
4791 hdd_device_mode_to_string(adapter->device_mode),
4792 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004793 return ret;
4794 }
4795
4796 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4797
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004798 hdd_info("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004799
4800
4801 /* validate argument of command */
4802 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004803 hdd_err("No arguments in command length %zu",
4804 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004805 ret = -EFAULT;
4806 goto exit;
4807 }
4808
4809 /* moving to arguments of commands */
4810 value = value + command_len;
4811 command_len = strlen(value);
4812
4813 /* oui_data can't be less than 3 bytes */
4814 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004815 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4816 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004817 ret = -EFAULT;
4818 goto exit;
4819 }
4820
4821 ibss_ie = qdf_mem_malloc(command_len);
4822 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004823 hdd_err("Could not allocate memory for command length %d",
4824 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004825 ret = -ENOMEM;
4826 goto exit;
4827 }
4828 qdf_mem_zero(ibss_ie, command_len);
4829
4830 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4831 &oui_length,
4832 command_len);
4833 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004834 hdd_err("Could not parse command %s return length %d",
4835 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004836 ret = -EFAULT;
4837 qdf_mem_free(ibss_ie);
4838 goto exit;
4839 }
4840
4841 pRoamProfile = &pWextState->roamProfile;
4842
4843 qdf_copy_macaddr(&ibssModifyIE.bssid,
4844 pRoamProfile->BSSIDs.bssid);
4845
4846 ibssModifyIE.smeSessionId = adapter->sessionId;
4847 ibssModifyIE.notify = true;
4848 ibssModifyIE.ieID = IE_EID_VENDOR;
4849 ibssModifyIE.ieIDLen = ibss_ie_length;
4850 ibssModifyIE.ieBufferlength = ibss_ie_length;
4851 ibssModifyIE.pIEBuffer = ibss_ie;
4852 ibssModifyIE.oui_length = oui_length;
4853
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004854 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4855 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004856 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004857 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004858
4859 /* Probe Bcn modification */
4860 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4861 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4862
4863 /* Populating probe resp frame */
4864 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4865 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4866
4867 qdf_mem_free(ibss_ie);
4868
4869 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4870 adapter->sessionId);
4871 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004872 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004873 status);
4874 ret = -EINVAL;
4875 goto exit;
4876 }
4877
4878exit:
4879 return ret;
4880}
4881
4882static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4883 hdd_context_t *hdd_ctx,
4884 uint8_t *command,
4885 uint8_t command_len,
4886 hdd_priv_data_t *priv_data)
4887{
4888 int ret = 0;
4889 uint8_t *value = command;
4890 uint8_t ucRmcEnable = 0;
4891 int status;
4892
Krunal Sonibe766b02016-03-10 13:00:44 -08004893 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4894 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004895 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4896 hdd_device_mode_to_string(adapter->device_mode),
4897 adapter->device_mode);
4898 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004899 ret = -EINVAL;
4900 goto exit;
4901 }
4902
4903 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4904 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004905 hdd_err("Invalid SETRMCENABLE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004906 ret = -EINVAL;
4907 goto exit;
4908 }
4909
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004910 hdd_info("ucRmcEnable %d ", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004911
4912 if (true == ucRmcEnable) {
4913 status = sme_enable_rmc((tHalHandle)
4914 (hdd_ctx->hHal),
4915 adapter->sessionId);
4916 } else if (false == ucRmcEnable) {
4917 status = sme_disable_rmc((tHalHandle)
4918 (hdd_ctx->hHal),
4919 adapter->sessionId);
4920 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004921 hdd_err("Invalid SETRMCENABLE command %d",
4922 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004923 ret = -EINVAL;
4924 goto exit;
4925 }
4926
4927 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004928 hdd_err("SETRMC %d failed status %d",
4929 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004930 ret = -EINVAL;
4931 goto exit;
4932 }
4933
4934exit:
4935 return ret;
4936}
4937
4938static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4939 hdd_context_t *hdd_ctx,
4940 uint8_t *command,
4941 uint8_t command_len,
4942 hdd_priv_data_t *priv_data)
4943{
4944 int ret = 0;
4945 uint8_t *value = command;
4946 uint32_t uActionPeriod = 0;
4947 int status;
4948
Krunal Sonibe766b02016-03-10 13:00:44 -08004949 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4950 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004951 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004952 hdd_device_mode_to_string(adapter->device_mode),
4953 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004954 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004955 ret = -EINVAL;
4956 goto exit;
4957 }
4958
4959 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4960 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004961 hdd_err("Invalid SETRMCACTIONPERIOD command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004962 ret = -EINVAL;
4963 goto exit;
4964 }
4965
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004966 hdd_info("uActionPeriod %d ",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004967 uActionPeriod);
4968
4969 if (sme_cfg_set_int(hdd_ctx->hHal,
4970 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4971 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004972 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4973 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004974 ret = -EINVAL;
4975 goto exit;
4976 }
4977
4978 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4979 adapter->sessionId);
4980 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004981 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004982 status);
4983 ret = -EINVAL;
4984 goto exit;
4985 }
4986
4987exit:
4988 return ret;
4989}
4990
4991static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
4992 hdd_context_t *hdd_ctx,
4993 uint8_t *command,
4994 uint8_t command_len,
4995 hdd_priv_data_t *priv_data)
4996{
4997 int ret = 0;
4998 int status = QDF_STATUS_SUCCESS;
4999 hdd_station_ctx_t *pHddStaCtx = NULL;
5000 char *extra = NULL;
5001 int idx = 0;
5002 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005003 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005004 uint32_t numOfBytestoPrint = 0;
5005
Krunal Sonibe766b02016-03-10 13:00:44 -08005006 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005007 hdd_warn("Unsupported in mode %s(%d)",
5008 hdd_device_mode_to_string(adapter->device_mode),
5009 adapter->device_mode);
5010 return -EINVAL;
5011 }
5012
5013 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005014 hdd_info("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005015
5016 /* Handle the command */
5017 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5018 if (QDF_STATUS_SUCCESS == status) {
5019 /*
5020 * The variable extra needed to be allocated on the heap since
5021 * amount of memory required to copy the data for 32 devices
5022 * exceeds the size of 1024 bytes of default stack size. On
5023 * 64 bit devices, the default max stack size of 2048 bytes
5024 */
5025 extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL);
5026
5027 if (NULL == extra) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005028 hdd_err("kmalloc failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005029 ret = -EINVAL;
5030 goto exit;
5031 }
5032
5033 /* Copy number of stations */
5034 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005035 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005036 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005037 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5038 idx++) {
5039 int8_t rssi;
5040 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005041
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005042 qdf_mem_copy(mac_addr,
5043 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5044 mac_addr, sizeof(mac_addr));
5045
5046 tx_rate =
5047 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5048 txRate;
5049 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5050 rssi;
5051
5052 length += scnprintf((extra + length),
5053 WLAN_MAX_BUF_SIZE - length,
5054 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5055 mac_addr[0], mac_addr[1], mac_addr[2],
5056 mac_addr[3], mac_addr[4], mac_addr[5],
5057 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005058 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005059 * cdf_trace_msg has limitation of 512 bytes for the
5060 * print buffer. Hence printing the data in two chunks.
5061 * The first chunk will have the data for 16 devices
5062 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005063 */
5064 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5065 numOfBytestoPrint = length;
5066 }
5067
5068 /*
5069 * Copy the data back into buffer, if the data to copy is
5070 * more than 512 bytes than we will split the data and do
5071 * it in two shots
5072 */
5073 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005074 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005075 ret = -EFAULT;
5076 goto exit;
5077 }
5078
5079 priv_data->buf[numOfBytestoPrint] = '\0';
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005080 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005081
5082 if (length > numOfBytestoPrint) {
5083 if (copy_to_user
5084 (priv_data->buf + numOfBytestoPrint,
5085 extra + numOfBytestoPrint,
5086 length - numOfBytestoPrint + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005087 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005088 ret = -EFAULT;
5089 goto exit;
5090 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005091 hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005092 }
5093
5094 /* Free temporary buffer */
5095 kfree(extra);
5096 } else {
5097 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005098 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5099 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005100 ret = -EINVAL;
5101 goto exit;
5102 }
5103 ret = 0;
5104
5105exit:
5106 return ret;
5107}
5108
5109/* Peer Info <Peer Addr> command */
5110static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5111 hdd_context_t *hdd_ctx,
5112 uint8_t *command,
5113 uint8_t command_len,
5114 hdd_priv_data_t *priv_data)
5115{
5116 int ret = 0;
5117 uint8_t *value = command;
5118 QDF_STATUS status;
5119 hdd_station_ctx_t *pHddStaCtx = NULL;
5120 char extra[128] = { 0 };
5121 uint32_t length = 0;
5122 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005123 struct qdf_mac_addr peerMacAddr;
5124
Krunal Sonibe766b02016-03-10 13:00:44 -08005125 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005126 hdd_warn("Unsupported in mode %s(%d)",
5127 hdd_device_mode_to_string(adapter->device_mode),
5128 adapter->device_mode);
5129 return -EINVAL;
5130 }
5131
5132 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5133
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005134 hdd_info("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005135
5136 /* if there are no peers, no need to continue with the command */
5137 if (eConnectionState_IbssConnected !=
5138 pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005139 hdd_info("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005140 ret = -EINVAL;
5141 goto exit;
5142 }
5143
5144 /* Parse the incoming command buffer */
5145 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5146 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005147 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005148 ret = -EINVAL;
5149 goto exit;
5150 }
5151
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005152 /* Get station index for the peer mac address and sanitize it */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005153 hdd_ibss_get_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
5154
5155 if (staIdx > MAX_IBSS_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005156 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005157 ret = -EINVAL;
5158 goto exit;
5159 }
5160
5161 /* Handle the command */
5162 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5163 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005164 uint32_t txRate =
5165 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005166
5167 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005168 (int)txRate,
5169 (int)pHddStaCtx->ibss_peer_info.
5170 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005171
5172 /* Copy the data back into buffer */
5173 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005174 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005175 ret = -EFAULT;
5176 goto exit;
5177 }
5178 } else {
5179 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005180 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5181 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005182 ret = -EINVAL;
5183 goto exit;
5184 }
5185
5186 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005187 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005188 ret = 0;
5189
5190exit:
5191 return ret;
5192}
5193
5194static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5195 hdd_context_t *hdd_ctx,
5196 uint8_t *command,
5197 uint8_t command_len,
5198 hdd_priv_data_t *priv_data)
5199{
5200 int ret = 0;
5201 uint8_t *value = command;
5202 uint32_t uRate = 0;
5203 tTxrateinfoflags txFlags = 0;
5204 tSirRateUpdateInd rateUpdateParams = {0};
5205 int status;
5206 struct hdd_config *pConfig = hdd_ctx->config;
5207
Krunal Sonibe766b02016-03-10 13:00:44 -08005208 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5209 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005210 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5211 hdd_device_mode_to_string(adapter->device_mode),
5212 adapter->device_mode);
5213 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005214 ret = -EINVAL;
5215 goto exit;
5216 }
5217
5218 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5219 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005220 hdd_err("Invalid SETRMCTXRATE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005221 ret = -EINVAL;
5222 goto exit;
5223 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005224 hdd_info("uRate %d ", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005225 /* -1 implies ignore this param */
5226 rateUpdateParams.ucastDataRate = -1;
5227
5228 /*
5229 * Fill the user specifieed RMC rate param
5230 * and the derived tx flags.
5231 */
5232 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5233 rateUpdateParams.reliableMcastDataRate = uRate;
5234 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5235 rateUpdateParams.dev_mode = adapter->device_mode;
5236 rateUpdateParams.bcastDataRate = -1;
5237 memcpy(rateUpdateParams.bssid.bytes,
5238 adapter->macAddressCurrent.bytes,
5239 sizeof(rateUpdateParams.bssid));
5240 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5241 &rateUpdateParams);
5242
5243exit:
5244 return ret;
5245}
5246
5247static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5248 hdd_context_t *hdd_ctx,
5249 uint8_t *command,
5250 uint8_t command_len,
5251 hdd_priv_data_t *priv_data)
5252{
5253 int ret = 0;
5254 char *value;
5255 uint8_t tx_fail_count = 0;
5256 uint16_t pid = 0;
5257
5258 value = command;
5259
5260 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5261
5262 if (0 != ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005263 hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005264 goto exit;
5265 }
5266
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005267 hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005268
5269 if (0 == tx_fail_count) {
5270 /* Disable TX Fail Indication */
5271 if (QDF_STATUS_SUCCESS ==
5272 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5273 tx_fail_count,
5274 NULL)) {
5275 cesium_pid = 0;
5276 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005277 hdd_err("failed to disable TX Fail Event ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005278 ret = -EINVAL;
5279 }
5280 } else {
5281 if (QDF_STATUS_SUCCESS ==
5282 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5283 tx_fail_count,
5284 (void *)hdd_tx_fail_ind_callback)) {
5285 cesium_pid = pid;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005286 hdd_info("Registered Cesium pid %u",
5287 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005288 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005289 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005290 ret = -EINVAL;
5291 }
5292 }
5293
5294exit:
5295 return ret;
5296}
5297
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005298#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005299static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5300 hdd_context_t *hdd_ctx,
5301 uint8_t *command,
5302 uint8_t command_len,
5303 hdd_priv_data_t *priv_data)
5304{
5305 int ret = 0;
5306 uint8_t *value = command;
5307 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5308 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305309 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005310
5311 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5312 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005313 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005314 goto exit;
5315 }
5316 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005317 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005318 numChannels,
5319 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5320 ret = -EINVAL;
5321 goto exit;
5322 }
5323 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5324 adapter->sessionId,
5325 ChannelList,
5326 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305327 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005328 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005329 ret = -EINVAL;
5330 goto exit;
5331 }
5332
5333exit:
5334 return ret;
5335}
5336
5337static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5338 hdd_context_t *hdd_ctx,
5339 uint8_t *command,
5340 uint8_t command_len,
5341 hdd_priv_data_t *priv_data)
5342{
5343 int ret = 0;
5344 uint8_t *value = command;
5345 char extra[128] = { 0 };
5346 int len = 0;
5347 uint8_t tid = 0;
5348 hdd_station_ctx_t *pHddStaCtx;
5349 tAniTrafStrmMetrics tsm_metrics;
5350
Krunal Sonibe766b02016-03-10 13:00:44 -08005351 if ((QDF_STA_MODE != adapter->device_mode) &&
5352 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005353 hdd_warn("Unsupported in mode %s(%d)",
5354 hdd_device_mode_to_string(adapter->device_mode),
5355 adapter->device_mode);
5356 return -EINVAL;
5357 }
5358
5359 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5360
5361 /* if not associated, return error */
5362 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005363 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005364 ret = -EINVAL;
5365 goto exit;
5366 }
5367
5368 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5369 value = value + command_len + 1;
5370
5371 /* Convert the value from ascii to integer */
5372 ret = kstrtou8(value, 10, &tid);
5373 if (ret < 0) {
5374 /*
5375 * If the input value is greater than max value of datatype,
5376 * then also kstrtou8 fails
5377 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005378 hdd_err("kstrtou8 failed range [%d - %d]",
5379 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005380 TID_MAX_VALUE);
5381 ret = -EINVAL;
5382 goto exit;
5383 }
5384 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005385 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005386 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5387 ret = -EINVAL;
5388 goto exit;
5389 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005390 hdd_info("Received Command to get tsm stats tid = %d",
5391 tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305392 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005393 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005394 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005395 ret = -EFAULT;
5396 goto exit;
5397 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005398 hdd_info(
5399 "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 -08005400 tsm_metrics.UplinkPktQueueDly,
5401 tsm_metrics.UplinkPktQueueDlyHist[0],
5402 tsm_metrics.UplinkPktQueueDlyHist[1],
5403 tsm_metrics.UplinkPktQueueDlyHist[2],
5404 tsm_metrics.UplinkPktQueueDlyHist[3],
5405 tsm_metrics.UplinkPktTxDly,
5406 tsm_metrics.UplinkPktLoss,
5407 tsm_metrics.UplinkPktCount,
5408 tsm_metrics.RoamingCount,
5409 tsm_metrics.RoamingDly);
5410 /*
5411 * Output TSM stats is of the format
5412 * GETTSMSTATS [PktQueueDly]
5413 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5414 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5415 */
5416 len = scnprintf(extra,
5417 sizeof(extra),
5418 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5419 command,
5420 tsm_metrics.UplinkPktQueueDly,
5421 tsm_metrics.UplinkPktQueueDlyHist[0],
5422 tsm_metrics.UplinkPktQueueDlyHist[1],
5423 tsm_metrics.UplinkPktQueueDlyHist[2],
5424 tsm_metrics.UplinkPktQueueDlyHist[3],
5425 tsm_metrics.UplinkPktTxDly,
5426 tsm_metrics.UplinkPktLoss,
5427 tsm_metrics.UplinkPktCount,
5428 tsm_metrics.RoamingCount,
5429 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305430 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005431 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005432 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005433 ret = -EFAULT;
5434 goto exit;
5435 }
5436
5437exit:
5438 return ret;
5439}
5440
5441static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5442 hdd_context_t *hdd_ctx,
5443 uint8_t *command,
5444 uint8_t command_len,
5445 hdd_priv_data_t *priv_data)
5446{
5447 int ret;
5448 uint8_t *value = command;
5449 uint8_t *cckmIe = NULL;
5450 uint8_t cckmIeLen = 0;
5451
5452 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5453 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005454 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005455 goto exit;
5456 }
5457
5458 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005459 hdd_err("CCKM Ie input length is more than max[%d]",
5460 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005461 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305462 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005463 cckmIe = NULL;
5464 }
5465 ret = -EINVAL;
5466 goto exit;
5467 }
5468
5469 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5470 cckmIe, cckmIeLen);
5471 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305472 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005473 cckmIe = NULL;
5474 }
5475
5476exit:
5477 return ret;
5478}
5479
5480static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5481 hdd_context_t *hdd_ctx,
5482 uint8_t *command,
5483 uint8_t command_len,
5484 hdd_priv_data_t *priv_data)
5485{
5486 int ret;
5487 uint8_t *value = command;
5488 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305489 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005490
Krunal Sonibe766b02016-03-10 13:00:44 -08005491 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005492 hdd_warn("Unsupported in mode %s(%d)",
5493 hdd_device_mode_to_string(adapter->device_mode),
5494 adapter->device_mode);
5495 return -EINVAL;
5496 }
5497
5498 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5499 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005500 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005501 goto exit;
5502 }
5503
5504 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005505 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005506 hdd_indicate_ese_bcn_report_no_results(adapter,
5507 eseBcnReq.bcnReq[0].measurementToken,
5508 0x02, /* BIT(1) set for measurement done */
5509 0); /* no BSS */
5510 goto exit;
5511 }
5512
5513 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5514 adapter->sessionId,
5515 &eseBcnReq);
5516
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305517 if (QDF_STATUS_E_RESOURCES == status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005518 hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress",
5519 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005520 ret = -EBUSY;
5521 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305522 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005523 hdd_err("sme_set_ese_beacon_request failed (%d)",
5524 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005525 ret = -EINVAL;
5526 goto exit;
5527 }
5528
5529exit:
5530 return ret;
5531}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005532#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005533
5534static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5535 hdd_context_t *hdd_ctx,
5536 uint8_t *command,
5537 uint8_t command_len,
5538 hdd_priv_data_t *priv_data)
5539{
5540 int ret = 0;
5541 uint8_t *value = command;
5542 int targetRate;
5543
5544 /* input value is in units of hundred kbps */
5545
5546 /* Move pointer to ahead of SETMCRATE<delimiter> */
5547 value = value + command_len + 1;
5548
5549 /* Convert the value from ascii to integer, decimal base */
5550 ret = kstrtouint(value, 10, &targetRate);
5551
5552 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5553 return ret;
5554}
5555
5556static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5557 hdd_context_t *hdd_ctx,
5558 uint8_t *command,
5559 uint8_t command_len,
5560 hdd_priv_data_t *priv_data)
5561{
5562 int ret = 0;
5563 int status;
5564 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305565 QDF_STATUS qdf_status;
5566 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005567 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305568 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5569 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005570 hdd_adapter_list_node_t *pAdapterNode = NULL;
5571 hdd_adapter_list_node_t *pNext = NULL;
5572
5573 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5574 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005575 hdd_err("Invalid MAXTXPOWER command ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005576 ret = -EINVAL;
5577 goto exit;
5578 }
5579
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305580 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005581 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305582 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005583 adapter = pAdapterNode->pAdapter;
5584 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305585 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005586 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305587 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005588 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005589
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005590 hdd_info("Device mode %d max tx power %d selfMac: "
5591 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005592 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005593 MAC_ADDR_ARRAY(selfMac.bytes),
5594 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005595
Srinivas Girigowda97215232015-09-24 12:26:28 -07005596 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5597 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305598 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005599 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005600 ret = -EINVAL;
5601 goto exit;
5602 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005603 hdd_info("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305604 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005605 &pNext);
5606 pAdapterNode = pNext;
5607 }
5608
5609exit:
5610 return ret;
5611}
5612
5613static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5614 hdd_context_t *hdd_ctx,
5615 uint8_t *command,
5616 uint8_t command_len,
5617 hdd_priv_data_t *priv_data)
5618{
5619 int ret = 0;
5620 uint8_t *value = command;
5621 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5622
5623 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5624 value = value + command_len + 1;
5625
5626 /* Convert the value from ascii to integer */
5627 ret = kstrtou8(value, 10, &dfsScanMode);
5628 if (ret < 0) {
5629 /*
5630 * If the input value is greater than max value of datatype,
5631 * then also kstrtou8 fails
5632 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005633 hdd_err("kstrtou8 failed range [%d - %d]",
5634 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005635 CFG_ROAMING_DFS_CHANNEL_MAX);
5636 ret = -EINVAL;
5637 goto exit;
5638 }
5639
5640 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5641 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005642 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005643 dfsScanMode,
5644 CFG_ROAMING_DFS_CHANNEL_MIN,
5645 CFG_ROAMING_DFS_CHANNEL_MAX);
5646 ret = -EINVAL;
5647 goto exit;
5648 }
5649
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005650 hdd_info("Received Command to Set DFS Scan Mode = %d",
5651 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005652
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005653 /* When DFS scanning is disabled, the DFS channels need to be
5654 * removed from the operation of device.
5655 */
5656 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5657 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5658 if (ret < 0) {
5659 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005660 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005661 goto exit;
5662 }
5663
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005664 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5665 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5666 dfsScanMode);
5667
5668exit:
5669 return ret;
5670}
5671
5672static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5673 hdd_context_t *hdd_ctx,
5674 uint8_t *command,
5675 uint8_t command_len,
5676 hdd_priv_data_t *priv_data)
5677{
5678 int ret = 0;
5679 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5680 char extra[32];
5681 uint8_t len = 0;
5682
5683 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305684 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005685 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005686 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005687 ret = -EFAULT;
5688 }
5689
5690 return ret;
5691}
5692
5693static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5694 hdd_context_t *hdd_ctx,
5695 uint8_t *command,
5696 uint8_t command_len,
5697 hdd_priv_data_t *priv_data)
5698{
5699 int ret = 0;
5700 int value = wlan_hdd_get_link_status(adapter);
5701 char extra[32];
5702 uint8_t len;
5703
5704 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305705 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005706 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005707 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005708 ret = -EFAULT;
5709 }
5710
5711 return ret;
5712}
5713
5714#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5715static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5716 hdd_context_t *hdd_ctx,
5717 uint8_t *command,
5718 uint8_t command_len,
5719 hdd_priv_data_t *priv_data)
5720{
5721 uint8_t *value = command;
5722 int set_value;
5723
5724 /* Move pointer to ahead of ENABLEEXTWOW */
5725 value = value + command_len;
5726
5727 sscanf(value, "%d", &set_value);
5728
5729 return hdd_enable_ext_wow_parser(adapter,
5730 adapter->sessionId,
5731 set_value);
5732}
5733
5734static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5735 hdd_context_t *hdd_ctx,
5736 uint8_t *command,
5737 uint8_t command_len,
5738 hdd_priv_data_t *priv_data)
5739{
5740 int ret;
5741 uint8_t *value = command;
5742
5743 /* Move pointer to ahead of SETAPP1PARAMS */
5744 value = value + command_len;
5745
5746 ret = hdd_set_app_type1_parser(adapter,
5747 value, strlen(value));
5748 if (ret >= 0)
5749 hdd_ctx->is_extwow_app_type1_param_set = true;
5750
5751 return ret;
5752}
5753
5754static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5755 hdd_context_t *hdd_ctx,
5756 uint8_t *command,
5757 uint8_t command_len,
5758 hdd_priv_data_t *priv_data)
5759{
5760 int ret;
5761 uint8_t *value = command;
5762
5763 /* Move pointer to ahead of SETAPP2PARAMS */
5764 value = value + command_len;
5765
5766 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5767 if (ret >= 0)
5768 hdd_ctx->is_extwow_app_type2_param_set = true;
5769
5770 return ret;
5771}
5772#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5773
5774#ifdef FEATURE_WLAN_TDLS
5775/**
5776 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5777 * @adapter: Pointer to the HDD adapter
5778 * @hdd_ctx: Pointer to the HDD context
5779 * @command: Driver command string
5780 * @command_len: Driver command string length
5781 * @priv_data: Private data coming with the driver command. Unused here
5782 *
5783 * This function handles driver command that sets the secondary tdls off channel
5784 * offset
5785 *
5786 * Return: 0 on success; negative errno otherwise
5787 */
5788static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5789 hdd_context_t *hdd_ctx,
5790 uint8_t *command,
5791 uint8_t command_len,
5792 hdd_priv_data_t *priv_data)
5793{
5794 int ret;
5795 uint8_t *value = command;
5796 int set_value;
5797
5798 /* Move pointer to point the string */
5799 value += command_len;
5800
5801 ret = sscanf(value, "%d", &set_value);
5802 if (ret != 1)
5803 return -EINVAL;
5804
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005805 hdd_info("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005806
5807 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5808
5809 return ret;
5810}
5811
5812/**
5813 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5814 * @adapter: Pointer to the HDD adapter
5815 * @hdd_ctx: Pointer to the HDD context
5816 * @command: Driver command string
5817 * @command_len: Driver command string length
5818 * @priv_data: Private data coming with the driver command. Unused here
5819 *
5820 * This function handles driver command that sets tdls off channel mode
5821 *
5822 * Return: 0 on success; negative errno otherwise
5823 */
5824static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5825 hdd_context_t *hdd_ctx,
5826 uint8_t *command,
5827 uint8_t command_len,
5828 hdd_priv_data_t *priv_data)
5829{
5830 int ret;
5831 uint8_t *value = command;
5832 int set_value;
5833
5834 /* Move pointer to point the string */
5835 value += command_len;
5836
5837 ret = sscanf(value, "%d", &set_value);
5838 if (ret != 1)
5839 return -EINVAL;
5840
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005841 hdd_info("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005842
5843 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5844
5845 return ret;
5846}
5847
5848/**
5849 * drv_cmd_tdls_off_channel() - set tdls off channel number
5850 * @adapter: Pointer to the HDD adapter
5851 * @hdd_ctx: Pointer to the HDD context
5852 * @command: Driver command string
5853 * @command_len: Driver command string length
5854 * @priv_data: Private data coming with the driver command. Unused here
5855 *
5856 * This function handles driver command that sets tdls off channel number
5857 *
5858 * Return: 0 on success; negative errno otherwise
5859 */
5860static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5861 hdd_context_t *hdd_ctx,
5862 uint8_t *command,
5863 uint8_t command_len,
5864 hdd_priv_data_t *priv_data)
5865{
5866 int ret;
5867 uint8_t *value = command;
5868 int set_value;
5869
5870 /* Move pointer to point the string */
5871 value += command_len;
5872
5873 ret = sscanf(value, "%d", &set_value);
5874 if (ret != 1)
5875 return -EINVAL;
5876
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005877 if (CDS_IS_DFS_CH(set_value)) {
5878 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5879 set_value);
5880 return -EINVAL;
5881 }
5882
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005883 hdd_info("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005884
5885 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5886
5887 return ret;
5888}
5889
5890/**
5891 * drv_cmd_tdls_scan() - set tdls scan type
5892 * @adapter: Pointer to the HDD adapter
5893 * @hdd_ctx: Pointer to the HDD context
5894 * @command: Driver command string
5895 * @command_len: Driver command string length
5896 * @priv_data: Private data coming with the driver command. Unused here
5897 *
5898 * This function handles driver command that sets tdls scan type
5899 *
5900 * Return: 0 on success; negative errno otherwise
5901 */
5902static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
5903 hdd_context_t *hdd_ctx,
5904 uint8_t *command,
5905 uint8_t command_len,
5906 hdd_priv_data_t *priv_data)
5907{
5908 int ret;
5909 uint8_t *value = command;
5910 int set_value;
5911
5912 /* Move pointer to point the string */
5913 value += command_len;
5914
5915 ret = sscanf(value, "%d", &set_value);
5916 if (ret != 1)
5917 return -EINVAL;
5918
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005919 hdd_info("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005920
5921 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
5922
5923 return ret;
5924}
5925#endif
5926
5927static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
5928 hdd_context_t *hdd_ctx,
5929 uint8_t *command,
5930 uint8_t command_len,
5931 hdd_priv_data_t *priv_data)
5932{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005933 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005934 int8_t rssi = 0;
5935 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005936
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005937 uint8_t len = 0;
5938
5939 wlan_hdd_get_rssi(adapter, &rssi);
5940
5941 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305942 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005943
5944 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005945 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005946 ret = -EFAULT;
5947 }
5948
5949 return ret;
5950}
5951
5952static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
5953 hdd_context_t *hdd_ctx,
5954 uint8_t *command,
5955 uint8_t command_len,
5956 hdd_priv_data_t *priv_data)
5957{
5958 int ret;
5959 uint32_t link_speed = 0;
5960 char extra[32];
5961 uint8_t len = 0;
5962
5963 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
5964 if (0 != ret)
5965 return ret;
5966
5967 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305968 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005969 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005970 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005971 ret = -EFAULT;
5972 }
5973
5974 return ret;
5975}
5976
5977#ifdef FEATURE_NAPI
5978/**
5979 * hdd_parse_napi() - helper functions to drv_cmd_napi
5980 * @str : source string to parse
5981 * @cmd : pointer to cmd part after parsing
5982 * @sub : pointer to subcmd part after parsing
5983 * @aux : pointer to optional aux part after parsing
5984 *
5985 * Example:
5986 * NAPI SCALE <n> +-- IN str
5987 * | | +------ OUT aux
5988 * | +------------ OUT subcmd
5989 * +----------------- OUT cmd
5990 *
5991 * Return: ==0: success; !=0: failure
5992 */
5993static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
5994{
5995 int rc;
5996 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
5997
5998 NAPI_DEBUG("-->\n");
5999
6000 token = strsep(str, " \t");
6001 if (NULL == token) {
6002 hdd_err("cannot parse cmd");
6003 goto parse_end;
6004 }
6005 lcmd = token;
6006
6007 token = strsep(str, " \t");
6008 if (NULL == token) {
6009 hdd_err("cannot parse subcmd");
6010 goto parse_end;
6011 }
6012 lsub = token;
6013
6014 token = strsep(str, " \t");
6015 if (NULL == token)
6016 hdd_warn("cannot parse aux\n");
6017 else
6018 laux = token;
6019
6020parse_end:
6021 if ((NULL == lcmd) || (NULL == lsub))
6022 rc = -EINVAL;
6023 else {
6024 rc = 0;
6025 *cmd = lcmd;
6026 *sub = lsub;
6027 if (NULL != aux)
6028 *aux = laux;
6029 }
6030 NAPI_DEBUG("<--[rc=%d]\n", rc);
6031 return rc;
6032}
6033
6034
6035/**
6036 * hdd_parse_stats() - print NAPI stats into a buffer
6037 * @buf : buffer to write stats into
6038 * @max : "size of buffer"
6039 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6040 * @napid: binary structure to retrieve the stats from
6041 *
6042 * Return: number of bytes written into the buffer
6043 */
6044int hdd_napi_stats(char *buf,
6045 int max,
6046 char *indp,
6047 struct qca_napi_data *napid)
6048{
6049 int n = 0;
6050 int i, j, k; /* NAPI, CPU, bucket indices */
6051 int from, to;
6052 struct qca_napi_info *napii;
6053 struct qca_napi_stat *napis;
6054
6055 NAPI_DEBUG("-->\n");
6056
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006057 if (NULL == napid)
6058 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006059 if (NULL == indp) {
6060 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006061 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006062 } else {
6063 if (0 > kstrtoint(indp, 10, &to)) {
6064 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006065 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006066 } else
6067 from = to;
6068 }
6069
6070 for (i = from; i < to; i++)
6071 if (napid->ce_map & (0x01 << i)) {
6072 napii = &(napid->napis[i]);
6073 for (j = 0; j < NR_CPUS; j++) {
6074 napis = &(napii->stats[j]);
6075 n += scnprintf(buf + n, max - n,
6076 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6077 i, j,
6078 napis->napi_schedules,
6079 napis->napi_polls,
6080 napis->napi_completes,
6081 napis->napi_workdone);
6082
6083 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6084 n += scnprintf(
6085 buf + n, max - n,
6086 " %d",
6087 napis->napi_budget_uses[k]);
6088 }
6089 n += scnprintf(buf+n, max - n, "\n");
6090 }
6091 }
6092
6093 NAPI_DEBUG("<--[n=%d]\n", n);
6094 return n;
6095}
6096
6097/**
6098 * napi_set_scale() - sets the scale attribute in all NAPI entries
6099 * @sc : scale to set
6100 *
6101 * Return: void
6102 */
6103static void napi_set_scale(uint8_t sc)
6104{
6105 uint32_t i;
6106 struct qca_napi_data *napi_data;
6107
6108 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006109 if (likely(NULL != napi_data))
6110 for (i = 0; i < CE_COUNT_MAX; i++)
6111 if (napi_data->ce_map & (0x01 << i))
6112 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006113
6114 return;
6115}
6116/**
6117 * drv_cmd_napi() - processes NAPI commands
6118 * @adapter : net_device
6119 * @hdd_ctx : HDD context
6120 * @command : command string from user command (including "NAPI")
6121 * @command_len: length of command
6122 * @priv_data : ifr_data
6123 *
6124 * Commands supported:
6125 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6126 * enable NAPI functionally, as some other conditions
6127 * may not have been satisfied yet
6128 * NAPI DISABLE : reverse operation of "enable"
6129 * NAPI STATUS : get global status of NAPI instances
6130 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6131 * NAPI SCALE <n> : set the scale factor
6132 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006133 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006134 */
6135static int drv_cmd_napi(hdd_adapter_t *adapter,
6136 hdd_context_t *hdd_ctx,
6137 uint8_t *command,
6138 uint8_t command_len,
6139 hdd_priv_data_t *priv_data)
6140{
6141 int rc = 0;
6142 int n, l;
6143 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6144 char *synopsis = "NAPI ENABLE\n"
6145 "NAPI DISABLE\n"
6146 "NAPI STATUS\n"
6147 "NAPI STATS [<n>] -- if no <n> then all\n"
6148 "NAPI SCALE <n> -- set the scale\n";
6149 char *reply = NULL;
6150
6151 /* make a local copy, as strsep modifies the str in place */
6152 char *str = NULL;
6153
6154 NAPI_DEBUG("-->\n");
6155
6156 /**
6157 * NOTE TO MAINTAINER: from this point to the end of the function,
6158 * please do not return anywhere in the code except the very end
6159 * to avoid memory leakage (goto end_drv_napi instead)
6160 * or make sure that reply+str is freed
6161 */
6162 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6163 if (NULL == reply) {
6164 hdd_err("could not allocate reply buffer");
6165 rc = -ENOMEM;
6166 goto end_drv_napi;
6167 }
6168
6169 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6170 if (NULL == str) {
6171 hdd_err("could not allocate copy of input buffer");
6172 rc = -ENOMEM;
6173 goto end_drv_napi;
6174 }
6175
6176 strlcpy(str, command, strlen(command) + 1);
6177 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6178 cmd, subcmd, aux);
6179
6180
6181 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6182
6183 if (0 != rc) {
6184 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306185 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006186 strlen(msg)+strlen(synopsis));
6187 n = scnprintf(reply, l, msg, synopsis);
6188
6189 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306190 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006191 hdd_err("failed to copy data to user buffer");
6192 hdd_debug("reply: %s", reply);
6193
6194 rc = -EINVAL;
6195 } else {
6196 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6197 cmd, subcmd, aux);
6198 if (!strcmp(subcmd, "ENABLE"))
6199 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6200 else if (!strcmp(subcmd, "DISABLE"))
6201 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6202 else if (!strcmp(subcmd, "STATUS")) {
6203 int n = 0;
6204 uint32_t i;
6205 struct qca_napi_data *napi_data;
6206
6207 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006208 if (unlikely(NULL == napi_data))
6209 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006210 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6211 "NAPI state: 0x%08x map: 0x%08x\n",
6212 napi_data->state,
6213 napi_data->ce_map);
6214
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006215 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006216 if (napi_data->ce_map & (0x01 << i)) {
6217 n += scnprintf(
6218 reply + n,
6219 MAX_USER_COMMAND_SIZE - n,
6220 "#%d: id: %d, scale=%d\n",
6221 i,
6222 napi_data->napis[i].id,
6223 napi_data->napis[i].scale);
6224 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006225 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006226 hdd_info("wlan: STATUS DATA:\n%s", reply);
6227 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306228 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006229 rc = -EINVAL;
6230 } else if (!strcmp(subcmd, "STATS")) {
6231 int n = 0;
6232 struct qca_napi_data *napi_data;
6233
6234 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006235 if (NULL != napi_data) {
6236 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6237 aux, napi_data);
6238 NAPI_DEBUG("STATS: returns %d\n", n);
6239 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006240 if (n > 0) {
6241 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306242 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006243 n)))
6244 rc = -EINVAL;
6245 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6246 } else
6247 rc = -EINVAL;
6248 } else if (!strcmp(subcmd, "SCALE")) {
6249 if (NULL == aux) {
6250 rc = -EINVAL;
6251 hdd_err("wlan: SCALE cmd requires <n>");
6252 } else {
6253 uint8_t sc;
6254 rc = kstrtou8(aux, 10, &sc);
6255 if (rc) {
6256 hdd_err("wlan: bad scale (%s)", aux);
6257 rc = -EINVAL;
6258 } else
6259 napi_set_scale(sc);
6260 }
6261 } /* SCALE */
6262 }
6263end_drv_napi:
6264 if (NULL != str)
6265 kfree(str);
6266 if (NULL != reply)
6267 kfree(reply);
6268
6269 NAPI_DEBUG("<--[rc=%d]\n", rc);
6270 return rc;
6271}
6272#endif /* FEATURE_NAPI */
6273
6274/**
6275 * hdd_set_rx_filter() - set RX filter
6276 * @adapter: Pointer to adapter
6277 * @action: Filter action
6278 * @pattern: Address pattern
6279 *
6280 * Address pattern is most significant byte of address for example
6281 * 0x01 for IPV4 multicast address
6282 * 0x33 for IPV6 multicast address
6283 * 0xFF for broadcast address
6284 *
6285 * Return: 0 for success, non-zero for failure
6286 */
6287static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6288 uint8_t pattern)
6289{
6290 int ret;
6291 uint8_t i;
6292 tHalHandle handle;
6293 tSirRcvFltMcAddrList *filter;
6294 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6295
6296 ret = wlan_hdd_validate_context(hdd_ctx);
6297 if (0 != ret)
6298 return ret;
6299
6300 handle = hdd_ctx->hHal;
6301
6302 if (NULL == handle) {
6303 hdd_err("HAL Handle is NULL");
6304 return -EINVAL;
6305 }
6306
6307 /*
6308 * If action is false it means start dropping packets
6309 * Set addr_filter_pattern which will be used when sending
6310 * MC/BC address list to target
6311 */
6312 if (!action)
6313 adapter->addr_filter_pattern = pattern;
6314 else
6315 adapter->addr_filter_pattern = 0;
6316
Krunal Sonibe766b02016-03-10 13:00:44 -08006317 if (((adapter->device_mode == QDF_STA_MODE) ||
6318 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006319 adapter->mc_addr_list.mc_cnt &&
6320 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6321
6322
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306323 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006324 if (NULL == filter) {
6325 hdd_err("Could not allocate Memory");
6326 return -ENOMEM;
6327 }
6328 filter->action = action;
6329 for (i = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
6330 if (!memcmp(adapter->mc_addr_list.addr[i],
6331 &pattern, 1)) {
Srinivas Girigowda98530492015-11-20 17:39:24 -08006332 memcpy(filter->multicastAddr[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006333 adapter->mc_addr_list.addr[i],
6334 sizeof(adapter->mc_addr_list.addr[i]));
6335 filter->ulMulticastAddrCnt++;
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006336 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006337 MAC_ADDRESS_STR,
6338 action ? "setting" : "clearing",
Srinivas Girigowda98530492015-11-20 17:39:24 -08006339 MAC_ADDR_ARRAY(filter->multicastAddr[i].bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006340 }
6341 }
6342 /* Set rx filter */
6343 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306344 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006345 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006346 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006347 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6348 }
6349
6350 return 0;
6351}
6352
6353/**
6354 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6355 * @command: Pointer to input string driver command
6356 * @adapter: Pointer to adapter
6357 * @action: Action to enable/disable filtering
6358 *
6359 * If action == false
6360 * Start filtering out data packets based on type
6361 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6362 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6363 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6364 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6365 *
6366 * if action == true
6367 * Stop filtering data packets based on type
6368 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6369 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6370 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6371 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6372 *
6373 * Current implementation only supports IPV4 address filtering by
6374 * selectively allowing IPV4 multicast data packest based on
6375 * address list received in .ndo_set_rx_mode
6376 *
6377 * Return: 0 for success, non-zero for failure
6378 */
6379static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6380 hdd_adapter_t *adapter,
6381 bool action)
6382{
6383 int ret = 0;
6384 uint8_t *value;
6385 uint8_t type;
6386
6387 value = command;
6388 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6389 if (!action)
6390 value = command + 16;
6391 else
6392 value = command + 13;
6393 ret = kstrtou8(value, 10, &type);
6394 if (ret < 0) {
6395 hdd_err("kstrtou8 failed invalid input value %d", type);
6396 return -EINVAL;
6397 }
6398
6399 switch (type) {
6400 case 2:
6401 /* Set rx filter for IPV4 multicast data packets */
6402 ret = hdd_set_rx_filter(adapter, action, 0x01);
6403 break;
6404 default:
6405 hdd_info("Unsupported RXFILTER type %d", type);
6406 break;
6407 }
6408
6409 return ret;
6410}
6411
6412/**
6413 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6414 * @adapter: Pointer to network adapter
6415 * @hdd_ctx: Pointer to hdd context
6416 * @command: Pointer to input command
6417 * @command_len: Command length
6418 * @priv_data: Pointer to private data in command
6419 */
6420static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6421 hdd_context_t *hdd_ctx,
6422 uint8_t *command,
6423 uint8_t command_len,
6424 hdd_priv_data_t *priv_data)
6425{
6426 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6427}
6428
6429/**
6430 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6431 * @adapter: Pointer to network adapter
6432 * @hdd_ctx: Pointer to hdd context
6433 * @command: Pointer to input command
6434 * @command_len: Command length
6435 * @priv_data: Pointer to private data in command
6436 */
6437static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6438 hdd_context_t *hdd_ctx,
6439 uint8_t *command,
6440 uint8_t command_len,
6441 hdd_priv_data_t *priv_data)
6442{
6443 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6444}
6445
Archana Ramachandran393f3792015-11-13 17:13:21 -08006446/**
6447 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6448 * command
6449 * @value: Pointer to SETANTENNAMODE command
6450 * @mode: Pointer to antenna mode
6451 * @reason: Pointer to reason for set antenna mode
6452 *
6453 * This function parses the SETANTENNAMODE command passed in the format
6454 * SETANTENNAMODE<space>mode
6455 *
6456 * Return: 0 for success non-zero for failure
6457 */
6458static int hdd_parse_setantennamode_command(const uint8_t *value)
6459{
6460 const uint8_t *in_ptr = value;
6461 int tmp, v;
6462 char arg1[32];
6463
6464 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6465
6466 /* no argument after the command */
6467 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006468 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006469 return -EINVAL;
6470 }
6471
6472 /* no space after the command */
6473 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006474 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006475 return -EINVAL;
6476 }
6477
6478 /* remove empty spaces */
6479 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6480 in_ptr++;
6481
6482 /* no argument followed by spaces */
6483 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006484 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006485 return -EINVAL;
6486 }
6487
6488 /* get the argument i.e. antenna mode */
6489 v = sscanf(in_ptr, "%31s ", arg1);
6490 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006491 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006492 return -EINVAL;
6493 }
6494
6495 v = kstrtos32(arg1, 10, &tmp);
6496 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006497 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006498 return -EINVAL;
6499 }
6500
6501 return tmp;
6502}
6503
6504/**
6505 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6506 * mask is 2x2 mode
6507 * @hdd_ctx: Pointer to hdd contex
6508 *
6509 * Return: true if supported chain mask 2x2 else false
6510 */
6511static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6512{
6513 /*
6514 * Revisit and the update logic to determine the number
6515 * of TX/RX chains supported in the system when
6516 * antenna sharing per band chain mask support is
6517 * brought in
6518 */
6519 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6520}
6521
6522/**
6523 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6524 * chain mask is 1x1
6525 * @hdd_ctx: Pointer to hdd contex
6526 *
6527 * Return: true if supported chain mask 1x1 else false
6528 */
6529static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6530{
6531 /*
6532 * Revisit and update the logic to determine the number
6533 * of TX/RX chains supported in the system when
6534 * antenna sharing per band chain mask support is
6535 * brought in
6536 */
6537 return (!hdd_ctx->config->enable2x2) ? true : false;
6538}
6539
6540/**
6541 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6542 * handler
6543 * @adapter: Pointer to network adapter
6544 * @hdd_ctx: Pointer to hdd context
6545 * @command: Pointer to input command
6546 * @command_len: Command length
6547 * @priv_data: Pointer to private data in command
6548 */
6549static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6550 hdd_context_t *hdd_ctx,
6551 uint8_t *command,
6552 uint8_t command_len,
6553 hdd_priv_data_t *priv_data)
6554{
6555 struct sir_antenna_mode_param params;
6556 QDF_STATUS status;
6557 int ret = 0;
6558 int mode;
6559 uint8_t *value = command;
6560 uint8_t smps_mode;
6561 uint8_t smps_enable;
6562
6563 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6564 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6565 hdd_err("Operation invalid in non sta or concurrent mode");
6566 ret = -EPERM;
6567 goto exit;
6568 }
6569
6570 mode = hdd_parse_setantennamode_command(value);
6571 if (mode < 0) {
6572 hdd_err("Invalid SETANTENNA command");
6573 ret = mode;
6574 goto exit;
6575 }
6576
6577 hdd_info("Processing antenna mode switch to: %d", mode);
6578
6579 if (hdd_ctx->current_antenna_mode == mode) {
6580 hdd_err("System already in the requested mode");
6581 ret = 0;
6582 goto exit;
6583 }
6584
6585 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6586 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6587 hdd_err("System does not support 2x2 mode");
6588 ret = -EPERM;
6589 goto exit;
6590 }
6591
6592 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6593 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6594 hdd_err("System only supports 1x1 mode");
6595 ret = 0;
6596 goto exit;
6597 }
6598
6599 switch (mode) {
6600 case HDD_ANTENNA_MODE_1X1:
6601 params.num_rx_chains = 1;
6602 params.num_tx_chains = 1;
6603 break;
6604 case HDD_ANTENNA_MODE_2X2:
6605 params.num_rx_chains = 2;
6606 params.num_tx_chains = 2;
6607 break;
6608 default:
6609 hdd_err("unsupported antenna mode");
6610 ret = -EINVAL;
6611 goto exit;
6612 }
6613
6614 params.set_antenna_mode_resp =
6615 (void *)wlan_hdd_soc_set_antenna_mode_cb;
6616 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
6617 params.num_rx_chains,
6618 params.num_tx_chains);
6619
6620
6621 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6622 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6623 if (QDF_STATUS_SUCCESS != status) {
6624 hdd_err("set antenna mode failed status : %d", status);
6625 ret = -EFAULT;
6626 goto exit;
6627 }
6628
6629 ret = wait_for_completion_timeout(
6630 &hdd_ctx->set_antenna_mode_cmpl,
6631 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6632 if (!ret) {
6633 ret = -EFAULT;
6634 hdd_err("send set antenna mode timed out");
6635 goto exit;
6636 }
6637
6638 /* Update SME SMPS config */
6639 if (HDD_ANTENNA_MODE_1X1 == mode) {
6640 smps_enable = true;
6641 smps_mode = HDD_SMPS_MODE_STATIC;
6642 } else {
6643 smps_enable = false;
6644 smps_mode = HDD_SMPS_MODE_DISABLED;
6645 }
6646
6647 hdd_info("Update SME SMPS enable: %d mode: %d",
6648 smps_enable, smps_mode);
6649 status = sme_update_mimo_power_save(
6650 hdd_ctx->hHal, smps_enable, smps_mode, false);
6651 if (QDF_STATUS_SUCCESS != status) {
6652 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6653 smps_enable, smps_mode, status);
6654 ret = -EFAULT;
6655 goto exit;
6656 }
6657
6658 hdd_info("Successfully switched to mode: %d x %d", mode, mode);
6659 ret = 0;
6660 hdd_ctx->current_antenna_mode = mode;
6661
6662exit:
6663 hdd_info("Set antenna status: %d current mode: %d",
6664 ret, hdd_ctx->current_antenna_mode);
6665 return ret;
6666
6667}
6668
6669/**
6670 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6671 * handler
6672 * @adapter: Pointer to hdd adapter
6673 * @hdd_ctx: Pointer to hdd context
6674 * @command: Pointer to input command
6675 * @command_len: length of the command
6676 * @priv_data: private data coming with the driver command
6677 *
6678 * Return: 0 for success non-zero for failure
6679 */
6680static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6681 hdd_context_t *hdd_ctx,
6682 uint8_t *command,
6683 uint8_t command_len,
6684 hdd_priv_data_t *priv_data)
6685{
6686 uint32_t antenna_mode = 0;
6687 char extra[32];
6688 uint8_t len = 0;
6689
6690 antenna_mode = hdd_ctx->current_antenna_mode;
6691 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6692 antenna_mode);
6693 len = QDF_MIN(priv_data->total_len, len + 1);
6694 if (copy_to_user(priv_data->buf, &extra, len)) {
6695 hdd_err("Failed to copy data to user buffer");
6696 return -EFAULT;
6697 }
6698
6699 hdd_info("Get antenna mode: %d", antenna_mode);
6700
6701 return 0;
6702}
6703
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006704/*
6705 * dummy (no-op) hdd driver command handler
6706 */
6707static int drv_cmd_dummy(hdd_adapter_t *adapter,
6708 hdd_context_t *hdd_ctx,
6709 uint8_t *command,
6710 uint8_t command_len,
6711 hdd_priv_data_t *priv_data)
6712{
6713 hdd_info("%s: Ignoring driver command \"%s\"",
6714 adapter->dev->name, command);
6715 return 0;
6716}
6717
6718/*
6719 * handler for any unsupported wlan hdd driver command
6720 */
6721static int drv_cmd_invalid(hdd_adapter_t *adapter,
6722 hdd_context_t *hdd_ctx,
6723 uint8_t *command,
6724 uint8_t command_len,
6725 hdd_priv_data_t *priv_data)
6726{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306727 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006728 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6729 adapter->sessionId, 0));
6730
6731 hdd_warn("%s: Unsupported driver command \"%s\"",
6732 adapter->dev->name, command);
6733
6734 return -ENOTSUPP;
6735}
6736
6737/**
6738 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6739 * @adapter: HDD adapter
6740 * @hdd_ctx: HDD context
6741 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6742 * @command_len: command len
6743 * @priv_data: private data
6744 *
6745 * Return: status
6746 */
6747static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6748 hdd_context_t *hdd_ctx,
6749 uint8_t *command,
6750 uint8_t command_len,
6751 hdd_priv_data_t *priv_data)
6752{
6753 uint8_t *value;
6754 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306755 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006756 int ret = 0;
6757
6758 /*
6759 * this command would be called by user-space when it detects WLAN
6760 * ON after airplane mode is set. When APM is set, WLAN turns off.
6761 * But it can be turned back on. Otherwise; when APM is turned back
6762 * off, WLAN would turn back on. So at that point the command is
6763 * expected to come down. 0 means disable, 1 means enable. The
6764 * constraint is removed when parameter 1 is set or different
6765 * country code is set
6766 */
6767
6768 value = command + command_len + 1;
6769
6770 ret = kstrtou8(value, 10, &fcc_constraint);
6771 if ((ret < 0) || (fcc_constraint > 1)) {
6772 /*
6773 * If the input value is greater than max value of datatype,
6774 * then also it is a failure
6775 */
6776 hdd_err("value out of range");
6777 return -EINVAL;
6778 }
6779
6780 status = sme_disable_non_fcc_channel(hdd_ctx->hHal, !fcc_constraint);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306781 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006782 hdd_err("sme disable fn. returned err");
6783 ret = -EPERM;
6784 }
6785
6786 return ret;
6787}
6788
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306789/**
6790 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6791 * command
6792 * @value: Pointer to the command
6793 * @chan_number: Pointer to the channel number
6794 * @chan_bw: Pointer to the channel bandwidth
6795 *
6796 * Parses and provides the channel number and channel width from the input
6797 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6798 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6799 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6800 *
6801 * Return: 0 for success, non-zero for failure
6802 */
6803static int hdd_parse_set_channel_switch_command(uint8_t *value,
6804 uint32_t *chan_number,
6805 uint32_t *chan_bw)
6806{
6807 const uint8_t *in_ptr = value;
6808 int ret;
6809
6810 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6811
6812 /* no argument after the command */
6813 if (NULL == in_ptr) {
6814 hdd_err("No argument after the command");
6815 return -EINVAL;
6816 }
6817
6818 /* no space after the command */
6819 if (SPACE_ASCII_VALUE != *in_ptr) {
6820 hdd_err("No space after the command ");
6821 return -EINVAL;
6822 }
6823
6824 /* remove empty spaces and move the next argument */
6825 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6826 in_ptr++;
6827
6828 /* no argument followed by spaces */
6829 if ('\0' == *in_ptr) {
6830 hdd_err("No argument followed by spaces");
6831 return -EINVAL;
6832 }
6833
6834 /* get the two arguments: channel number and bandwidth */
6835 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6836 if (ret != 2) {
6837 hdd_err("Arguments retrieval from cmd string failed");
6838 return -EINVAL;
6839 }
6840
6841 return 0;
6842}
6843
6844/**
6845 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6846 * @adapter: HDD adapter
6847 * @hdd_ctx: HDD context
6848 * @command: Pointer to the input command CHANNEL_SWITCH
6849 * @command_len: Command len
6850 * @priv_data: Private data
6851 *
6852 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6853 * of SAP/P2P-GO
6854 *
6855 * Return: 0 for success, non-zero for failure
6856 */
6857static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
6858 hdd_context_t *hdd_ctx,
6859 uint8_t *command,
6860 uint8_t command_len,
6861 hdd_priv_data_t *priv_data)
6862{
6863 struct net_device *dev = adapter->dev;
6864 int status;
6865 uint32_t chan_number = 0, chan_bw = 0;
6866 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006867 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306868
Krunal Sonibe766b02016-03-10 13:00:44 -08006869 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6870 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306871 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6872 adapter->device_mode);
6873 return -EINVAL;
6874 }
6875
6876 status = hdd_parse_set_channel_switch_command(value,
6877 &chan_number, &chan_bw);
6878 if (status) {
6879 hdd_err("Invalid CHANNEL_SWITCH command");
6880 return status;
6881 }
6882
6883 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6884 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6885 return -EINVAL;
6886 }
6887
6888 if (chan_bw == 80)
6889 width = CH_WIDTH_80MHZ;
6890 else if (chan_bw == 40)
6891 width = CH_WIDTH_40MHZ;
6892 else
6893 width = CH_WIDTH_20MHZ;
6894
6895 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
6896
6897 status = hdd_softap_set_channel_change(dev, chan_number, width);
6898 if (status) {
6899 hdd_err("Set channel change fail");
6900 return status;
6901 }
6902
6903 return 0;
6904}
6905
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006906/*
6907 * The following table contains all supported WLAN HDD
6908 * IOCTL driver commands and the handler for each of them.
6909 */
6910static const hdd_drv_cmd_t hdd_drv_cmds[] = {
6911 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
6912 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
6913 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
6914 {"SETBAND", drv_cmd_set_band},
6915 {"SETWMMPS", drv_cmd_set_wmmps},
6916 {"COUNTRY", drv_cmd_country},
6917 {"SETSUSPENDMODE", drv_cmd_dummy},
6918 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
6919 {"BTCOEXSCAN", drv_cmd_dummy},
6920 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006921 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
6922 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
6923 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
6924 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
6925 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
6926 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006927 {"SETROAMMODE", drv_cmd_set_roam_mode},
6928 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006929 {"SETROAMDELTA", drv_cmd_set_roam_delta},
6930 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006931 {"GETBAND", drv_cmd_get_band},
6932 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
6933 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
6934 {"GETCCXMODE", drv_cmd_get_ccx_mode},
6935 {"GETOKCMODE", drv_cmd_get_okc_mode},
6936 {"GETFASTROAM", drv_cmd_get_fast_roam},
6937 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
6938 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
6939 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
6940 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
6941 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
6942 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
6943 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
6944 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
6945 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
6946 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
6947 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
6948 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
6949 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
6950 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
6951 {"REASSOC", drv_cmd_reassoc},
6952 {"SETWESMODE", drv_cmd_set_wes_mode},
6953 {"GETWESMODE", drv_cmd_get_wes_mode},
6954 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
6955 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
6956 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
6957 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006958 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006959 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
6960 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006961 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
6962#ifdef FEATURE_WLAN_OKC
6963 {"SETOKCMODE", drv_cmd_set_okc_mode},
6964#endif /* FEATURE_WLAN_OKC */
6965 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
6966 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
6967 {"SCAN-ACTIVE", drv_cmd_scan_active},
6968 {"SCAN-PASSIVE", drv_cmd_scan_passive},
6969 {"GETDWELLTIME", drv_cmd_get_dwell_time},
6970 {"SETDWELLTIME", drv_cmd_set_dwell_time},
6971 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08006972 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
6973 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
6974 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
6975 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
6976 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
6977 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
6978 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006979#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006980 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
6981 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
6982 {"SETCCKMIE", drv_cmd_set_cckm_ie},
6983 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006984#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006985 {"SETMCRATE", drv_cmd_set_mc_rate},
6986 {"MAXTXPOWER", drv_cmd_max_tx_power},
6987 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
6988 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
6989 {"GETLINKSTATUS", drv_cmd_get_link_status},
6990#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6991 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
6992 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
6993 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
6994#endif
6995#ifdef FEATURE_WLAN_TDLS
6996 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
6997 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
6998 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
6999 {"TDLSSCAN", drv_cmd_tdls_scan},
7000#endif
7001 {"RSSI", drv_cmd_get_rssi},
7002 {"LINKSPEED", drv_cmd_get_linkspeed},
7003#ifdef FEATURE_NAPI
7004 {"NAPI", drv_cmd_napi},
7005#endif /* FEATURE_NAPI */
7006 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7007 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7008 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307009 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007010 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7011 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007012};
7013
7014/**
7015 * hdd_drv_cmd_process() - chooses and runs the proper
7016 * handler based on the input command
7017 * @adapter: Pointer to the hdd adapter
7018 * @cmd: Pointer to the driver command
7019 * @priv_data: Pointer to the data associated with the command
7020 *
7021 * This function parses the input hdd driver command and runs
7022 * the proper handler
7023 *
7024 * Return: 0 for success non-zero for failure
7025 */
7026static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7027 uint8_t *cmd,
7028 hdd_priv_data_t *priv_data)
7029{
7030 hdd_context_t *hdd_ctx;
7031 int i;
7032 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7033 uint8_t *cmd_i = NULL;
7034 hdd_drv_cmd_handler_t handler = NULL;
7035 int len = 0;
7036
7037 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007038 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007039 return -EINVAL;
7040 }
7041
7042 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7043
7044 for (i = 0; i < cmd_num_total; i++) {
7045
7046 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7047 handler = hdd_drv_cmds[i].handler;
7048 len = strlen(cmd_i);
7049
7050 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007051 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007052 return -EINVAL;
7053 }
7054
7055 if (strncasecmp(cmd, cmd_i, len) == 0)
7056 return handler(adapter, hdd_ctx,
7057 cmd, len, priv_data);
7058 }
7059
7060 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7061}
7062
7063/**
7064 * hdd_driver_command() - top level wlan hdd driver command handler
7065 * @adapter: Pointer to the hdd adapter
7066 * @priv_data: Pointer to the raw command data
7067 *
7068 * This function is the top level wlan hdd driver command handler. It
7069 * handles the command with the help of hdd_drv_cmd_process()
7070 *
7071 * Return: 0 for success non-zero for failure
7072 */
7073static int hdd_driver_command(hdd_adapter_t *adapter,
7074 hdd_priv_data_t *priv_data)
7075{
7076 uint8_t *command = NULL;
7077 int ret = 0;
7078
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307079 ENTER();
7080
Anurag Chouhan6d760662016-02-20 16:05:43 +05307081 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007082 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007083 return -EINVAL;
7084 }
7085
7086 /*
7087 * Note that valid pointers are provided by caller
7088 */
7089
7090 /* copy to local struct to avoid numerous changes to legacy code */
7091 if (priv_data->total_len <= 0 ||
7092 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007093 hdd_warn("Invalid priv_data.total_len(%d)!!!",
7094 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007095 ret = -EINVAL;
7096 goto exit;
7097 }
7098
7099 /* Allocate +1 for '\0' */
7100 command = kmalloc(priv_data->total_len + 1, GFP_KERNEL);
7101 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007102 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007103 ret = -ENOMEM;
7104 goto exit;
7105 }
7106
7107 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7108 ret = -EFAULT;
7109 goto exit;
7110 }
7111
7112 /* Make sure the command is NUL-terminated */
7113 command[priv_data->total_len] = '\0';
7114
7115 hdd_info("%s: %s", adapter->dev->name, command);
7116 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7117
7118exit:
7119 if (command)
7120 kfree(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307121 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007122 return ret;
7123}
7124
7125#ifdef CONFIG_COMPAT
7126static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7127{
7128 struct {
7129 compat_uptr_t buf;
7130 int used_len;
7131 int total_len;
7132 } compat_priv_data;
7133 hdd_priv_data_t priv_data;
7134 int ret = 0;
7135
7136 /*
7137 * Note that adapter and ifr have already been verified by caller,
7138 * and HDD context has also been validated
7139 */
7140 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7141 sizeof(compat_priv_data))) {
7142 ret = -EFAULT;
7143 goto exit;
7144 }
7145 priv_data.buf = compat_ptr(compat_priv_data.buf);
7146 priv_data.used_len = compat_priv_data.used_len;
7147 priv_data.total_len = compat_priv_data.total_len;
7148 ret = hdd_driver_command(adapter, &priv_data);
7149exit:
7150 return ret;
7151}
7152#else /* CONFIG_COMPAT */
7153static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7154{
7155 /* will never be invoked */
7156 return 0;
7157}
7158#endif /* CONFIG_COMPAT */
7159
7160static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7161{
7162 hdd_priv_data_t priv_data;
7163 int ret = 0;
7164
7165 /*
7166 * Note that adapter and ifr have already been verified by caller,
7167 * and HDD context has also been validated
7168 */
7169 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7170 ret = -EFAULT;
7171 else
7172 ret = hdd_driver_command(adapter, &priv_data);
7173
7174 return ret;
7175}
7176
7177/**
7178 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7179 * @dev: device upon which the ioctl was received
7180 * @ifr: ioctl request information
7181 * @cmd: ioctl command
7182 *
7183 * This function does initial processing of wlan device ioctls.
7184 * Currently two flavors of ioctls are supported. The primary ioctl
7185 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7186 * for Android "DRIVER" commands. The other ioctl that is
7187 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7188 * for FTM on some platforms. This function simply verifies that the
7189 * driver is in a sane state, and that the ioctl is one of the
7190 * supported flavors, in which case flavor-specific handlers are
7191 * dispatched.
7192 *
7193 * Return: 0 on success, non-zero on error
7194 */
7195static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7196{
7197 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7198 hdd_context_t *hdd_ctx;
7199 int ret;
7200
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007201 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307202
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007203 if (dev != adapter->dev) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007204 hdd_alert("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007205 ret = -ENODEV;
7206 goto exit;
7207 }
7208
7209 if ((!ifr) || (!ifr->ifr_data)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007210 hdd_err("invalid data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007211 ret = -EINVAL;
7212 goto exit;
7213 }
7214#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307215 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007216 if (SIOCIOCTLTX99 == cmd) {
7217 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7218 goto exit;
7219 }
7220 }
7221#endif
7222
7223 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7224 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307225 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007226 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007227
7228 switch (cmd) {
7229 case (SIOCDEVPRIVATE + 1):
7230 if (is_compat_task())
7231 ret = hdd_driver_compat_ioctl(adapter, ifr);
7232 else
7233 ret = hdd_driver_ioctl(adapter, ifr);
7234 break;
7235 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007236 hdd_err("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007237 ret = -EINVAL;
7238 break;
7239 }
7240exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307241 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007242 return ret;
7243}
7244
7245/**
7246 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7247 * @dev: device upon which the ioctl was received
7248 * @ifr: ioctl request information
7249 * @cmd: ioctl command
7250 *
7251 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7252 * which is where the ioctls are really handled.
7253 *
7254 * Return: 0 on success, non-zero on error
7255 */
7256int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7257{
7258 int ret;
7259
7260 cds_ssr_protect(__func__);
7261 ret = __hdd_ioctl(dev, ifr, cmd);
7262 cds_ssr_unprotect(__func__);
7263 return ret;
7264}