blob: e8d80bb0da8dded80531087b9a0f84277b1d9d75 [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
30#include <wlan_hdd_includes.h>
31#include <wlan_hdd_wowl.h>
32#include "wlan_hdd_trace.h"
33#include "wlan_hdd_ioctl.h"
34#include "wlan_hdd_power.h"
35#include "wlan_hdd_driver_ops.h"
36#include "cds_concurrency.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053037#include "wlan_hdd_hostapd.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080038
39#include "wlan_hdd_p2p.h"
40#include <linux/ctype.h>
41#include "wma.h"
42#include "wlan_hdd_napi.h"
43
44#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
45#include <sme_api.h>
46#include <sir_api.h>
47#endif
48#include "hif.h"
49
50#if defined(LINUX_QCMBR)
51#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
52#endif
53
54/*
55 * Size of Driver command strings from upper layer
56 */
57#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
58#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
59
60
61#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
62#define TID_MIN_VALUE 0
63#define TID_MAX_VALUE 15
64#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
65
66/*
67 * Maximum buffer size used for returning the data back to user space
68 */
69#define WLAN_MAX_BUF_SIZE 1024
70#define WLAN_PRIV_DATA_MAX_LEN 8192
71
72/*
73 * Driver miracast parameters 0-Disabled
74 * 1-Source, 2-Sink
75 */
76#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
77#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
78
79/*
80 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
81 * we will split the printing.
82 */
83#define NUM_OF_STA_DATA_TO_PRINT 16
84
85/*
86 * Android DRIVER command structures
87 */
88struct android_wifi_reassoc_params {
89 unsigned char bssid[18];
90 int channel;
91};
92
93#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
94struct android_wifi_af_params {
95 unsigned char bssid[18];
96 int channel;
97 int dwell_time;
98 int len;
99 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
100};
101
102/*
103 * Define HDD driver command handling entry, each contains a command
104 * string and the handler.
105 */
106typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
107 hdd_context_t *hdd_ctx,
108 uint8_t *cmd,
109 uint8_t cmd_name_len,
110 hdd_priv_data_t *priv_data);
111
112typedef struct {
113 const char *cmd;
114 hdd_drv_cmd_handler_t handler;
115} hdd_drv_cmd_t;
116
117#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
118#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
119#define WLAN_HDD_MAX_TCP_PORT 65535
120#endif
121
122#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
123static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
124 const uint32_t staId, void *context)
125{
126 struct statsContext *stats_context = NULL;
127 hdd_adapter_t *adapter = NULL;
128
129 if (NULL == context) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530130 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800131 "%s: Bad param, context [%p]", __func__, context);
132 return;
133 }
134
135 /*
136 * there is a race condition that exists between this callback
137 * function and the caller since the caller could time out either
138 * before or while this code is executing. we use a spinlock to
139 * serialize these actions
140 */
141 spin_lock(&hdd_context_lock);
142
143 stats_context = context;
144 adapter = stats_context->pAdapter;
145 if ((NULL == adapter) ||
146 (STATS_CONTEXT_MAGIC != stats_context->magic)) {
147 /*
148 * the caller presumably timed out so there is
149 * nothing we can do
150 */
151 spin_unlock(&hdd_context_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530152 hddLog(QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800153 "%s: Invalid context, adapter [%p] magic [%08x]",
154 __func__, adapter, stats_context->magic);
155 return;
156 }
157
158 /* context is valid so caller is still waiting */
159
160 /* paranoia: invalidate the magic */
161 stats_context->magic = 0;
162
163 /* copy over the tsm stats */
164 adapter->tsmStats.UplinkPktQueueDly = tsm_metrics.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530165 qdf_mem_copy(adapter->tsmStats.UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800166 tsm_metrics.UplinkPktQueueDlyHist,
167 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
168 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist[0]));
169 adapter->tsmStats.UplinkPktTxDly = tsm_metrics.UplinkPktTxDly;
170 adapter->tsmStats.UplinkPktLoss = tsm_metrics.UplinkPktLoss;
171 adapter->tsmStats.UplinkPktCount = tsm_metrics.UplinkPktCount;
172 adapter->tsmStats.RoamingCount = tsm_metrics.RoamingCount;
173 adapter->tsmStats.RoamingDly = tsm_metrics.RoamingDly;
174
175 /* notify the caller */
176 complete(&stats_context->completion);
177
178 /* serialization is complete */
179 spin_unlock(&hdd_context_lock);
180}
181
182static
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530183QDF_STATUS hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184 const uint8_t tid,
185 tAniTrafStrmMetrics *tsm_metrics)
186{
187 hdd_station_ctx_t *hdd_sta_ctx = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530188 QDF_STATUS hstatus;
189 QDF_STATUS vstatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800190 unsigned long rc;
191 struct statsContext context;
192 hdd_context_t *hdd_ctx = NULL;
193
194 if (NULL == adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530195 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800196 "%s: adapter is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530197 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800198 }
199
200 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
201 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
202
203 /* we are connected prepare our callback context */
204 init_completion(&context.completion);
205 context.pAdapter = adapter;
206 context.magic = STATS_CONTEXT_MAGIC;
207
208 /* query tsm stats */
209 hstatus = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
210 hdd_sta_ctx->conn_info.staId[0],
211 hdd_sta_ctx->conn_info.bssId,
212 &context, hdd_ctx->pcds_context, tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530213 if (QDF_STATUS_SUCCESS != hstatus) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530214 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800215 "%s: Unable to retrieve statistics", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530216 vstatus = QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800217 } else {
218 /* request was sent -- wait for the response */
219 rc = wait_for_completion_timeout(&context.completion,
220 msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
221 if (!rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530222 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 "%s: SME timed out while retrieving statistics",
224 __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530225 vstatus = QDF_STATUS_E_TIMEOUT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800226 }
227 }
228
229 /*
230 * either we never sent a request, we sent a request and received a
231 * response or we sent a request and timed out. if we never sent a
232 * request or if we sent a request and got a response, we want to
233 * clear the magic out of paranoia. if we timed out there is a
234 * race condition such that the callback function could be
235 * executing at the same time we are. of primary concern is if the
236 * callback function had already verified the "magic" but had not
237 * yet set the completion variable when a timeout occurred. we
238 * serialize these activities by invalidating the magic while
239 * holding a shared spinlock which will cause us to block if the
240 * callback is currently executing
241 */
242 spin_lock(&hdd_context_lock);
243 context.magic = 0;
244 spin_unlock(&hdd_context_lock);
245
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530246 if (QDF_STATUS_SUCCESS == vstatus) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800247 tsm_metrics->UplinkPktQueueDly =
248 adapter->tsmStats.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530249 qdf_mem_copy(tsm_metrics->UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800250 adapter->tsmStats.UplinkPktQueueDlyHist,
251 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
252 sizeof(adapter->tsmStats.
253 UplinkPktQueueDlyHist[0]));
254 tsm_metrics->UplinkPktTxDly = adapter->tsmStats.UplinkPktTxDly;
255 tsm_metrics->UplinkPktLoss = adapter->tsmStats.UplinkPktLoss;
256 tsm_metrics->UplinkPktCount = adapter->tsmStats.UplinkPktCount;
257 tsm_metrics->RoamingCount = adapter->tsmStats.RoamingCount;
258 tsm_metrics->RoamingDly = adapter->tsmStats.RoamingDly;
259 }
260 return vstatus;
261}
262#endif /*FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
263
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800264static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
265{
266 eCsrBand band = -1;
267 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
268 switch (band) {
269 case eCSR_BAND_ALL:
270 *pBand = WLAN_HDD_UI_BAND_AUTO;
271 break;
272
273 case eCSR_BAND_24:
274 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
275 break;
276
277 case eCSR_BAND_5G:
278 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
279 break;
280
281 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530282 hddLog(QDF_TRACE_LEVEL_WARN, "%s: Invalid Band %d", __func__,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800283 band);
284 *pBand = -1;
285 break;
286 }
287}
288
289/**
290 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
291 * @data: input data
292 * @target_ap_bssid: pointer to bssid (output parameter)
293 * @channel: pointer to channel (output parameter)
294 *
295 * Return: 0 if parsing is successful; -EINVAL otherwise
296 */
297static int _hdd_parse_bssid_and_chan(const uint8_t **data,
298 uint8_t *bssid,
299 uint8_t *channel)
300{
301 const uint8_t *in_ptr;
302 int v = 0;
303 int temp_int;
304 uint8_t temp_buf[32];
305
306 /* 12 hexa decimal digits, 5 ':' and '\0' */
307 uint8_t mac_addr[18];
308
309 if (!data || !*data)
310 return -EINVAL;
311
312 in_ptr = *data;
313
314 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
315 /* no argument after the command */
316 if (NULL == in_ptr)
317 goto error;
318 /* no space after the command */
319 else if (SPACE_ASCII_VALUE != *in_ptr)
320 goto error;
321
322 /* remove empty spaces */
323 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
324 in_ptr++;
325
326 /* no argument followed by spaces */
327 if ('\0' == *in_ptr)
328 goto error;
329
330 v = sscanf(in_ptr, "%17s", mac_addr);
331 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
332 hddLog(LOGE,
333 FL(
334 "Invalid MAC address or All hex inputs are not read (%d)"
335 ),
336 v);
337 goto error;
338 }
339
340 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
341 hex_to_bin(mac_addr[1]);
342 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
343 hex_to_bin(mac_addr[4]);
344 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
345 hex_to_bin(mac_addr[7]);
346 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
347 hex_to_bin(mac_addr[10]);
348 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
349 hex_to_bin(mac_addr[13]);
350 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
351 hex_to_bin(mac_addr[16]);
352
353 /* point to the next argument */
354 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
355 /* no argument after the command */
356 if (NULL == in_ptr)
357 goto error;
358
359 /* remove empty spaces */
360 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
361 in_ptr++;
362
363 /* no argument followed by spaces */
364 if ('\0' == *in_ptr)
365 goto error;
366
367 /* get the next argument ie the channel number */
368 v = sscanf(in_ptr, "%31s ", temp_buf);
369 if (1 != v)
370 goto error;
371
372 v = kstrtos32(temp_buf, 10, &temp_int);
373 if ((v < 0) || (temp_int < 0) ||
374 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
375 return -EINVAL;
376
377 *channel = temp_int;
378 *data = in_ptr;
379 return 0;
380error:
381 *data = in_ptr;
382 return -EINVAL;
383}
384
385/**
386 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
387 * @pValue: Pointer to input data
388 * @pTargetApBssid: Pointer to target Ap bssid
389 * @pChannel: Pointer to the Target AP channel
390 * @pDwellTime: Pointer to the time to stay off-channel
391 * after transmitting action frame
392 * @pBuf: Pointer to data
393 * @pBufLen: Pointer to data length
394 *
395 * This function parses the send action frame data passed in the format
396 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
397 *
398 * Return: 0 for success non-zero for failure
399 */
400static int
401hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
402 uint8_t *pTargetApBssid,
403 uint8_t *pChannel, uint8_t *pDwellTime,
404 uint8_t **pBuf, uint8_t *pBufLen)
405{
406 const uint8_t *inPtr = pValue;
407 const uint8_t *dataEnd;
408 int tempInt;
409 int j = 0;
410 int i = 0;
411 int v = 0;
412 uint8_t tempBuf[32];
413 uint8_t tempByte = 0;
414
415 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
416 return -EINVAL;
417
418 /* point to the next argument */
419 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
420 /* no argument after the command */
421 if (NULL == inPtr)
422 return -EINVAL;
423 /* removing empty spaces */
424 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
425 inPtr++;
426
427 /* no argument followed by spaces */
428 if ('\0' == *inPtr) {
429 return -EINVAL;
430 }
431
432 /* getting the next argument ie the dwell time */
433 v = sscanf(inPtr, "%31s ", tempBuf);
434 if (1 != v)
435 return -EINVAL;
436
437 v = kstrtos32(tempBuf, 10, &tempInt);
438 if (v < 0 || tempInt < 0)
439 return -EINVAL;
440
441 *pDwellTime = tempInt;
442
443 /* point to the next argument */
444 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
445 /* no argument after the command */
446 if (NULL == inPtr)
447 return -EINVAL;
448 /* removing empty spaces */
449 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
450 inPtr++;
451
452 /* no argument followed by spaces */
453 if ('\0' == *inPtr) {
454 return -EINVAL;
455 }
456
457 /* find the length of data */
458 dataEnd = inPtr;
459 while (('\0' != *dataEnd)) {
460 dataEnd++;
461 }
462 *pBufLen = dataEnd - inPtr;
463 if (*pBufLen <= 0)
464 return -EINVAL;
465
466 /*
467 * Allocate the number of bytes based on the number of input characters
468 * whether it is even or odd.
469 * if the number of input characters are even, then we need N/2 byte.
470 * if the number of input characters are odd, then we need do (N+1)/2
471 * to compensate rounding off.
472 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
473 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
474 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530475 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 if (NULL == *pBuf) {
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530477 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800478 return -ENOMEM;
479 }
480
481 /* the buffer received from the upper layer is character buffer,
482 * we need to prepare the buffer taking 2 characters in to a U8 hex
483 * decimal number for example 7f0000f0...form a buffer to contain 7f
484 * in 0th location, 00 in 1st and f0 in 3rd location
485 */
486 for (i = 0, j = 0; j < *pBufLen; j += 2) {
487 if (j + 1 == *pBufLen) {
488 tempByte = hex_to_bin(inPtr[j]);
489 } else {
490 tempByte =
491 (hex_to_bin(inPtr[j]) << 4) |
492 (hex_to_bin(inPtr[j + 1]));
493 }
494 (*pBuf)[i++] = tempByte;
495 }
496 *pBufLen = i;
497 return 0;
498}
499
500/**
501 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
502 * @pValue: Pointer to input data (its a NULL terminated string)
503 * @pTargetApBssid: Pointer to target Ap bssid
504 * @pChannel: Pointer to the Target AP channel
505 *
506 * This function parses the reasoc command data passed in the format
507 * REASSOC<space><bssid><space><channel>
508 *
509 * Return: 0 for success non-zero for failure
510 */
511static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
512 uint8_t *pTargetApBssid,
513 uint8_t *pChannel)
514{
515 const uint8_t *inPtr = pValue;
516
517 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
518 return -EINVAL;
519
520 return 0;
521}
522
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800523/**
524 * hdd_reassoc() - perform a userspace-directed reassoc
525 * @adapter: Adapter upon which the command was received
526 * @bssid: BSSID with which to reassociate
527 * @channel: channel upon which to reassociate
528 *
529 * This function performs a userspace-directed reassoc operation
530 *
531 * Return: 0 for success non-zero for failure
532 */
533static int
534hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
535 const uint8_t channel)
536{
537 hdd_station_ctx_t *pHddStaCtx;
538 int ret = 0;
539
540 if (WLAN_HDD_INFRA_STATION != adapter->device_mode) {
541 hdd_warn("Unsupported in mode %s(%d)",
542 hdd_device_mode_to_string(adapter->device_mode),
543 adapter->device_mode);
544 return -EINVAL;
545 }
546
547 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
548
549 /* if not associated, no need to proceed with reassoc */
550 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530551 hddLog(QDF_TRACE_LEVEL_INFO, "%s: Not associated", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800552 ret = -EINVAL;
553 goto exit;
554 }
555
556 /*
557 * if the target bssid is same as currently associated AP,
558 * then no need to proceed with reassoc
559 */
560 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530561 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800562 hddLog(LOG1,
563 FL("Reassoc BSSID is same as currently associated AP bssid"));
564 ret = -EINVAL;
565 goto exit;
566 }
567
568 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530569 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800570 wlan_hdd_validate_operation_channel(adapter, channel)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530571 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: Invalid Channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800572 __func__, channel);
573 ret = -EINVAL;
574 goto exit;
575 }
576
577 /* Proceed with reassoc */
578 {
579 tCsrHandoffRequest handoffInfo;
580 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
581
582 handoffInfo.channel = channel;
583 handoffInfo.src = REASSOC;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530584 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800585 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
586 &handoffInfo);
587 }
588exit:
589 return ret;
590}
591
592/**
593 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
594 * @adapter: Adapter upon which the command was received
595 * @command: ASCII text command that was received
596 *
597 * This function parses the v1 REASSOC command with the format
598 *
599 * REASSOC xx:xx:xx:xx:xx:xx CH
600 *
601 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
602 * BSSID and CH is the ASCII representation of the channel. For
603 * example
604 *
605 * REASSOC 00:0a:0b:11:22:33 48
606 *
607 * Return: 0 for success non-zero for failure
608 */
609static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
610{
611 uint8_t channel = 0;
612 tSirMacAddr bssid;
613 int ret;
614
615 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
616 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530617 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800618 "%s: Failed to parse reassoc command data", __func__);
619 } else {
620 ret = hdd_reassoc(adapter, bssid, channel);
621 }
622 return ret;
623}
624
625/**
626 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
627 * @adapter: Adapter upon which the command was received
628 * @command: Command that was received, ASCII command
629 * followed by binary data
630 *
631 * This function parses the v2 REASSOC command with the format
632 *
633 * REASSOC <android_wifi_reassoc_params>
634 *
635 * Return: 0 for success non-zero for failure
636 */
637static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
638{
639 struct android_wifi_reassoc_params params;
640 tSirMacAddr bssid;
641 int ret;
642
643 /* The params are located after "REASSOC " */
644 memcpy(&params, command + 8, sizeof(params));
645
646 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
647 hddLog(LOGE, "%s: MAC address parsing failed", __func__);
648 ret = -EINVAL;
649 } else {
650 ret = hdd_reassoc(adapter, bssid, params.channel);
651 }
652 return ret;
653}
654
655/**
656 * hdd_parse_reassoc() - parse the REASSOC command
657 * @adapter: Adapter upon which the command was received
658 * @command: Command that was received
659 *
660 * There are two different versions of the REASSOC command. Version 1
661 * of the command contains a parameter list that is ASCII characters
662 * whereas version 2 contains a combination of ASCII and binary
663 * payload. Determine if a version 1 or a version 2 command is being
664 * parsed by examining the parameters, and then dispatch the parser
665 * that is appropriate for the command.
666 *
667 * Return: 0 for success non-zero for failure
668 */
669static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
670{
671 int ret;
672
673 /* both versions start with "REASSOC "
674 * v1 has a bssid and channel # as an ASCII string
675 * REASSOC xx:xx:xx:xx:xx:xx CH
676 * v2 has a C struct
677 * REASSOC <binary c struct>
678 *
679 * The first field in the v2 struct is also the bssid in ASCII.
680 * But in the case of a v2 message the BSSID is NUL-terminated.
681 * Hence we can peek at that offset to see if this is V1 or V2
682 * REASSOC xx:xx:xx:xx:xx:xx*
683 * 1111111111222222
684 * 01234567890123456789012345
685 */
686 if (command[25]) {
687 ret = hdd_parse_reassoc_v1(adapter, command);
688 } else {
689 ret = hdd_parse_reassoc_v2(adapter, command);
690 }
691
692 return ret;
693}
694
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800695/**
696 * hdd_sendactionframe() - send a userspace-supplied action frame
697 * @adapter: Adapter upon which the command was received
698 * @bssid: BSSID target of the action frame
699 * @channel: Channel upon which to send the frame
700 * @dwell_time: Amount of time to dwell when the frame is sent
701 * @payload_len:Length of the payload
702 * @payload: Payload of the frame
703 *
704 * This function sends a userspace-supplied action frame
705 *
706 * Return: 0 for success non-zero for failure
707 */
708static int
709hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
710 const uint8_t channel, const uint8_t dwell_time,
711 const uint8_t payload_len, const uint8_t *payload)
712{
713 struct ieee80211_channel chan;
714 uint8_t frame_len;
715 uint8_t *frame;
716 struct ieee80211_hdr_3addr *hdr;
717 u64 cookie;
718 hdd_station_ctx_t *pHddStaCtx;
719 hdd_context_t *hdd_ctx;
720 int ret = 0;
721 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
722 (tpSirMacVendorSpecificFrameHdr) payload;
723#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
724 struct cfg80211_mgmt_tx_params params;
725#endif
726
727 if (WLAN_HDD_INFRA_STATION != adapter->device_mode) {
728 hdd_warn("Unsupported in mode %s(%d)",
729 hdd_device_mode_to_string(adapter->device_mode),
730 adapter->device_mode);
731 return -EINVAL;
732 }
733
734 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
735 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
736
737 /* if not associated, no need to send action frame */
738 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530739 hddLog(QDF_TRACE_LEVEL_INFO, "%s: Not associated", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800740 ret = -EINVAL;
741 goto exit;
742 }
743
744 /*
745 * if the target bssid is different from currently associated AP,
746 * then no need to send action frame
747 */
748 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530749 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800750 hddLog(LOG1, FL("STA is not associated to this AP"));
751 ret = -EINVAL;
752 goto exit;
753 }
754
755 chan.center_freq = sme_chn_to_freq(channel);
756 /* Check if it is specific action frame */
757 if (pVendorSpecific->category ==
758 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
759 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530760 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761 /*
762 * if the channel number is different from operating
763 * channel then no need to send action frame
764 */
765 if (channel != 0) {
766 if (channel !=
767 pHddStaCtx->conn_info.operationChannel) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530768 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800769 "%s: channel(%d) is different from operating channel(%d)",
770 __func__, channel,
771 pHddStaCtx->conn_info.
772 operationChannel);
773 ret = -EINVAL;
774 goto exit;
775 }
776 /*
777 * If channel number is specified and same
778 * as home channel, ensure that action frame
779 * is sent immediately by cancelling
780 * roaming scans. Otherwise large dwell times
781 * may cause long delays in sending action
782 * frames.
783 */
784 sme_abort_roam_scan(hdd_ctx->hHal,
785 adapter->sessionId);
786 } else {
787 /*
788 * 0 is accepted as current home channel,
789 * delayed transmission of action frame is ok.
790 */
791 chan.center_freq =
792 sme_chn_to_freq(pHddStaCtx->conn_info.
793 operationChannel);
794 }
795 }
796 }
797 if (chan.center_freq == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530798 hddLog(QDF_TRACE_LEVEL_ERROR, "%s:invalid channel number %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800799 __func__, channel);
800 ret = -EINVAL;
801 goto exit;
802 }
803
804 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530805 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800806 if (!frame) {
807 hddLog(LOGE, FL("memory allocation failed"));
808 ret = -ENOMEM;
809 goto exit;
810 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530811 qdf_mem_zero(frame, frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800812
813 hdr = (struct ieee80211_hdr_3addr *)frame;
814 hdr->frame_control =
815 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530816 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
817 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530818 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530819 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
820 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800821
822#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
823 params.chan = &chan;
824 params.offchan = 0;
825 params.wait = dwell_time;
826 params.buf = frame;
827 params.len = frame_len;
828 params.no_cck = 1;
829 params.dont_wait_for_ack = 1;
830 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
831#else
832 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -0700835
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800836 dwell_time, frame, frame_len, 1, 1, &cookie);
837#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
838
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530839 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840exit:
841 return ret;
842}
843
844/**
845 * hdd_parse_sendactionframe_v1() - parse version 1 of the
846 * SENDACTIONFRAME command
847 * @adapter: Adapter upon which the command was received
848 * @command: ASCII text command that was received
849 *
850 * This function parses the v1 SENDACTIONFRAME command with the format
851 *
852 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
853 *
854 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
855 * BSSID, CH is the ASCII representation of the channel, DW is the
856 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
857 * payload. For example
858 *
859 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
860 *
861 * Return: 0 for success non-zero for failure
862 */
863static int
864hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
865{
866 uint8_t channel = 0;
867 uint8_t dwell_time = 0;
868 uint8_t payload_len = 0;
869 uint8_t *payload = NULL;
870 tSirMacAddr bssid;
871 int ret;
872
873 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
874 &dwell_time, &payload,
875 &payload_len);
876 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530877 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 "%s: Failed to parse send action frame data", __func__);
879 } else {
880 ret = hdd_sendactionframe(adapter, bssid, channel,
881 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530882 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800883 }
884
885 return ret;
886}
887
888/**
889 * hdd_parse_sendactionframe_v2() - parse version 2 of the
890 * SENDACTIONFRAME command
891 * @adapter: Adapter upon which the command was received
892 * @command: Command that was received, ASCII command
893 * followed by binary data
894 *
895 * This function parses the v2 SENDACTIONFRAME command with the format
896 *
897 * SENDACTIONFRAME <android_wifi_af_params>
898 *
899 * Return: 0 for success non-zero for failure
900 */
901static int
902hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter, const char *command)
903{
904 struct android_wifi_af_params *params;
905 tSirMacAddr bssid;
906 int ret;
907
908 /* params are large so keep off the stack */
909 params = kmalloc(sizeof(*params), GFP_KERNEL);
910 if (!params)
911 return -ENOMEM;
912
913 /* The params are located after "SENDACTIONFRAME " */
914 memcpy(params, command + 16, sizeof(*params));
915
916 if (!mac_pton(params->bssid, (u8 *) &bssid)) {
917 hddLog(LOGE, "%s: MAC address parsing failed", __func__);
918 ret = -EINVAL;
919 } else {
920 ret = hdd_sendactionframe(adapter, bssid, params->channel,
921 params->dwell_time, params->len,
922 params->data);
923 }
924 kfree(params);
925 return ret;
926}
927
928/**
929 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
930 * @adapter: Adapter upon which the command was received
931 * @command: Command that was received
932 *
933 * There are two different versions of the SENDACTIONFRAME command.
934 * Version 1 of the command contains a parameter list that is ASCII
935 * characters whereas version 2 contains a combination of ASCII and
936 * binary payload. Determine if a version 1 or a version 2 command is
937 * being parsed by examining the parameters, and then dispatch the
938 * parser that is appropriate for the version of the command.
939 *
940 * Return: 0 for success non-zero for failure
941 */
942static int
943hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command)
944{
945 int ret;
946
947 /*
948 * both versions start with "SENDACTIONFRAME "
949 * v1 has a bssid and other parameters as an ASCII string
950 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
951 * v2 has a C struct
952 * SENDACTIONFRAME <binary c struct>
953 *
954 * The first field in the v2 struct is also the bssid in ASCII.
955 * But in the case of a v2 message the BSSID is NUL-terminated.
956 * Hence we can peek at that offset to see if this is V1 or V2
957 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
958 * 111111111122222222223333
959 * 0123456789012345678901234567890123
960 */
961 if (command[33]) {
962 ret = hdd_parse_sendactionframe_v1(adapter, command);
963 } else {
964 ret = hdd_parse_sendactionframe_v2(adapter, command);
965 }
966
967 return ret;
968}
969
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800970/**
971 * hdd_parse_channellist() - HDD Parse channel list
972 * @pValue: Pointer to input channel list
973 * @ChannelList: Pointer to local output array to record
974 * channel list
975 * @pNumChannels: Pointer to number of roam scan channels
976 *
977 * This function parses the channel list passed in the format
978 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
979 * if the Number of channels (N) does not match with the actual number
980 * of channels passed then take the minimum of N and count of
981 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
982 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
983 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
984 * removing duplicate channels from the list
985 *
986 * Return: 0 for success non-zero for failure
987 */
988static int
989hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
990 uint8_t *pNumChannels)
991{
992 const uint8_t *inPtr = pValue;
993 int tempInt;
994 int j = 0;
995 int v = 0;
996 char buf[32];
997
998 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
999 /* no argument after the command */
1000 if (NULL == inPtr) {
1001 return -EINVAL;
1002 }
1003
1004 /* no space after the command */
1005 else if (SPACE_ASCII_VALUE != *inPtr) {
1006 return -EINVAL;
1007 }
1008
1009 /* remove empty spaces */
1010 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1011 inPtr++;
1012
1013 /* no argument followed by spaces */
1014 if ('\0' == *inPtr) {
1015 return -EINVAL;
1016 }
1017
1018 /* get the first argument ie the number of channels */
1019 v = sscanf(inPtr, "%31s ", buf);
1020 if (1 != v)
1021 return -EINVAL;
1022
1023 v = kstrtos32(buf, 10, &tempInt);
1024 if ((v < 0) ||
1025 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1026 return -EINVAL;
1027 }
1028
1029 *pNumChannels = tempInt;
1030
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301031 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032 "Number of channels are: %d", *pNumChannels);
1033
1034 for (j = 0; j < (*pNumChannels); j++) {
1035 /*
1036 * inPtr pointing to the beginning of first space after number
1037 * of channels
1038 */
1039 inPtr = strpbrk(inPtr, " ");
1040 /* no channel list after the number of channels argument */
1041 if (NULL == inPtr) {
1042 if (0 != j) {
1043 *pNumChannels = j;
1044 return 0;
1045 } else {
1046 return -EINVAL;
1047 }
1048 }
1049
1050 /* remove empty space */
1051 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1052 inPtr++;
1053
1054 /*
1055 * no channel list after the number of channels
1056 * argument and spaces
1057 */
1058 if ('\0' == *inPtr) {
1059 if (0 != j) {
1060 *pNumChannels = j;
1061 return 0;
1062 } else {
1063 return -EINVAL;
1064 }
1065 }
1066
1067 v = sscanf(inPtr, "%31s ", buf);
1068 if (1 != v)
1069 return -EINVAL;
1070
1071 v = kstrtos32(buf, 10, &tempInt);
1072 if ((v < 0) ||
1073 (tempInt <= 0) ||
1074 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1075 return -EINVAL;
1076 }
1077 pChannelList[j] = tempInt;
1078
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301079 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001080 "Channel %d added to preferred channel list",
1081 pChannelList[j]);
1082 }
1083
1084 return 0;
1085}
1086
1087/**
1088 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1089 * SETROAMSCANCHANNELS command
1090 * @adapter: Adapter upon which the command was received
1091 * @command: ASCII text command that was received
1092 *
1093 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1094 *
1095 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1096 *
1097 * Where "N" is the ASCII representation of the number of channels and
1098 * C1 thru Cn is the ASCII representation of the channels. For example
1099 *
1100 * SETROAMSCANCHANNELS 4 36 40 44 48
1101 *
1102 * Return: 0 for success non-zero for failure
1103 */
1104static int
1105hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1106 const char *command)
1107{
1108 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1109 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301110 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001111 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1112 int ret;
1113
1114 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1115 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301116 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 "%s: Failed to parse channel list information",
1118 __func__);
1119 goto exit;
1120 }
1121
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301122 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001123 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1124 adapter->sessionId, num_chan));
1125
1126 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301127 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 "%s: number of channels (%d) supported exceeded max (%d)",
1129 __func__, num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
1130 ret = -EINVAL;
1131 goto exit;
1132 }
1133
1134 status =
1135 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1136 adapter->sessionId,
1137 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301138 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301139 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140 "%s: Failed to update channel list information",
1141 __func__);
1142 ret = -EINVAL;
1143 goto exit;
1144 }
1145exit:
1146 return ret;
1147}
1148
1149/**
1150 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1151 * SETROAMSCANCHANNELS command
1152 * @adapter: Adapter upon which the command was received
1153 * @command: Command that was received, ASCII command
1154 * followed by binary data
1155 *
1156 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1157 *
1158 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1159 *
1160 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1161 * what follows the space is an array of u08 parameters. For example
1162 *
1163 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1164 *
1165 * Return: 0 for success non-zero for failure
1166 */
1167static int
1168hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1169 const char *command)
1170{
1171 const uint8_t *value;
1172 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1173 uint8_t channel;
1174 uint8_t num_chan;
1175 int i;
1176 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301177 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001178 int ret = 0;
1179
1180 /* array of values begins after "SETROAMSCANCHANNELS " */
1181 value = command + 20;
1182
1183 num_chan = *value++;
1184 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301185 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001186 "%s: number of channels (%d) supported exceeded max (%d)",
1187 __func__, num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
1188 ret = -EINVAL;
1189 goto exit;
1190 }
1191
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301192 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001193 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1194 adapter->sessionId, num_chan));
1195
1196 for (i = 0; i < num_chan; i++) {
1197 channel = *value++;
1198 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301199 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001200 "%s: index %d invalid channel %d", __func__,
1201 i, channel);
1202 ret = -EINVAL;
1203 goto exit;
1204 }
1205 channel_list[i] = channel;
1206 }
1207 status =
1208 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1209 adapter->sessionId,
1210 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301211 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301212 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001213 "%s: Failed to update channel list information",
1214 __func__);
1215 ret = -EINVAL;
1216 goto exit;
1217 }
1218exit:
1219 return ret;
1220}
1221
1222/**
1223 * hdd_parse_set_roam_scan_channels() - parse the
1224 * SETROAMSCANCHANNELS command
1225 * @adapter: Adapter upon which the command was received
1226 * @command: Command that was received
1227 *
1228 * There are two different versions of the SETROAMSCANCHANNELS command.
1229 * Version 1 of the command contains a parameter list that is ASCII
1230 * characters whereas version 2 contains a binary payload. Determine
1231 * if a version 1 or a version 2 command is being parsed by examining
1232 * the parameters, and then dispatch the parser that is appropriate for
1233 * the command.
1234 *
1235 * Return: 0 for success non-zero for failure
1236 */
1237static int
1238hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1239{
1240 const char *cursor;
1241 char ch;
1242 bool v1;
1243 int ret;
1244
1245 /* start after "SETROAMSCANCHANNELS " */
1246 cursor = command + 20;
1247
1248 /* assume we have a version 1 command until proven otherwise */
1249 v1 = true;
1250
1251 /* v1 params will only contain ASCII digits and space */
1252 while ((ch = *cursor++) && v1) {
1253 if (!(isdigit(ch) || isspace(ch))) {
1254 v1 = false;
1255 }
1256 }
1257 if (v1) {
1258 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1259 } else {
1260 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1261 }
1262
1263 return ret;
1264}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265
1266#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
1267/**
1268 * hdd_parse_plm_cmd() - HDD Parse Plm command
1269 * @pValue: Pointer to input data
1270 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1271 *
1272 * This function parses the plm command passed in the format
1273 * CCXPLMREQ<space><enable><space><dialog_token><space>
1274 * <meas_token><space><num_of_bursts><space><burst_int><space>
1275 * <measu duration><space><burst_len><space><desired_tx_pwr>
1276 * <space><multcast_addr><space><number_of_channels>
1277 * <space><channel_numbers>
1278 *
1279 * Return: 0 for success non-zero for failure
1280 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301281QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001282{
1283 uint8_t *cmdPtr = NULL;
1284 int count, content = 0, ret = 0;
1285 char buf[32];
1286
1287 /* move to argument list */
1288 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1289 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301290 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001291
1292 /* no space after the command */
1293 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301294 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001295
1296 /* remove empty spaces */
1297 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1298 cmdPtr++;
1299
1300 /* START/STOP PLM req */
1301 ret = sscanf(cmdPtr, "%31s ", buf);
1302 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301303 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001304
1305 ret = kstrtos32(buf, 10, &content);
1306 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301307 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001308
1309 pPlmRequest->enable = content;
1310 cmdPtr = strpbrk(cmdPtr, " ");
1311
1312 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301313 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001314
1315 /* remove empty spaces */
1316 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1317 cmdPtr++;
1318
1319 /* Dialog token of radio meas req containing meas reqIE */
1320 ret = sscanf(cmdPtr, "%31s ", buf);
1321 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301322 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001323
1324 ret = kstrtos32(buf, 10, &content);
1325 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301326 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001327
1328 pPlmRequest->diag_token = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301329 hddLog(QDF_TRACE_LEVEL_DEBUG, "diag token %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001330 pPlmRequest->diag_token);
1331 cmdPtr = strpbrk(cmdPtr, " ");
1332
1333 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301334 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001335
1336 /* remove empty spaces */
1337 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1338 cmdPtr++;
1339
1340 /* measurement token of meas req IE */
1341 ret = sscanf(cmdPtr, "%31s ", buf);
1342 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301343 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001344
1345 ret = kstrtos32(buf, 10, &content);
1346 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301347 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001348
1349 pPlmRequest->meas_token = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301350 hddLog(QDF_TRACE_LEVEL_DEBUG, "meas token %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001351 pPlmRequest->meas_token);
1352
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301353 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354 "PLM req %s", pPlmRequest->enable ? "START" : "STOP");
1355 if (pPlmRequest->enable) {
1356
1357 cmdPtr = strpbrk(cmdPtr, " ");
1358
1359 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301360 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001361
1362 /* remove empty spaces */
1363 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1364 cmdPtr++;
1365
1366 /* total number of bursts after which STA stops sending */
1367 ret = sscanf(cmdPtr, "%31s ", buf);
1368 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301369 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001370
1371 ret = kstrtos32(buf, 10, &content);
1372 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301373 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001374
1375 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301376 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377
1378 pPlmRequest->numBursts = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301379 hddLog(QDF_TRACE_LEVEL_DEBUG, "num burst %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001380 pPlmRequest->numBursts);
1381 cmdPtr = strpbrk(cmdPtr, " ");
1382
1383 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301384 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001385
1386 /* remove empty spaces */
1387 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1388 cmdPtr++;
1389
1390 /* burst interval in seconds */
1391 ret = sscanf(cmdPtr, "%31s ", buf);
1392 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301393 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001394
1395 ret = kstrtos32(buf, 10, &content);
1396 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301397 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001398
1399 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301400 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401
1402 pPlmRequest->burstInt = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301403 hddLog(QDF_TRACE_LEVEL_DEBUG, "burst Int %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001404 pPlmRequest->burstInt);
1405 cmdPtr = strpbrk(cmdPtr, " ");
1406
1407 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301408 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001409
1410 /* remove empty spaces */
1411 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1412 cmdPtr++;
1413
1414 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1415 ret = sscanf(cmdPtr, "%31s ", buf);
1416 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301417 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001418
1419 ret = kstrtos32(buf, 10, &content);
1420 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301421 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001422
1423 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301424 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001425
1426 pPlmRequest->measDuration = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301427 hddLog(QDF_TRACE_LEVEL_DEBUG, "measDur %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001428 pPlmRequest->measDuration);
1429 cmdPtr = strpbrk(cmdPtr, " ");
1430
1431 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301432 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001433
1434 /* remove empty spaces */
1435 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1436 cmdPtr++;
1437
1438 /* burst length of PLM bursts */
1439 ret = sscanf(cmdPtr, "%31s ", buf);
1440 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301441 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001442
1443 ret = kstrtos32(buf, 10, &content);
1444 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301445 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446
1447 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301448 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449
1450 pPlmRequest->burstLen = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301451 hddLog(QDF_TRACE_LEVEL_DEBUG, "burstLen %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001452 pPlmRequest->burstLen);
1453 cmdPtr = strpbrk(cmdPtr, " ");
1454
1455 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301456 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001457
1458 /* remove empty spaces */
1459 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1460 cmdPtr++;
1461
1462 /* desired tx power for transmission of PLM bursts */
1463 ret = sscanf(cmdPtr, "%31s ", buf);
1464 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301465 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001466
1467 ret = kstrtos32(buf, 10, &content);
1468 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301469 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001470
1471 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301472 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001473
1474 pPlmRequest->desiredTxPwr = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301475 hddLog(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001476 "desiredTxPwr %d", pPlmRequest->desiredTxPwr);
1477
Anurag Chouhan6d760662016-02-20 16:05:43 +05301478 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001479 cmdPtr = strpbrk(cmdPtr, " ");
1480
1481 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301482 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001483
1484 /* remove empty spaces */
1485 while ((SPACE_ASCII_VALUE == *cmdPtr)
1486 && ('\0' != *cmdPtr))
1487 cmdPtr++;
1488
1489 ret = sscanf(cmdPtr, "%31s ", buf);
1490 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301491 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001492
1493 ret = kstrtos32(buf, 16, &content);
1494 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301495 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001497 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498 }
1499
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001500 hdd_debug("MC addr " MAC_ADDRESS_STR,
1501 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001502
1503 cmdPtr = strpbrk(cmdPtr, " ");
1504
1505 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301506 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001507
1508 /* remove empty spaces */
1509 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1510 cmdPtr++;
1511
1512 /* number of channels */
1513 ret = sscanf(cmdPtr, "%31s ", buf);
1514 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301515 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001516
1517 ret = kstrtos32(buf, 10, &content);
1518 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301519 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001520
1521 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301522 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523
1524 pPlmRequest->plmNumCh = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301525 hddLog(QDF_TRACE_LEVEL_DEBUG, "numch %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001526 pPlmRequest->plmNumCh);
1527
1528 /* Channel numbers */
1529 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1530 cmdPtr = strpbrk(cmdPtr, " ");
1531
1532 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301533 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001534
1535 /* remove empty spaces */
1536 while ((SPACE_ASCII_VALUE == *cmdPtr)
1537 && ('\0' != *cmdPtr))
1538 cmdPtr++;
1539
1540 ret = sscanf(cmdPtr, "%31s ", buf);
1541 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301542 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001543
1544 ret = kstrtos32(buf, 10, &content);
1545 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301546 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001547
1548 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301549 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001550
1551 pPlmRequest->plmChList[count] = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301552 hddLog(QDF_TRACE_LEVEL_DEBUG, " ch- %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553 pPlmRequest->plmChList[count]);
1554 }
1555 }
1556 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301557 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001558}
1559#endif
1560
1561#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1562static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1563{
1564 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1565 int rc;
1566
1567 rc = wlan_hdd_validate_context(hdd_ctx);
1568 if (0 != rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301569 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001570 return;
1571 }
1572 hdd_ctx->ext_wow_should_suspend = is_success;
1573 complete(&hdd_ctx->ready_to_extwow);
1574}
1575
1576static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1577 tpSirExtWoWParams arg_params)
1578{
1579 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301580 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001581 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1582 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1583 int rc;
1584
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301585 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586
1587 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1588
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301589 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001590 &wlan_hdd_ready_to_extwow,
1591 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301592 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301593 hddLog(QDF_TRACE_LEVEL_ERROR,
Krishna Kumaar Natarajand9131902015-10-19 11:52:47 -07001594 FL("sme_configure_ext_wow returned failure %d"),
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301595 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001596 return -EPERM;
1597 }
1598
1599 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1600 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1601 if (!rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301602 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603 "%s: Failed to get ready to extwow", __func__);
1604 return -EPERM;
1605 }
1606
1607 if (hdd_ctx->ext_wow_should_suspend) {
1608 if (hdd_ctx->config->extWowGotoSuspend) {
1609 pm_message_t state;
1610
1611 state.event = PM_EVENT_SUSPEND;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301612 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613 "%s: Received ready to ExtWoW. Going to suspend",
1614 __func__);
1615
1616 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1617 if (rc < 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301618 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619 "%s: wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1620 __func__, rc);
1621 return rc;
1622 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301623 qdf_ret_status = wlan_hdd_bus_suspend(state);
1624 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301625 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626 "%s: wlan_hdd_suspend failed, status = %d",
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301627 __func__, qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1629 return -EPERM;
1630 }
1631 }
1632 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301633 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634 "%s: Received ready to ExtWoW failure", __func__);
1635 return -EPERM;
1636 }
1637
1638 return 0;
1639}
1640
1641static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1642 int value)
1643{
1644 tSirExtWoWParams params;
1645 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1646 int rc;
1647
1648 rc = wlan_hdd_validate_context(hdd_ctx);
1649 if (0 != rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301650 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001651 return -EINVAL;
1652 }
1653
1654 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1655 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301656 hddLog(QDF_TRACE_LEVEL_ERROR, FL("Invalid type"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001657 return -EINVAL;
1658 }
1659
1660 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1661 hdd_ctx->is_extwow_app_type1_param_set)
1662 params.type = value;
1663 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1664 hdd_ctx->is_extwow_app_type2_param_set)
1665 params.type = value;
1666 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1667 hdd_ctx->is_extwow_app_type1_param_set &&
1668 hdd_ctx->is_extwow_app_type2_param_set)
1669 params.type = value;
1670 else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301671 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672 FL("Set app params before enable it value %d"), value);
1673 return -EINVAL;
1674 }
1675
1676 params.vdev_id = vdev_id;
1677 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1678 (hdd_ctx->config->extWowApp2WakeupPinNumber
1679 << 8);
1680
1681 return hdd_enable_ext_wow(adapter, &params);
1682}
1683
1684static int hdd_set_app_type1_params(tHalHandle hHal,
1685 tpSirAppType1Params arg_params)
1686{
1687 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301688 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301690 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301692 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1693 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301694 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695 FL("sme_configure_app_type1_params returned failure %d"),
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301696 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 return -EPERM;
1698 }
1699
1700 return 0;
1701}
1702
1703static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
1704 char *arg, int len)
1705{
1706 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1707 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1708 char id[20], password[20];
1709 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001710 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711
1712 rc = wlan_hdd_validate_context(hdd_ctx);
1713 if (0 != rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301714 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001715 return -EINVAL;
1716 }
1717
1718 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301719 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720 FL("Invalid Number of arguments"));
1721 return -EINVAL;
1722 }
1723
1724 memset(&params, 0, sizeof(tSirAppType1Params));
1725 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05301726 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001727
1728 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301729 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301731 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301733 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734 "%s: %d %pM %.8s %u %.16s %u",
Srinivas Girigowda04209912015-11-24 12:11:13 -08001735 __func__, params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736 params.identification_id, params.id_length,
1737 params.password, params.pass_length);
1738
1739 return hdd_set_app_type1_params(hHal, &params);
1740}
1741
1742static int hdd_set_app_type2_params(tHalHandle hHal,
1743 tpSirAppType2Params arg_params)
1744{
1745 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301746 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001747
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301748 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301750 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
1751 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301752 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753 FL("sme_configure_app_type2_params returned failure %d"),
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301754 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001755 return -EPERM;
1756 }
1757
1758 return 0;
1759}
1760
1761static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
1762 char *arg, int len)
1763{
1764 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1765 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1766 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05301767 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001768 tSirAppType2Params params;
1769 int ret;
1770
1771 ret = wlan_hdd_validate_context(hdd_ctx);
1772 if (0 != ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301773 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774 return -EINVAL;
1775 }
1776
1777 memset(&params, 0, sizeof(tSirAppType2Params));
1778
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05301779 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 -08001780 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
1781 (unsigned int *)&params.ip_device_ip,
1782 (unsigned int *)&params.ip_server_ip,
1783 (unsigned int *)&params.tcp_seq,
1784 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05301785 (uint16_t *)&params.tcp_src_port,
1786 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001787 (unsigned int *)&params.keepalive_init,
1788 (unsigned int *)&params.keepalive_min,
1789 (unsigned int *)&params.keepalive_max,
1790 (unsigned int *)&params.keepalive_inc,
1791 (unsigned int *)&params.tcp_tx_timeout_val,
1792 (unsigned int *)&params.tcp_rx_timeout_val);
1793
1794 if (ret != 15 && ret != 7) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301795 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001796 "Invalid Number of arguments");
1797 return -EINVAL;
1798 }
1799
1800 if (6 !=
1801 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
1802 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
1803 &gateway_mac[4], &gateway_mac[5])) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301804 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001805 "Invalid MacAddress Input %s", mac_addr);
1806 return -EINVAL;
1807 }
1808
1809 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
1810 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301811 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812 "Invalid TCP Port Number");
1813 return -EINVAL;
1814 }
1815
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301816 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301817 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001818
1819 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301820 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821
1822 params.vdev_id = adapter->sessionId;
1823 params.tcp_src_port = (params.tcp_src_port != 0) ?
1824 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
1825 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
1826 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
1827 params.keepalive_init = (params.keepalive_init != 0) ?
1828 params.keepalive_init : hdd_ctx->config->
1829 extWowApp2KAInitPingInterval;
1830 params.keepalive_min =
1831 (params.keepalive_min != 0) ?
1832 params.keepalive_min :
1833 hdd_ctx->config->extWowApp2KAMinPingInterval;
1834 params.keepalive_max =
1835 (params.keepalive_max != 0) ?
1836 params.keepalive_max :
1837 hdd_ctx->config->extWowApp2KAMaxPingInterval;
1838 params.keepalive_inc =
1839 (params.keepalive_inc != 0) ?
1840 params.keepalive_inc :
1841 hdd_ctx->config->extWowApp2KAIncPingInterval;
1842 params.tcp_tx_timeout_val =
1843 (params.tcp_tx_timeout_val != 0) ?
1844 params.tcp_tx_timeout_val :
1845 hdd_ctx->config->extWowApp2TcpTxTimeout;
1846 params.tcp_rx_timeout_val =
1847 (params.tcp_rx_timeout_val != 0) ?
1848 params.tcp_rx_timeout_val :
1849 hdd_ctx->config->extWowApp2TcpRxTimeout;
1850
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301851 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001852 "%s: %pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
1853 __func__, gateway_mac, rc4_key, params.ip_id,
1854 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
1855 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
1856 params.keepalive_init, params.keepalive_min,
1857 params.keepalive_max, params.keepalive_inc,
1858 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
1859
1860 return hdd_set_app_type2_params(hHal, &params);
1861}
1862#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
1863
1864/**
1865 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
1866 * @pValue: Pointer to MAXTXPOWER command
1867 * @pDbm: Pointer to tx power
1868 *
1869 * This function parses the MAXTXPOWER command passed in the format
1870 * MAXTXPOWER<space>X(Tx power in dbm)
1871 *
1872 * For example input commands:
1873 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
1874 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
1875 *
1876 * Return: 0 for success non-zero for failure
1877 */
1878static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
1879{
1880 uint8_t *inPtr = pValue;
1881 int tempInt;
1882 int v = 0;
1883 *pTxPower = 0;
1884
1885 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1886 /* no argument after the command */
1887 if (NULL == inPtr) {
1888 return -EINVAL;
1889 }
1890
1891 /* no space after the command */
1892 else if (SPACE_ASCII_VALUE != *inPtr) {
1893 return -EINVAL;
1894 }
1895
1896 /* remove empty spaces */
1897 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1898 inPtr++;
1899
1900 /* no argument followed by spaces */
1901 if ('\0' == *inPtr) {
1902 return 0;
1903 }
1904
1905 v = kstrtos32(inPtr, 10, &tempInt);
1906
1907 /* Range checking for passed parameter */
1908 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
1909 return -EINVAL;
1910 }
1911
1912 *pTxPower = tempInt;
1913
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301914 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915 "SETMAXTXPOWER: %d", *pTxPower);
1916
1917 return 0;
1918} /* End of hdd_parse_setmaxtxpower_command */
1919
1920static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
1921 char *extra, uint8_t n, uint8_t *len)
1922{
1923 int ret = 0;
1924
1925 if (!pCfg || !command || !extra || !len) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301926 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927 "%s: argument passed for GETDWELLTIME is incorrect",
1928 __func__);
1929 ret = -EINVAL;
1930 return ret;
1931 }
1932
1933 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
1934 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
1935 (int)pCfg->nActiveMaxChnTime);
1936 return ret;
1937 } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
1938 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
1939 (int)pCfg->nActiveMinChnTime);
1940 return ret;
1941 } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
1942 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
1943 (int)pCfg->nPassiveMaxChnTime);
1944 return ret;
1945 } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
1946 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
1947 (int)pCfg->nPassiveMinChnTime);
1948 return ret;
1949 } else if (strncmp(command, "GETDWELLTIME", 12) == 0) {
1950 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
1951 (int)pCfg->nActiveMaxChnTime);
1952 return ret;
1953 } else {
1954 ret = -EINVAL;
1955 }
1956
1957 return ret;
1958}
1959
1960static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
1961{
1962 tHalHandle hHal;
1963 struct hdd_config *pCfg;
1964 uint8_t *value = command;
1965 tSmeConfigParams smeConfig;
1966 int val = 0, temp = 0;
1967
1968 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
1969 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1970 if (!pCfg || !hHal) {
1971 hddLog(LOGE,
1972 FL("argument passed for SETDWELLTIME is incorrect"));
1973 return -EINVAL;
1974 }
1975
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301976 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001977 sme_get_config_param(hHal, &smeConfig);
1978
1979 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
1980 value = value + 24;
1981 temp = kstrtou32(value, 10, &val);
1982 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
1983 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
1984 hddLog(LOGE,
1985 FL("argument passed for SETDWELLTIME ACTIVE MAX is incorrect"));
1986 return -EFAULT;
1987 }
1988 pCfg->nActiveMaxChnTime = val;
1989 smeConfig.csrConfig.nActiveMaxChnTime = val;
1990 sme_update_config(hHal, &smeConfig);
1991 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
1992 value = value + 24;
1993 temp = kstrtou32(value, 10, &val);
1994 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
1995 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
1996 hddLog(LOGE,
1997 FL("argument passed for SETDWELLTIME ACTIVE MIN is incorrect"));
1998 return -EFAULT;
1999 }
2000 pCfg->nActiveMinChnTime = val;
2001 smeConfig.csrConfig.nActiveMinChnTime = val;
2002 sme_update_config(hHal, &smeConfig);
2003 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2004 value = value + 25;
2005 temp = kstrtou32(value, 10, &val);
2006 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2007 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
2008 hddLog(LOGE,
2009 FL("argument passed for SETDWELLTIME PASSIVE MAX is incorrect"));
2010 return -EFAULT;
2011 }
2012 pCfg->nPassiveMaxChnTime = val;
2013 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2014 sme_update_config(hHal, &smeConfig);
2015 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2016 value = value + 25;
2017 temp = kstrtou32(value, 10, &val);
2018 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2019 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
2020 hddLog(LOGE,
2021 FL("argument passed for SETDWELLTIME PASSIVE MIN is incorrect"));
2022 return -EFAULT;
2023 }
2024 pCfg->nPassiveMinChnTime = val;
2025 smeConfig.csrConfig.nPassiveMinChnTime = val;
2026 sme_update_config(hHal, &smeConfig);
2027 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2028 value = value + 13;
2029 temp = kstrtou32(value, 10, &val);
2030 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2031 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
2032 hddLog(LOGE,
2033 FL("argument passed for SETDWELLTIME is incorrect"));
2034 return -EFAULT;
2035 }
2036 pCfg->nActiveMaxChnTime = val;
2037 smeConfig.csrConfig.nActiveMaxChnTime = val;
2038 sme_update_config(hHal, &smeConfig);
2039 } else {
2040 return -EINVAL;
2041 }
2042
2043 return 0;
2044}
2045
2046static void hdd_get_link_status_cb(uint8_t status, void *context)
2047{
2048 struct statsContext *pLinkContext;
2049 hdd_adapter_t *adapter;
2050
2051 if (NULL == context) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302052 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: Bad context [%p]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002053 __func__, context);
2054 return;
2055 }
2056
2057 pLinkContext = context;
2058 adapter = pLinkContext->pAdapter;
2059
2060 spin_lock(&hdd_context_lock);
2061
2062 if ((NULL == adapter) ||
2063 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2064 /*
2065 * the caller presumably timed out so there is
2066 * nothing we can do
2067 */
2068 spin_unlock(&hdd_context_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302069 hddLog(QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002070 "%s: Invalid context, adapter [%p] magic [%08x]",
2071 __func__, adapter, pLinkContext->magic);
2072 return;
2073 }
2074
2075 /* context is valid so caller is still waiting */
2076
2077 /* paranoia: invalidate the magic */
2078 pLinkContext->magic = 0;
2079
2080 /* copy over the status */
2081 adapter->linkStatus = status;
2082
2083 /* notify the caller */
2084 complete(&pLinkContext->completion);
2085
2086 /* serialization is complete */
2087 spin_unlock(&hdd_context_lock);
2088}
2089
2090/**
2091 * wlan_hdd_get_link_status() - get link status
2092 * @pAdapter: pointer to the adapter
2093 *
2094 * This function sends a request to query the link status and waits
2095 * on a timer to invoke the callback. if the callback is invoked then
2096 * latest link status shall be returned or otherwise cached value
2097 * will be returned.
2098 *
2099 * Return: On success, link status shall be returned.
2100 * On error or not associated, link status 0 will be returned.
2101 */
2102static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2103{
2104
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002105 hdd_station_ctx_t *pHddStaCtx =
2106 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2107 struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302108 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002109 unsigned long rc;
2110
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002111 if (cds_is_driver_recovering()) {
2112 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2113 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002114 return 0;
2115 }
2116
2117 if ((WLAN_HDD_INFRA_STATION != adapter->device_mode) &&
2118 (WLAN_HDD_P2P_CLIENT != adapter->device_mode)) {
2119 hdd_warn("Unsupported in mode %s(%d)",
2120 hdd_device_mode_to_string(adapter->device_mode),
2121 adapter->device_mode);
2122 return 0;
2123 }
2124
2125 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2126 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2127 /* If not associated, then expected link status return
2128 * value is 0
2129 */
2130 hddLog(LOG1, FL("Not associated!"));
2131 return 0;
2132 }
2133
2134 init_completion(&context.completion);
2135 context.pAdapter = adapter;
2136 context.magic = LINK_STATUS_MAGIC;
2137 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2138 hdd_get_link_status_cb,
2139 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302140 if (QDF_STATUS_SUCCESS != hstatus) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302141 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002142 "%s: Unable to retrieve link status", __func__);
2143 /* return a cached value */
2144 } else {
2145 /* request is sent -- wait for the response */
2146 rc = wait_for_completion_timeout(&context.completion,
2147 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2148 if (!rc)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302149 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002150 FL("SME timed out while retrieving link status"));
2151 }
2152
2153 spin_lock(&hdd_context_lock);
2154 context.magic = 0;
2155 spin_unlock(&hdd_context_lock);
2156
2157 /* either callback updated adapter stats or it has cached data */
2158 return adapter->linkStatus;
2159}
2160
2161#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
2162/**
2163 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2164 * @pValue: Pointer to data
2165 * @pEseBcnReq: Output pointer to store parsed ie information
2166 *
2167 * This function parses the ese beacon request passed in the format
2168 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2169 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2170 * <space>Scan Mode N<space>Meas Duration N
2171 *
2172 * If the Number of bcn req fields (N) does not match with the
2173 * actual number of fields passed then take N.
2174 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2175 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2176 * This function does not take care of removing duplicate channels from the
2177 * list
2178 *
2179 * Return: 0 for success non-zero for failure
2180 */
2181static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2182 tCsrEseBeaconReq *pEseBcnReq)
2183{
2184 uint8_t *inPtr = pValue;
2185 int tempInt = 0;
2186 int j = 0, i = 0, v = 0;
2187 char buf[32];
2188
2189 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2190 /* no argument after the command */
2191 if (NULL == inPtr) {
2192 return -EINVAL;
2193 }
2194 /* no space after the command */
2195 else if (SPACE_ASCII_VALUE != *inPtr) {
2196 return -EINVAL;
2197 }
2198
2199 /* remove empty spaces */
2200 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2201 inPtr++;
2202
2203 /* no argument followed by spaces */
2204 if ('\0' == *inPtr)
2205 return -EINVAL;
2206
2207 /* get the first argument ie measurement token */
2208 v = sscanf(inPtr, "%31s ", buf);
2209 if (1 != v)
2210 return -EINVAL;
2211
2212 v = kstrtos32(buf, 10, &tempInt);
2213 if (v < 0)
2214 return -EINVAL;
2215
2216 pEseBcnReq->numBcnReqIe = tempInt;
2217
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302218 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002219 "Number of Bcn Req Ie fields(%d)", pEseBcnReq->numBcnReqIe);
2220
2221 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2222 for (i = 0; i < 4; i++) {
2223 /*
2224 * inPtr pointing to the beginning of 1st space
2225 * after number of ie fields
2226 */
2227 inPtr = strpbrk(inPtr, " ");
2228 /* no ie data after the number of ie fields argument */
2229 if (NULL == inPtr)
2230 return -EINVAL;
2231
2232 /* remove empty space */
2233 while ((SPACE_ASCII_VALUE == *inPtr)
2234 && ('\0' != *inPtr))
2235 inPtr++;
2236
2237 /*
2238 * no ie data after the number of ie fields
2239 * argument and spaces
2240 */
2241 if ('\0' == *inPtr)
2242 return -EINVAL;
2243
2244 v = sscanf(inPtr, "%31s ", buf);
2245 if (1 != v)
2246 return -EINVAL;
2247
2248 v = kstrtos32(buf, 10, &tempInt);
2249 if (v < 0)
2250 return -EINVAL;
2251
2252 switch (i) {
2253 case 0: /* Measurement token */
2254 if (tempInt <= 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302255 QDF_TRACE(QDF_MODULE_ID_HDD,
2256 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002257 "Invalid Measurement Token(%d)",
2258 tempInt);
2259 return -EINVAL;
2260 }
2261 pEseBcnReq->bcnReq[j].measurementToken =
2262 tempInt;
2263 break;
2264
2265 case 1: /* Channel number */
2266 if ((tempInt <= 0) ||
2267 (tempInt >
2268 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302269 QDF_TRACE(QDF_MODULE_ID_HDD,
2270 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002271 "Invalid Channel Number(%d)",
2272 tempInt);
2273 return -EINVAL;
2274 }
2275 pEseBcnReq->bcnReq[j].channel = tempInt;
2276 break;
2277
2278 case 2: /* Scan mode */
2279 if ((tempInt < eSIR_PASSIVE_SCAN)
2280 || (tempInt > eSIR_BEACON_TABLE)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302281 QDF_TRACE(QDF_MODULE_ID_HDD,
2282 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002283 "Invalid Scan Mode(%d) Expected{0|1|2}",
2284 tempInt);
2285 return -EINVAL;
2286 }
2287 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2288 break;
2289
2290 case 3: /* Measurement duration */
2291 if (((tempInt <= 0)
2292 && (pEseBcnReq->bcnReq[j].scanMode !=
2293 eSIR_BEACON_TABLE)) ||
2294 ((tempInt < 0) &&
2295 (pEseBcnReq->bcnReq[j].scanMode ==
2296 eSIR_BEACON_TABLE))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302297 QDF_TRACE(QDF_MODULE_ID_HDD,
2298 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002299 "Invalid Measurement Duration(%d)",
2300 tempInt);
2301 return -EINVAL;
2302 }
2303 pEseBcnReq->bcnReq[j].measurementDuration =
2304 tempInt;
2305 break;
2306 }
2307 }
2308 }
2309
2310 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302311 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002312 "Index(%d) Measurement Token(%u) Channel(%u) Scan Mode(%u) Measurement Duration(%u)",
2313 j,
2314 pEseBcnReq->bcnReq[j].measurementToken,
2315 pEseBcnReq->bcnReq[j].channel,
2316 pEseBcnReq->bcnReq[j].scanMode,
2317 pEseBcnReq->bcnReq[j].measurementDuration);
2318 }
2319
2320 return 0;
2321}
2322#endif /* defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) */
2323
2324#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
2325/**
2326 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2327 * @pValue: Pointer to input data
2328 * @pCckmIe: Pointer to output cckm Ie
2329 * @pCckmIeLen: Pointer to output cckm ie length
2330 *
2331 * This function parses the SETCCKM IE command
2332 * SETCCKMIE<space><ie data>
2333 *
2334 * Return: 0 for success non-zero for failure
2335 */
2336static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2337 uint8_t *pCckmIeLen)
2338{
2339 uint8_t *inPtr = pValue;
2340 uint8_t *dataEnd;
2341 int j = 0;
2342 int i = 0;
2343 uint8_t tempByte = 0;
2344 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2345 /* no argument after the command */
2346 if (NULL == inPtr) {
2347 return -EINVAL;
2348 }
2349 /* no space after the command */
2350 else if (SPACE_ASCII_VALUE != *inPtr) {
2351 return -EINVAL;
2352 }
2353 /* remove empty spaces */
2354 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2355 inPtr++;
2356 /* no argument followed by spaces */
2357 if ('\0' == *inPtr) {
2358 return -EINVAL;
2359 }
2360 /* find the length of data */
2361 dataEnd = inPtr;
2362 while (('\0' != *dataEnd)) {
2363 dataEnd++;
2364 ++(*pCckmIeLen);
2365 }
2366 if (*pCckmIeLen <= 0)
2367 return -EINVAL;
2368 /*
2369 * Allocate the number of bytes based on the number of input characters
2370 * whether it is even or odd.
2371 * if the number of input characters are even, then we need N / 2 byte.
2372 * if the number of input characters are odd, then we need do
2373 * (N + 1) / 2 to compensate rounding off.
2374 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2375 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2376 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302377 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002378 if (NULL == *pCckmIe) {
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302379 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002380 return -ENOMEM;
2381 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302382 qdf_mem_zero(*pCckmIe, (*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002383 /*
2384 * the buffer received from the upper layer is character buffer,
2385 * we need to prepare the buffer taking 2 characters in to a U8 hex
2386 * decimal number for example 7f0000f0...form a buffer to contain
2387 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2388 */
2389 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2390 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2391 (hex_to_bin(inPtr[j + 1]));
2392 (*pCckmIe)[i++] = tempByte;
2393 }
2394 *pCckmIeLen = i;
2395 return 0;
2396}
2397#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
2398
2399int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2400{
2401 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302402 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002403 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2404 struct hdd_config *pConfig = NULL;
2405
2406 if (pHddCtx == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302407 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002408 "%s: HDD context is null", __func__);
2409 return -EINVAL;
2410 }
2411 if ((WLAN_HDD_IBSS != pAdapter->device_mode) &&
2412 (WLAN_HDD_SOFTAP != pAdapter->device_mode) &&
2413 (WLAN_HDD_INFRA_STATION != pAdapter->device_mode)) {
2414 hddLog(LOGE,
2415 FL("Received SETMCRATE cmd in invalid mode %s(%d)"),
2416 hdd_device_mode_to_string(pAdapter->device_mode),
2417 pAdapter->device_mode);
2418 hddLog(LOGE,
2419 FL("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode"));
2420 return -EINVAL;
2421 }
2422 pConfig = pHddCtx->config;
2423 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2424 rateUpdate.dev_mode = pAdapter->device_mode;
2425 rateUpdate.mcastDataRate24GHz = targetRate;
2426 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2427 rateUpdate.mcastDataRate5GHz = targetRate;
2428 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302429 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002430 hddLog(LOG1,
2431 FL("MC Target rate %d, mac = %pM, dev_mode %s(%d)"),
Srinivas Girigowdaafede182015-11-18 22:36:12 -08002432 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002433 hdd_device_mode_to_string(pAdapter->device_mode),
2434 pAdapter->device_mode);
2435 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302436 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302437 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: SETMCRATE failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002438 __func__);
2439 return -EFAULT;
2440 }
2441 return 0;
2442}
2443
2444static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2445 hdd_context_t *hdd_ctx,
2446 uint8_t *command,
2447 uint8_t command_len,
2448 hdd_priv_data_t *priv_data)
2449{
2450 int ret = 0;
2451
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302452 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002453 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2454 adapter->sessionId,
2455 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2456 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2457 + 3) << 16 | *(hdd_ctx->
2458 p2pDeviceAddress.bytes + 4) << 8 |
2459 *(hdd_ctx->p2pDeviceAddress.bytes +
2460 5))));
2461
2462 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2463 sizeof(tSirMacAddr))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302464 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002465 "%s: failed to copy data to user buffer",
2466 __func__);
2467 ret = -EFAULT;
2468 }
2469
2470 return ret;
2471}
2472
2473/**
2474 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2475 * @adapter: Adapter on which the command was received
2476 * @hdd_ctx: HDD global context
2477 * @command: Entire driver command received from userspace
2478 * @command_len: Length of @command
2479 * @priv_data: Pointer to ioctl private data structure
2480 *
2481 * This is a trivial command hander function which simply forwards the
2482 * command to the actual command processor within the P2P module.
2483 *
2484 * Return: 0 on success, non-zero on failure
2485 */
2486static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2487 hdd_context_t *hdd_ctx,
2488 uint8_t *command,
2489 uint8_t command_len,
2490 hdd_priv_data_t *priv_data)
2491{
2492 return hdd_set_p2p_noa(adapter->dev, command);
2493}
2494
2495/**
2496 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2497 * @adapter: Adapter on which the command was received
2498 * @hdd_ctx: HDD global context
2499 * @command: Entire driver command received from userspace
2500 * @command_len: Length of @command
2501 * @priv_data: Pointer to ioctl private data structure
2502 *
2503 * This is a trivial command hander function which simply forwards the
2504 * command to the actual command processor within the P2P module.
2505 *
2506 * Return: 0 on success, non-zero on failure
2507 */
2508static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2509 hdd_context_t *hdd_ctx,
2510 uint8_t *command,
2511 uint8_t command_len,
2512 hdd_priv_data_t *priv_data)
2513{
2514 return hdd_set_p2p_opps(adapter->dev, command);
2515}
2516
2517static int drv_cmd_set_band(hdd_adapter_t *adapter,
2518 hdd_context_t *hdd_ctx,
2519 uint8_t *command,
2520 uint8_t command_len,
2521 hdd_priv_data_t *priv_data)
2522{
2523 int ret = 0;
2524
2525 uint8_t *ptr = command;
2526
2527 /* Change band request received */
2528
2529 /*
2530 * First 8 bytes will have "SETBAND " and
2531 * 9 byte will have band setting value
2532 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302533 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002534 "%s: SetBandCommand Info comm %s UL %d, TL %d",
2535 __func__, command, priv_data->used_len,
2536 priv_data->total_len);
2537
2538 /* Change band request received */
2539 ret = hdd_set_band_helper(adapter->dev, ptr);
2540
2541 return ret;
2542}
2543
2544static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2545 hdd_context_t *hdd_ctx,
2546 uint8_t *command,
2547 uint8_t command_len,
2548 hdd_priv_data_t *priv_data)
2549{
2550 return hdd_wmmps_helper(adapter, command);
2551}
2552
2553static int drv_cmd_country(hdd_adapter_t *adapter,
2554 hdd_context_t *hdd_ctx,
2555 uint8_t *command,
2556 uint8_t command_len,
2557 hdd_priv_data_t *priv_data)
2558{
2559 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302560 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002561 unsigned long rc;
2562 char *country_code;
2563
2564 country_code = command + 8;
2565
2566 INIT_COMPLETION(adapter->change_country_code);
2567
2568 status = sme_change_country_code(hdd_ctx->hHal,
2569 wlan_hdd_change_country_code_callback,
2570 country_code,
2571 adapter,
2572 hdd_ctx->pcds_context,
2573 eSIR_TRUE,
2574 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302575 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002576 rc = wait_for_completion_timeout(
2577 &adapter->change_country_code,
2578 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
2579 if (!rc)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302580 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002581 "%s: SME while setting country code timed out",
2582 __func__);
2583 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302584 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002585 "%s: SME Change Country code fail, status=%d",
2586 __func__, status);
2587 ret = -EINVAL;
2588 }
2589
2590 return ret;
2591}
2592
2593static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
2594 hdd_context_t *hdd_ctx,
2595 uint8_t *command,
2596 uint8_t command_len,
2597 hdd_priv_data_t *priv_data)
2598{
2599 int ret = 0;
2600 uint8_t *value = command;
2601 int8_t rssi = 0;
2602 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302603 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002604
2605 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2606 value = value + command_len + 1;
2607
2608 /* Convert the value from ascii to integer */
2609 ret = kstrtos8(value, 10, &rssi);
2610 if (ret < 0) {
2611 /*
2612 * If the input value is greater than max value of datatype,
2613 * then also kstrtou8 fails
2614 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302615 QDF_TRACE(QDF_MODULE_ID_HDD,
2616 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002617 "%s: kstrtou8 failed Input value may be out of range[%d - %d]",
2618 __func__,
2619 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2620 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
2621 ret = -EINVAL;
2622 goto exit;
2623 }
2624
2625 lookUpThreshold = abs(rssi);
2626
2627 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
2628 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302629 QDF_TRACE(QDF_MODULE_ID_HDD,
2630 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002631 "Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
2632 lookUpThreshold,
2633 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2634 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
2635 ret = -EINVAL;
2636 goto exit;
2637 }
2638
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302639 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002640 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
2641 adapter->sessionId, lookUpThreshold));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302642 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002643 "%s: Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
2644 __func__,
2645 lookUpThreshold);
2646
2647 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
2648 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
2649 adapter->sessionId,
2650 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302651 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302652 QDF_TRACE(QDF_MODULE_ID_HDD,
2653 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002654 "%s: Failed to set roam trigger, try again",
2655 __func__);
2656 ret = -EPERM;
2657 goto exit;
2658 }
2659
2660exit:
2661 return ret;
2662}
2663
2664static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
2665 hdd_context_t *hdd_ctx,
2666 uint8_t *command,
2667 uint8_t command_len,
2668 hdd_priv_data_t *priv_data)
2669{
2670 int ret = 0;
2671 uint8_t lookUpThreshold =
2672 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
2673 int rssi = (-1) * lookUpThreshold;
2674 char extra[32];
2675 uint8_t len = 0;
2676
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302677 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002678 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
2679 adapter->sessionId, lookUpThreshold));
2680
2681 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05302682 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002683 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302684 QDF_TRACE(QDF_MODULE_ID_HDD,
2685 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002686 "%s: failed to copy data to user buffer",
2687 __func__);
2688 ret = -EFAULT;
2689 }
2690
2691 return ret;
2692}
2693
2694static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
2695 hdd_context_t *hdd_ctx,
2696 uint8_t *command,
2697 uint8_t command_len,
2698 hdd_priv_data_t *priv_data)
2699{
2700 int ret = 0;
2701 uint8_t *value = command;
2702 uint8_t roamScanPeriod = 0;
2703 uint16_t neighborEmptyScanRefreshPeriod =
2704 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
2705
2706 /* input refresh period is in terms of seconds */
2707
2708 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
2709 value = value + command_len + 1;
2710
2711 /* Convert the value from ascii to integer */
2712 ret = kstrtou8(value, 10, &roamScanPeriod);
2713 if (ret < 0) {
2714 /*
2715 * If the input value is greater than max value of datatype,
2716 * then also kstrtou8 fails
2717 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302718 QDF_TRACE(QDF_MODULE_ID_HDD,
2719 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720 "%s: kstrtou8 failed Input value may be out of range[%d - %d]",
2721 __func__,
2722 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
2723 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
2724 ret = -EINVAL;
2725 goto exit;
2726 }
2727
2728 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
2729 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302730 QDF_TRACE(QDF_MODULE_ID_HDD,
2731 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732 "Roam scan period value %d is out of range (Min: %d Max: %d)",
2733 roamScanPeriod,
2734 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
2735 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
2736 ret = -EINVAL;
2737 goto exit;
2738 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302739 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002740 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
2741 adapter->sessionId, roamScanPeriod));
2742 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
2743
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302744 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002745 "%s: Received Command to Set roam scan period (Empty Scan refresh period) = %d",
2746 __func__,
2747 roamScanPeriod);
2748
2749 hdd_ctx->config->nEmptyScanRefreshPeriod =
2750 neighborEmptyScanRefreshPeriod;
2751 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
2752 adapter->sessionId,
2753 neighborEmptyScanRefreshPeriod);
2754
2755exit:
2756 return ret;
2757}
2758
2759static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
2760 hdd_context_t *hdd_ctx,
2761 uint8_t *command,
2762 uint8_t command_len,
2763 hdd_priv_data_t *priv_data)
2764{
2765 int ret = 0;
2766 uint16_t nEmptyScanRefreshPeriod =
2767 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
2768 char extra[32];
2769 uint8_t len = 0;
2770
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302771 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002772 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
2773 adapter->sessionId,
2774 nEmptyScanRefreshPeriod));
2775 len = scnprintf(extra, sizeof(extra), "%s %d",
2776 "GETROAMSCANPERIOD",
2777 (nEmptyScanRefreshPeriod / 1000));
2778 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05302779 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002780 if (copy_to_user(priv_data->buf, &extra, len)) {
2781 hddLog(LOGE,
2782 FL("failed to copy data to user buffer"));
2783 ret = -EFAULT;
2784 }
2785
2786 return ret;
2787}
2788
2789static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
2790 hdd_context_t *hdd_ctx,
2791 uint8_t *command,
2792 uint8_t command_len,
2793 hdd_priv_data_t *priv_data)
2794{
2795 int ret = 0;
2796 uint8_t *value = command;
2797 uint8_t roamScanRefreshPeriod = 0;
2798 uint16_t neighborScanRefreshPeriod =
2799 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
2800
2801 /* input refresh period is in terms of seconds */
2802 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
2803 value = value + command_len + 1;
2804
2805 /* Convert the value from ascii to integer */
2806 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
2807 if (ret < 0) {
2808 /*
2809 * If the input value is greater than max value of datatype,
2810 * then also kstrtou8 fails
2811 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302812 QDF_TRACE(QDF_MODULE_ID_HDD,
2813 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002814 "%s: kstrtou8 failed Input value may be out of range[%d - %d]",
2815 __func__,
2816 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
2817 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
2818 ret = -EINVAL;
2819 goto exit;
2820 }
2821
2822 if ((roamScanRefreshPeriod <
2823 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
2824 || (roamScanRefreshPeriod >
2825 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302826 QDF_TRACE(QDF_MODULE_ID_HDD,
2827 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002828 "Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
2829 roamScanRefreshPeriod,
2830 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
2831 / 1000),
2832 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
2833 / 1000));
2834 ret = -EINVAL;
2835 goto exit;
2836 }
2837 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
2838
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302839 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002840 "%s: Received Command to Set roam scan refresh period (Scan refresh period) = %d",
2841 __func__,
2842 roamScanRefreshPeriod);
2843
2844 hdd_ctx->config->nNeighborResultsRefreshPeriod =
2845 neighborScanRefreshPeriod;
2846 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
2847 adapter->sessionId,
2848 neighborScanRefreshPeriod);
2849
2850exit:
2851 return ret;
2852}
2853
2854static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
2855 hdd_context_t *hdd_ctx,
2856 uint8_t *command,
2857 uint8_t command_len,
2858 hdd_priv_data_t *priv_data)
2859{
2860 int ret = 0;
2861 uint16_t value =
2862 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
2863 char extra[32];
2864 uint8_t len = 0;
2865
2866 len = scnprintf(extra, sizeof(extra), "%s %d",
2867 "GETROAMSCANREFRESHPERIOD",
2868 (value / 1000));
2869 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05302870 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002871 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302872 QDF_TRACE(QDF_MODULE_ID_HDD,
2873 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002874 "%s: failed to copy data to user buffer",
2875 __func__);
2876 ret = -EFAULT;
2877 }
2878
2879 return ret;
2880}
2881
2882static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
2883 hdd_context_t *hdd_ctx,
2884 uint8_t *command,
2885 uint8_t command_len,
2886 hdd_priv_data_t *priv_data)
2887{
2888 int ret = 0;
2889 uint8_t *value = command;
2890 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
2891
2892 /* Move pointer to ahead of SETROAMMODE<delimiter> */
2893 value = value + SIZE_OF_SETROAMMODE + 1;
2894
2895 /* Convert the value from ascii to integer */
2896 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
2897 if (ret < 0) {
2898 /*
2899 * If the input value is greater than max value of datatype,
2900 * then also kstrtou8 fails
2901 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302902 QDF_TRACE(QDF_MODULE_ID_HDD,
2903 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002904 "%s: kstrtou8 failed range [%d - %d]",
2905 __func__, CFG_LFR_FEATURE_ENABLED_MIN,
2906 CFG_LFR_FEATURE_ENABLED_MAX);
2907 ret = -EINVAL;
2908 goto exit;
2909 }
2910 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
2911 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302912 QDF_TRACE(QDF_MODULE_ID_HDD,
2913 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002914 "Roam Mode value %d is out of range (Min: %d Max: %d)",
2915 roamMode,
2916 CFG_LFR_FEATURE_ENABLED_MIN,
2917 CFG_LFR_FEATURE_ENABLED_MAX);
2918 ret = -EINVAL;
2919 goto exit;
2920 }
2921
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302922 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002923 "%s: Received Command to Set Roam Mode = %d",
2924 __func__, roamMode);
2925 /*
2926 * Note that
2927 * SETROAMMODE 0 is to enable LFR while
2928 * SETROAMMODE 1 is to disable LFR, but
2929 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
2930 * enable/disable. So, we have to invert the value
2931 * to call sme_update_is_fast_roam_ini_feature_enabled.
2932 */
2933 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
2934 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
2935 else
2936 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
2937
2938 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
2939 if (roamMode) {
2940 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
2941 sme_update_roam_scan_offload_enabled(
2942 (tHalHandle)(hdd_ctx->hHal),
2943 hdd_ctx->config->isRoamOffloadScanEnabled);
2944 sme_update_is_fast_roam_ini_feature_enabled(
2945 hdd_ctx->hHal,
2946 adapter->sessionId,
2947 roamMode);
2948 } else {
2949 sme_update_is_fast_roam_ini_feature_enabled(
2950 hdd_ctx->hHal,
2951 adapter->sessionId,
2952 roamMode);
2953 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
2954 sme_update_roam_scan_offload_enabled(
2955 (tHalHandle)(hdd_ctx->hHal),
2956 hdd_ctx->config->isRoamOffloadScanEnabled);
2957 }
2958
2959
2960exit:
2961 return ret;
2962}
2963
2964static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
2965 hdd_context_t *hdd_ctx,
2966 uint8_t *command,
2967 uint8_t command_len,
2968 hdd_priv_data_t *priv_data)
2969{
2970 int ret = 0;
2971 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
2972 char extra[32];
2973 uint8_t len = 0;
2974
2975 /*
2976 * roamMode value shall be inverted because the sementics is different.
2977 */
2978 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
2979 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
2980 else
2981 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
2982
2983 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05302984 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002985 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302986 QDF_TRACE(QDF_MODULE_ID_HDD,
2987 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002988 "%s: failed to copy data to user buffer",
2989 __func__);
2990 ret = -EFAULT;
2991 }
2992
2993 return ret;
2994}
2995
2996static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
2997 hdd_context_t *hdd_ctx,
2998 uint8_t *command,
2999 uint8_t command_len,
3000 hdd_priv_data_t *priv_data)
3001{
3002 int ret = 0;
3003 uint8_t *value = command;
3004 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3005
3006 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3007 value = value + command_len + 1;
3008
3009 /* Convert the value from ascii to integer */
3010 ret = kstrtou8(value, 10, &roamRssiDiff);
3011 if (ret < 0) {
3012 /*
3013 * If the input value is greater than max value of datatype,
3014 * then also kstrtou8 fails
3015 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303016 QDF_TRACE(QDF_MODULE_ID_HDD,
3017 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 "%s: kstrtou8 failed range [%d - %d]",
3019 __func__, CFG_ROAM_RSSI_DIFF_MIN,
3020 CFG_ROAM_RSSI_DIFF_MAX);
3021 ret = -EINVAL;
3022 goto exit;
3023 }
3024
3025 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3026 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303027 QDF_TRACE(QDF_MODULE_ID_HDD,
3028 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003029 "Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3030 roamRssiDiff,
3031 CFG_ROAM_RSSI_DIFF_MIN,
3032 CFG_ROAM_RSSI_DIFF_MAX);
3033 ret = -EINVAL;
3034 goto exit;
3035 }
3036
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303037 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003038 "%s: Received Command to Set roam rssi diff = %d",
3039 __func__, roamRssiDiff);
3040
3041 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3042 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3043 adapter->sessionId,
3044 roamRssiDiff);
3045
3046exit:
3047 return ret;
3048}
3049
3050static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3051 hdd_context_t *hdd_ctx,
3052 uint8_t *command,
3053 uint8_t command_len,
3054 hdd_priv_data_t *priv_data)
3055{
3056 int ret = 0;
3057 uint8_t roamRssiDiff =
3058 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3059 char extra[32];
3060 uint8_t len = 0;
3061
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303062 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003063 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3064 adapter->sessionId, roamRssiDiff));
3065
3066 len = scnprintf(extra, sizeof(extra), "%s %d",
3067 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303068 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003069
3070 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303071 QDF_TRACE(QDF_MODULE_ID_HDD,
3072 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003073 "%s: failed to copy data to user buffer",
3074 __func__);
3075 ret = -EFAULT;
3076 }
3077
3078 return ret;
3079}
3080
3081static int drv_cmd_get_band(hdd_adapter_t *adapter,
3082 hdd_context_t *hdd_ctx,
3083 uint8_t *command,
3084 uint8_t command_len,
3085 hdd_priv_data_t *priv_data)
3086{
3087 int ret = 0;
3088 int band = -1;
3089 char extra[32];
3090 uint8_t len = 0;
3091
3092 hdd_get_band_helper(hdd_ctx, &band);
3093
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303094 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003095 TRACE_CODE_HDD_GETBAND_IOCTL,
3096 adapter->sessionId, band));
3097
3098 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303099 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003100
3101 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303102 QDF_TRACE(QDF_MODULE_ID_HDD,
3103 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003104 "%s: failed to copy data to user buffer",
3105 __func__);
3106 ret = -EFAULT;
3107 }
3108
3109 return ret;
3110}
3111
3112static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3113 hdd_context_t *hdd_ctx,
3114 uint8_t *command,
3115 uint8_t command_len,
3116 hdd_priv_data_t *priv_data)
3117{
3118 return hdd_parse_set_roam_scan_channels(adapter, command);
3119}
3120
3121static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3122 hdd_context_t *hdd_ctx,
3123 uint8_t *command,
3124 uint8_t command_len,
3125 hdd_priv_data_t *priv_data)
3126{
3127 int ret = 0;
3128 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3129 uint8_t numChannels = 0;
3130 uint8_t j = 0;
3131 char extra[128] = { 0 };
3132 int len;
3133
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303134 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3136 ChannelList,
3137 &numChannels,
3138 adapter->sessionId)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303139 QDF_TRACE(QDF_MODULE_ID_HDD,
3140 QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003141 "%s: failed to get roam scan channel list",
3142 __func__);
3143 ret = -EFAULT;
3144 goto exit;
3145 }
3146
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303147 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003148 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3149 adapter->sessionId, numChannels));
3150 /*
3151 * output channel list is of the format
3152 * [Number of roam scan channels][Channel1][Channel2]...
3153 * copy the number of channels in the 0th index
3154 */
3155 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3156 numChannels);
3157 for (j = 0; (j < numChannels); j++)
3158 len += scnprintf(extra + len, sizeof(extra) - len,
3159 " %d", ChannelList[j]);
3160
Anurag Chouhan6d760662016-02-20 16:05:43 +05303161 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003162 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303163 QDF_TRACE(QDF_MODULE_ID_HDD,
3164 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003165 "%s: failed to copy data to user buffer",
3166 __func__);
3167 ret = -EFAULT;
3168 goto exit;
3169 }
3170
3171exit:
3172 return ret;
3173}
3174
3175static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3176 hdd_context_t *hdd_ctx,
3177 uint8_t *command,
3178 uint8_t command_len,
3179 hdd_priv_data_t *priv_data)
3180{
3181 int ret = 0;
3182 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3183 char extra[32];
3184 uint8_t len = 0;
3185
3186 /*
3187 * Check if the features OKC/ESE/11R are supported simultaneously,
3188 * then this operation is not permitted (return FAILURE)
3189 */
3190 if (eseMode &&
3191 hdd_is_okc_mode_enabled(hdd_ctx) &&
3192 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303193 QDF_TRACE(QDF_MODULE_ID_HDD,
3194 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003195 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
3196 __func__);
3197 ret = -EPERM;
3198 goto exit;
3199 }
3200
3201 len = scnprintf(extra, sizeof(extra), "%s %d",
3202 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303203 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003204 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303205 QDF_TRACE(QDF_MODULE_ID_HDD,
3206 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003207 "%s: failed to copy data to user buffer",
3208 __func__);
3209 ret = -EFAULT;
3210 goto exit;
3211 }
3212
3213exit:
3214 return ret;
3215}
3216
3217static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3218 hdd_context_t *hdd_ctx,
3219 uint8_t *command,
3220 uint8_t command_len,
3221 hdd_priv_data_t *priv_data)
3222{
3223 int ret = 0;
3224 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3225 char extra[32];
3226 uint8_t len = 0;
3227
3228 /*
3229 * Check if the features OKC/ESE/11R are supported simultaneously,
3230 * then this operation is not permitted (return FAILURE)
3231 */
3232 if (okcMode &&
3233 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3234 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303235 QDF_TRACE(QDF_MODULE_ID_HDD,
3236 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003237 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
3238 __func__);
3239 ret = -EPERM;
3240 goto exit;
3241 }
3242
3243 len = scnprintf(extra, sizeof(extra), "%s %d",
3244 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303245 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003246
3247 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303248 QDF_TRACE(QDF_MODULE_ID_HDD,
3249 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003250 "%s: failed to copy data to user buffer",
3251 __func__);
3252 ret = -EFAULT;
3253 goto exit;
3254 }
3255
3256exit:
3257 return ret;
3258}
3259
3260static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3261 hdd_context_t *hdd_ctx,
3262 uint8_t *command,
3263 uint8_t command_len,
3264 hdd_priv_data_t *priv_data)
3265{
3266 int ret = 0;
3267 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3268 char extra[32];
3269 uint8_t len = 0;
3270
3271 len = scnprintf(extra, sizeof(extra), "%s %d",
3272 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303273 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003274
3275 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303276 QDF_TRACE(QDF_MODULE_ID_HDD,
3277 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003278 "%s: failed to copy data to user buffer",
3279 __func__);
3280 ret = -EFAULT;
3281 }
3282
3283 return ret;
3284}
3285
3286static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3287 hdd_context_t *hdd_ctx,
3288 uint8_t *command,
3289 uint8_t command_len,
3290 hdd_priv_data_t *priv_data)
3291{
3292 int ret = 0;
3293 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3294 char extra[32];
3295 uint8_t len = 0;
3296
3297 len = scnprintf(extra, sizeof(extra), "%s %d",
3298 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303299 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003300
3301 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303302 QDF_TRACE(QDF_MODULE_ID_HDD,
3303 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003304 "%s: failed to copy data to user buffer",
3305 __func__);
3306 ret = -EFAULT;
3307 }
3308
3309 return ret;
3310}
3311
3312static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3313 hdd_context_t *hdd_ctx,
3314 uint8_t *command,
3315 uint8_t command_len,
3316 hdd_priv_data_t *priv_data)
3317{
3318 int ret = 0;
3319 uint8_t *value = command;
3320 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3321
3322 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3323 value = value + command_len + 1;
3324
3325 /* Convert the value from ascii to integer */
3326 ret = kstrtou8(value, 10, &minTime);
3327 if (ret < 0) {
3328 /*
3329 * If the input value is greater than max value of datatype,
3330 * then also kstrtou8 fails
3331 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303332 QDF_TRACE(QDF_MODULE_ID_HDD,
3333 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003334 "%s: kstrtou8 failed range [%d - %d]",
3335 __func__,
3336 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3337 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
3338 ret = -EINVAL;
3339 goto exit;
3340 }
3341
3342 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3343 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303344 QDF_TRACE(QDF_MODULE_ID_HDD,
3345 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003346 "scan min channel time value %d is out of range (Min: %d Max: %d)",
3347 minTime,
3348 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3349 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
3350 ret = -EINVAL;
3351 goto exit;
3352 }
3353
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303354 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003355 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3356 adapter->sessionId, minTime));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303357 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003358 "%s: Received Command to change channel min time = %d",
3359 __func__, minTime);
3360
3361 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3362 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3363 minTime,
3364 adapter->sessionId);
3365
3366exit:
3367 return ret;
3368}
3369
3370static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3371 hdd_context_t *hdd_ctx,
3372 uint8_t *command,
3373 uint8_t command_len,
3374 hdd_priv_data_t *priv_data)
3375{
3376 return hdd_parse_sendactionframe(adapter, command);
3377}
3378
3379static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3380 hdd_context_t *hdd_ctx,
3381 uint8_t *command,
3382 uint8_t command_len,
3383 hdd_priv_data_t *priv_data)
3384{
3385 int ret = 0;
3386 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3387 adapter->sessionId);
3388 char extra[32];
3389 uint8_t len = 0;
3390
3391 /* value is interms of msec */
3392 len = scnprintf(extra, sizeof(extra), "%s %d",
3393 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303394 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003395
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303396 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003397 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3398 adapter->sessionId, val));
3399
3400 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303401 QDF_TRACE(QDF_MODULE_ID_HDD,
3402 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403 "%s: failed to copy data to user buffer",
3404 __func__);
3405 ret = -EFAULT;
3406 }
3407
3408 return ret;
3409}
3410
3411static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3412 hdd_context_t *hdd_ctx,
3413 uint8_t *command,
3414 uint8_t command_len,
3415 hdd_priv_data_t *priv_data)
3416{
3417 int ret = 0;
3418 uint8_t *value = command;
3419 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3420
3421 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3422 value = value + command_len + 1;
3423
3424 /* Convert the value from ascii to integer */
3425 ret = kstrtou16(value, 10, &maxTime);
3426 if (ret < 0) {
3427 /*
3428 * If the input value is greater than max value of datatype,
3429 * then also kstrtou8 fails
3430 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303431 QDF_TRACE(QDF_MODULE_ID_HDD,
3432 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433 "%s: kstrtou16 failed range [%d - %d]",
3434 __func__,
3435 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3436 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
3437 ret = -EINVAL;
3438 goto exit;
3439 }
3440
3441 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3442 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303443 QDF_TRACE(QDF_MODULE_ID_HDD,
3444 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003445 "lfr mode value %d is out of range (Min: %d Max: %d)",
3446 maxTime,
3447 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3448 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
3449 ret = -EINVAL;
3450 goto exit;
3451 }
3452
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303453 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003454 "%s: Received Command to change channel max time = %d",
3455 __func__, maxTime);
3456
3457 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3458 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3459 adapter->sessionId,
3460 maxTime);
3461
3462exit:
3463 return ret;
3464}
3465
3466static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3467 hdd_context_t *hdd_ctx,
3468 uint8_t *command,
3469 uint8_t command_len,
3470 hdd_priv_data_t *priv_data)
3471{
3472 int ret = 0;
3473 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3474 adapter->sessionId);
3475 char extra[32];
3476 uint8_t len = 0;
3477
3478 /* value is interms of msec */
3479 len = scnprintf(extra, sizeof(extra), "%s %d",
3480 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303481 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003482
3483 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303484 QDF_TRACE(QDF_MODULE_ID_HDD,
3485 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003486 "%s: failed to copy data to user buffer",
3487 __func__);
3488 ret = -EFAULT;
3489 }
3490
3491 return ret;
3492}
3493
3494static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3495 hdd_context_t *hdd_ctx,
3496 uint8_t *command,
3497 uint8_t command_len,
3498 hdd_priv_data_t *priv_data)
3499{
3500 int ret = 0;
3501 uint8_t *value = command;
3502 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3503
3504 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3505 value = value + command_len + 1;
3506
3507 /* Convert the value from ascii to integer */
3508 ret = kstrtou16(value, 10, &val);
3509 if (ret < 0) {
3510 /*
3511 * If the input value is greater than max value of datatype,
3512 * then also kstrtou8 fails
3513 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303514 QDF_TRACE(QDF_MODULE_ID_HDD,
3515 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003516 "%s: kstrtou16 failed range [%d - %d]",
3517 __func__,
3518 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3519 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
3520 ret = -EINVAL;
3521 goto exit;
3522 }
3523
3524 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3525 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303526 QDF_TRACE(QDF_MODULE_ID_HDD,
3527 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003528 "scan home time value %d is out of range (Min: %d Max: %d)",
3529 val,
3530 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3531 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
3532 ret = -EINVAL;
3533 goto exit;
3534 }
3535
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303536 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003537 "%s: Received Command to change scan home time = %d",
3538 __func__, val);
3539
3540 hdd_ctx->config->nNeighborScanPeriod = val;
3541 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3542 adapter->sessionId, val);
3543
3544exit:
3545 return ret;
3546}
3547
3548static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3549 hdd_context_t *hdd_ctx,
3550 uint8_t *command,
3551 uint8_t command_len,
3552 hdd_priv_data_t *priv_data)
3553{
3554 int ret = 0;
3555 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3556 adapter->
3557 sessionId);
3558 char extra[32];
3559 uint8_t len = 0;
3560
3561 /* value is interms of msec */
3562 len = scnprintf(extra, sizeof(extra), "%s %d",
3563 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303564 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003565
3566 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303567 QDF_TRACE(QDF_MODULE_ID_HDD,
3568 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003569 "%s: failed to copy data to user buffer",
3570 __func__);
3571 ret = -EFAULT;
3572 }
3573
3574 return ret;
3575}
3576
3577static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3578 hdd_context_t *hdd_ctx,
3579 uint8_t *command,
3580 uint8_t command_len,
3581 hdd_priv_data_t *priv_data)
3582{
3583 int ret = 0;
3584 uint8_t *value = command;
3585 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3586
3587 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3588 value = value + command_len + 1;
3589
3590 /* Convert the value from ascii to integer */
3591 ret = kstrtou8(value, 10, &val);
3592 if (ret < 0) {
3593 /*
3594 * If the input value is greater than max value of datatype,
3595 * then also kstrtou8 fails
3596 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303597 QDF_TRACE(QDF_MODULE_ID_HDD,
3598 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003599 "%s: kstrtou8 failed range [%d - %d]",
3600 __func__, CFG_ROAM_INTRA_BAND_MIN,
3601 CFG_ROAM_INTRA_BAND_MAX);
3602 ret = -EINVAL;
3603 goto exit;
3604 }
3605
3606 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3607 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303608 QDF_TRACE(QDF_MODULE_ID_HDD,
3609 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003610 "intra band mode value %d is out of range (Min: %d Max: %d)",
3611 val,
3612 CFG_ROAM_INTRA_BAND_MIN,
3613 CFG_ROAM_INTRA_BAND_MAX);
3614 ret = -EINVAL;
3615 goto exit;
3616 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303617 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003618 "%s: Received Command to change intra band = %d",
3619 __func__, val);
3620
3621 hdd_ctx->config->nRoamIntraBand = val;
3622 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3623
3624exit:
3625 return ret;
3626}
3627
3628static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3629 hdd_context_t *hdd_ctx,
3630 uint8_t *command,
3631 uint8_t command_len,
3632 hdd_priv_data_t *priv_data)
3633{
3634 int ret = 0;
3635 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3636 char extra[32];
3637 uint8_t len = 0;
3638
3639 /* value is interms of msec */
3640 len = scnprintf(extra, sizeof(extra), "%s %d",
3641 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303642 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003643 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303644 QDF_TRACE(QDF_MODULE_ID_HDD,
3645 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003646 "%s: failed to copy data to user buffer",
3647 __func__);
3648 ret = -EFAULT;
3649 }
3650
3651 return ret;
3652}
3653
3654static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3655 hdd_context_t *hdd_ctx,
3656 uint8_t *command,
3657 uint8_t command_len,
3658 hdd_priv_data_t *priv_data)
3659{
3660 int ret = 0;
3661 uint8_t *value = command;
3662 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3663
3664 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3665 value = value + command_len + 1;
3666
3667 /* Convert the value from ascii to integer */
3668 ret = kstrtou8(value, 10, &nProbes);
3669 if (ret < 0) {
3670 /*
3671 * If the input value is greater than max value of datatype,
3672 * then also kstrtou8 fails
3673 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303674 QDF_TRACE(QDF_MODULE_ID_HDD,
3675 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003676 "%s: kstrtou8 failed range [%d - %d]",
3677 __func__, CFG_ROAM_SCAN_N_PROBES_MIN,
3678 CFG_ROAM_SCAN_N_PROBES_MAX);
3679 ret = -EINVAL;
3680 goto exit;
3681 }
3682
3683 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3684 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303685 QDF_TRACE(QDF_MODULE_ID_HDD,
3686 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003687 "NProbes value %d is out of range (Min: %d Max: %d)",
3688 nProbes,
3689 CFG_ROAM_SCAN_N_PROBES_MIN,
3690 CFG_ROAM_SCAN_N_PROBES_MAX);
3691 ret = -EINVAL;
3692 goto exit;
3693 }
3694
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303695 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003696 "%s: Received Command to Set nProbes = %d",
3697 __func__, nProbes);
3698
3699 hdd_ctx->config->nProbes = nProbes;
3700 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3701 adapter->sessionId, nProbes);
3702
3703exit:
3704 return ret;
3705}
3706
3707static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3708 hdd_context_t *hdd_ctx,
3709 uint8_t *command,
3710 uint8_t command_len,
3711 hdd_priv_data_t *priv_data)
3712{
3713 int ret = 0;
3714 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3715 char extra[32];
3716 uint8_t len = 0;
3717
3718 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303719 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003720 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303721 QDF_TRACE(QDF_MODULE_ID_HDD,
3722 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003723 "%s: failed to copy data to user buffer",
3724 __func__);
3725 ret = -EFAULT;
3726 }
3727
3728 return ret;
3729}
3730
3731static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
3732 hdd_context_t *hdd_ctx,
3733 uint8_t *command,
3734 uint8_t command_len,
3735 hdd_priv_data_t *priv_data)
3736{
3737 int ret = 0;
3738 uint8_t *value = command;
3739 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3740
3741 /* input value is in units of msec */
3742
3743 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3744 value = value + command_len + 1;
3745
3746 /* Convert the value from ascii to integer */
3747 ret = kstrtou16(value, 10, &homeAwayTime);
3748 if (ret < 0) {
3749 /*
3750 * If the input value is greater than max value of datatype,
3751 * then also kstrtou8 fails
3752 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303753 QDF_TRACE(QDF_MODULE_ID_HDD,
3754 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003755 "%s: kstrtou8 failed range [%d - %d]",
3756 __func__,
3757 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3758 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
3759 ret = -EINVAL;
3760 goto exit;
3761 }
3762
3763 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
3764 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303765 QDF_TRACE(QDF_MODULE_ID_HDD,
3766 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003767 "homeAwayTime value %d is out of range (Min: %d Max: %d)",
3768 homeAwayTime,
3769 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3770 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
3771 ret = -EINVAL;
3772 goto exit;
3773 }
3774
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303775 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003776 "%s: Received Command to Set scan away time = %d",
3777 __func__, homeAwayTime);
3778
3779 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
3780 homeAwayTime) {
3781 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
3782 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
3783 adapter->sessionId,
3784 homeAwayTime,
3785 true);
3786 }
3787
3788exit:
3789 return ret;
3790}
3791
3792static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
3793 hdd_context_t *hdd_ctx,
3794 uint8_t *command,
3795 uint8_t command_len,
3796 hdd_priv_data_t *priv_data)
3797{
3798 int ret = 0;
3799 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
3800 char extra[32];
3801 uint8_t len = 0;
3802
3803 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303804 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003805
3806 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303807 QDF_TRACE(QDF_MODULE_ID_HDD,
3808 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003809 "%s: failed to copy data to user buffer",
3810 __func__);
3811 ret = -EFAULT;
3812 }
3813
3814 return ret;
3815}
3816
3817static int drv_cmd_reassoc(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 return hdd_parse_reassoc(adapter, command);
3824}
3825
3826static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
3827 hdd_context_t *hdd_ctx,
3828 uint8_t *command,
3829 uint8_t command_len,
3830 hdd_priv_data_t *priv_data)
3831{
3832 int ret = 0;
3833 uint8_t *value = command;
3834 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
3835
3836 /* Move pointer to ahead of SETWESMODE<delimiter> */
3837 value = value + command_len + 1;
3838
3839 /* Convert the value from ascii to integer */
3840 ret = kstrtou8(value, 10, &wesMode);
3841 if (ret < 0) {
3842 /*
3843 * If the input value is greater than max value of datatype,
3844 * then also kstrtou8 fails
3845 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303846 QDF_TRACE(QDF_MODULE_ID_HDD,
3847 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003848 "%s: kstrtou8 failed range [%d - %d]",
3849 __func__,
3850 CFG_ENABLE_WES_MODE_NAME_MIN,
3851 CFG_ENABLE_WES_MODE_NAME_MAX);
3852 ret = -EINVAL;
3853 goto exit;
3854 }
3855
3856 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
3857 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303858 QDF_TRACE(QDF_MODULE_ID_HDD,
3859 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003860 "WES Mode value %d is out of range (Min: %d Max: %d)",
3861 wesMode,
3862 CFG_ENABLE_WES_MODE_NAME_MIN,
3863 CFG_ENABLE_WES_MODE_NAME_MAX);
3864 ret = -EINVAL;
3865 goto exit;
3866 }
3867
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303868 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003869 "%s: Received Command to Set WES Mode rssi diff = %d",
3870 __func__, wesMode);
3871
3872 hdd_ctx->config->isWESModeEnabled = wesMode;
3873 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
3874
3875exit:
3876 return ret;
3877}
3878
3879static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
3880 hdd_context_t *hdd_ctx,
3881 uint8_t *command,
3882 uint8_t command_len,
3883 hdd_priv_data_t *priv_data)
3884{
3885 int ret = 0;
3886 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
3887 char extra[32];
3888 uint8_t len = 0;
3889
3890 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303891 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003892 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303893 QDF_TRACE(QDF_MODULE_ID_HDD,
3894 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003895 "%s: failed to copy data to user buffer",
3896 __func__);
3897 ret = -EFAULT;
3898 }
3899
3900 return ret;
3901}
3902
3903static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
3904 hdd_context_t *hdd_ctx,
3905 uint8_t *command,
3906 uint8_t command_len,
3907 hdd_priv_data_t *priv_data)
3908{
3909 int ret = 0;
3910 uint8_t *value = command;
3911 uint8_t nOpportunisticThresholdDiff =
3912 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
3913
3914 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
3915 value = value + command_len + 1;
3916
3917 /* Convert the value from ascii to integer */
3918 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
3919 if (ret < 0) {
3920 /*
3921 * If the input value is greater than max value of datatype,
3922 * then also kstrtou8 fails
3923 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303924 QDF_TRACE(QDF_MODULE_ID_HDD,
3925 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003926 "%s: kstrtou8 failed.", __func__);
3927 ret = -EINVAL;
3928 goto exit;
3929 }
3930
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303931 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003932 "%s: Received Command to Set Opportunistic Threshold diff = %d",
3933 __func__, nOpportunisticThresholdDiff);
3934
3935 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
3936 adapter->sessionId,
3937 nOpportunisticThresholdDiff);
3938
3939exit:
3940 return ret;
3941}
3942
3943static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
3944 hdd_context_t *hdd_ctx,
3945 uint8_t *command,
3946 uint8_t command_len,
3947 hdd_priv_data_t *priv_data)
3948{
3949 int ret = 0;
3950 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
3951 hdd_ctx->hHal);
3952 char extra[32];
3953 uint8_t len = 0;
3954
3955 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303956 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003957 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303958 QDF_TRACE(QDF_MODULE_ID_HDD,
3959 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003960 "%s: failed to copy data to user buffer",
3961 __func__);
3962 ret = -EFAULT;
3963 }
3964
3965 return ret;
3966}
3967
3968static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
3969 hdd_context_t *hdd_ctx,
3970 uint8_t *command,
3971 uint8_t command_len,
3972 hdd_priv_data_t *priv_data)
3973{
3974 int ret = 0;
3975 uint8_t *value = command;
3976 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
3977
3978 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
3979 value = value + command_len + 1;
3980
3981 /* Convert the value from ascii to integer */
3982 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
3983 if (ret < 0) {
3984 /*
3985 * If the input value is greater than max value of datatype,
3986 * then also kstrtou8 fails
3987 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303988 QDF_TRACE(QDF_MODULE_ID_HDD,
3989 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003990 "%s: kstrtou8 failed.", __func__);
3991 ret = -EINVAL;
3992 goto exit;
3993 }
3994
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303995 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003996 "%s: Received Command to Set Roam Rescan RSSI Diff = %d",
3997 __func__, nRoamRescanRssiDiff);
3998
3999 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4000 adapter->sessionId,
4001 nRoamRescanRssiDiff);
4002
4003exit:
4004 return ret;
4005}
4006
4007static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4008 hdd_context_t *hdd_ctx,
4009 uint8_t *command,
4010 uint8_t command_len,
4011 hdd_priv_data_t *priv_data)
4012{
4013 int ret = 0;
4014 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4015 char extra[32];
4016 uint8_t len = 0;
4017
4018 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304019 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004020 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304021 QDF_TRACE(QDF_MODULE_ID_HDD,
4022 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004023 "%s: failed to copy data to user buffer",
4024 __func__);
4025 ret = -EFAULT;
4026 }
4027
4028 return ret;
4029}
4030
4031static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4032 hdd_context_t *hdd_ctx,
4033 uint8_t *command,
4034 uint8_t command_len,
4035 hdd_priv_data_t *priv_data)
4036{
4037 int ret = 0;
4038 uint8_t *value = command;
4039 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4040
4041 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4042 value = value + command_len + 1;
4043
4044 /* Convert the value from ascii to integer */
4045 ret = kstrtou8(value, 10, &lfrMode);
4046 if (ret < 0) {
4047 /*
4048 * If the input value is greater than max value of datatype,
4049 * then also kstrtou8 fails
4050 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304051 QDF_TRACE(QDF_MODULE_ID_HDD,
4052 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004053 "%s: kstrtou8 failed range [%d - %d]",
4054 __func__, CFG_LFR_FEATURE_ENABLED_MIN,
4055 CFG_LFR_FEATURE_ENABLED_MAX);
4056 ret = -EINVAL;
4057 goto exit;
4058 }
4059
4060 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4061 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304062 QDF_TRACE(QDF_MODULE_ID_HDD,
4063 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004064 "lfr mode value %d is out of range (Min: %d Max: %d)",
4065 lfrMode,
4066 CFG_LFR_FEATURE_ENABLED_MIN,
4067 CFG_LFR_FEATURE_ENABLED_MAX);
4068 ret = -EINVAL;
4069 goto exit;
4070 }
4071
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304072 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004073 "%s: Received Command to change lfr mode = %d",
4074 __func__, lfrMode);
4075
4076 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4077 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4078 adapter->
4079 sessionId,
4080 lfrMode);
4081
4082exit:
4083 return ret;
4084}
4085
4086static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4087 hdd_context_t *hdd_ctx,
4088 uint8_t *command,
4089 uint8_t command_len,
4090 hdd_priv_data_t *priv_data)
4091{
4092 int ret = 0;
4093 uint8_t *value = command;
4094 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4095
4096 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4097 value = value + command_len + 1;
4098
4099 /* Convert the value from ascii to integer */
4100 ret = kstrtou8(value, 10, &ft);
4101 if (ret < 0) {
4102 /*
4103 * If the input value is greater than max value of datatype,
4104 * then also kstrtou8 fails
4105 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304106 QDF_TRACE(QDF_MODULE_ID_HDD,
4107 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004108 "%s: kstrtou8 failed range [%d - %d]",
4109 __func__,
4110 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4111 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4112 ret = -EINVAL;
4113 goto exit;
4114 }
4115
4116 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4117 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304118 QDF_TRACE(QDF_MODULE_ID_HDD,
4119 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004120 "ft mode value %d is out of range (Min: %d Max: %d)",
4121 ft,
4122 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4123 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4124 ret = -EINVAL;
4125 goto exit;
4126 }
4127
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304128 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004129 "%s: Received Command to change ft mode = %d",
4130 __func__, ft);
4131
4132 hdd_ctx->config->isFastTransitionEnabled = ft;
4133 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4134
4135exit:
4136 return ret;
4137}
4138
4139#ifdef WLAN_FEATURE_ROAM_OFFLOAD
4140static void hdd_wma_send_fastreassoc_cmd(int sessionId, tSirMacAddr bssid,
4141 int channel)
4142{
4143 struct wma_roam_invoke_cmd *fastreassoc;
4144 cds_msg_t msg = {0};
4145
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304146 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004147 if (NULL == fastreassoc) {
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05304148 hddLog(LOGE, FL("qdf_mem_malloc failed for fastreassoc"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004149 return;
4150 }
4151 fastreassoc->vdev_id = sessionId;
4152 fastreassoc->channel = channel;
4153 fastreassoc->bssid[0] = bssid[0];
4154 fastreassoc->bssid[1] = bssid[1];
4155 fastreassoc->bssid[2] = bssid[2];
4156 fastreassoc->bssid[3] = bssid[3];
4157 fastreassoc->bssid[4] = bssid[4];
4158 fastreassoc->bssid[5] = bssid[5];
4159
4160 msg.type = SIR_HAL_ROAM_INVOKE;
4161 msg.reserved = 0;
4162 msg.bodyptr = fastreassoc;
Anurag Chouhan6d760662016-02-20 16:05:43 +05304163 if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004164 &msg)) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304165 qdf_mem_free(fastreassoc);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304166 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004167 FL("Not able to post ROAM_INVOKE_CMD message to WMA"));
4168 }
4169}
4170#endif
4171static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4172 hdd_context_t *hdd_ctx,
4173 uint8_t *command,
4174 uint8_t command_len,
4175 hdd_priv_data_t *priv_data)
4176{
4177 int ret = 0;
4178 uint8_t *value = command;
4179 uint8_t channel = 0;
4180 tSirMacAddr targetApBssid;
4181 uint32_t roamId = 0;
4182 tCsrRoamModifyProfileFields modProfileFields;
4183#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
4184 tCsrHandoffRequest handoffInfo;
4185#endif
4186 hdd_station_ctx_t *pHddStaCtx;
4187
4188 if (WLAN_HDD_INFRA_STATION != adapter->device_mode) {
4189 hdd_warn("Unsupported in mode %s(%d)",
4190 hdd_device_mode_to_string(adapter->device_mode),
4191 adapter->device_mode);
4192 return -EINVAL;
4193 }
4194
4195 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4196
4197 /* if not associated, no need to proceed with reassoc */
4198 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304199 QDF_TRACE(QDF_MODULE_ID_HDD,
4200 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004201 "%s:Not associated!", __func__);
4202 ret = -EINVAL;
4203 goto exit;
4204 }
4205
4206 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4207 &channel);
4208 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304209 QDF_TRACE(QDF_MODULE_ID_HDD,
4210 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004211 "%s: Failed to parse reassoc command data",
4212 __func__);
4213 goto exit;
4214 }
4215
4216 /*
4217 * if the target bssid is same as currently associated AP,
4218 * issue reassoc to same AP
4219 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304220 if (true != qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004221 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304222 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004223 /* Reassoc to same AP, only supported for Open Security*/
4224 if ((pHddStaCtx->conn_info.ucEncryptionType ||
4225 pHddStaCtx->conn_info.mcEncryptionType)) {
4226 hddLog(LOGE,
4227 FL("Reassoc to same AP, only supported for Open Security"));
4228 return -ENOTSUPP;
4229 }
4230 hddLog(LOG1,
4231 FL("Reassoc BSSID is same as currently associated AP bssid"));
4232 sme_get_modify_profile_fields(hdd_ctx->hHal, adapter->sessionId,
4233 &modProfileFields);
4234 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4235 NULL, modProfileFields, &roamId, 1);
4236 return 0;
4237 }
4238
4239 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304240 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004241 wlan_hdd_validate_operation_channel(adapter, channel)) {
4242 hddLog(LOGE, FL("Invalid Channel [%d]"), channel);
4243 return -EINVAL;
4244 }
4245#ifdef WLAN_FEATURE_ROAM_OFFLOAD
4246 if (hdd_ctx->config->isRoamOffloadEnabled) {
4247 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4248 targetApBssid, (int)channel);
4249 goto exit;
4250 }
4251#endif
4252 /* Proceed with reassoc */
4253#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
4254 handoffInfo.channel = channel;
4255 handoffInfo.src = FASTREASSOC;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304256 qdf_mem_copy(handoffInfo.bssid, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257 sizeof(tSirMacAddr));
4258 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4259 &handoffInfo);
4260#endif
4261
4262exit:
4263 return ret;
4264}
4265
4266#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
4267static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
4268 hdd_context_t *hdd_ctx,
4269 uint8_t *command,
4270 uint8_t command_len,
4271 hdd_priv_data_t *priv_data)
4272{
4273 int ret = 0;
4274 uint8_t *value = command;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304275 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004276 tpSirPlmReq pPlmRequest = NULL;
4277
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304278 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004279 if (NULL == pPlmRequest) {
4280 ret = -ENOMEM;
4281 goto exit;
4282 }
4283
4284 status = hdd_parse_plm_cmd(value, pPlmRequest);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304285 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304286 qdf_mem_free(pPlmRequest);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004287 pPlmRequest = NULL;
4288 ret = -EINVAL;
4289 goto exit;
4290 }
4291 pPlmRequest->sessionId = adapter->sessionId;
4292
4293 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304294 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304295 qdf_mem_free(pPlmRequest);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004296 pPlmRequest = NULL;
4297 ret = -EINVAL;
4298 goto exit;
4299 }
4300
4301exit:
4302 return ret;
4303}
4304#endif
4305
4306#ifdef FEATURE_WLAN_ESE
4307static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
4308 hdd_context_t *hdd_ctx,
4309 uint8_t *command,
4310 uint8_t command_len,
4311 hdd_priv_data_t *priv_data)
4312{
4313 int ret = 0;
4314 uint8_t *value = command;
4315 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
4316
4317 /*
4318 * Check if the features OKC/ESE/11R are supported simultaneously,
4319 * then this operation is not permitted (return FAILURE)
4320 */
4321 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4322 hdd_is_okc_mode_enabled(hdd_ctx) &&
4323 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304324 QDF_TRACE(QDF_MODULE_ID_HDD,
4325 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004326 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
4327 __func__);
4328 ret = -EPERM;
4329 goto exit;
4330 }
4331
4332 /* Move pointer to ahead of SETCCXMODE<delimiter> */
4333 value = value + command_len + 1;
4334
4335 /* Convert the value from ascii to integer */
4336 ret = kstrtou8(value, 10, &eseMode);
4337 if (ret < 0) {
4338 /*
4339 * If the input value is greater than max value of datatype,
4340 * then also kstrtou8 fails
4341 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304342 QDF_TRACE(QDF_MODULE_ID_HDD,
4343 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344 "%s: kstrtou8 failed range [%d - %d]",
4345 __func__, CFG_ESE_FEATURE_ENABLED_MIN,
4346 CFG_ESE_FEATURE_ENABLED_MAX);
4347 ret = -EINVAL;
4348 goto exit;
4349 }
4350
4351 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
4352 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304353 QDF_TRACE(QDF_MODULE_ID_HDD,
4354 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355 "Ese mode value %d is out of range (Min: %d Max: %d)",
4356 eseMode,
4357 CFG_ESE_FEATURE_ENABLED_MIN,
4358 CFG_ESE_FEATURE_ENABLED_MAX);
4359 ret = -EINVAL;
4360 goto exit;
4361 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304362 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363 "%s: Received Command to change ese mode = %d",
4364 __func__, eseMode);
4365
4366 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
4367 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
4368 adapter->sessionId,
4369 eseMode);
4370
4371exit:
4372 return ret;
4373}
4374#endif
4375
4376static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4377 hdd_context_t *hdd_ctx,
4378 uint8_t *command,
4379 uint8_t command_len,
4380 hdd_priv_data_t *priv_data)
4381{
4382 int ret = 0;
4383 uint8_t *value = command;
4384 uint8_t roamScanControl = 0;
4385
4386 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4387 value = value + command_len + 1;
4388
4389 /* Convert the value from ascii to integer */
4390 ret = kstrtou8(value, 10, &roamScanControl);
4391 if (ret < 0) {
4392 /*
4393 * If the input value is greater than max value of datatype,
4394 * then also kstrtou8 fails
4395 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304396 QDF_TRACE(QDF_MODULE_ID_HDD,
4397 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004398 "%s: kstrtou8 failed ", __func__);
4399 ret = -EINVAL;
4400 goto exit;
4401 }
4402
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304403 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004404 "%s: Received Command to Set roam scan control = %d",
4405 __func__, roamScanControl);
4406
4407 if (0 != roamScanControl) {
4408 ret = 0; /* return success but ignore param value "true" */
4409 goto exit;
4410 }
4411
4412 sme_set_roam_scan_control(hdd_ctx->hHal,
4413 adapter->sessionId,
4414 roamScanControl);
4415
4416exit:
4417 return ret;
4418}
4419
4420static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4421 hdd_context_t *hdd_ctx,
4422 uint8_t *command,
4423 uint8_t command_len,
4424 hdd_priv_data_t *priv_data)
4425{
4426 int ret = 0;
4427 uint8_t *value = command;
4428 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4429
4430 /*
4431 * Check if the features OKC/ESE/11R are supported simultaneously,
4432 * then this operation is not permitted (return FAILURE)
4433 */
4434 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4435 hdd_is_okc_mode_enabled(hdd_ctx) &&
4436 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304437 QDF_TRACE(QDF_MODULE_ID_HDD,
4438 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004439 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
4440 __func__);
4441 ret = -EPERM;
4442 goto exit;
4443 }
4444
4445 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4446 value = value + command_len + 1;
4447
4448 /* Convert the value from ascii to integer */
4449 ret = kstrtou8(value, 10, &okcMode);
4450 if (ret < 0) {
4451 /*
4452 * If the input value is greater than max value of datatype,
4453 * then also kstrtou8 fails
4454 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304455 QDF_TRACE(QDF_MODULE_ID_HDD,
4456 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004457 "%s: kstrtou8 failed range [%d - %d]",
4458 __func__, CFG_OKC_FEATURE_ENABLED_MIN,
4459 CFG_OKC_FEATURE_ENABLED_MAX);
4460 ret = -EINVAL;
4461 goto exit;
4462 }
4463
4464 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4465 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304466 QDF_TRACE(QDF_MODULE_ID_HDD,
4467 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468 "Okc mode value %d is out of range (Min: %d Max: %d)",
4469 okcMode,
4470 CFG_OKC_FEATURE_ENABLED_MIN,
4471 CFG_OKC_FEATURE_ENABLED_MAX);
4472 ret = -EINVAL;
4473 goto exit;
4474 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304475 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004476 "%s: Received Command to change okc mode = %d",
4477 __func__, okcMode);
4478
4479 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4480
4481exit:
4482 return ret;
4483}
4484
4485static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4486 hdd_context_t *hdd_ctx,
4487 uint8_t *command,
4488 uint8_t command_len,
4489 hdd_priv_data_t *priv_data)
4490{
4491 int ret = 0;
4492 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4493 char extra[32];
4494 uint8_t len = 0;
4495
4496 len = scnprintf(extra, sizeof(extra), "%s %d",
4497 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304498 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004499 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304500 QDF_TRACE(QDF_MODULE_ID_HDD,
4501 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502 "%s: failed to copy data to user buffer",
4503 __func__);
4504 ret = -EFAULT;
4505 }
4506
4507 return ret;
4508}
4509
4510static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4511 hdd_context_t *hdd_ctx,
4512 uint8_t *command,
4513 uint8_t command_len,
4514 hdd_priv_data_t *priv_data)
4515{
4516 int ret = 0;
4517 char *bcMode;
4518
4519 bcMode = command + 11;
4520 if ('1' == *bcMode) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304521 QDF_TRACE(QDF_MODULE_ID_HDD,
4522 QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004523 FL("BTCOEXMODE %d"), *bcMode);
4524 hdd_ctx->btCoexModeSet = true;
4525 ret = wlan_hdd_scan_abort(adapter);
4526 if (ret < 0) {
4527 hddLog(LOGE,
4528 FL("Failed to abort existing scan status:%d"), ret);
4529 }
4530 } else if ('2' == *bcMode) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304531 QDF_TRACE(QDF_MODULE_ID_HDD,
4532 QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004533 FL("BTCOEXMODE %d"), *bcMode);
4534 hdd_ctx->btCoexModeSet = false;
4535 }
4536
4537 return ret;
4538}
4539
4540static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4541 hdd_context_t *hdd_ctx,
4542 uint8_t *command,
4543 uint8_t command_len,
4544 hdd_priv_data_t *priv_data)
4545{
4546 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4547 return 0;
4548}
4549
4550static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4551 hdd_context_t *hdd_ctx,
4552 uint8_t *command,
4553 uint8_t command_len,
4554 hdd_priv_data_t *priv_data)
4555{
4556 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4557 return 0;
4558}
4559
4560static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4561 hdd_context_t *hdd_ctx,
4562 uint8_t *command,
4563 uint8_t command_len,
4564 hdd_priv_data_t *priv_data)
4565{
4566 int ret = 0;
4567 struct hdd_config *pCfg =
4568 (WLAN_HDD_GET_CTX(adapter))->config;
4569 char extra[32];
4570 uint8_t len = 0;
4571
4572 memset(extra, 0, sizeof(extra));
4573 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
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 (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304576 QDF_TRACE(QDF_MODULE_ID_HDD,
4577 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004578 "%s: failed to copy data to user buffer",
4579 __func__);
4580 ret = -EFAULT;
4581 goto exit;
4582 }
4583 ret = len;
4584exit:
4585 return ret;
4586}
4587
4588static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4589 hdd_context_t *hdd_ctx,
4590 uint8_t *command,
4591 uint8_t command_len,
4592 hdd_priv_data_t *priv_data)
4593{
4594 return hdd_set_dwell_time(adapter, command);
4595}
4596
4597static int drv_cmd_miracast(hdd_adapter_t *adapter,
4598 hdd_context_t *hdd_ctx,
4599 uint8_t *command,
4600 uint8_t command_len,
4601 hdd_priv_data_t *priv_data)
4602{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304603 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004604 int ret = 0;
4605 tHalHandle hHal;
4606 uint8_t filterType = 0;
4607 hdd_context_t *pHddCtx = NULL;
4608 uint8_t *value;
4609
4610 pHddCtx = WLAN_HDD_GET_CTX(adapter);
4611 if (0 != wlan_hdd_validate_context(pHddCtx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304612 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 "%s pHddCtx is not valid, Unable to set miracast mode",
4614 __func__);
4615 return -EINVAL;
4616 }
4617
4618 hHal = pHddCtx->hHal;
4619 value = command + 9;
4620
4621 /* Convert the value from ascii to integer */
4622 ret = kstrtou8(value, 10, &filterType);
4623 if (ret < 0) {
4624 /*
4625 * If the input value is greater than max value of datatype,
4626 * then also kstrtou8 fails
4627 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304628 QDF_TRACE(QDF_MODULE_ID_HDD,
4629 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004630 "%s: kstrtou8 failed range ",
4631 __func__);
4632 ret = -EINVAL;
4633 goto exit;
4634 }
4635 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4636 || (filterType >
4637 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304638 QDF_TRACE(QDF_MODULE_ID_HDD,
4639 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 "%s: Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ",
4641 __func__);
4642 ret = -EINVAL;
4643 goto exit;
4644 }
4645 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4646 pHddCtx->miracast_value = filterType;
4647
4648 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304649 if (QDF_STATUS_SUCCESS != ret_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004650 hddLog(LOGE, "Failed to set miracast");
4651 return -EBUSY;
4652 }
4653
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004654 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004655 return cds_set_mas(adapter, filterType);
4656
4657exit:
4658 return ret;
4659}
4660
4661#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
4662static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
4663 hdd_context_t *hdd_ctx,
4664 uint8_t *command,
4665 uint8_t command_len,
4666 hdd_priv_data_t *priv_data)
4667{
4668 int ret = 0;
4669 uint8_t *value = command;
4670 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
4671 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304672 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004673
4674 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
4675 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304676 QDF_TRACE(QDF_MODULE_ID_HDD,
4677 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004678 "%s: Failed to parse channel list information",
4679 __func__);
4680 goto exit;
4681 }
4682 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304683 QDF_TRACE(QDF_MODULE_ID_HDD,
4684 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004685 "%s: number of channels (%d) supported exceeded max (%d)",
4686 __func__,
4687 numChannels,
4688 WNI_CFG_VALID_CHANNEL_LIST_LEN);
4689 ret = -EINVAL;
4690 goto exit;
4691 }
4692 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
4693 adapter->sessionId,
4694 ChannelList,
4695 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304696 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304697 QDF_TRACE(QDF_MODULE_ID_HDD,
4698 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004699 "%s: Failed to update channel list information",
4700 __func__);
4701 ret = -EINVAL;
4702 goto exit;
4703 }
4704
4705exit:
4706 return ret;
4707}
4708
4709static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
4710 hdd_context_t *hdd_ctx,
4711 uint8_t *command,
4712 uint8_t command_len,
4713 hdd_priv_data_t *priv_data)
4714{
4715 int ret = 0;
4716 uint8_t *value = command;
4717 char extra[128] = { 0 };
4718 int len = 0;
4719 uint8_t tid = 0;
4720 hdd_station_ctx_t *pHddStaCtx;
4721 tAniTrafStrmMetrics tsm_metrics;
4722
4723 if ((WLAN_HDD_INFRA_STATION != adapter->device_mode) &&
4724 (WLAN_HDD_P2P_CLIENT != adapter->device_mode)) {
4725 hdd_warn("Unsupported in mode %s(%d)",
4726 hdd_device_mode_to_string(adapter->device_mode),
4727 adapter->device_mode);
4728 return -EINVAL;
4729 }
4730
4731 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4732
4733 /* if not associated, return error */
4734 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304735 QDF_TRACE(QDF_MODULE_ID_HDD,
4736 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004737 "%s:Not associated!", __func__);
4738 ret = -EINVAL;
4739 goto exit;
4740 }
4741
4742 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
4743 value = value + command_len + 1;
4744
4745 /* Convert the value from ascii to integer */
4746 ret = kstrtou8(value, 10, &tid);
4747 if (ret < 0) {
4748 /*
4749 * If the input value is greater than max value of datatype,
4750 * then also kstrtou8 fails
4751 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304752 QDF_TRACE(QDF_MODULE_ID_HDD,
4753 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004754 "%s: kstrtou8 failed range [%d - %d]",
4755 __func__, TID_MIN_VALUE,
4756 TID_MAX_VALUE);
4757 ret = -EINVAL;
4758 goto exit;
4759 }
4760 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304761 QDF_TRACE(QDF_MODULE_ID_HDD,
4762 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004763 "tid value %d is out of range (Min: %d Max: %d)",
4764 tid, TID_MIN_VALUE, TID_MAX_VALUE);
4765 ret = -EINVAL;
4766 goto exit;
4767 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304768 QDF_TRACE(QDF_MODULE_ID_HDD,
4769 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004770 "%s: Received Command to get tsm stats tid = %d",
4771 __func__, tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304772 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004773 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304774 QDF_TRACE(QDF_MODULE_ID_HDD,
4775 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004776 "%s: failed to get tsm stats",
4777 __func__);
4778 ret = -EFAULT;
4779 goto exit;
4780 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304781 QDF_TRACE(QDF_MODULE_ID_HDD,
4782 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004783 "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)",
4784 tsm_metrics.UplinkPktQueueDly,
4785 tsm_metrics.UplinkPktQueueDlyHist[0],
4786 tsm_metrics.UplinkPktQueueDlyHist[1],
4787 tsm_metrics.UplinkPktQueueDlyHist[2],
4788 tsm_metrics.UplinkPktQueueDlyHist[3],
4789 tsm_metrics.UplinkPktTxDly,
4790 tsm_metrics.UplinkPktLoss,
4791 tsm_metrics.UplinkPktCount,
4792 tsm_metrics.RoamingCount,
4793 tsm_metrics.RoamingDly);
4794 /*
4795 * Output TSM stats is of the format
4796 * GETTSMSTATS [PktQueueDly]
4797 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
4798 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
4799 */
4800 len = scnprintf(extra,
4801 sizeof(extra),
4802 "%s %d %d:%d:%d:%d %u %d %d %d %d",
4803 command,
4804 tsm_metrics.UplinkPktQueueDly,
4805 tsm_metrics.UplinkPktQueueDlyHist[0],
4806 tsm_metrics.UplinkPktQueueDlyHist[1],
4807 tsm_metrics.UplinkPktQueueDlyHist[2],
4808 tsm_metrics.UplinkPktQueueDlyHist[3],
4809 tsm_metrics.UplinkPktTxDly,
4810 tsm_metrics.UplinkPktLoss,
4811 tsm_metrics.UplinkPktCount,
4812 tsm_metrics.RoamingCount,
4813 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304814 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004815 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304816 QDF_TRACE(QDF_MODULE_ID_HDD,
4817 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004818 "%s: failed to copy data to user buffer",
4819 __func__);
4820 ret = -EFAULT;
4821 goto exit;
4822 }
4823
4824exit:
4825 return ret;
4826}
4827
4828static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
4829 hdd_context_t *hdd_ctx,
4830 uint8_t *command,
4831 uint8_t command_len,
4832 hdd_priv_data_t *priv_data)
4833{
4834 int ret;
4835 uint8_t *value = command;
4836 uint8_t *cckmIe = NULL;
4837 uint8_t cckmIeLen = 0;
4838
4839 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
4840 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304841 QDF_TRACE(QDF_MODULE_ID_HDD,
4842 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004843 "%s: Failed to parse cckm ie data",
4844 __func__);
4845 goto exit;
4846 }
4847
4848 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304849 QDF_TRACE(QDF_MODULE_ID_HDD,
4850 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004851 "%s: CCKM Ie input length is more than max[%d]",
4852 __func__, DOT11F_IE_RSN_MAX_LEN);
4853 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304854 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004855 cckmIe = NULL;
4856 }
4857 ret = -EINVAL;
4858 goto exit;
4859 }
4860
4861 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
4862 cckmIe, cckmIeLen);
4863 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304864 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004865 cckmIe = NULL;
4866 }
4867
4868exit:
4869 return ret;
4870}
4871
4872static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
4873 hdd_context_t *hdd_ctx,
4874 uint8_t *command,
4875 uint8_t command_len,
4876 hdd_priv_data_t *priv_data)
4877{
4878 int ret;
4879 uint8_t *value = command;
4880 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304881 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004882
4883 if (WLAN_HDD_INFRA_STATION != adapter->device_mode) {
4884 hdd_warn("Unsupported in mode %s(%d)",
4885 hdd_device_mode_to_string(adapter->device_mode),
4886 adapter->device_mode);
4887 return -EINVAL;
4888 }
4889
4890 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
4891 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304892 QDF_TRACE(QDF_MODULE_ID_HDD,
4893 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004894 "%s: Failed to parse ese beacon req",
4895 __func__);
4896 goto exit;
4897 }
4898
4899 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304900 hddLog(QDF_TRACE_LEVEL_INFO, FL("Not associated"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004901 hdd_indicate_ese_bcn_report_no_results(adapter,
4902 eseBcnReq.bcnReq[0].measurementToken,
4903 0x02, /* BIT(1) set for measurement done */
4904 0); /* no BSS */
4905 goto exit;
4906 }
4907
4908 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
4909 adapter->sessionId,
4910 &eseBcnReq);
4911
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304912 if (QDF_STATUS_E_RESOURCES == status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304913 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004914 FL("sme_set_ese_beacon_request failed (%d), a request already in progress"),
4915 status);
4916 ret = -EBUSY;
4917 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304918 } else if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304919 QDF_TRACE(QDF_MODULE_ID_HDD,
4920 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004921 "%s: sme_set_ese_beacon_request failed (%d)",
4922 __func__, status);
4923 ret = -EINVAL;
4924 goto exit;
4925 }
4926
4927exit:
4928 return ret;
4929}
4930#endif /* #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) */
4931
4932static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
4933 hdd_context_t *hdd_ctx,
4934 uint8_t *command,
4935 uint8_t command_len,
4936 hdd_priv_data_t *priv_data)
4937{
4938 int ret = 0;
4939 uint8_t *value = command;
4940 int targetRate;
4941
4942 /* input value is in units of hundred kbps */
4943
4944 /* Move pointer to ahead of SETMCRATE<delimiter> */
4945 value = value + command_len + 1;
4946
4947 /* Convert the value from ascii to integer, decimal base */
4948 ret = kstrtouint(value, 10, &targetRate);
4949
4950 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
4951 return ret;
4952}
4953
4954static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
4955 hdd_context_t *hdd_ctx,
4956 uint8_t *command,
4957 uint8_t command_len,
4958 hdd_priv_data_t *priv_data)
4959{
4960 int ret = 0;
4961 int status;
4962 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304963 QDF_STATUS qdf_status;
4964 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004965 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05304966 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
4967 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004968 hdd_adapter_list_node_t *pAdapterNode = NULL;
4969 hdd_adapter_list_node_t *pNext = NULL;
4970
4971 status = hdd_parse_setmaxtxpower_command(value, &txPower);
4972 if (status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304973 QDF_TRACE(QDF_MODULE_ID_HDD,
4974 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004975 "Invalid MAXTXPOWER command ");
4976 ret = -EINVAL;
4977 goto exit;
4978 }
4979
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304980 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004981 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304982 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004983 adapter = pAdapterNode->pAdapter;
4984 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05304985 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07004986 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05304987 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07004988 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004989
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304990 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004991 "Device mode %d max tx power %d selfMac: " MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
4992 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07004993 MAC_ADDR_ARRAY(selfMac.bytes),
4994 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004995
Srinivas Girigowda97215232015-09-24 12:26:28 -07004996 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
4997 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304998 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304999 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005000 "%s:Set max tx power failed",
5001 __func__);
5002 ret = -EINVAL;
5003 goto exit;
5004 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305005 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005006 "%s: Set max tx power success",
5007 __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305008 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005009 &pNext);
5010 pAdapterNode = pNext;
5011 }
5012
5013exit:
5014 return ret;
5015}
5016
5017static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5018 hdd_context_t *hdd_ctx,
5019 uint8_t *command,
5020 uint8_t command_len,
5021 hdd_priv_data_t *priv_data)
5022{
5023 int ret = 0;
5024 uint8_t *value = command;
5025 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5026
5027 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5028 value = value + command_len + 1;
5029
5030 /* Convert the value from ascii to integer */
5031 ret = kstrtou8(value, 10, &dfsScanMode);
5032 if (ret < 0) {
5033 /*
5034 * If the input value is greater than max value of datatype,
5035 * then also kstrtou8 fails
5036 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305037 QDF_TRACE(QDF_MODULE_ID_HDD,
5038 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005039 "%s: kstrtou8 failed range [%d - %d]",
5040 __func__, CFG_ROAMING_DFS_CHANNEL_MIN,
5041 CFG_ROAMING_DFS_CHANNEL_MAX);
5042 ret = -EINVAL;
5043 goto exit;
5044 }
5045
5046 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5047 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305048 QDF_TRACE(QDF_MODULE_ID_HDD,
5049 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005050 "dfsScanMode value %d is out of range (Min: %d Max: %d)",
5051 dfsScanMode,
5052 CFG_ROAMING_DFS_CHANNEL_MIN,
5053 CFG_ROAMING_DFS_CHANNEL_MAX);
5054 ret = -EINVAL;
5055 goto exit;
5056 }
5057
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305058 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005059 "%s: Received Command to Set DFS Scan Mode = %d",
5060 __func__, dfsScanMode);
5061
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005062 /* When DFS scanning is disabled, the DFS channels need to be
5063 * removed from the operation of device.
5064 */
5065 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5066 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5067 if (ret < 0) {
5068 /* Some conditions prevented it from disabling DFS channels */
5069 hddLog(LOGE,
5070 FL("disable/enable DFS channel request was denied"));
5071 goto exit;
5072 }
5073
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005074 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5075 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5076 dfsScanMode);
5077
5078exit:
5079 return ret;
5080}
5081
5082static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5083 hdd_context_t *hdd_ctx,
5084 uint8_t *command,
5085 uint8_t command_len,
5086 hdd_priv_data_t *priv_data)
5087{
5088 int ret = 0;
5089 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5090 char extra[32];
5091 uint8_t len = 0;
5092
5093 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305094 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005095 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305096 QDF_TRACE(QDF_MODULE_ID_HDD,
5097 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005098 "%s: failed to copy data to user buffer",
5099 __func__);
5100 ret = -EFAULT;
5101 }
5102
5103 return ret;
5104}
5105
5106static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5107 hdd_context_t *hdd_ctx,
5108 uint8_t *command,
5109 uint8_t command_len,
5110 hdd_priv_data_t *priv_data)
5111{
5112 int ret = 0;
5113 int value = wlan_hdd_get_link_status(adapter);
5114 char extra[32];
5115 uint8_t len;
5116
5117 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305118 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005119 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305120 QDF_TRACE(QDF_MODULE_ID_HDD,
5121 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005122 "%s: failed to copy data to user buffer",
5123 __func__);
5124 ret = -EFAULT;
5125 }
5126
5127 return ret;
5128}
5129
5130#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5131static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5132 hdd_context_t *hdd_ctx,
5133 uint8_t *command,
5134 uint8_t command_len,
5135 hdd_priv_data_t *priv_data)
5136{
5137 uint8_t *value = command;
5138 int set_value;
5139
5140 /* Move pointer to ahead of ENABLEEXTWOW */
5141 value = value + command_len;
5142
5143 sscanf(value, "%d", &set_value);
5144
5145 return hdd_enable_ext_wow_parser(adapter,
5146 adapter->sessionId,
5147 set_value);
5148}
5149
5150static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5151 hdd_context_t *hdd_ctx,
5152 uint8_t *command,
5153 uint8_t command_len,
5154 hdd_priv_data_t *priv_data)
5155{
5156 int ret;
5157 uint8_t *value = command;
5158
5159 /* Move pointer to ahead of SETAPP1PARAMS */
5160 value = value + command_len;
5161
5162 ret = hdd_set_app_type1_parser(adapter,
5163 value, strlen(value));
5164 if (ret >= 0)
5165 hdd_ctx->is_extwow_app_type1_param_set = true;
5166
5167 return ret;
5168}
5169
5170static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5171 hdd_context_t *hdd_ctx,
5172 uint8_t *command,
5173 uint8_t command_len,
5174 hdd_priv_data_t *priv_data)
5175{
5176 int ret;
5177 uint8_t *value = command;
5178
5179 /* Move pointer to ahead of SETAPP2PARAMS */
5180 value = value + command_len;
5181
5182 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5183 if (ret >= 0)
5184 hdd_ctx->is_extwow_app_type2_param_set = true;
5185
5186 return ret;
5187}
5188#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5189
5190#ifdef FEATURE_WLAN_TDLS
5191/**
5192 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5193 * @adapter: Pointer to the HDD adapter
5194 * @hdd_ctx: Pointer to the HDD context
5195 * @command: Driver command string
5196 * @command_len: Driver command string length
5197 * @priv_data: Private data coming with the driver command. Unused here
5198 *
5199 * This function handles driver command that sets the secondary tdls off channel
5200 * offset
5201 *
5202 * Return: 0 on success; negative errno otherwise
5203 */
5204static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5205 hdd_context_t *hdd_ctx,
5206 uint8_t *command,
5207 uint8_t command_len,
5208 hdd_priv_data_t *priv_data)
5209{
5210 int ret;
5211 uint8_t *value = command;
5212 int set_value;
5213
5214 /* Move pointer to point the string */
5215 value += command_len;
5216
5217 ret = sscanf(value, "%d", &set_value);
5218 if (ret != 1)
5219 return -EINVAL;
5220
5221 hddLog(LOG1, FL("Tdls offchannel offset:%d"), set_value);
5222
5223 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5224
5225 return ret;
5226}
5227
5228/**
5229 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5230 * @adapter: Pointer to the HDD adapter
5231 * @hdd_ctx: Pointer to the HDD context
5232 * @command: Driver command string
5233 * @command_len: Driver command string length
5234 * @priv_data: Private data coming with the driver command. Unused here
5235 *
5236 * This function handles driver command that sets tdls off channel mode
5237 *
5238 * Return: 0 on success; negative errno otherwise
5239 */
5240static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5241 hdd_context_t *hdd_ctx,
5242 uint8_t *command,
5243 uint8_t command_len,
5244 hdd_priv_data_t *priv_data)
5245{
5246 int ret;
5247 uint8_t *value = command;
5248 int set_value;
5249
5250 /* Move pointer to point the string */
5251 value += command_len;
5252
5253 ret = sscanf(value, "%d", &set_value);
5254 if (ret != 1)
5255 return -EINVAL;
5256
5257 hddLog(LOG1, FL("Tdls offchannel mode:%d"), set_value);
5258
5259 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5260
5261 return ret;
5262}
5263
5264/**
5265 * drv_cmd_tdls_off_channel() - set tdls off channel number
5266 * @adapter: Pointer to the HDD adapter
5267 * @hdd_ctx: Pointer to the HDD context
5268 * @command: Driver command string
5269 * @command_len: Driver command string length
5270 * @priv_data: Private data coming with the driver command. Unused here
5271 *
5272 * This function handles driver command that sets tdls off channel number
5273 *
5274 * Return: 0 on success; negative errno otherwise
5275 */
5276static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5277 hdd_context_t *hdd_ctx,
5278 uint8_t *command,
5279 uint8_t command_len,
5280 hdd_priv_data_t *priv_data)
5281{
5282 int ret;
5283 uint8_t *value = command;
5284 int set_value;
5285
5286 /* Move pointer to point the string */
5287 value += command_len;
5288
5289 ret = sscanf(value, "%d", &set_value);
5290 if (ret != 1)
5291 return -EINVAL;
5292
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005293 if (CDS_IS_DFS_CH(set_value)) {
5294 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5295 set_value);
5296 return -EINVAL;
5297 }
5298
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005299 hddLog(LOG1, FL("Tdls offchannel num: %d"), set_value);
5300
5301 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5302
5303 return ret;
5304}
5305
5306/**
5307 * drv_cmd_tdls_scan() - set tdls scan type
5308 * @adapter: Pointer to the HDD adapter
5309 * @hdd_ctx: Pointer to the HDD context
5310 * @command: Driver command string
5311 * @command_len: Driver command string length
5312 * @priv_data: Private data coming with the driver command. Unused here
5313 *
5314 * This function handles driver command that sets tdls scan type
5315 *
5316 * Return: 0 on success; negative errno otherwise
5317 */
5318static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
5319 hdd_context_t *hdd_ctx,
5320 uint8_t *command,
5321 uint8_t command_len,
5322 hdd_priv_data_t *priv_data)
5323{
5324 int ret;
5325 uint8_t *value = command;
5326 int set_value;
5327
5328 /* Move pointer to point the string */
5329 value += command_len;
5330
5331 ret = sscanf(value, "%d", &set_value);
5332 if (ret != 1)
5333 return -EINVAL;
5334
5335 hddLog(LOG1, FL("Tdls scan type val: %d"), set_value);
5336
5337 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
5338
5339 return ret;
5340}
5341#endif
5342
5343static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
5344 hdd_context_t *hdd_ctx,
5345 uint8_t *command,
5346 uint8_t command_len,
5347 hdd_priv_data_t *priv_data)
5348{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005349 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005350 int8_t rssi = 0;
5351 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005352
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005353 uint8_t len = 0;
5354
5355 wlan_hdd_get_rssi(adapter, &rssi);
5356
5357 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305358 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005359
5360 if (copy_to_user(priv_data->buf, &extra, len)) {
5361 hddLog(LOGE, FL("Failed to copy data to user buffer"));
5362 ret = -EFAULT;
5363 }
5364
5365 return ret;
5366}
5367
5368static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
5369 hdd_context_t *hdd_ctx,
5370 uint8_t *command,
5371 uint8_t command_len,
5372 hdd_priv_data_t *priv_data)
5373{
5374 int ret;
5375 uint32_t link_speed = 0;
5376 char extra[32];
5377 uint8_t len = 0;
5378
5379 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
5380 if (0 != ret)
5381 return ret;
5382
5383 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305384 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005385 if (copy_to_user(priv_data->buf, &extra, len)) {
5386 hddLog(LOGE, FL("Failed to copy data to user buffer"));
5387 ret = -EFAULT;
5388 }
5389
5390 return ret;
5391}
5392
5393#ifdef FEATURE_NAPI
5394/**
5395 * hdd_parse_napi() - helper functions to drv_cmd_napi
5396 * @str : source string to parse
5397 * @cmd : pointer to cmd part after parsing
5398 * @sub : pointer to subcmd part after parsing
5399 * @aux : pointer to optional aux part after parsing
5400 *
5401 * Example:
5402 * NAPI SCALE <n> +-- IN str
5403 * | | +------ OUT aux
5404 * | +------------ OUT subcmd
5405 * +----------------- OUT cmd
5406 *
5407 * Return: ==0: success; !=0: failure
5408 */
5409static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
5410{
5411 int rc;
5412 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
5413
5414 NAPI_DEBUG("-->\n");
5415
5416 token = strsep(str, " \t");
5417 if (NULL == token) {
5418 hdd_err("cannot parse cmd");
5419 goto parse_end;
5420 }
5421 lcmd = token;
5422
5423 token = strsep(str, " \t");
5424 if (NULL == token) {
5425 hdd_err("cannot parse subcmd");
5426 goto parse_end;
5427 }
5428 lsub = token;
5429
5430 token = strsep(str, " \t");
5431 if (NULL == token)
5432 hdd_warn("cannot parse aux\n");
5433 else
5434 laux = token;
5435
5436parse_end:
5437 if ((NULL == lcmd) || (NULL == lsub))
5438 rc = -EINVAL;
5439 else {
5440 rc = 0;
5441 *cmd = lcmd;
5442 *sub = lsub;
5443 if (NULL != aux)
5444 *aux = laux;
5445 }
5446 NAPI_DEBUG("<--[rc=%d]\n", rc);
5447 return rc;
5448}
5449
5450
5451/**
5452 * hdd_parse_stats() - print NAPI stats into a buffer
5453 * @buf : buffer to write stats into
5454 * @max : "size of buffer"
5455 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
5456 * @napid: binary structure to retrieve the stats from
5457 *
5458 * Return: number of bytes written into the buffer
5459 */
5460int hdd_napi_stats(char *buf,
5461 int max,
5462 char *indp,
5463 struct qca_napi_data *napid)
5464{
5465 int n = 0;
5466 int i, j, k; /* NAPI, CPU, bucket indices */
5467 int from, to;
5468 struct qca_napi_info *napii;
5469 struct qca_napi_stat *napis;
5470
5471 NAPI_DEBUG("-->\n");
5472
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005473 if (NULL == napid)
5474 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005475 if (NULL == indp) {
5476 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005477 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005478 } else {
5479 if (0 > kstrtoint(indp, 10, &to)) {
5480 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005481 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005482 } else
5483 from = to;
5484 }
5485
5486 for (i = from; i < to; i++)
5487 if (napid->ce_map & (0x01 << i)) {
5488 napii = &(napid->napis[i]);
5489 for (j = 0; j < NR_CPUS; j++) {
5490 napis = &(napii->stats[j]);
5491 n += scnprintf(buf + n, max - n,
5492 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
5493 i, j,
5494 napis->napi_schedules,
5495 napis->napi_polls,
5496 napis->napi_completes,
5497 napis->napi_workdone);
5498
5499 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
5500 n += scnprintf(
5501 buf + n, max - n,
5502 " %d",
5503 napis->napi_budget_uses[k]);
5504 }
5505 n += scnprintf(buf+n, max - n, "\n");
5506 }
5507 }
5508
5509 NAPI_DEBUG("<--[n=%d]\n", n);
5510 return n;
5511}
5512
5513/**
5514 * napi_set_scale() - sets the scale attribute in all NAPI entries
5515 * @sc : scale to set
5516 *
5517 * Return: void
5518 */
5519static void napi_set_scale(uint8_t sc)
5520{
5521 uint32_t i;
5522 struct qca_napi_data *napi_data;
5523
5524 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005525 if (likely(NULL != napi_data))
5526 for (i = 0; i < CE_COUNT_MAX; i++)
5527 if (napi_data->ce_map & (0x01 << i))
5528 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005529
5530 return;
5531}
5532/**
5533 * drv_cmd_napi() - processes NAPI commands
5534 * @adapter : net_device
5535 * @hdd_ctx : HDD context
5536 * @command : command string from user command (including "NAPI")
5537 * @command_len: length of command
5538 * @priv_data : ifr_data
5539 *
5540 * Commands supported:
5541 * NAPI ENABLE : enables NAPI administratively. Note that this may not
5542 * enable NAPI functionally, as some other conditions
5543 * may not have been satisfied yet
5544 * NAPI DISABLE : reverse operation of "enable"
5545 * NAPI STATUS : get global status of NAPI instances
5546 * NAPI STATS [<n>] : get the stats for a given NAPI instance
5547 * NAPI SCALE <n> : set the scale factor
5548 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005549 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005550 */
5551static int drv_cmd_napi(hdd_adapter_t *adapter,
5552 hdd_context_t *hdd_ctx,
5553 uint8_t *command,
5554 uint8_t command_len,
5555 hdd_priv_data_t *priv_data)
5556{
5557 int rc = 0;
5558 int n, l;
5559 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
5560 char *synopsis = "NAPI ENABLE\n"
5561 "NAPI DISABLE\n"
5562 "NAPI STATUS\n"
5563 "NAPI STATS [<n>] -- if no <n> then all\n"
5564 "NAPI SCALE <n> -- set the scale\n";
5565 char *reply = NULL;
5566
5567 /* make a local copy, as strsep modifies the str in place */
5568 char *str = NULL;
5569
5570 NAPI_DEBUG("-->\n");
5571
5572 /**
5573 * NOTE TO MAINTAINER: from this point to the end of the function,
5574 * please do not return anywhere in the code except the very end
5575 * to avoid memory leakage (goto end_drv_napi instead)
5576 * or make sure that reply+str is freed
5577 */
5578 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
5579 if (NULL == reply) {
5580 hdd_err("could not allocate reply buffer");
5581 rc = -ENOMEM;
5582 goto end_drv_napi;
5583 }
5584
5585 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
5586 if (NULL == str) {
5587 hdd_err("could not allocate copy of input buffer");
5588 rc = -ENOMEM;
5589 goto end_drv_napi;
5590 }
5591
5592 strlcpy(str, command, strlen(command) + 1);
5593 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
5594 cmd, subcmd, aux);
5595
5596
5597 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
5598
5599 if (0 != rc) {
5600 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05305601 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005602 strlen(msg)+strlen(synopsis));
5603 n = scnprintf(reply, l, msg, synopsis);
5604
5605 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05305606 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005607 hdd_err("failed to copy data to user buffer");
5608 hdd_debug("reply: %s", reply);
5609
5610 rc = -EINVAL;
5611 } else {
5612 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
5613 cmd, subcmd, aux);
5614 if (!strcmp(subcmd, "ENABLE"))
5615 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
5616 else if (!strcmp(subcmd, "DISABLE"))
5617 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
5618 else if (!strcmp(subcmd, "STATUS")) {
5619 int n = 0;
5620 uint32_t i;
5621 struct qca_napi_data *napi_data;
5622
5623 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005624 if (unlikely(NULL == napi_data))
5625 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005626 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
5627 "NAPI state: 0x%08x map: 0x%08x\n",
5628 napi_data->state,
5629 napi_data->ce_map);
5630
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005631 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005632 if (napi_data->ce_map & (0x01 << i)) {
5633 n += scnprintf(
5634 reply + n,
5635 MAX_USER_COMMAND_SIZE - n,
5636 "#%d: id: %d, scale=%d\n",
5637 i,
5638 napi_data->napis[i].id,
5639 napi_data->napis[i].scale);
5640 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005641 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005642 hdd_info("wlan: STATUS DATA:\n%s", reply);
5643 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05305644 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005645 rc = -EINVAL;
5646 } else if (!strcmp(subcmd, "STATS")) {
5647 int n = 0;
5648 struct qca_napi_data *napi_data;
5649
5650 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005651 if (NULL != napi_data) {
5652 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
5653 aux, napi_data);
5654 NAPI_DEBUG("STATS: returns %d\n", n);
5655 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005656 if (n > 0) {
5657 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05305658 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005659 n)))
5660 rc = -EINVAL;
5661 hdd_info("wlan: STATS_DATA\n%s\n", reply);
5662 } else
5663 rc = -EINVAL;
5664 } else if (!strcmp(subcmd, "SCALE")) {
5665 if (NULL == aux) {
5666 rc = -EINVAL;
5667 hdd_err("wlan: SCALE cmd requires <n>");
5668 } else {
5669 uint8_t sc;
5670 rc = kstrtou8(aux, 10, &sc);
5671 if (rc) {
5672 hdd_err("wlan: bad scale (%s)", aux);
5673 rc = -EINVAL;
5674 } else
5675 napi_set_scale(sc);
5676 }
5677 } /* SCALE */
5678 }
5679end_drv_napi:
5680 if (NULL != str)
5681 kfree(str);
5682 if (NULL != reply)
5683 kfree(reply);
5684
5685 NAPI_DEBUG("<--[rc=%d]\n", rc);
5686 return rc;
5687}
5688#endif /* FEATURE_NAPI */
5689
5690/**
5691 * hdd_set_rx_filter() - set RX filter
5692 * @adapter: Pointer to adapter
5693 * @action: Filter action
5694 * @pattern: Address pattern
5695 *
5696 * Address pattern is most significant byte of address for example
5697 * 0x01 for IPV4 multicast address
5698 * 0x33 for IPV6 multicast address
5699 * 0xFF for broadcast address
5700 *
5701 * Return: 0 for success, non-zero for failure
5702 */
5703static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
5704 uint8_t pattern)
5705{
5706 int ret;
5707 uint8_t i;
5708 tHalHandle handle;
5709 tSirRcvFltMcAddrList *filter;
5710 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5711
5712 ret = wlan_hdd_validate_context(hdd_ctx);
5713 if (0 != ret)
5714 return ret;
5715
5716 handle = hdd_ctx->hHal;
5717
5718 if (NULL == handle) {
5719 hdd_err("HAL Handle is NULL");
5720 return -EINVAL;
5721 }
5722
5723 /*
5724 * If action is false it means start dropping packets
5725 * Set addr_filter_pattern which will be used when sending
5726 * MC/BC address list to target
5727 */
5728 if (!action)
5729 adapter->addr_filter_pattern = pattern;
5730 else
5731 adapter->addr_filter_pattern = 0;
5732
5733 if (((adapter->device_mode == WLAN_HDD_INFRA_STATION) ||
5734 (adapter->device_mode == WLAN_HDD_P2P_CLIENT)) &&
5735 adapter->mc_addr_list.mc_cnt &&
5736 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
5737
5738
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305739 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005740 if (NULL == filter) {
5741 hdd_err("Could not allocate Memory");
5742 return -ENOMEM;
5743 }
5744 filter->action = action;
5745 for (i = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
5746 if (!memcmp(adapter->mc_addr_list.addr[i],
5747 &pattern, 1)) {
Srinivas Girigowda98530492015-11-20 17:39:24 -08005748 memcpy(filter->multicastAddr[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005749 adapter->mc_addr_list.addr[i],
5750 sizeof(adapter->mc_addr_list.addr[i]));
5751 filter->ulMulticastAddrCnt++;
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08005752 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005753 MAC_ADDRESS_STR,
5754 action ? "setting" : "clearing",
Srinivas Girigowda98530492015-11-20 17:39:24 -08005755 MAC_ADDR_ARRAY(filter->multicastAddr[i].bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005756 }
5757 }
5758 /* Set rx filter */
5759 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305760 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005761 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08005762 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005763 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
5764 }
5765
5766 return 0;
5767}
5768
5769/**
5770 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
5771 * @command: Pointer to input string driver command
5772 * @adapter: Pointer to adapter
5773 * @action: Action to enable/disable filtering
5774 *
5775 * If action == false
5776 * Start filtering out data packets based on type
5777 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
5778 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
5779 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
5780 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
5781 *
5782 * if action == true
5783 * Stop filtering data packets based on type
5784 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
5785 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
5786 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
5787 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
5788 *
5789 * Current implementation only supports IPV4 address filtering by
5790 * selectively allowing IPV4 multicast data packest based on
5791 * address list received in .ndo_set_rx_mode
5792 *
5793 * Return: 0 for success, non-zero for failure
5794 */
5795static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
5796 hdd_adapter_t *adapter,
5797 bool action)
5798{
5799 int ret = 0;
5800 uint8_t *value;
5801 uint8_t type;
5802
5803 value = command;
5804 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
5805 if (!action)
5806 value = command + 16;
5807 else
5808 value = command + 13;
5809 ret = kstrtou8(value, 10, &type);
5810 if (ret < 0) {
5811 hdd_err("kstrtou8 failed invalid input value %d", type);
5812 return -EINVAL;
5813 }
5814
5815 switch (type) {
5816 case 2:
5817 /* Set rx filter for IPV4 multicast data packets */
5818 ret = hdd_set_rx_filter(adapter, action, 0x01);
5819 break;
5820 default:
5821 hdd_info("Unsupported RXFILTER type %d", type);
5822 break;
5823 }
5824
5825 return ret;
5826}
5827
5828/**
5829 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
5830 * @adapter: Pointer to network adapter
5831 * @hdd_ctx: Pointer to hdd context
5832 * @command: Pointer to input command
5833 * @command_len: Command length
5834 * @priv_data: Pointer to private data in command
5835 */
5836static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
5837 hdd_context_t *hdd_ctx,
5838 uint8_t *command,
5839 uint8_t command_len,
5840 hdd_priv_data_t *priv_data)
5841{
5842 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
5843}
5844
5845/**
5846 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
5847 * @adapter: Pointer to network adapter
5848 * @hdd_ctx: Pointer to hdd context
5849 * @command: Pointer to input command
5850 * @command_len: Command length
5851 * @priv_data: Pointer to private data in command
5852 */
5853static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
5854 hdd_context_t *hdd_ctx,
5855 uint8_t *command,
5856 uint8_t command_len,
5857 hdd_priv_data_t *priv_data)
5858{
5859 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
5860}
5861
5862/*
5863 * dummy (no-op) hdd driver command handler
5864 */
5865static int drv_cmd_dummy(hdd_adapter_t *adapter,
5866 hdd_context_t *hdd_ctx,
5867 uint8_t *command,
5868 uint8_t command_len,
5869 hdd_priv_data_t *priv_data)
5870{
5871 hdd_info("%s: Ignoring driver command \"%s\"",
5872 adapter->dev->name, command);
5873 return 0;
5874}
5875
5876/*
5877 * handler for any unsupported wlan hdd driver command
5878 */
5879static int drv_cmd_invalid(hdd_adapter_t *adapter,
5880 hdd_context_t *hdd_ctx,
5881 uint8_t *command,
5882 uint8_t command_len,
5883 hdd_priv_data_t *priv_data)
5884{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305885 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005886 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
5887 adapter->sessionId, 0));
5888
5889 hdd_warn("%s: Unsupported driver command \"%s\"",
5890 adapter->dev->name, command);
5891
5892 return -ENOTSUPP;
5893}
5894
5895/**
5896 * drv_cmd_set_fcc_channel() - handle fcc constraint request
5897 * @adapter: HDD adapter
5898 * @hdd_ctx: HDD context
5899 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
5900 * @command_len: command len
5901 * @priv_data: private data
5902 *
5903 * Return: status
5904 */
5905static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
5906 hdd_context_t *hdd_ctx,
5907 uint8_t *command,
5908 uint8_t command_len,
5909 hdd_priv_data_t *priv_data)
5910{
5911 uint8_t *value;
5912 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305913 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005914 int ret = 0;
5915
5916 /*
5917 * this command would be called by user-space when it detects WLAN
5918 * ON after airplane mode is set. When APM is set, WLAN turns off.
5919 * But it can be turned back on. Otherwise; when APM is turned back
5920 * off, WLAN would turn back on. So at that point the command is
5921 * expected to come down. 0 means disable, 1 means enable. The
5922 * constraint is removed when parameter 1 is set or different
5923 * country code is set
5924 */
5925
5926 value = command + command_len + 1;
5927
5928 ret = kstrtou8(value, 10, &fcc_constraint);
5929 if ((ret < 0) || (fcc_constraint > 1)) {
5930 /*
5931 * If the input value is greater than max value of datatype,
5932 * then also it is a failure
5933 */
5934 hdd_err("value out of range");
5935 return -EINVAL;
5936 }
5937
5938 status = sme_disable_non_fcc_channel(hdd_ctx->hHal, !fcc_constraint);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305939 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005940 hdd_err("sme disable fn. returned err");
5941 ret = -EPERM;
5942 }
5943
5944 return ret;
5945}
5946
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05305947/**
5948 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
5949 * command
5950 * @value: Pointer to the command
5951 * @chan_number: Pointer to the channel number
5952 * @chan_bw: Pointer to the channel bandwidth
5953 *
5954 * Parses and provides the channel number and channel width from the input
5955 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
5956 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
5957 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
5958 *
5959 * Return: 0 for success, non-zero for failure
5960 */
5961static int hdd_parse_set_channel_switch_command(uint8_t *value,
5962 uint32_t *chan_number,
5963 uint32_t *chan_bw)
5964{
5965 const uint8_t *in_ptr = value;
5966 int ret;
5967
5968 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
5969
5970 /* no argument after the command */
5971 if (NULL == in_ptr) {
5972 hdd_err("No argument after the command");
5973 return -EINVAL;
5974 }
5975
5976 /* no space after the command */
5977 if (SPACE_ASCII_VALUE != *in_ptr) {
5978 hdd_err("No space after the command ");
5979 return -EINVAL;
5980 }
5981
5982 /* remove empty spaces and move the next argument */
5983 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
5984 in_ptr++;
5985
5986 /* no argument followed by spaces */
5987 if ('\0' == *in_ptr) {
5988 hdd_err("No argument followed by spaces");
5989 return -EINVAL;
5990 }
5991
5992 /* get the two arguments: channel number and bandwidth */
5993 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
5994 if (ret != 2) {
5995 hdd_err("Arguments retrieval from cmd string failed");
5996 return -EINVAL;
5997 }
5998
5999 return 0;
6000}
6001
6002/**
6003 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6004 * @adapter: HDD adapter
6005 * @hdd_ctx: HDD context
6006 * @command: Pointer to the input command CHANNEL_SWITCH
6007 * @command_len: Command len
6008 * @priv_data: Private data
6009 *
6010 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6011 * of SAP/P2P-GO
6012 *
6013 * Return: 0 for success, non-zero for failure
6014 */
6015static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
6016 hdd_context_t *hdd_ctx,
6017 uint8_t *command,
6018 uint8_t command_len,
6019 hdd_priv_data_t *priv_data)
6020{
6021 struct net_device *dev = adapter->dev;
6022 int status;
6023 uint32_t chan_number = 0, chan_bw = 0;
6024 uint8_t *value = command;
Amar Singhale4f28ee2015-10-21 14:36:56 -07006025 enum ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306026
6027 if ((adapter->device_mode != WLAN_HDD_P2P_GO) &&
6028 (adapter->device_mode != WLAN_HDD_SOFTAP)) {
6029 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6030 adapter->device_mode);
6031 return -EINVAL;
6032 }
6033
6034 status = hdd_parse_set_channel_switch_command(value,
6035 &chan_number, &chan_bw);
6036 if (status) {
6037 hdd_err("Invalid CHANNEL_SWITCH command");
6038 return status;
6039 }
6040
6041 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6042 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6043 return -EINVAL;
6044 }
6045
6046 if (chan_bw == 80)
6047 width = CH_WIDTH_80MHZ;
6048 else if (chan_bw == 40)
6049 width = CH_WIDTH_40MHZ;
6050 else
6051 width = CH_WIDTH_20MHZ;
6052
6053 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
6054
6055 status = hdd_softap_set_channel_change(dev, chan_number, width);
6056 if (status) {
6057 hdd_err("Set channel change fail");
6058 return status;
6059 }
6060
6061 return 0;
6062}
6063
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006064/*
6065 * The following table contains all supported WLAN HDD
6066 * IOCTL driver commands and the handler for each of them.
6067 */
6068static const hdd_drv_cmd_t hdd_drv_cmds[] = {
6069 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
6070 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
6071 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
6072 {"SETBAND", drv_cmd_set_band},
6073 {"SETWMMPS", drv_cmd_set_wmmps},
6074 {"COUNTRY", drv_cmd_country},
6075 {"SETSUSPENDMODE", drv_cmd_dummy},
6076 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
6077 {"BTCOEXSCAN", drv_cmd_dummy},
6078 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006079 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
6080 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
6081 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
6082 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
6083 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
6084 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006085 {"SETROAMMODE", drv_cmd_set_roam_mode},
6086 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006087 {"SETROAMDELTA", drv_cmd_set_roam_delta},
6088 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006089 {"GETBAND", drv_cmd_get_band},
6090 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
6091 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
6092 {"GETCCXMODE", drv_cmd_get_ccx_mode},
6093 {"GETOKCMODE", drv_cmd_get_okc_mode},
6094 {"GETFASTROAM", drv_cmd_get_fast_roam},
6095 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
6096 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
6097 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
6098 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
6099 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
6100 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
6101 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
6102 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
6103 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
6104 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
6105 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
6106 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
6107 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
6108 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
6109 {"REASSOC", drv_cmd_reassoc},
6110 {"SETWESMODE", drv_cmd_set_wes_mode},
6111 {"GETWESMODE", drv_cmd_get_wes_mode},
6112 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
6113 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
6114 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
6115 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006116 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006117 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
6118 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006119#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
6120 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
6121#endif
6122#ifdef FEATURE_WLAN_ESE
6123 {"SETCCXMODE", drv_cmd_set_ccx_mode},
6124#endif
6125 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
6126#ifdef FEATURE_WLAN_OKC
6127 {"SETOKCMODE", drv_cmd_set_okc_mode},
6128#endif /* FEATURE_WLAN_OKC */
6129 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
6130 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
6131 {"SCAN-ACTIVE", drv_cmd_scan_active},
6132 {"SCAN-PASSIVE", drv_cmd_scan_passive},
6133 {"GETDWELLTIME", drv_cmd_get_dwell_time},
6134 {"SETDWELLTIME", drv_cmd_set_dwell_time},
6135 {"MIRACAST", drv_cmd_miracast},
6136#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
6137 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
6138 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
6139 {"SETCCKMIE", drv_cmd_set_cckm_ie},
6140 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
6141#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
6142 {"SETMCRATE", drv_cmd_set_mc_rate},
6143 {"MAXTXPOWER", drv_cmd_max_tx_power},
6144 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
6145 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
6146 {"GETLINKSTATUS", drv_cmd_get_link_status},
6147#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6148 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
6149 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
6150 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
6151#endif
6152#ifdef FEATURE_WLAN_TDLS
6153 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
6154 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
6155 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
6156 {"TDLSSCAN", drv_cmd_tdls_scan},
6157#endif
6158 {"RSSI", drv_cmd_get_rssi},
6159 {"LINKSPEED", drv_cmd_get_linkspeed},
6160#ifdef FEATURE_NAPI
6161 {"NAPI", drv_cmd_napi},
6162#endif /* FEATURE_NAPI */
6163 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
6164 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
6165 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306166 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006167};
6168
6169/**
6170 * hdd_drv_cmd_process() - chooses and runs the proper
6171 * handler based on the input command
6172 * @adapter: Pointer to the hdd adapter
6173 * @cmd: Pointer to the driver command
6174 * @priv_data: Pointer to the data associated with the command
6175 *
6176 * This function parses the input hdd driver command and runs
6177 * the proper handler
6178 *
6179 * Return: 0 for success non-zero for failure
6180 */
6181static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
6182 uint8_t *cmd,
6183 hdd_priv_data_t *priv_data)
6184{
6185 hdd_context_t *hdd_ctx;
6186 int i;
6187 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6188 uint8_t *cmd_i = NULL;
6189 hdd_drv_cmd_handler_t handler = NULL;
6190 int len = 0;
6191
6192 if (!adapter || !cmd || !priv_data) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306193 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006194 "%s: at least 1 param is NULL", __func__);
6195 return -EINVAL;
6196 }
6197
6198 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
6199
6200 for (i = 0; i < cmd_num_total; i++) {
6201
6202 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6203 handler = hdd_drv_cmds[i].handler;
6204 len = strlen(cmd_i);
6205
6206 if (!handler) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306207 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006208 "%s: no. %d handler is NULL", __func__, i);
6209 return -EINVAL;
6210 }
6211
6212 if (strncasecmp(cmd, cmd_i, len) == 0)
6213 return handler(adapter, hdd_ctx,
6214 cmd, len, priv_data);
6215 }
6216
6217 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6218}
6219
6220/**
6221 * hdd_driver_command() - top level wlan hdd driver command handler
6222 * @adapter: Pointer to the hdd adapter
6223 * @priv_data: Pointer to the raw command data
6224 *
6225 * This function is the top level wlan hdd driver command handler. It
6226 * handles the command with the help of hdd_drv_cmd_process()
6227 *
6228 * Return: 0 for success non-zero for failure
6229 */
6230static int hdd_driver_command(hdd_adapter_t *adapter,
6231 hdd_priv_data_t *priv_data)
6232{
6233 uint8_t *command = NULL;
6234 int ret = 0;
6235
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306236 ENTER();
6237
Anurag Chouhan6d760662016-02-20 16:05:43 +05306238 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006239 hddLog(LOGE, FL("Command not allowed in FTM mode"));
6240 return -EINVAL;
6241 }
6242
6243 /*
6244 * Note that valid pointers are provided by caller
6245 */
6246
6247 /* copy to local struct to avoid numerous changes to legacy code */
6248 if (priv_data->total_len <= 0 ||
6249 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306250 hddLog(QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006251 "%s:invalid priv_data.total_len(%d)!!!", __func__,
6252 priv_data->total_len);
6253 ret = -EINVAL;
6254 goto exit;
6255 }
6256
6257 /* Allocate +1 for '\0' */
6258 command = kmalloc(priv_data->total_len + 1, GFP_KERNEL);
6259 if (!command) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306260 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006261 "%s: failed to allocate memory", __func__);
6262 ret = -ENOMEM;
6263 goto exit;
6264 }
6265
6266 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6267 ret = -EFAULT;
6268 goto exit;
6269 }
6270
6271 /* Make sure the command is NUL-terminated */
6272 command[priv_data->total_len] = '\0';
6273
6274 hdd_info("%s: %s", adapter->dev->name, command);
6275 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6276
6277exit:
6278 if (command)
6279 kfree(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306280 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006281 return ret;
6282}
6283
6284#ifdef CONFIG_COMPAT
6285static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6286{
6287 struct {
6288 compat_uptr_t buf;
6289 int used_len;
6290 int total_len;
6291 } compat_priv_data;
6292 hdd_priv_data_t priv_data;
6293 int ret = 0;
6294
6295 /*
6296 * Note that adapter and ifr have already been verified by caller,
6297 * and HDD context has also been validated
6298 */
6299 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
6300 sizeof(compat_priv_data))) {
6301 ret = -EFAULT;
6302 goto exit;
6303 }
6304 priv_data.buf = compat_ptr(compat_priv_data.buf);
6305 priv_data.used_len = compat_priv_data.used_len;
6306 priv_data.total_len = compat_priv_data.total_len;
6307 ret = hdd_driver_command(adapter, &priv_data);
6308exit:
6309 return ret;
6310}
6311#else /* CONFIG_COMPAT */
6312static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6313{
6314 /* will never be invoked */
6315 return 0;
6316}
6317#endif /* CONFIG_COMPAT */
6318
6319static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6320{
6321 hdd_priv_data_t priv_data;
6322 int ret = 0;
6323
6324 /*
6325 * Note that adapter and ifr have already been verified by caller,
6326 * and HDD context has also been validated
6327 */
6328 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
6329 ret = -EFAULT;
6330 else
6331 ret = hdd_driver_command(adapter, &priv_data);
6332
6333 return ret;
6334}
6335
6336/**
6337 * __hdd_ioctl() - ioctl handler for wlan network interfaces
6338 * @dev: device upon which the ioctl was received
6339 * @ifr: ioctl request information
6340 * @cmd: ioctl command
6341 *
6342 * This function does initial processing of wlan device ioctls.
6343 * Currently two flavors of ioctls are supported. The primary ioctl
6344 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
6345 * for Android "DRIVER" commands. The other ioctl that is
6346 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
6347 * for FTM on some platforms. This function simply verifies that the
6348 * driver is in a sane state, and that the ioctl is one of the
6349 * supported flavors, in which case flavor-specific handlers are
6350 * dispatched.
6351 *
6352 * Return: 0 on success, non-zero on error
6353 */
6354static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
6355{
6356 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
6357 hdd_context_t *hdd_ctx;
6358 int ret;
6359
Jeff Johnson3c3994a2016-02-11 08:12:30 -08006360 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306361
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006362 if (dev != adapter->dev) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306363 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006364 "%s: HDD adapter/dev inconsistency", __func__);
6365 ret = -ENODEV;
6366 goto exit;
6367 }
6368
6369 if ((!ifr) || (!ifr->ifr_data)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306370 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006371 "%s: invalid data", __func__);
6372 ret = -EINVAL;
6373 goto exit;
6374 }
6375#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05306376 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006377 if (SIOCIOCTLTX99 == cmd) {
6378 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
6379 goto exit;
6380 }
6381 }
6382#endif
6383
6384 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6385 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306386 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006387 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006388
6389 switch (cmd) {
6390 case (SIOCDEVPRIVATE + 1):
6391 if (is_compat_task())
6392 ret = hdd_driver_compat_ioctl(adapter, ifr);
6393 else
6394 ret = hdd_driver_ioctl(adapter, ifr);
6395 break;
6396 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306397 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006398 __func__, cmd);
6399 ret = -EINVAL;
6400 break;
6401 }
6402exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306403 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006404 return ret;
6405}
6406
6407/**
6408 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
6409 * @dev: device upon which the ioctl was received
6410 * @ifr: ioctl request information
6411 * @cmd: ioctl command
6412 *
6413 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
6414 * which is where the ioctls are really handled.
6415 *
6416 * Return: 0 on success, non-zero on error
6417 */
6418int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
6419{
6420 int ret;
6421
6422 cds_ssr_protect(__func__);
6423 ret = __hdd_ioctl(dev, ifr, cmd);
6424 cds_ssr_unprotect(__func__);
6425 return ret;
6426}