blob: 12e562447881625ec53d0ad9b7b7166d74c4beba [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Rajeev Kumarea95edd2017-01-11 20:49:36 -08002 * Copyright (c) 2012-2017 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"
Jeff Johnson253c0c22017-01-23 16:59:38 -080035#include "wlan_hdd_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080036#include "wlan_hdd_driver_ops.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080037#include "wlan_policy_mgr_api.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053038#include "wlan_hdd_hostapd.h"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080039#include "scheduler_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080040
41#include "wlan_hdd_p2p.h"
42#include <linux/ctype.h>
43#include "wma.h"
44#include "wlan_hdd_napi.h"
45
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080046#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080047#include <sme_api.h>
48#include <sir_api.h>
49#endif
50#include "hif.h"
51
52#if defined(LINUX_QCMBR)
53#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
54#endif
55
56/*
57 * Size of Driver command strings from upper layer
58 */
59#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
60#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
61
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080062/*
63 * Ibss prop IE from command will be of size:
64 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
65 * OUI_DATA should be at least 3 bytes long
66 */
67#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080068
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080069#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080070#define TID_MIN_VALUE 0
71#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080072#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080073
74/*
75 * Maximum buffer size used for returning the data back to user space
76 */
77#define WLAN_MAX_BUF_SIZE 1024
78#define WLAN_PRIV_DATA_MAX_LEN 8192
79
80/*
81 * Driver miracast parameters 0-Disabled
82 * 1-Source, 2-Sink
83 */
84#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
85#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
86
87/*
88 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
89 * we will split the printing.
90 */
91#define NUM_OF_STA_DATA_TO_PRINT 16
92
93/*
94 * Android DRIVER command structures
95 */
96struct android_wifi_reassoc_params {
97 unsigned char bssid[18];
98 int channel;
99};
100
101#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
102struct android_wifi_af_params {
103 unsigned char bssid[18];
104 int channel;
105 int dwell_time;
106 int len;
107 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
108};
109
110/*
111 * Define HDD driver command handling entry, each contains a command
112 * string and the handler.
113 */
114typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
115 hdd_context_t *hdd_ctx,
116 uint8_t *cmd,
117 uint8_t cmd_name_len,
118 hdd_priv_data_t *priv_data);
119
120typedef struct {
121 const char *cmd;
122 hdd_drv_cmd_handler_t handler;
123} hdd_drv_cmd_t;
124
125#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
126#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
127#define WLAN_HDD_MAX_TCP_PORT 65535
128#endif
129
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800130static uint16_t cesium_pid;
131extern struct sock *cesium_nl_srv_sock;
132
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800133#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800134struct tsm_priv {
135 tAniTrafStrmMetrics tsm_metrics;
136};
137
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800138static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
139 const uint32_t staId, void *context)
140{
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800141 struct hdd_request *request;
142 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800144 request = hdd_request_get(context);
145 if (!request) {
146 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800147 return;
148 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800149 priv = hdd_request_priv(request);
150 priv->tsm_metrics = tsm_metrics;
151 hdd_request_complete(request);
152 hdd_request_put(request);
153 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800154
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800155}
156
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800157static int hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800158 const uint8_t tid,
159 tAniTrafStrmMetrics *tsm_metrics)
160{
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800161 hdd_context_t *hdd_ctx;
162 hdd_station_ctx_t *hdd_sta_ctx;
163 QDF_STATUS status;
164 int ret;
165 void *cookie;
166 struct hdd_request *request;
167 struct tsm_priv *priv;
168 static const struct hdd_request_params params = {
169 .priv_size = sizeof(*priv),
170 .timeout_ms = WLAN_WAIT_TIME_STATS,
171 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800172
173 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700174 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800175 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176 }
177
178 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
179 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
180
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800181 request = hdd_request_alloc(&params);
182 if (!request) {
183 hdd_err("Request allocation failure");
184 return -ENOMEM;
185 }
186 cookie = hdd_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800187
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800188 status = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
189 hdd_sta_ctx->conn_info.staId[0],
190 hdd_sta_ctx->conn_info.bssId,
191 cookie, hdd_ctx->pcds_context, tid);
192 if (QDF_STATUS_SUCCESS != status) {
193 hdd_err("Unable to retrieve tsm statistics");
194 ret = qdf_status_to_os_return(status);
195 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800196 }
197
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800198 ret = hdd_request_wait_for_response(request);
199 if (ret) {
200 hdd_err("SME timed out while retrieving tsm statistics");
201 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800203
204 priv = hdd_request_priv(request);
205 *tsm_metrics = priv->tsm_metrics;
206
207 cleanup:
208 hdd_request_put(request);
209
210 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800212#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800213
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800214/* Function header is left blank intentionally */
215static int hdd_parse_setrmcenable_command(uint8_t *pValue,
216 uint8_t *pRmcEnable)
217{
218 uint8_t *inPtr = pValue;
219 int tempInt;
220 int v = 0;
221 char buf[32];
222 *pRmcEnable = 0;
223
224 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
225
226 if (NULL == inPtr) {
227 return 0;
228 }
229
230 else if (SPACE_ASCII_VALUE != *inPtr) {
231 return 0;
232 }
233
234 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
235 inPtr++;
236
237 if ('\0' == *inPtr) {
238 return 0;
239 }
240
241 sscanf(inPtr, "%32s ", buf);
242 v = kstrtos32(buf, 10, &tempInt);
243 if (v < 0) {
244 return -EINVAL;
245 }
246
247 *pRmcEnable = tempInt;
248
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800249 hdd_debug("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800250
251 return 0;
252}
253
254/* Function header is left blank intentionally */
255static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
256 uint32_t *pActionPeriod)
257{
258 uint8_t *inPtr = pValue;
259 int tempInt;
260 int v = 0;
261 char buf[32];
262 *pActionPeriod = 0;
263
264 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
265
266 if (NULL == inPtr) {
267 return -EINVAL;
268 }
269
270 else if (SPACE_ASCII_VALUE != *inPtr) {
271 return -EINVAL;
272 }
273
274 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
275 inPtr++;
276
277 if ('\0' == *inPtr) {
278 return 0;
279 }
280
281 sscanf(inPtr, "%32s ", buf);
282 v = kstrtos32(buf, 10, &tempInt);
283 if (v < 0) {
284 return -EINVAL;
285 }
286
287 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
288 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) {
289 return -EINVAL;
290 }
291
292 *pActionPeriod = tempInt;
293
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800294 hdd_debug("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800295
296 return 0;
297}
298
299/* Function header is left blank intentionally */
300static int hdd_parse_setrmcrate_command(uint8_t *pValue,
301 uint32_t *pRate,
302 tTxrateinfoflags *pTxFlags)
303{
304 uint8_t *inPtr = pValue;
305 int tempInt;
306 int v = 0;
307 char buf[32];
308 *pRate = 0;
309 *pTxFlags = 0;
310
311 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
312
313 if (NULL == inPtr) {
314 return -EINVAL;
315 }
316
317 else if (SPACE_ASCII_VALUE != *inPtr) {
318 return -EINVAL;
319 }
320
321 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
322 inPtr++;
323
324 if ('\0' == *inPtr) {
325 return 0;
326 }
327
328 sscanf(inPtr, "%32s ", buf);
329 v = kstrtos32(buf, 10, &tempInt);
330 if (v < 0) {
331 return -EINVAL;
332 }
333
334 switch (tempInt) {
335 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700336 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800337 return -EINVAL;
338 case 0:
339 case 6:
340 case 9:
341 case 12:
342 case 18:
343 case 24:
344 case 36:
345 case 48:
346 case 54:
347 *pTxFlags = eHAL_TX_RATE_LEGACY;
348 *pRate = tempInt * 10;
349 break;
350 case 65:
351 *pTxFlags = eHAL_TX_RATE_HT20;
352 *pRate = tempInt * 10;
353 break;
354 case 72:
355 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
356 *pRate = 722;
357 break;
358 }
359
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800360 hdd_debug("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800361
362 return 0;
363}
364
365/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700366 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
367 * @UserData: Adapter private data
368 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800369 *
370 * This is an asynchronous callback function from SME when the peer info
371 * is received
372 *
373 * Return: 0 for success non-zero for failure
374 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700375void
376hdd_get_ibss_peer_info_cb(void *pUserData,
377 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800378{
379 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800380 hdd_station_ctx_t *pStaCtx;
381 uint8_t i;
382
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800383 if ((NULL == adapter) ||
384 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800385 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800386 return;
387 }
388
389 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
390 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700391 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530392 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
393 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700394 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530395 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800396 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530397 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
398 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
399
400 for (i = 0; i < pPeerInfo->numPeers; i++)
401 pStaCtx->ibss_peer_info.peerInfoParams[i] =
402 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800403 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800404 hdd_debug("peerInfo %s: status %u, numPeers %u",
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530405 pPeerInfo ? "valid" : "null",
406 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
407 pPeerInfo ? pPeerInfo->numPeers : 0);
408 pStaCtx->ibss_peer_info.numPeers = 0;
409 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800410 }
411
412 complete(&adapter->ibss_peer_info_comp);
413}
414
415/**
416 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
417 * @adapter: Adapter context
418 *
419 * Request function to get IBSS peer info from lower layers
420 *
421 * Return: 0 for success non-zero for failure
422 */
423static
424QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
425{
426 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
427 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
428 unsigned long rc;
429
430 INIT_COMPLETION(adapter->ibss_peer_info_comp);
431
432 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700433 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800434 true, 0xFF);
435
436 if (QDF_STATUS_SUCCESS == retStatus) {
437 rc = wait_for_completion_timeout
438 (&adapter->ibss_peer_info_comp,
439 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
440
441 /* status will be 0 if timed out */
442 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700443 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800444 retStatus = QDF_STATUS_E_FAILURE;
445 return retStatus;
446 }
447 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700448 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800449 }
450
451 return retStatus;
452}
453
454/**
455 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
456 * @adapter: Adapter context
457 * @staIdx: Sta index for which the peer info is requested
458 *
459 * Request function to get IBSS peer info from lower layers
460 *
461 * Return: 0 for success non-zero for failure
462 */
463static QDF_STATUS
464hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
465{
466 unsigned long rc;
467 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
468 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
469
470 INIT_COMPLETION(adapter->ibss_peer_info_comp);
471
472 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700473 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800474 false, staIdx);
475
476 if (QDF_STATUS_SUCCESS == retStatus) {
477 rc = wait_for_completion_timeout(
478 &adapter->ibss_peer_info_comp,
479 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
480
481 /* status = 0 on timeout */
482 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700483 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800484 retStatus = QDF_STATUS_E_FAILURE;
485 return retStatus;
486 }
487 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700488 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800489 }
490
491 return retStatus;
492}
493
494/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700495static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800496hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
497{
498 uint8_t *inPtr = pValue;
499 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
500
501 if (NULL == inPtr) {
502 return QDF_STATUS_E_FAILURE;;
503 }
504
505 else if (SPACE_ASCII_VALUE != *inPtr) {
506 return QDF_STATUS_E_FAILURE;;
507 }
508
509 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
510 inPtr++;
511
512 if ('\0' == *inPtr) {
513 return QDF_STATUS_E_FAILURE;;
514 }
515
516 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
517 inPtr[11] != ':' || inPtr[14] != ':') {
518 return QDF_STATUS_E_FAILURE;;
519 }
520 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
521 (unsigned int *)&pPeerMacAddr->bytes[0],
522 (unsigned int *)&pPeerMacAddr->bytes[1],
523 (unsigned int *)&pPeerMacAddr->bytes[2],
524 (unsigned int *)&pPeerMacAddr->bytes[3],
525 (unsigned int *)&pPeerMacAddr->bytes[4],
526 (unsigned int *)&pPeerMacAddr->bytes[5]);
527
528 return QDF_STATUS_SUCCESS;
529}
530
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800531static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
532{
533 eCsrBand band = -1;
534 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
535 switch (band) {
536 case eCSR_BAND_ALL:
537 *pBand = WLAN_HDD_UI_BAND_AUTO;
538 break;
539
540 case eCSR_BAND_24:
541 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
542 break;
543
544 case eCSR_BAND_5G:
545 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
546 break;
547
548 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700549 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550 *pBand = -1;
551 break;
552 }
553}
554
555/**
556 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
557 * @data: input data
558 * @target_ap_bssid: pointer to bssid (output parameter)
559 * @channel: pointer to channel (output parameter)
560 *
561 * Return: 0 if parsing is successful; -EINVAL otherwise
562 */
563static int _hdd_parse_bssid_and_chan(const uint8_t **data,
564 uint8_t *bssid,
565 uint8_t *channel)
566{
567 const uint8_t *in_ptr;
568 int v = 0;
569 int temp_int;
570 uint8_t temp_buf[32];
571
572 /* 12 hexa decimal digits, 5 ':' and '\0' */
573 uint8_t mac_addr[18];
574
575 if (!data || !*data)
576 return -EINVAL;
577
578 in_ptr = *data;
579
580 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
581 /* no argument after the command */
582 if (NULL == in_ptr)
583 goto error;
584 /* no space after the command */
585 else if (SPACE_ASCII_VALUE != *in_ptr)
586 goto error;
587
588 /* remove empty spaces */
589 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
590 in_ptr++;
591
592 /* no argument followed by spaces */
593 if ('\0' == *in_ptr)
594 goto error;
595
596 v = sscanf(in_ptr, "%17s", mac_addr);
597 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700598 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
599 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800600 goto error;
601 }
602
603 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
604 hex_to_bin(mac_addr[1]);
605 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
606 hex_to_bin(mac_addr[4]);
607 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
608 hex_to_bin(mac_addr[7]);
609 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
610 hex_to_bin(mac_addr[10]);
611 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
612 hex_to_bin(mac_addr[13]);
613 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
614 hex_to_bin(mac_addr[16]);
615
616 /* point to the next argument */
617 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
618 /* no argument after the command */
619 if (NULL == in_ptr)
620 goto error;
621
622 /* remove empty spaces */
623 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
624 in_ptr++;
625
626 /* no argument followed by spaces */
627 if ('\0' == *in_ptr)
628 goto error;
629
630 /* get the next argument ie the channel number */
631 v = sscanf(in_ptr, "%31s ", temp_buf);
632 if (1 != v)
633 goto error;
634
635 v = kstrtos32(temp_buf, 10, &temp_int);
636 if ((v < 0) || (temp_int < 0) ||
637 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
638 return -EINVAL;
639
640 *channel = temp_int;
641 *data = in_ptr;
642 return 0;
643error:
644 *data = in_ptr;
645 return -EINVAL;
646}
647
648/**
649 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
650 * @pValue: Pointer to input data
651 * @pTargetApBssid: Pointer to target Ap bssid
652 * @pChannel: Pointer to the Target AP channel
653 * @pDwellTime: Pointer to the time to stay off-channel
654 * after transmitting action frame
655 * @pBuf: Pointer to data
656 * @pBufLen: Pointer to data length
657 *
658 * This function parses the send action frame data passed in the format
659 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
660 *
661 * Return: 0 for success non-zero for failure
662 */
663static int
664hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
665 uint8_t *pTargetApBssid,
666 uint8_t *pChannel, uint8_t *pDwellTime,
667 uint8_t **pBuf, uint8_t *pBufLen)
668{
669 const uint8_t *inPtr = pValue;
670 const uint8_t *dataEnd;
671 int tempInt;
672 int j = 0;
673 int i = 0;
674 int v = 0;
675 uint8_t tempBuf[32];
676 uint8_t tempByte = 0;
677
678 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
679 return -EINVAL;
680
681 /* point to the next argument */
682 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
683 /* no argument after the command */
684 if (NULL == inPtr)
685 return -EINVAL;
686 /* removing empty spaces */
687 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
688 inPtr++;
689
690 /* no argument followed by spaces */
691 if ('\0' == *inPtr) {
692 return -EINVAL;
693 }
694
695 /* getting the next argument ie the dwell time */
696 v = sscanf(inPtr, "%31s ", tempBuf);
697 if (1 != v)
698 return -EINVAL;
699
700 v = kstrtos32(tempBuf, 10, &tempInt);
701 if (v < 0 || tempInt < 0)
702 return -EINVAL;
703
704 *pDwellTime = tempInt;
705
706 /* point to the next argument */
707 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
708 /* no argument after the command */
709 if (NULL == inPtr)
710 return -EINVAL;
711 /* removing empty spaces */
712 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
713 inPtr++;
714
715 /* no argument followed by spaces */
716 if ('\0' == *inPtr) {
717 return -EINVAL;
718 }
719
720 /* find the length of data */
721 dataEnd = inPtr;
722 while (('\0' != *dataEnd)) {
723 dataEnd++;
724 }
725 *pBufLen = dataEnd - inPtr;
726 if (*pBufLen <= 0)
727 return -EINVAL;
728
729 /*
730 * Allocate the number of bytes based on the number of input characters
731 * whether it is even or odd.
732 * if the number of input characters are even, then we need N/2 byte.
733 * if the number of input characters are odd, then we need do (N+1)/2
734 * to compensate rounding off.
735 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
736 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
737 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530738 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800739 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700740 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800741 return -ENOMEM;
742 }
743
744 /* the buffer received from the upper layer is character buffer,
745 * we need to prepare the buffer taking 2 characters in to a U8 hex
746 * decimal number for example 7f0000f0...form a buffer to contain 7f
747 * in 0th location, 00 in 1st and f0 in 3rd location
748 */
749 for (i = 0, j = 0; j < *pBufLen; j += 2) {
750 if (j + 1 == *pBufLen) {
751 tempByte = hex_to_bin(inPtr[j]);
752 } else {
753 tempByte =
754 (hex_to_bin(inPtr[j]) << 4) |
755 (hex_to_bin(inPtr[j + 1]));
756 }
757 (*pBuf)[i++] = tempByte;
758 }
759 *pBufLen = i;
760 return 0;
761}
762
763/**
764 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
765 * @pValue: Pointer to input data (its a NULL terminated string)
766 * @pTargetApBssid: Pointer to target Ap bssid
767 * @pChannel: Pointer to the Target AP channel
768 *
769 * This function parses the reasoc command data passed in the format
770 * REASSOC<space><bssid><space><channel>
771 *
772 * Return: 0 for success non-zero for failure
773 */
774static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
775 uint8_t *pTargetApBssid,
776 uint8_t *pChannel)
777{
778 const uint8_t *inPtr = pValue;
779
780 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
781 return -EINVAL;
782
783 return 0;
784}
785
Naveen Rawat05376ee2016-07-18 16:43:32 -0700786#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800787void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter,
788 const tSirMacAddr bssid, int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700789{
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800790 QDF_STATUS status;
791 hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
792 tCsrRoamProfile *profile = &wext_state->roamProfile;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700793 struct wma_roam_invoke_cmd *fastreassoc;
Rajeev Kumarea95edd2017-01-11 20:49:36 -0800794 struct scheduler_msg msg = {0};
Naveen Rawat05376ee2016-07-18 16:43:32 -0700795
796 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
797 if (NULL == fastreassoc) {
798 hdd_err("qdf_mem_malloc failed for fastreassoc");
799 return;
800 }
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800801 fastreassoc->vdev_id = adapter->sessionId;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700802 fastreassoc->channel = channel;
803 fastreassoc->bssid[0] = bssid[0];
804 fastreassoc->bssid[1] = bssid[1];
805 fastreassoc->bssid[2] = bssid[2];
806 fastreassoc->bssid[3] = bssid[3];
807 fastreassoc->bssid[4] = bssid[4];
808 fastreassoc->bssid[5] = bssid[5];
809
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800810 status = sme_get_beacon_frm(WLAN_HDD_GET_HAL_CTX(adapter), profile,
811 bssid, &fastreassoc->frame_buf,
812 &fastreassoc->frame_len);
813
814 if (QDF_STATUS_SUCCESS != status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800815 hdd_warn("sme_get_beacon_frm failed");
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800816 fastreassoc->frame_buf = NULL;
817 fastreassoc->frame_len = 0;
818 }
819
Naveen Rawat05376ee2016-07-18 16:43:32 -0700820 msg.type = SIR_HAL_ROAM_INVOKE;
821 msg.reserved = 0;
822 msg.bodyptr = fastreassoc;
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800823 status = scheduler_post_msg(QDF_MODULE_ID_WMA, &msg);
824 if (QDF_STATUS_SUCCESS != status) {
Naveen Rawat05376ee2016-07-18 16:43:32 -0700825 hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA");
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800826 qdf_mem_free(fastreassoc);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700827 }
828}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700829#endif
830
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800831/**
832 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800833 * @adapter: Adapter upon which the command was received
834 * @bssid: BSSID with which to reassociate
835 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700836 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800837 *
838 * This function performs a userspace-directed reassoc operation
839 *
840 * Return: 0 for success non-zero for failure
841 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700842int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800843 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800844{
845 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700846 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847 int ret = 0;
848
Naveen Rawat05376ee2016-07-18 16:43:32 -0700849 if (hdd_ctx == NULL) {
850 hdd_err("Invalid hdd ctx");
851 return -EINVAL;
852 }
853
Krunal Sonibe766b02016-03-10 13:00:44 -0800854 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800855 hdd_warn("Unsupported in mode %s(%d)",
856 hdd_device_mode_to_string(adapter->device_mode),
857 adapter->device_mode);
858 return -EINVAL;
859 }
860
861 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
862
863 /* if not associated, no need to proceed with reassoc */
864 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800865 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 ret = -EINVAL;
867 goto exit;
868 }
869
870 /*
871 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800872 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873 */
874 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530875 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800876 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800877 channel = pHddStaCtx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 }
879
880 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530881 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800883 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800884 ret = -EINVAL;
885 goto exit;
886 }
887
888 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700889 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800890 hdd_wma_send_fastreassoc_cmd(adapter,
Naveen Rawat05376ee2016-07-18 16:43:32 -0700891 bssid, (int)channel);
892 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800893 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800894
895 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700896 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530897 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
899 &handoffInfo);
900 }
901exit:
902 return ret;
903}
904
905/**
906 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
907 * @adapter: Adapter upon which the command was received
908 * @command: ASCII text command that was received
909 *
910 * This function parses the v1 REASSOC command with the format
911 *
912 * REASSOC xx:xx:xx:xx:xx:xx CH
913 *
914 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
915 * BSSID and CH is the ASCII representation of the channel. For
916 * example
917 *
918 * REASSOC 00:0a:0b:11:22:33 48
919 *
920 * Return: 0 for success non-zero for failure
921 */
922static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
923{
924 uint8_t channel = 0;
925 tSirMacAddr bssid;
926 int ret;
927
928 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
929 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700930 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700932 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933 }
934 return ret;
935}
936
937/**
938 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
939 * @adapter: Adapter upon which the command was received
940 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700941 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800942 *
943 * This function parses the v2 REASSOC command with the format
944 *
945 * REASSOC <android_wifi_reassoc_params>
946 *
947 * Return: 0 for success non-zero for failure
948 */
949static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
950{
951 struct android_wifi_reassoc_params params;
952 tSirMacAddr bssid;
953 int ret;
954
955 /* The params are located after "REASSOC " */
956 memcpy(&params, command + 8, sizeof(params));
957
958 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700959 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800960 ret = -EINVAL;
961 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700962 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800963 }
964 return ret;
965}
966
967/**
968 * hdd_parse_reassoc() - parse the REASSOC command
969 * @adapter: Adapter upon which the command was received
970 * @command: Command that was received
971 *
972 * There are two different versions of the REASSOC command. Version 1
973 * of the command contains a parameter list that is ASCII characters
974 * whereas version 2 contains a combination of ASCII and binary
975 * payload. Determine if a version 1 or a version 2 command is being
976 * parsed by examining the parameters, and then dispatch the parser
977 * that is appropriate for the command.
978 *
979 * Return: 0 for success non-zero for failure
980 */
981static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
982{
983 int ret;
984
985 /* both versions start with "REASSOC "
986 * v1 has a bssid and channel # as an ASCII string
987 * REASSOC xx:xx:xx:xx:xx:xx CH
988 * v2 has a C struct
989 * REASSOC <binary c struct>
990 *
991 * The first field in the v2 struct is also the bssid in ASCII.
992 * But in the case of a v2 message the BSSID is NUL-terminated.
993 * Hence we can peek at that offset to see if this is V1 or V2
994 * REASSOC xx:xx:xx:xx:xx:xx*
995 * 1111111111222222
996 * 01234567890123456789012345
997 */
998 if (command[25]) {
999 ret = hdd_parse_reassoc_v1(adapter, command);
1000 } else {
1001 ret = hdd_parse_reassoc_v2(adapter, command);
1002 }
1003
1004 return ret;
1005}
1006
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001007/**
1008 * hdd_sendactionframe() - send a userspace-supplied action frame
1009 * @adapter: Adapter upon which the command was received
1010 * @bssid: BSSID target of the action frame
1011 * @channel: Channel upon which to send the frame
1012 * @dwell_time: Amount of time to dwell when the frame is sent
1013 * @payload_len:Length of the payload
1014 * @payload: Payload of the frame
1015 *
1016 * This function sends a userspace-supplied action frame
1017 *
1018 * Return: 0 for success non-zero for failure
1019 */
1020static int
1021hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1022 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001023 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001024{
1025 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001026 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 uint8_t *frame;
1028 struct ieee80211_hdr_3addr *hdr;
1029 u64 cookie;
1030 hdd_station_ctx_t *pHddStaCtx;
1031 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1033 (tpSirMacVendorSpecificFrameHdr) payload;
1034#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1035 struct cfg80211_mgmt_tx_params params;
1036#endif
1037
Krunal Sonibe766b02016-03-10 13:00:44 -08001038 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 hdd_warn("Unsupported in mode %s(%d)",
1040 hdd_device_mode_to_string(adapter->device_mode),
1041 adapter->device_mode);
1042 return -EINVAL;
1043 }
1044
1045 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1046 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1047
1048 /* if not associated, no need to send action frame */
1049 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001050 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001051 ret = -EINVAL;
1052 goto exit;
1053 }
1054
1055 /*
1056 * if the target bssid is different from currently associated AP,
1057 * then no need to send action frame
1058 */
1059 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301060 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001061 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001062 ret = -EINVAL;
1063 goto exit;
1064 }
1065
1066 chan.center_freq = sme_chn_to_freq(channel);
1067 /* Check if it is specific action frame */
1068 if (pVendorSpecific->category ==
1069 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1070 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301071 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001072 /*
1073 * if the channel number is different from operating
1074 * channel then no need to send action frame
1075 */
1076 if (channel != 0) {
1077 if (channel !=
1078 pHddStaCtx->conn_info.operationChannel) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001079 hdd_warn("channel(%d) is different from operating channel(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001080 channel,
1081 pHddStaCtx->conn_info.
1082 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001083 ret = -EINVAL;
1084 goto exit;
1085 }
1086 /*
1087 * If channel number is specified and same
1088 * as home channel, ensure that action frame
1089 * is sent immediately by cancelling
1090 * roaming scans. Otherwise large dwell times
1091 * may cause long delays in sending action
1092 * frames.
1093 */
1094 sme_abort_roam_scan(hdd_ctx->hHal,
1095 adapter->sessionId);
1096 } else {
1097 /*
1098 * 0 is accepted as current home channel,
1099 * delayed transmission of action frame is ok.
1100 */
1101 chan.center_freq =
1102 sme_chn_to_freq(pHddStaCtx->conn_info.
1103 operationChannel);
1104 }
1105 }
1106 }
1107 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001108 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109 ret = -EINVAL;
1110 goto exit;
1111 }
1112
1113 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301114 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001115 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001116 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 ret = -ENOMEM;
1118 goto exit;
1119 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001120
1121 hdr = (struct ieee80211_hdr_3addr *)frame;
1122 hdr->frame_control =
1123 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301124 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1125 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301126 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301127 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1128 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001129
1130#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1131 params.chan = &chan;
1132 params.offchan = 0;
1133 params.wait = dwell_time;
1134 params.buf = frame;
1135 params.len = frame_len;
1136 params.no_cck = 1;
1137 params.dont_wait_for_ack = 1;
1138 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1139#else
1140 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001141 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001143
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001144 dwell_time, frame, frame_len, 1, 1, &cookie);
1145#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1146
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301147 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148exit:
1149 return ret;
1150}
1151
1152/**
1153 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1154 * SENDACTIONFRAME command
1155 * @adapter: Adapter upon which the command was received
1156 * @command: ASCII text command that was received
1157 *
1158 * This function parses the v1 SENDACTIONFRAME command with the format
1159 *
1160 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1161 *
1162 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1163 * BSSID, CH is the ASCII representation of the channel, DW is the
1164 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1165 * payload. For example
1166 *
1167 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1168 *
1169 * Return: 0 for success non-zero for failure
1170 */
1171static int
1172hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1173{
1174 uint8_t channel = 0;
1175 uint8_t dwell_time = 0;
1176 uint8_t payload_len = 0;
1177 uint8_t *payload = NULL;
1178 tSirMacAddr bssid;
1179 int ret;
1180
1181 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1182 &dwell_time, &payload,
1183 &payload_len);
1184 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001185 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001186 } else {
1187 ret = hdd_sendactionframe(adapter, bssid, channel,
1188 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301189 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190 }
1191
1192 return ret;
1193}
1194
1195/**
1196 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1197 * SENDACTIONFRAME command
1198 * @adapter: Adapter upon which the command was received
1199 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001200 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001201 *
1202 * This function parses the v2 SENDACTIONFRAME command with the format
1203 *
1204 * SENDACTIONFRAME <android_wifi_af_params>
1205 *
1206 * Return: 0 for success non-zero for failure
1207 */
1208static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001209hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1210 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001211{
1212 struct android_wifi_af_params *params;
1213 tSirMacAddr bssid;
1214 int ret;
1215
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001216 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001217 total_len -= 16;
1218 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001219
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001220 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1221 (params->len > total_len)) {
1222 hdd_err("Invalid payload length: %d", params->len);
1223 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001224 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001225
1226 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1227 hdd_err("MAC address parsing failed");
1228 return -EINVAL;
1229 }
1230
1231 if (params->channel < 0 ||
1232 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1233 hdd_err("Invalid channel: %d", params->channel);
1234 return -EINVAL;
1235 }
1236
1237 if (params->dwell_time < 0) {
1238 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1239 return -EINVAL;
1240 }
1241
1242 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1243 params->dwell_time, params->len, params->data);
1244
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001245 return ret;
1246}
1247
1248/**
1249 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1250 * @adapter: Adapter upon which the command was received
1251 * @command: Command that was received
1252 *
1253 * There are two different versions of the SENDACTIONFRAME command.
1254 * Version 1 of the command contains a parameter list that is ASCII
1255 * characters whereas version 2 contains a combination of ASCII and
1256 * binary payload. Determine if a version 1 or a version 2 command is
1257 * being parsed by examining the parameters, and then dispatch the
1258 * parser that is appropriate for the version of the command.
1259 *
1260 * Return: 0 for success non-zero for failure
1261 */
1262static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001263hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1264 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265{
1266 int ret;
1267
1268 /*
1269 * both versions start with "SENDACTIONFRAME "
1270 * v1 has a bssid and other parameters as an ASCII string
1271 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1272 * v2 has a C struct
1273 * SENDACTIONFRAME <binary c struct>
1274 *
1275 * The first field in the v2 struct is also the bssid in ASCII.
1276 * But in the case of a v2 message the BSSID is NUL-terminated.
1277 * Hence we can peek at that offset to see if this is V1 or V2
1278 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1279 * 111111111122222222223333
1280 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001281 * For both the commands, a valid command must have atleast
1282 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001283 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001284 if (total_len < 34) {
1285 hdd_err("Invalid command (total_len=%d)", total_len);
1286 return -EINVAL;
1287 }
1288
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001289 if (command[33]) {
1290 ret = hdd_parse_sendactionframe_v1(adapter, command);
1291 } else {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001292 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001293 }
1294
1295 return ret;
1296}
1297
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001298/**
1299 * hdd_parse_channellist() - HDD Parse channel list
1300 * @pValue: Pointer to input channel list
1301 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001302 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001303 * @pNumChannels: Pointer to number of roam scan channels
1304 *
1305 * This function parses the channel list passed in the format
1306 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1307 * if the Number of channels (N) does not match with the actual number
1308 * of channels passed then take the minimum of N and count of
1309 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1310 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1311 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1312 * removing duplicate channels from the list
1313 *
1314 * Return: 0 for success non-zero for failure
1315 */
1316static int
1317hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1318 uint8_t *pNumChannels)
1319{
1320 const uint8_t *inPtr = pValue;
1321 int tempInt;
1322 int j = 0;
1323 int v = 0;
1324 char buf[32];
1325
1326 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1327 /* no argument after the command */
1328 if (NULL == inPtr) {
1329 return -EINVAL;
1330 }
1331
1332 /* no space after the command */
1333 else if (SPACE_ASCII_VALUE != *inPtr) {
1334 return -EINVAL;
1335 }
1336
1337 /* remove empty spaces */
1338 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1339 inPtr++;
1340
1341 /* no argument followed by spaces */
1342 if ('\0' == *inPtr) {
1343 return -EINVAL;
1344 }
1345
1346 /* get the first argument ie the number of channels */
1347 v = sscanf(inPtr, "%31s ", buf);
1348 if (1 != v)
1349 return -EINVAL;
1350
1351 v = kstrtos32(buf, 10, &tempInt);
1352 if ((v < 0) ||
1353 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1354 return -EINVAL;
1355 }
1356
1357 *pNumChannels = tempInt;
1358
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001359 hdd_debug("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001360
1361 for (j = 0; j < (*pNumChannels); j++) {
1362 /*
1363 * inPtr pointing to the beginning of first space after number
1364 * of channels
1365 */
1366 inPtr = strpbrk(inPtr, " ");
1367 /* no channel list after the number of channels argument */
1368 if (NULL == inPtr) {
1369 if (0 != j) {
1370 *pNumChannels = j;
1371 return 0;
1372 } else {
1373 return -EINVAL;
1374 }
1375 }
1376
1377 /* remove empty space */
1378 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1379 inPtr++;
1380
1381 /*
1382 * no channel list after the number of channels
1383 * argument and spaces
1384 */
1385 if ('\0' == *inPtr) {
1386 if (0 != j) {
1387 *pNumChannels = j;
1388 return 0;
1389 } else {
1390 return -EINVAL;
1391 }
1392 }
1393
1394 v = sscanf(inPtr, "%31s ", buf);
1395 if (1 != v)
1396 return -EINVAL;
1397
1398 v = kstrtos32(buf, 10, &tempInt);
1399 if ((v < 0) ||
1400 (tempInt <= 0) ||
1401 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1402 return -EINVAL;
1403 }
1404 pChannelList[j] = tempInt;
1405
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001406 hdd_debug("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001407 pChannelList[j]);
1408 }
1409
1410 return 0;
1411}
1412
1413/**
1414 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1415 * SETROAMSCANCHANNELS command
1416 * @adapter: Adapter upon which the command was received
1417 * @command: ASCII text command that was received
1418 *
1419 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1420 *
1421 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1422 *
1423 * Where "N" is the ASCII representation of the number of channels and
1424 * C1 thru Cn is the ASCII representation of the channels. For example
1425 *
1426 * SETROAMSCANCHANNELS 4 36 40 44 48
1427 *
1428 * Return: 0 for success non-zero for failure
1429 */
1430static int
1431hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1432 const char *command)
1433{
1434 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1435 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301436 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001437 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1438 int ret;
1439
1440 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1441 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001442 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001443 goto exit;
1444 }
1445
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301446 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001447 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1448 adapter->sessionId, num_chan));
1449
1450 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001451 hdd_err("number of channels (%d) supported exceeded max (%d)",
1452 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 ret = -EINVAL;
1454 goto exit;
1455 }
1456
1457 status =
1458 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1459 adapter->sessionId,
1460 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301461 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001462 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001463 ret = -EINVAL;
1464 goto exit;
1465 }
1466exit:
1467 return ret;
1468}
1469
1470/**
1471 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1472 * SETROAMSCANCHANNELS command
1473 * @adapter: Adapter upon which the command was received
1474 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001475 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001476 *
1477 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1478 *
1479 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1480 *
1481 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1482 * what follows the space is an array of u08 parameters. For example
1483 *
1484 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1485 *
1486 * Return: 0 for success non-zero for failure
1487 */
1488static int
1489hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1490 const char *command)
1491{
1492 const uint8_t *value;
1493 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1494 uint8_t channel;
1495 uint8_t num_chan;
1496 int i;
1497 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301498 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001499 int ret = 0;
1500
1501 /* array of values begins after "SETROAMSCANCHANNELS " */
1502 value = command + 20;
1503
1504 num_chan = *value++;
1505 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001506 hdd_err("number of channels (%d) supported exceeded max (%d)",
1507 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001508 ret = -EINVAL;
1509 goto exit;
1510 }
1511
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301512 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1514 adapter->sessionId, num_chan));
1515
1516 for (i = 0; i < num_chan; i++) {
1517 channel = *value++;
1518 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001519 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001520 i, channel);
1521 ret = -EINVAL;
1522 goto exit;
1523 }
1524 channel_list[i] = channel;
1525 }
1526 status =
1527 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1528 adapter->sessionId,
1529 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301530 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001531 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001532 ret = -EINVAL;
1533 goto exit;
1534 }
1535exit:
1536 return ret;
1537}
1538
1539/**
1540 * hdd_parse_set_roam_scan_channels() - parse the
1541 * SETROAMSCANCHANNELS command
1542 * @adapter: Adapter upon which the command was received
1543 * @command: Command that was received
1544 *
1545 * There are two different versions of the SETROAMSCANCHANNELS command.
1546 * Version 1 of the command contains a parameter list that is ASCII
1547 * characters whereas version 2 contains a binary payload. Determine
1548 * if a version 1 or a version 2 command is being parsed by examining
1549 * the parameters, and then dispatch the parser that is appropriate for
1550 * the command.
1551 *
1552 * Return: 0 for success non-zero for failure
1553 */
1554static int
1555hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1556{
1557 const char *cursor;
1558 char ch;
1559 bool v1;
1560 int ret;
1561
1562 /* start after "SETROAMSCANCHANNELS " */
1563 cursor = command + 20;
1564
1565 /* assume we have a version 1 command until proven otherwise */
1566 v1 = true;
1567
1568 /* v1 params will only contain ASCII digits and space */
1569 while ((ch = *cursor++) && v1) {
1570 if (!(isdigit(ch) || isspace(ch))) {
1571 v1 = false;
1572 }
1573 }
1574 if (v1) {
1575 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1576 } else {
1577 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1578 }
1579
1580 return ret;
1581}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001582
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001583#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001584/**
1585 * hdd_parse_plm_cmd() - HDD Parse Plm command
1586 * @pValue: Pointer to input data
1587 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1588 *
1589 * This function parses the plm command passed in the format
1590 * CCXPLMREQ<space><enable><space><dialog_token><space>
1591 * <meas_token><space><num_of_bursts><space><burst_int><space>
1592 * <measu duration><space><burst_len><space><desired_tx_pwr>
1593 * <space><multcast_addr><space><number_of_channels>
1594 * <space><channel_numbers>
1595 *
1596 * Return: 0 for success non-zero for failure
1597 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001598static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001599{
1600 uint8_t *cmdPtr = NULL;
1601 int count, content = 0, ret = 0;
1602 char buf[32];
1603
1604 /* move to argument list */
1605 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1606 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301607 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608
1609 /* no space after the command */
1610 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301611 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001612
1613 /* remove empty spaces */
1614 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1615 cmdPtr++;
1616
1617 /* START/STOP PLM req */
1618 ret = sscanf(cmdPtr, "%31s ", buf);
1619 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301620 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001621
1622 ret = kstrtos32(buf, 10, &content);
1623 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301624 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625
1626 pPlmRequest->enable = content;
1627 cmdPtr = strpbrk(cmdPtr, " ");
1628
1629 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301630 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001631
1632 /* remove empty spaces */
1633 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1634 cmdPtr++;
1635
1636 /* Dialog token of radio meas req containing meas reqIE */
1637 ret = sscanf(cmdPtr, "%31s ", buf);
1638 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301639 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001640
1641 ret = kstrtos32(buf, 10, &content);
1642 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301643 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001644
1645 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001646 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647 cmdPtr = strpbrk(cmdPtr, " ");
1648
1649 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301650 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001651
1652 /* remove empty spaces */
1653 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1654 cmdPtr++;
1655
1656 /* measurement token of meas req IE */
1657 ret = sscanf(cmdPtr, "%31s ", buf);
1658 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301659 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001660
1661 ret = kstrtos32(buf, 10, &content);
1662 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301663 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001664
1665 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001666 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001667
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001668 hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001669 if (pPlmRequest->enable) {
1670
1671 cmdPtr = strpbrk(cmdPtr, " ");
1672
1673 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301674 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001675
1676 /* remove empty spaces */
1677 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1678 cmdPtr++;
1679
1680 /* total number of bursts after which STA stops sending */
1681 ret = sscanf(cmdPtr, "%31s ", buf);
1682 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301683 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001684
1685 ret = kstrtos32(buf, 10, &content);
1686 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301687 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688
1689 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301690 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691
1692 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001693 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694 cmdPtr = strpbrk(cmdPtr, " ");
1695
1696 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301697 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698
1699 /* remove empty spaces */
1700 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1701 cmdPtr++;
1702
1703 /* burst interval in seconds */
1704 ret = sscanf(cmdPtr, "%31s ", buf);
1705 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301706 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001707
1708 ret = kstrtos32(buf, 10, &content);
1709 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301710 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711
1712 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301713 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001714
1715 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001716 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001717 cmdPtr = strpbrk(cmdPtr, " ");
1718
1719 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301720 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721
1722 /* remove empty spaces */
1723 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1724 cmdPtr++;
1725
1726 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1727 ret = sscanf(cmdPtr, "%31s ", buf);
1728 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301729 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730
1731 ret = kstrtos32(buf, 10, &content);
1732 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301733 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734
1735 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301736 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001737
1738 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001739 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740 cmdPtr = strpbrk(cmdPtr, " ");
1741
1742 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301743 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001744
1745 /* remove empty spaces */
1746 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1747 cmdPtr++;
1748
1749 /* burst length of PLM bursts */
1750 ret = sscanf(cmdPtr, "%31s ", buf);
1751 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301752 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753
1754 ret = kstrtos32(buf, 10, &content);
1755 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301756 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757
1758 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301759 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001760
1761 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001762 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763 cmdPtr = strpbrk(cmdPtr, " ");
1764
1765 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301766 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767
1768 /* remove empty spaces */
1769 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1770 cmdPtr++;
1771
1772 /* desired tx power for transmission of PLM bursts */
1773 ret = sscanf(cmdPtr, "%31s ", buf);
1774 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301775 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001776
1777 ret = kstrtos32(buf, 10, &content);
1778 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301779 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001780
1781 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301782 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783
1784 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001785 hdd_debug("desiredTxPwr %d",
1786 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001787
Anurag Chouhan6d760662016-02-20 16:05:43 +05301788 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789 cmdPtr = strpbrk(cmdPtr, " ");
1790
1791 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301792 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001793
1794 /* remove empty spaces */
1795 while ((SPACE_ASCII_VALUE == *cmdPtr)
1796 && ('\0' != *cmdPtr))
1797 cmdPtr++;
1798
1799 ret = sscanf(cmdPtr, "%31s ", buf);
1800 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301801 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802
1803 ret = kstrtos32(buf, 16, &content);
1804 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301805 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001807 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808 }
1809
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001810 hdd_debug("MC addr " MAC_ADDRESS_STR,
1811 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812
1813 cmdPtr = strpbrk(cmdPtr, " ");
1814
1815 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301816 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817
1818 /* remove empty spaces */
1819 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1820 cmdPtr++;
1821
1822 /* number of channels */
1823 ret = sscanf(cmdPtr, "%31s ", buf);
1824 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301825 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001826
1827 ret = kstrtos32(buf, 10, &content);
1828 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301829 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830
1831 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301832 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001833
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001834 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001836 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001837
1838 /* Channel numbers */
1839 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1840 cmdPtr = strpbrk(cmdPtr, " ");
1841
1842 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301843 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844
1845 /* remove empty spaces */
1846 while ((SPACE_ASCII_VALUE == *cmdPtr)
1847 && ('\0' != *cmdPtr))
1848 cmdPtr++;
1849
1850 ret = sscanf(cmdPtr, "%31s ", buf);
1851 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301852 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001853
1854 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001855 if (ret < 0 || content <= 0 ||
1856 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301857 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858
1859 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001860 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001861 }
1862 }
1863 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301864 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001865}
1866#endif
1867
1868#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1869static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1870{
1871 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1872 int rc;
1873
1874 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301875 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 hdd_ctx->ext_wow_should_suspend = is_success;
1878 complete(&hdd_ctx->ready_to_extwow);
1879}
1880
1881static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1882 tpSirExtWoWParams arg_params)
1883{
1884 tSirExtWoWParams params;
Jeff Johnson17d62672017-03-27 08:00:11 -07001885 QDF_STATUS qdf_ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001886 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1887 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1888 int rc;
1889
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301890 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891
1892 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1893
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301894 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895 &wlan_hdd_ready_to_extwow,
1896 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301897 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001898 hdd_err("sme_configure_ext_wow returned failure %d",
1899 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900 return -EPERM;
1901 }
1902
1903 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1904 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1905 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001906 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001907 return -EPERM;
1908 }
1909
Jeff Johnson17d62672017-03-27 08:00:11 -07001910 if (!hdd_ctx->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001911 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001912 return -EPERM;
1913 }
1914
Jeff Johnson17d62672017-03-27 08:00:11 -07001915 if (hdd_ctx->config->extWowGotoSuspend) {
1916 hdd_info("Received ready to ExtWoW. Going to suspend");
1917
1918 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1919 if (rc < 0) {
1920 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1921 rc);
1922 return rc;
1923 }
1924 rc = wlan_hdd_bus_suspend();
1925 if (rc) {
1926 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1927 rc);
1928 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1929 return rc;
1930 }
1931 }
1932
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933 return 0;
1934}
1935
1936static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1937 int value)
1938{
1939 tSirExtWoWParams params;
1940 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1941 int rc;
1942
1943 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301944 if (rc)
1945 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946
1947 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1948 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001949 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950 return -EINVAL;
1951 }
1952
1953 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1954 hdd_ctx->is_extwow_app_type1_param_set)
1955 params.type = value;
1956 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1957 hdd_ctx->is_extwow_app_type2_param_set)
1958 params.type = value;
1959 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1960 hdd_ctx->is_extwow_app_type1_param_set &&
1961 hdd_ctx->is_extwow_app_type2_param_set)
1962 params.type = value;
1963 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001964 hdd_err("Set app params before enable it value %d",
1965 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001966 return -EINVAL;
1967 }
1968
1969 params.vdev_id = vdev_id;
1970 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1971 (hdd_ctx->config->extWowApp2WakeupPinNumber
1972 << 8);
1973
1974 return hdd_enable_ext_wow(adapter, &params);
1975}
1976
1977static int hdd_set_app_type1_params(tHalHandle hHal,
1978 tpSirAppType1Params arg_params)
1979{
1980 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301981 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001982
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301983 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301985 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1986 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001987 hdd_err("sme_configure_app_type1_params returned failure %d",
1988 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001989 return -EPERM;
1990 }
1991
1992 return 0;
1993}
1994
1995static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
1996 char *arg, int len)
1997{
1998 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1999 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2000 char id[20], password[20];
2001 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002002 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003
2004 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302005 if (rc)
2006 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002007
2008 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002009 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002010 return -EINVAL;
2011 }
2012
2013 memset(&params, 0, sizeof(tSirAppType1Params));
2014 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302015 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002016
2017 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302018 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002019 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302020 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002022 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002023 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024 params.identification_id, params.id_length,
2025 params.password, params.pass_length);
2026
2027 return hdd_set_app_type1_params(hHal, &params);
2028}
2029
2030static int hdd_set_app_type2_params(tHalHandle hHal,
2031 tpSirAppType2Params arg_params)
2032{
2033 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302034 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002035
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302036 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302038 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2039 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002040 hdd_err("sme_configure_app_type2_params returned failure %d",
2041 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042 return -EPERM;
2043 }
2044
2045 return 0;
2046}
2047
2048static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2049 char *arg, int len)
2050{
2051 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2052 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2053 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302054 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 tSirAppType2Params params;
2056 int ret;
2057
2058 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302059 if (ret)
2060 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002061
2062 memset(&params, 0, sizeof(tSirAppType2Params));
2063
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302064 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 -08002065 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2066 (unsigned int *)&params.ip_device_ip,
2067 (unsigned int *)&params.ip_server_ip,
2068 (unsigned int *)&params.tcp_seq,
2069 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302070 (uint16_t *)&params.tcp_src_port,
2071 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002072 (unsigned int *)&params.keepalive_init,
2073 (unsigned int *)&params.keepalive_min,
2074 (unsigned int *)&params.keepalive_max,
2075 (unsigned int *)&params.keepalive_inc,
2076 (unsigned int *)&params.tcp_tx_timeout_val,
2077 (unsigned int *)&params.tcp_rx_timeout_val);
2078
2079 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002080 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081 return -EINVAL;
2082 }
2083
2084 if (6 !=
2085 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2086 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2087 &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002088 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002089 return -EINVAL;
2090 }
2091
2092 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2093 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002094 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002095 return -EINVAL;
2096 }
2097
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302098 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302099 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100
2101 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302102 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002103
2104 params.vdev_id = adapter->sessionId;
2105 params.tcp_src_port = (params.tcp_src_port != 0) ?
2106 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2107 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2108 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2109 params.keepalive_init = (params.keepalive_init != 0) ?
2110 params.keepalive_init : hdd_ctx->config->
2111 extWowApp2KAInitPingInterval;
2112 params.keepalive_min =
2113 (params.keepalive_min != 0) ?
2114 params.keepalive_min :
2115 hdd_ctx->config->extWowApp2KAMinPingInterval;
2116 params.keepalive_max =
2117 (params.keepalive_max != 0) ?
2118 params.keepalive_max :
2119 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2120 params.keepalive_inc =
2121 (params.keepalive_inc != 0) ?
2122 params.keepalive_inc :
2123 hdd_ctx->config->extWowApp2KAIncPingInterval;
2124 params.tcp_tx_timeout_val =
2125 (params.tcp_tx_timeout_val != 0) ?
2126 params.tcp_tx_timeout_val :
2127 hdd_ctx->config->extWowApp2TcpTxTimeout;
2128 params.tcp_rx_timeout_val =
2129 (params.tcp_rx_timeout_val != 0) ?
2130 params.tcp_rx_timeout_val :
2131 hdd_ctx->config->extWowApp2TcpRxTimeout;
2132
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002133 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002134 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002135 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2136 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2137 params.keepalive_init, params.keepalive_min,
2138 params.keepalive_max, params.keepalive_inc,
2139 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2140
2141 return hdd_set_app_type2_params(hHal, &params);
2142}
2143#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2144
2145/**
2146 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2147 * @pValue: Pointer to MAXTXPOWER command
2148 * @pDbm: Pointer to tx power
2149 *
2150 * This function parses the MAXTXPOWER command passed in the format
2151 * MAXTXPOWER<space>X(Tx power in dbm)
2152 *
2153 * For example input commands:
2154 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2155 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2156 *
2157 * Return: 0 for success non-zero for failure
2158 */
2159static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2160{
2161 uint8_t *inPtr = pValue;
2162 int tempInt;
2163 int v = 0;
2164 *pTxPower = 0;
2165
2166 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2167 /* no argument after the command */
2168 if (NULL == inPtr) {
2169 return -EINVAL;
2170 }
2171
2172 /* no space after the command */
2173 else if (SPACE_ASCII_VALUE != *inPtr) {
2174 return -EINVAL;
2175 }
2176
2177 /* remove empty spaces */
2178 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2179 inPtr++;
2180
2181 /* no argument followed by spaces */
2182 if ('\0' == *inPtr) {
2183 return 0;
2184 }
2185
2186 v = kstrtos32(inPtr, 10, &tempInt);
2187
2188 /* Range checking for passed parameter */
2189 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2190 return -EINVAL;
2191 }
2192
2193 *pTxPower = tempInt;
2194
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002195 hdd_debug("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002196
2197 return 0;
2198} /* End of hdd_parse_setmaxtxpower_command */
2199
2200static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2201 char *extra, uint8_t n, uint8_t *len)
2202{
Jeff Johnson68755312017-02-10 11:46:55 -08002203 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002204
2205 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002206 hdd_err("argument passed for GETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002207 ret = -EINVAL;
2208 return ret;
2209 }
2210
2211 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2212 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2213 (int)pCfg->nActiveMaxChnTime);
2214 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002215 }
2216 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002217 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2218 (int)pCfg->nActiveMinChnTime);
2219 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002220 }
2221 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002222 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2223 (int)pCfg->nPassiveMaxChnTime);
2224 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002225 }
2226 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002227 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2228 (int)pCfg->nPassiveMinChnTime);
2229 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002230 }
2231 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002232 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2233 (int)pCfg->nActiveMaxChnTime);
2234 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002235 }
Jeff Johnson68755312017-02-10 11:46:55 -08002236 ret = -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002237
2238 return ret;
2239}
2240
2241static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2242{
2243 tHalHandle hHal;
2244 struct hdd_config *pCfg;
2245 uint8_t *value = command;
2246 tSmeConfigParams smeConfig;
2247 int val = 0, temp = 0;
2248
2249 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2250 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2251 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002252 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002253 return -EINVAL;
2254 }
2255
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302256 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002257 sme_get_config_param(hHal, &smeConfig);
2258
2259 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2260 value = value + 24;
2261 temp = kstrtou32(value, 10, &val);
2262 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2263 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002264 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002265 return -EFAULT;
2266 }
2267 pCfg->nActiveMaxChnTime = val;
2268 smeConfig.csrConfig.nActiveMaxChnTime = val;
2269 sme_update_config(hHal, &smeConfig);
2270 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2271 value = value + 24;
2272 temp = kstrtou32(value, 10, &val);
2273 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2274 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002275 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002276 return -EFAULT;
2277 }
2278 pCfg->nActiveMinChnTime = val;
2279 smeConfig.csrConfig.nActiveMinChnTime = val;
2280 sme_update_config(hHal, &smeConfig);
2281 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2282 value = value + 25;
2283 temp = kstrtou32(value, 10, &val);
2284 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2285 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002286 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002287 return -EFAULT;
2288 }
2289 pCfg->nPassiveMaxChnTime = val;
2290 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2291 sme_update_config(hHal, &smeConfig);
2292 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2293 value = value + 25;
2294 temp = kstrtou32(value, 10, &val);
2295 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2296 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002297 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002298 return -EFAULT;
2299 }
2300 pCfg->nPassiveMinChnTime = val;
2301 smeConfig.csrConfig.nPassiveMinChnTime = val;
2302 sme_update_config(hHal, &smeConfig);
2303 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2304 value = value + 13;
2305 temp = kstrtou32(value, 10, &val);
2306 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2307 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002308 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002309 return -EFAULT;
2310 }
2311 pCfg->nActiveMaxChnTime = val;
2312 smeConfig.csrConfig.nActiveMaxChnTime = val;
2313 sme_update_config(hHal, &smeConfig);
2314 } else {
2315 return -EINVAL;
2316 }
2317
2318 return 0;
2319}
2320
Jeff Johnson253c0c22017-01-23 16:59:38 -08002321struct link_status_priv {
2322 uint8_t link_status;
2323};
2324
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002325static void hdd_get_link_status_cb(uint8_t status, void *context)
2326{
Jeff Johnson253c0c22017-01-23 16:59:38 -08002327 struct hdd_request *request;
2328 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329
Jeff Johnson253c0c22017-01-23 16:59:38 -08002330 request = hdd_request_get(context);
2331 if (!request) {
2332 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002333 return;
2334 }
2335
Jeff Johnson253c0c22017-01-23 16:59:38 -08002336 priv = hdd_request_priv(request);
2337 priv->link_status = status;
2338 hdd_request_complete(request);
2339 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002340}
2341
2342/**
2343 * wlan_hdd_get_link_status() - get link status
2344 * @pAdapter: pointer to the adapter
2345 *
2346 * This function sends a request to query the link status and waits
2347 * on a timer to invoke the callback. if the callback is invoked then
2348 * latest link status shall be returned or otherwise cached value
2349 * will be returned.
2350 *
2351 * Return: On success, link status shall be returned.
2352 * On error or not associated, link status 0 will be returned.
2353 */
2354static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2355{
2356
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002357 hdd_station_ctx_t *pHddStaCtx =
2358 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302359 QDF_STATUS hstatus;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002360 int ret;
2361 void *cookie;
2362 struct hdd_request *request;
2363 struct link_status_priv *priv;
2364 static const struct hdd_request_params params = {
2365 .priv_size = sizeof(*priv),
2366 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2367 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002368
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002369 if (cds_is_driver_recovering()) {
2370 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2371 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002372 return 0;
2373 }
2374
Krunal Sonibe766b02016-03-10 13:00:44 -08002375 if ((QDF_STA_MODE != adapter->device_mode) &&
2376 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002377 hdd_warn("Unsupported in mode %s(%d)",
2378 hdd_device_mode_to_string(adapter->device_mode),
2379 adapter->device_mode);
2380 return 0;
2381 }
2382
2383 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2384 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2385 /* If not associated, then expected link status return
2386 * value is 0
2387 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002388 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002389 return 0;
2390 }
2391
Jeff Johnson253c0c22017-01-23 16:59:38 -08002392 request = hdd_request_alloc(&params);
2393 if (!request) {
2394 hdd_err("Request allocation failure");
2395 return 0;
2396 }
2397 cookie = hdd_request_cookie(request);
2398
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002399 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2400 hdd_get_link_status_cb,
Jeff Johnson253c0c22017-01-23 16:59:38 -08002401 cookie, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302402 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002403 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002404 /* return a cached value */
2405 } else {
2406 /* request is sent -- wait for the response */
Jeff Johnson253c0c22017-01-23 16:59:38 -08002407 ret = hdd_request_wait_for_response(request);
2408 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002409 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002410 /* return a cached value */
2411 } else {
2412 /* update the adapter with the fresh results */
2413 priv = hdd_request_priv(request);
2414 adapter->linkStatus = priv->link_status;
2415 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002416 }
2417
Jeff Johnson253c0c22017-01-23 16:59:38 -08002418 /*
2419 * either we never sent a request, we sent a request and
2420 * received a response or we sent a request and timed out.
2421 * regardless we are done with the request.
2422 */
2423 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002424
2425 /* either callback updated adapter stats or it has cached data */
2426 return adapter->linkStatus;
2427}
2428
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002429static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2430{
2431 int payload_len;
2432 struct sk_buff *skb;
2433 struct nlmsghdr *nlh;
2434 uint8_t *data;
2435
2436 payload_len = ETH_ALEN;
2437
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002438 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002439 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002440 return;
2441 }
2442
2443 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2444 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002445 hdd_err("nlmsg_new() failed for msg size[%d]",
2446 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002447 return;
2448 }
2449
2450 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2451
2452 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002453 hdd_err("nlmsg_put() failed for msg size[%d]",
2454 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002455
2456 kfree_skb(skb);
2457 return;
2458 }
2459
2460 data = nlmsg_data(nlh);
2461 memcpy(data, MacAddr, ETH_ALEN);
2462
2463 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002464 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2465 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002466 }
2467
2468 return;
2469}
2470
2471
2472/**
2473 * hdd_ParseuserParams - return a pointer to the next argument
2474 * @pValue: Input argument string
2475 * @ppArg: Output pointer to the next argument
2476 *
2477 * This function parses argument stream and finds the pointer
2478 * to the next argument
2479 *
2480 * Return: 0 if the next argument found; -EINVAL otherwise
2481 */
2482static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2483{
2484 uint8_t *pVal;
2485
2486 pVal = strnchr(pValue, strlen(pValue), ' ');
2487
2488 if (NULL == pVal) {
2489 /* no argument remains */
2490 return -EINVAL;
2491 } else if (SPACE_ASCII_VALUE != *pVal) {
2492 /* no space after the current argument */
2493 return -EINVAL;
2494 }
2495
2496 pVal++;
2497
2498 /* remove empty spaces */
2499 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2500 pVal++;
2501 }
2502
2503 /* no argument followed by spaces */
2504 if ('\0' == *pVal) {
2505 return -EINVAL;
2506 }
2507
2508 *ppArg = pVal;
2509
2510 return 0;
2511}
2512
2513/**
2514 * hdd_parse_ibsstx_fail_event_params - Parse params
2515 * for SETIBSSTXFAILEVENT
2516 * @pValue: Input ibss tx fail event argument
2517 * @tx_fail_count: (Output parameter) Tx fail counter
2518 * @pid: (Output parameter) PID
2519 *
2520 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2521 */
2522static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2523 uint8_t *tx_fail_count,
2524 uint16_t *pid)
2525{
2526 uint8_t *param = NULL;
2527 int ret;
2528
2529 ret = hdd_parse_user_params(pValue, &param);
2530
2531 if (0 == ret && NULL != param) {
2532 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2533 ret = -EINVAL;
2534 goto done;
2535 }
2536 } else {
2537 goto done;
2538 }
2539
2540 if (0 == *tx_fail_count) {
2541 *pid = 0;
2542 goto done;
2543 }
2544
2545 pValue = param;
2546 pValue++;
2547
2548 ret = hdd_parse_user_params(pValue, &param);
2549
2550 if (0 == ret) {
2551 if (1 != sscanf(param, "%hu", pid)) {
2552 ret = -EINVAL;
2553 goto done;
2554 }
2555 } else {
2556 goto done;
2557 }
2558
2559done:
2560 return ret;
2561}
2562
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002563#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002564/**
2565 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2566 * @pValue: Pointer to data
2567 * @pEseBcnReq: Output pointer to store parsed ie information
2568 *
2569 * This function parses the ese beacon request passed in the format
2570 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2571 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2572 * <space>Scan Mode N<space>Meas Duration N
2573 *
2574 * If the Number of bcn req fields (N) does not match with the
2575 * actual number of fields passed then take N.
2576 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2577 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2578 * This function does not take care of removing duplicate channels from the
2579 * list
2580 *
2581 * Return: 0 for success non-zero for failure
2582 */
2583static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2584 tCsrEseBeaconReq *pEseBcnReq)
2585{
2586 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002587 uint8_t input = 0;
2588 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002589 int j = 0, i = 0, v = 0;
2590 char buf[32];
2591
2592 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2593 /* no argument after the command */
2594 if (NULL == inPtr) {
2595 return -EINVAL;
2596 }
2597 /* no space after the command */
2598 else if (SPACE_ASCII_VALUE != *inPtr) {
2599 return -EINVAL;
2600 }
2601
2602 /* remove empty spaces */
2603 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2604 inPtr++;
2605
2606 /* no argument followed by spaces */
2607 if ('\0' == *inPtr)
2608 return -EINVAL;
2609
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002610 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002611 v = sscanf(inPtr, "%31s ", buf);
2612 if (1 != v)
2613 return -EINVAL;
2614
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002615 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002616 if (v < 0)
2617 return -EINVAL;
2618
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002619 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2620 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002621
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002622 hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002623
2624 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2625 for (i = 0; i < 4; i++) {
2626 /*
2627 * inPtr pointing to the beginning of 1st space
2628 * after number of ie fields
2629 */
2630 inPtr = strpbrk(inPtr, " ");
2631 /* no ie data after the number of ie fields argument */
2632 if (NULL == inPtr)
2633 return -EINVAL;
2634
2635 /* remove empty space */
2636 while ((SPACE_ASCII_VALUE == *inPtr)
2637 && ('\0' != *inPtr))
2638 inPtr++;
2639
2640 /*
2641 * no ie data after the number of ie fields
2642 * argument and spaces
2643 */
2644 if ('\0' == *inPtr)
2645 return -EINVAL;
2646
2647 v = sscanf(inPtr, "%31s ", buf);
2648 if (1 != v)
2649 return -EINVAL;
2650
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002651 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002652 if (v < 0)
2653 return -EINVAL;
2654
2655 switch (i) {
2656 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002657 if (!tempInt) {
2658 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002659 tempInt);
2660 return -EINVAL;
2661 }
2662 pEseBcnReq->bcnReq[j].measurementToken =
2663 tempInt;
2664 break;
2665
2666 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002667 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002668 (tempInt >
2669 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002670 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002671 tempInt);
2672 return -EINVAL;
2673 }
2674 pEseBcnReq->bcnReq[j].channel = tempInt;
2675 break;
2676
2677 case 2: /* Scan mode */
2678 if ((tempInt < eSIR_PASSIVE_SCAN)
2679 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002680 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002681 tempInt);
2682 return -EINVAL;
2683 }
2684 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2685 break;
2686
2687 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002688 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002689 && (pEseBcnReq->bcnReq[j].scanMode !=
2690 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002691 (pEseBcnReq->bcnReq[j].scanMode ==
2692 eSIR_BEACON_TABLE)) {
2693 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002694 tempInt);
2695 return -EINVAL;
2696 }
2697 pEseBcnReq->bcnReq[j].measurementDuration =
2698 tempInt;
2699 break;
2700 }
2701 }
2702 }
2703
2704 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002705 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002706 j,
2707 pEseBcnReq->bcnReq[j].measurementToken,
2708 pEseBcnReq->bcnReq[j].channel,
2709 pEseBcnReq->bcnReq[j].scanMode,
2710 pEseBcnReq->bcnReq[j].measurementDuration);
2711 }
2712
2713 return 0;
2714}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002715
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002716/**
2717 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2718 * @pValue: Pointer to input data
2719 * @pCckmIe: Pointer to output cckm Ie
2720 * @pCckmIeLen: Pointer to output cckm ie length
2721 *
2722 * This function parses the SETCCKM IE command
2723 * SETCCKMIE<space><ie data>
2724 *
2725 * Return: 0 for success non-zero for failure
2726 */
2727static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2728 uint8_t *pCckmIeLen)
2729{
2730 uint8_t *inPtr = pValue;
2731 uint8_t *dataEnd;
2732 int j = 0;
2733 int i = 0;
2734 uint8_t tempByte = 0;
2735 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2736 /* no argument after the command */
2737 if (NULL == inPtr) {
2738 return -EINVAL;
2739 }
2740 /* no space after the command */
2741 else if (SPACE_ASCII_VALUE != *inPtr) {
2742 return -EINVAL;
2743 }
2744 /* remove empty spaces */
2745 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2746 inPtr++;
2747 /* no argument followed by spaces */
2748 if ('\0' == *inPtr) {
2749 return -EINVAL;
2750 }
2751 /* find the length of data */
2752 dataEnd = inPtr;
2753 while (('\0' != *dataEnd)) {
2754 dataEnd++;
2755 ++(*pCckmIeLen);
2756 }
2757 if (*pCckmIeLen <= 0)
2758 return -EINVAL;
2759 /*
2760 * Allocate the number of bytes based on the number of input characters
2761 * whether it is even or odd.
2762 * if the number of input characters are even, then we need N / 2 byte.
2763 * if the number of input characters are odd, then we need do
2764 * (N + 1) / 2 to compensate rounding off.
2765 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2766 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2767 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302768 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002769 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002770 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002771 return -ENOMEM;
2772 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002773 /*
2774 * the buffer received from the upper layer is character buffer,
2775 * we need to prepare the buffer taking 2 characters in to a U8 hex
2776 * decimal number for example 7f0000f0...form a buffer to contain
2777 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2778 */
2779 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2780 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2781 (hex_to_bin(inPtr[j + 1]));
2782 (*pCckmIe)[i++] = tempByte;
2783 }
2784 *pCckmIeLen = i;
2785 return 0;
2786}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002787#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002788
2789int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2790{
2791 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302792 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002793 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2794 struct hdd_config *pConfig = NULL;
2795
2796 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002797 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002798 return -EINVAL;
2799 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002800 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2801 (QDF_SAP_MODE != pAdapter->device_mode) &&
2802 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002803 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2804 hdd_device_mode_to_string(pAdapter->device_mode),
2805 pAdapter->device_mode);
2806 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002807 return -EINVAL;
2808 }
2809 pConfig = pHddCtx->config;
2810 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2811 rateUpdate.dev_mode = pAdapter->device_mode;
2812 rateUpdate.mcastDataRate24GHz = targetRate;
2813 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2814 rateUpdate.mcastDataRate5GHz = targetRate;
2815 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302816 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002817 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002818 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2819 hdd_device_mode_to_string(pAdapter->device_mode),
2820 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002821 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302822 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002823 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002824 return -EFAULT;
2825 }
2826 return 0;
2827}
2828
2829static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2830 hdd_context_t *hdd_ctx,
2831 uint8_t *command,
2832 uint8_t command_len,
2833 hdd_priv_data_t *priv_data)
2834{
2835 int ret = 0;
2836
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302837 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002838 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2839 adapter->sessionId,
2840 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2841 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2842 + 3) << 16 | *(hdd_ctx->
2843 p2pDeviceAddress.bytes + 4) << 8 |
2844 *(hdd_ctx->p2pDeviceAddress.bytes +
2845 5))));
2846
2847 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2848 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002849 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002850 ret = -EFAULT;
2851 }
2852
2853 return ret;
2854}
2855
2856/**
2857 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2858 * @adapter: Adapter on which the command was received
2859 * @hdd_ctx: HDD global context
2860 * @command: Entire driver command received from userspace
2861 * @command_len: Length of @command
2862 * @priv_data: Pointer to ioctl private data structure
2863 *
2864 * This is a trivial command hander function which simply forwards the
2865 * command to the actual command processor within the P2P module.
2866 *
2867 * Return: 0 on success, non-zero on failure
2868 */
2869static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2870 hdd_context_t *hdd_ctx,
2871 uint8_t *command,
2872 uint8_t command_len,
2873 hdd_priv_data_t *priv_data)
2874{
2875 return hdd_set_p2p_noa(adapter->dev, command);
2876}
2877
2878/**
2879 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2880 * @adapter: Adapter on which the command was received
2881 * @hdd_ctx: HDD global context
2882 * @command: Entire driver command received from userspace
2883 * @command_len: Length of @command
2884 * @priv_data: Pointer to ioctl private data structure
2885 *
2886 * This is a trivial command hander function which simply forwards the
2887 * command to the actual command processor within the P2P module.
2888 *
2889 * Return: 0 on success, non-zero on failure
2890 */
2891static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2892 hdd_context_t *hdd_ctx,
2893 uint8_t *command,
2894 uint8_t command_len,
2895 hdd_priv_data_t *priv_data)
2896{
2897 return hdd_set_p2p_opps(adapter->dev, command);
2898}
2899
2900static int drv_cmd_set_band(hdd_adapter_t *adapter,
2901 hdd_context_t *hdd_ctx,
2902 uint8_t *command,
2903 uint8_t command_len,
2904 hdd_priv_data_t *priv_data)
2905{
2906 int ret = 0;
2907
2908 uint8_t *ptr = command;
2909
2910 /* Change band request received */
2911
2912 /*
2913 * First 8 bytes will have "SETBAND " and
2914 * 9 byte will have band setting value
2915 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002916 hdd_debug("SetBandCommand Info comm %s UL %d, TL %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002917 command, priv_data->used_len,
2918 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002919
2920 /* Change band request received */
2921 ret = hdd_set_band_helper(adapter->dev, ptr);
2922
2923 return ret;
2924}
2925
2926static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2927 hdd_context_t *hdd_ctx,
2928 uint8_t *command,
2929 uint8_t command_len,
2930 hdd_priv_data_t *priv_data)
2931{
2932 return hdd_wmmps_helper(adapter, command);
2933}
2934
2935static int drv_cmd_country(hdd_adapter_t *adapter,
2936 hdd_context_t *hdd_ctx,
2937 uint8_t *command,
2938 uint8_t command_len,
2939 hdd_priv_data_t *priv_data)
2940{
2941 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302942 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002943 unsigned long rc;
2944 char *country_code;
2945
2946 country_code = command + 8;
2947
2948 INIT_COMPLETION(adapter->change_country_code);
2949
2950 status = sme_change_country_code(hdd_ctx->hHal,
2951 wlan_hdd_change_country_code_callback,
2952 country_code,
2953 adapter,
2954 hdd_ctx->pcds_context,
2955 eSIR_TRUE,
2956 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302957 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002958 rc = wait_for_completion_timeout(
2959 &adapter->change_country_code,
2960 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
2961 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002962 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002963 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002964 hdd_err("SME Change Country code fail, status %d",
2965 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002966 ret = -EINVAL;
2967 }
2968
2969 return ret;
2970}
2971
2972static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
2973 hdd_context_t *hdd_ctx,
2974 uint8_t *command,
2975 uint8_t command_len,
2976 hdd_priv_data_t *priv_data)
2977{
2978 int ret = 0;
2979 uint8_t *value = command;
2980 int8_t rssi = 0;
2981 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302982 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002983
2984 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2985 value = value + command_len + 1;
2986
2987 /* Convert the value from ascii to integer */
2988 ret = kstrtos8(value, 10, &rssi);
2989 if (ret < 0) {
2990 /*
2991 * If the input value is greater than max value of datatype,
2992 * then also kstrtou8 fails
2993 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002994 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2995 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2996 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002997 ret = -EINVAL;
2998 goto exit;
2999 }
3000
3001 lookUpThreshold = abs(rssi);
3002
3003 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3004 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003005 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003006 lookUpThreshold,
3007 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3008 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3009 ret = -EINVAL;
3010 goto exit;
3011 }
3012
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303013 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3015 adapter->sessionId, lookUpThreshold));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003016 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003017 lookUpThreshold);
3018
3019 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3020 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3021 adapter->sessionId,
3022 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303023 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003024 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003025 ret = -EPERM;
3026 goto exit;
3027 }
3028
3029exit:
3030 return ret;
3031}
3032
3033static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3034 hdd_context_t *hdd_ctx,
3035 uint8_t *command,
3036 uint8_t command_len,
3037 hdd_priv_data_t *priv_data)
3038{
3039 int ret = 0;
3040 uint8_t lookUpThreshold =
3041 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3042 int rssi = (-1) * lookUpThreshold;
3043 char extra[32];
3044 uint8_t len = 0;
3045
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303046 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003047 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3048 adapter->sessionId, lookUpThreshold));
3049
3050 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303051 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003052 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003053 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003054 ret = -EFAULT;
3055 }
3056
3057 return ret;
3058}
3059
3060static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3061 hdd_context_t *hdd_ctx,
3062 uint8_t *command,
3063 uint8_t command_len,
3064 hdd_priv_data_t *priv_data)
3065{
3066 int ret = 0;
3067 uint8_t *value = command;
3068 uint8_t roamScanPeriod = 0;
3069 uint16_t neighborEmptyScanRefreshPeriod =
3070 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3071
3072 /* input refresh period is in terms of seconds */
3073
3074 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3075 value = value + command_len + 1;
3076
3077 /* Convert the value from ascii to integer */
3078 ret = kstrtou8(value, 10, &roamScanPeriod);
3079 if (ret < 0) {
3080 /*
3081 * If the input value is greater than max value of datatype,
3082 * then also kstrtou8 fails
3083 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003084 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3085 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3086 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003087 ret = -EINVAL;
3088 goto exit;
3089 }
3090
3091 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3092 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003093 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3094 roamScanPeriod,
3095 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3096 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003097 ret = -EINVAL;
3098 goto exit;
3099 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303100 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3102 adapter->sessionId, roamScanPeriod));
3103 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3104
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003105 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003106 roamScanPeriod);
3107
3108 hdd_ctx->config->nEmptyScanRefreshPeriod =
3109 neighborEmptyScanRefreshPeriod;
3110 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3111 adapter->sessionId,
3112 neighborEmptyScanRefreshPeriod);
3113
3114exit:
3115 return ret;
3116}
3117
3118static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3119 hdd_context_t *hdd_ctx,
3120 uint8_t *command,
3121 uint8_t command_len,
3122 hdd_priv_data_t *priv_data)
3123{
3124 int ret = 0;
3125 uint16_t nEmptyScanRefreshPeriod =
3126 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3127 char extra[32];
3128 uint8_t len = 0;
3129
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303130 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003131 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3132 adapter->sessionId,
3133 nEmptyScanRefreshPeriod));
3134 len = scnprintf(extra, sizeof(extra), "%s %d",
3135 "GETROAMSCANPERIOD",
3136 (nEmptyScanRefreshPeriod / 1000));
3137 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303138 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003139 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003140 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003141 ret = -EFAULT;
3142 }
3143
3144 return ret;
3145}
3146
3147static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3148 hdd_context_t *hdd_ctx,
3149 uint8_t *command,
3150 uint8_t command_len,
3151 hdd_priv_data_t *priv_data)
3152{
3153 int ret = 0;
3154 uint8_t *value = command;
3155 uint8_t roamScanRefreshPeriod = 0;
3156 uint16_t neighborScanRefreshPeriod =
3157 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3158
3159 /* input refresh period is in terms of seconds */
3160 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3161 value = value + command_len + 1;
3162
3163 /* Convert the value from ascii to integer */
3164 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3165 if (ret < 0) {
3166 /*
3167 * If the input value is greater than max value of datatype,
3168 * then also kstrtou8 fails
3169 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003170 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3171 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3172 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003173 ret = -EINVAL;
3174 goto exit;
3175 }
3176
3177 if ((roamScanRefreshPeriod <
3178 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3179 || (roamScanRefreshPeriod >
3180 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003181 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3182 roamScanRefreshPeriod,
3183 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3184 / 1000),
3185 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3186 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003187 ret = -EINVAL;
3188 goto exit;
3189 }
3190 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3191
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003192 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003193 roamScanRefreshPeriod);
3194
3195 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3196 neighborScanRefreshPeriod;
3197 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3198 adapter->sessionId,
3199 neighborScanRefreshPeriod);
3200
3201exit:
3202 return ret;
3203}
3204
3205static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3206 hdd_context_t *hdd_ctx,
3207 uint8_t *command,
3208 uint8_t command_len,
3209 hdd_priv_data_t *priv_data)
3210{
3211 int ret = 0;
3212 uint16_t value =
3213 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3214 char extra[32];
3215 uint8_t len = 0;
3216
3217 len = scnprintf(extra, sizeof(extra), "%s %d",
3218 "GETROAMSCANREFRESHPERIOD",
3219 (value / 1000));
3220 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303221 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003222 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003223 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003224 ret = -EFAULT;
3225 }
3226
3227 return ret;
3228}
3229
3230static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3231 hdd_context_t *hdd_ctx,
3232 uint8_t *command,
3233 uint8_t command_len,
3234 hdd_priv_data_t *priv_data)
3235{
3236 int ret = 0;
3237 uint8_t *value = command;
3238 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3239
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003240 if (!adapter->fast_roaming_allowed) {
3241 hdd_err("Roaming is always disabled on this interface");
3242 goto exit;
3243 }
3244
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003245 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3246 value = value + SIZE_OF_SETROAMMODE + 1;
3247
3248 /* Convert the value from ascii to integer */
3249 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3250 if (ret < 0) {
3251 /*
3252 * If the input value is greater than max value of datatype,
3253 * then also kstrtou8 fails
3254 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003255 hdd_err("kstrtou8 failed range [%d - %d]",
3256 CFG_LFR_FEATURE_ENABLED_MIN,
3257 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003258 ret = -EINVAL;
3259 goto exit;
3260 }
3261 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3262 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003263 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3264 roamMode,
3265 CFG_LFR_FEATURE_ENABLED_MIN,
3266 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003267 ret = -EINVAL;
3268 goto exit;
3269 }
3270
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003271 hdd_debug("Received Command to Set Roam Mode = %d",
3272 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003273 /*
3274 * Note that
3275 * SETROAMMODE 0 is to enable LFR while
3276 * SETROAMMODE 1 is to disable LFR, but
3277 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3278 * enable/disable. So, we have to invert the value
3279 * to call sme_update_is_fast_roam_ini_feature_enabled.
3280 */
3281 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3282 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3283 else
3284 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3285
3286 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3287 if (roamMode) {
3288 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3289 sme_update_roam_scan_offload_enabled(
3290 (tHalHandle)(hdd_ctx->hHal),
3291 hdd_ctx->config->isRoamOffloadScanEnabled);
3292 sme_update_is_fast_roam_ini_feature_enabled(
3293 hdd_ctx->hHal,
3294 adapter->sessionId,
3295 roamMode);
3296 } else {
3297 sme_update_is_fast_roam_ini_feature_enabled(
3298 hdd_ctx->hHal,
3299 adapter->sessionId,
3300 roamMode);
3301 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3302 sme_update_roam_scan_offload_enabled(
3303 (tHalHandle)(hdd_ctx->hHal),
3304 hdd_ctx->config->isRoamOffloadScanEnabled);
3305 }
3306
3307
3308exit:
3309 return ret;
3310}
3311
3312static int drv_cmd_get_roam_mode(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 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3320 char extra[32];
3321 uint8_t len = 0;
3322
3323 /*
3324 * roamMode value shall be inverted because the sementics is different.
3325 */
3326 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3327 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3328 else
3329 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3330
3331 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303332 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003333 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003334 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003335 ret = -EFAULT;
3336 }
3337
3338 return ret;
3339}
3340
3341static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3342 hdd_context_t *hdd_ctx,
3343 uint8_t *command,
3344 uint8_t command_len,
3345 hdd_priv_data_t *priv_data)
3346{
3347 int ret = 0;
3348 uint8_t *value = command;
3349 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3350
3351 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3352 value = value + command_len + 1;
3353
3354 /* Convert the value from ascii to integer */
3355 ret = kstrtou8(value, 10, &roamRssiDiff);
3356 if (ret < 0) {
3357 /*
3358 * If the input value is greater than max value of datatype,
3359 * then also kstrtou8 fails
3360 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003361 hdd_err("kstrtou8 failed range [%d - %d]",
3362 CFG_ROAM_RSSI_DIFF_MIN,
3363 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364 ret = -EINVAL;
3365 goto exit;
3366 }
3367
3368 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3369 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003370 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3371 roamRssiDiff,
3372 CFG_ROAM_RSSI_DIFF_MIN,
3373 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003374 ret = -EINVAL;
3375 goto exit;
3376 }
3377
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003378 hdd_debug("Received Command to Set roam rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003379 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003380
3381 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3382 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3383 adapter->sessionId,
3384 roamRssiDiff);
3385
3386exit:
3387 return ret;
3388}
3389
3390static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3391 hdd_context_t *hdd_ctx,
3392 uint8_t *command,
3393 uint8_t command_len,
3394 hdd_priv_data_t *priv_data)
3395{
3396 int ret = 0;
3397 uint8_t roamRssiDiff =
3398 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3399 char extra[32];
3400 uint8_t len = 0;
3401
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303402 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3404 adapter->sessionId, roamRssiDiff));
3405
3406 len = scnprintf(extra, sizeof(extra), "%s %d",
3407 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303408 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003409
3410 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003411 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003412 ret = -EFAULT;
3413 }
3414
3415 return ret;
3416}
3417
3418static int drv_cmd_get_band(hdd_adapter_t *adapter,
3419 hdd_context_t *hdd_ctx,
3420 uint8_t *command,
3421 uint8_t command_len,
3422 hdd_priv_data_t *priv_data)
3423{
3424 int ret = 0;
3425 int band = -1;
3426 char extra[32];
3427 uint8_t len = 0;
3428
3429 hdd_get_band_helper(hdd_ctx, &band);
3430
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303431 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003432 TRACE_CODE_HDD_GETBAND_IOCTL,
3433 adapter->sessionId, band));
3434
3435 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303436 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003437
3438 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003439 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003440 ret = -EFAULT;
3441 }
3442
3443 return ret;
3444}
3445
3446static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3447 hdd_context_t *hdd_ctx,
3448 uint8_t *command,
3449 uint8_t command_len,
3450 hdd_priv_data_t *priv_data)
3451{
3452 return hdd_parse_set_roam_scan_channels(adapter, command);
3453}
3454
3455static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3456 hdd_context_t *hdd_ctx,
3457 uint8_t *command,
3458 uint8_t command_len,
3459 hdd_priv_data_t *priv_data)
3460{
3461 int ret = 0;
3462 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3463 uint8_t numChannels = 0;
3464 uint8_t j = 0;
3465 char extra[128] = { 0 };
3466 int len;
3467
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303468 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003469 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3470 ChannelList,
3471 &numChannels,
3472 adapter->sessionId)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003473 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003474 ret = -EFAULT;
3475 goto exit;
3476 }
3477
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303478 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3480 adapter->sessionId, numChannels));
3481 /*
3482 * output channel list is of the format
3483 * [Number of roam scan channels][Channel1][Channel2]...
3484 * copy the number of channels in the 0th index
3485 */
3486 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3487 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303488 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003489 len += scnprintf(extra + len, sizeof(extra) - len,
3490 " %d", ChannelList[j]);
3491
Anurag Chouhan6d760662016-02-20 16:05:43 +05303492 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003493 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003494 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003495 ret = -EFAULT;
3496 goto exit;
3497 }
3498
3499exit:
3500 return ret;
3501}
3502
3503static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3504 hdd_context_t *hdd_ctx,
3505 uint8_t *command,
3506 uint8_t command_len,
3507 hdd_priv_data_t *priv_data)
3508{
3509 int ret = 0;
3510 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3511 char extra[32];
3512 uint8_t len = 0;
3513
3514 /*
3515 * Check if the features OKC/ESE/11R are supported simultaneously,
3516 * then this operation is not permitted (return FAILURE)
3517 */
3518 if (eseMode &&
3519 hdd_is_okc_mode_enabled(hdd_ctx) &&
3520 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003521 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003522 ret = -EPERM;
3523 goto exit;
3524 }
3525
3526 len = scnprintf(extra, sizeof(extra), "%s %d",
3527 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303528 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003529 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003530 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003531 ret = -EFAULT;
3532 goto exit;
3533 }
3534
3535exit:
3536 return ret;
3537}
3538
3539static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3540 hdd_context_t *hdd_ctx,
3541 uint8_t *command,
3542 uint8_t command_len,
3543 hdd_priv_data_t *priv_data)
3544{
3545 int ret = 0;
3546 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3547 char extra[32];
3548 uint8_t len = 0;
3549
3550 /*
3551 * Check if the features OKC/ESE/11R are supported simultaneously,
3552 * then this operation is not permitted (return FAILURE)
3553 */
3554 if (okcMode &&
3555 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3556 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003557 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003558 ret = -EPERM;
3559 goto exit;
3560 }
3561
3562 len = scnprintf(extra, sizeof(extra), "%s %d",
3563 "GETOKCMODE", okcMode);
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)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003567 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003568 ret = -EFAULT;
3569 goto exit;
3570 }
3571
3572exit:
3573 return ret;
3574}
3575
3576static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3577 hdd_context_t *hdd_ctx,
3578 uint8_t *command,
3579 uint8_t command_len,
3580 hdd_priv_data_t *priv_data)
3581{
3582 int ret = 0;
3583 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3584 char extra[32];
3585 uint8_t len = 0;
3586
3587 len = scnprintf(extra, sizeof(extra), "%s %d",
3588 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303589 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590
3591 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003592 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003593 ret = -EFAULT;
3594 }
3595
3596 return ret;
3597}
3598
3599static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3600 hdd_context_t *hdd_ctx,
3601 uint8_t *command,
3602 uint8_t command_len,
3603 hdd_priv_data_t *priv_data)
3604{
3605 int ret = 0;
3606 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3607 char extra[32];
3608 uint8_t len = 0;
3609
3610 len = scnprintf(extra, sizeof(extra), "%s %d",
3611 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303612 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613
3614 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003615 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003616 ret = -EFAULT;
3617 }
3618
3619 return ret;
3620}
3621
3622static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3623 hdd_context_t *hdd_ctx,
3624 uint8_t *command,
3625 uint8_t command_len,
3626 hdd_priv_data_t *priv_data)
3627{
3628 int ret = 0;
3629 uint8_t *value = command;
3630 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3631
3632 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3633 value = value + command_len + 1;
3634
3635 /* Convert the value from ascii to integer */
3636 ret = kstrtou8(value, 10, &minTime);
3637 if (ret < 0) {
3638 /*
3639 * If the input value is greater than max value of datatype,
3640 * then also kstrtou8 fails
3641 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003642 hdd_err("kstrtou8 failed range [%d - %d]",
3643 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3644 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003645 ret = -EINVAL;
3646 goto exit;
3647 }
3648
3649 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3650 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003651 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3652 minTime,
3653 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3654 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003655 ret = -EINVAL;
3656 goto exit;
3657 }
3658
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303659 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003660 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3661 adapter->sessionId, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003662 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003663 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003664
3665 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3666 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3667 minTime,
3668 adapter->sessionId);
3669
3670exit:
3671 return ret;
3672}
3673
3674static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3675 hdd_context_t *hdd_ctx,
3676 uint8_t *command,
3677 uint8_t command_len,
3678 hdd_priv_data_t *priv_data)
3679{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003680 return hdd_parse_sendactionframe(adapter, command,
3681 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003682}
3683
3684static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3685 hdd_context_t *hdd_ctx,
3686 uint8_t *command,
3687 uint8_t command_len,
3688 hdd_priv_data_t *priv_data)
3689{
3690 int ret = 0;
3691 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3692 adapter->sessionId);
3693 char extra[32];
3694 uint8_t len = 0;
3695
3696 /* value is interms of msec */
3697 len = scnprintf(extra, sizeof(extra), "%s %d",
3698 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303699 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003700
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303701 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003702 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3703 adapter->sessionId, val));
3704
3705 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003706 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707 ret = -EFAULT;
3708 }
3709
3710 return ret;
3711}
3712
3713static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3714 hdd_context_t *hdd_ctx,
3715 uint8_t *command,
3716 uint8_t command_len,
3717 hdd_priv_data_t *priv_data)
3718{
3719 int ret = 0;
3720 uint8_t *value = command;
3721 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3722
3723 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3724 value = value + command_len + 1;
3725
3726 /* Convert the value from ascii to integer */
3727 ret = kstrtou16(value, 10, &maxTime);
3728 if (ret < 0) {
3729 /*
3730 * If the input value is greater than max value of datatype,
3731 * then also kstrtou8 fails
3732 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003733 hdd_err("kstrtou16 failed range [%d - %d]",
3734 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3735 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003736 ret = -EINVAL;
3737 goto exit;
3738 }
3739
3740 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3741 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003742 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3743 maxTime,
3744 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3745 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003746 ret = -EINVAL;
3747 goto exit;
3748 }
3749
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003750 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003751 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003752
3753 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3754 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3755 adapter->sessionId,
3756 maxTime);
3757
3758exit:
3759 return ret;
3760}
3761
3762static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3763 hdd_context_t *hdd_ctx,
3764 uint8_t *command,
3765 uint8_t command_len,
3766 hdd_priv_data_t *priv_data)
3767{
3768 int ret = 0;
3769 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3770 adapter->sessionId);
3771 char extra[32];
3772 uint8_t len = 0;
3773
3774 /* value is interms of msec */
3775 len = scnprintf(extra, sizeof(extra), "%s %d",
3776 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303777 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003778
3779 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003780 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003781 ret = -EFAULT;
3782 }
3783
3784 return ret;
3785}
3786
3787static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3788 hdd_context_t *hdd_ctx,
3789 uint8_t *command,
3790 uint8_t command_len,
3791 hdd_priv_data_t *priv_data)
3792{
3793 int ret = 0;
3794 uint8_t *value = command;
3795 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3796
3797 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3798 value = value + command_len + 1;
3799
3800 /* Convert the value from ascii to integer */
3801 ret = kstrtou16(value, 10, &val);
3802 if (ret < 0) {
3803 /*
3804 * If the input value is greater than max value of datatype,
3805 * then also kstrtou8 fails
3806 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003807 hdd_err("kstrtou16 failed range [%d - %d]",
3808 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3809 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003810 ret = -EINVAL;
3811 goto exit;
3812 }
3813
3814 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3815 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003816 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3817 val,
3818 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3819 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003820 ret = -EINVAL;
3821 goto exit;
3822 }
3823
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003824 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003825 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826
3827 hdd_ctx->config->nNeighborScanPeriod = val;
3828 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3829 adapter->sessionId, val);
3830
3831exit:
3832 return ret;
3833}
3834
3835static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3836 hdd_context_t *hdd_ctx,
3837 uint8_t *command,
3838 uint8_t command_len,
3839 hdd_priv_data_t *priv_data)
3840{
3841 int ret = 0;
3842 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3843 adapter->
3844 sessionId);
3845 char extra[32];
3846 uint8_t len = 0;
3847
3848 /* value is interms of msec */
3849 len = scnprintf(extra, sizeof(extra), "%s %d",
3850 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303851 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003852
3853 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003854 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003855 ret = -EFAULT;
3856 }
3857
3858 return ret;
3859}
3860
3861static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3862 hdd_context_t *hdd_ctx,
3863 uint8_t *command,
3864 uint8_t command_len,
3865 hdd_priv_data_t *priv_data)
3866{
3867 int ret = 0;
3868 uint8_t *value = command;
3869 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3870
3871 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3872 value = value + command_len + 1;
3873
3874 /* Convert the value from ascii to integer */
3875 ret = kstrtou8(value, 10, &val);
3876 if (ret < 0) {
3877 /*
3878 * If the input value is greater than max value of datatype,
3879 * then also kstrtou8 fails
3880 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003881 hdd_err("kstrtou8 failed range [%d - %d]",
3882 CFG_ROAM_INTRA_BAND_MIN,
3883 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003884 ret = -EINVAL;
3885 goto exit;
3886 }
3887
3888 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3889 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003890 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3891 val,
3892 CFG_ROAM_INTRA_BAND_MIN,
3893 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003894 ret = -EINVAL;
3895 goto exit;
3896 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003897 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003898 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003899
3900 hdd_ctx->config->nRoamIntraBand = val;
3901 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3902
3903exit:
3904 return ret;
3905}
3906
3907static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3908 hdd_context_t *hdd_ctx,
3909 uint8_t *command,
3910 uint8_t command_len,
3911 hdd_priv_data_t *priv_data)
3912{
3913 int ret = 0;
3914 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3915 char extra[32];
3916 uint8_t len = 0;
3917
3918 /* value is interms of msec */
3919 len = scnprintf(extra, sizeof(extra), "%s %d",
3920 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303921 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003922 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003923 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003924 ret = -EFAULT;
3925 }
3926
3927 return ret;
3928}
3929
3930static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3931 hdd_context_t *hdd_ctx,
3932 uint8_t *command,
3933 uint8_t command_len,
3934 hdd_priv_data_t *priv_data)
3935{
3936 int ret = 0;
3937 uint8_t *value = command;
3938 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3939
3940 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3941 value = value + command_len + 1;
3942
3943 /* Convert the value from ascii to integer */
3944 ret = kstrtou8(value, 10, &nProbes);
3945 if (ret < 0) {
3946 /*
3947 * If the input value is greater than max value of datatype,
3948 * then also kstrtou8 fails
3949 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003950 hdd_err("kstrtou8 failed range [%d - %d]",
3951 CFG_ROAM_SCAN_N_PROBES_MIN,
3952 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003953 ret = -EINVAL;
3954 goto exit;
3955 }
3956
3957 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3958 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003959 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3960 nProbes,
3961 CFG_ROAM_SCAN_N_PROBES_MIN,
3962 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003963 ret = -EINVAL;
3964 goto exit;
3965 }
3966
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003967 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003968 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003969
3970 hdd_ctx->config->nProbes = nProbes;
3971 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3972 adapter->sessionId, nProbes);
3973
3974exit:
3975 return ret;
3976}
3977
3978static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3979 hdd_context_t *hdd_ctx,
3980 uint8_t *command,
3981 uint8_t command_len,
3982 hdd_priv_data_t *priv_data)
3983{
3984 int ret = 0;
3985 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3986 char extra[32];
3987 uint8_t len = 0;
3988
3989 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303990 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003991 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003992 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003993 ret = -EFAULT;
3994 }
3995
3996 return ret;
3997}
3998
3999static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4000 hdd_context_t *hdd_ctx,
4001 uint8_t *command,
4002 uint8_t command_len,
4003 hdd_priv_data_t *priv_data)
4004{
4005 int ret = 0;
4006 uint8_t *value = command;
4007 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4008
4009 /* input value is in units of msec */
4010
4011 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4012 value = value + command_len + 1;
4013
4014 /* Convert the value from ascii to integer */
4015 ret = kstrtou16(value, 10, &homeAwayTime);
4016 if (ret < 0) {
4017 /*
4018 * If the input value is greater than max value of datatype,
4019 * then also kstrtou8 fails
4020 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004021 hdd_err("kstrtou8 failed range [%d - %d]",
4022 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4023 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004024 ret = -EINVAL;
4025 goto exit;
4026 }
4027
4028 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4029 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004030 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004031 homeAwayTime,
4032 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4033 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4034 ret = -EINVAL;
4035 goto exit;
4036 }
4037
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004038 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004039 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004040
4041 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4042 homeAwayTime) {
4043 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4044 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4045 adapter->sessionId,
4046 homeAwayTime,
4047 true);
4048 }
4049
4050exit:
4051 return ret;
4052}
4053
4054static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4055 hdd_context_t *hdd_ctx,
4056 uint8_t *command,
4057 uint8_t command_len,
4058 hdd_priv_data_t *priv_data)
4059{
4060 int ret = 0;
4061 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4062 char extra[32];
4063 uint8_t len = 0;
4064
4065 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304066 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004067
4068 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004069 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004070 ret = -EFAULT;
4071 }
4072
4073 return ret;
4074}
4075
4076static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4077 hdd_context_t *hdd_ctx,
4078 uint8_t *command,
4079 uint8_t command_len,
4080 hdd_priv_data_t *priv_data)
4081{
4082 return hdd_parse_reassoc(adapter, command);
4083}
4084
4085static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4086 hdd_context_t *hdd_ctx,
4087 uint8_t *command,
4088 uint8_t command_len,
4089 hdd_priv_data_t *priv_data)
4090{
4091 int ret = 0;
4092 uint8_t *value = command;
4093 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4094
4095 /* Move pointer to ahead of SETWESMODE<delimiter> */
4096 value = value + command_len + 1;
4097
4098 /* Convert the value from ascii to integer */
4099 ret = kstrtou8(value, 10, &wesMode);
4100 if (ret < 0) {
4101 /*
4102 * If the input value is greater than max value of datatype,
4103 * then also kstrtou8 fails
4104 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004105 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004106 CFG_ENABLE_WES_MODE_NAME_MIN,
4107 CFG_ENABLE_WES_MODE_NAME_MAX);
4108 ret = -EINVAL;
4109 goto exit;
4110 }
4111
4112 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4113 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004114 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115 wesMode,
4116 CFG_ENABLE_WES_MODE_NAME_MIN,
4117 CFG_ENABLE_WES_MODE_NAME_MAX);
4118 ret = -EINVAL;
4119 goto exit;
4120 }
4121
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004122 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004123 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004124
4125 hdd_ctx->config->isWESModeEnabled = wesMode;
4126 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4127
4128exit:
4129 return ret;
4130}
4131
4132static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4133 hdd_context_t *hdd_ctx,
4134 uint8_t *command,
4135 uint8_t command_len,
4136 hdd_priv_data_t *priv_data)
4137{
4138 int ret = 0;
4139 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4140 char extra[32];
4141 uint8_t len = 0;
4142
4143 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304144 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004145 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004146 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004147 ret = -EFAULT;
4148 }
4149
4150 return ret;
4151}
4152
4153static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4154 hdd_context_t *hdd_ctx,
4155 uint8_t *command,
4156 uint8_t command_len,
4157 hdd_priv_data_t *priv_data)
4158{
4159 int ret = 0;
4160 uint8_t *value = command;
4161 uint8_t nOpportunisticThresholdDiff =
4162 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4163
4164 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4165 value = value + command_len + 1;
4166
4167 /* Convert the value from ascii to integer */
4168 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4169 if (ret < 0) {
4170 /*
4171 * If the input value is greater than max value of datatype,
4172 * then also kstrtou8 fails
4173 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004174 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004175 ret = -EINVAL;
4176 goto exit;
4177 }
4178
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004179 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004180 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004181
4182 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4183 adapter->sessionId,
4184 nOpportunisticThresholdDiff);
4185
4186exit:
4187 return ret;
4188}
4189
4190static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4191 hdd_context_t *hdd_ctx,
4192 uint8_t *command,
4193 uint8_t command_len,
4194 hdd_priv_data_t *priv_data)
4195{
4196 int ret = 0;
4197 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4198 hdd_ctx->hHal);
4199 char extra[32];
4200 uint8_t len = 0;
4201
4202 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304203 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004204 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004205 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004206 ret = -EFAULT;
4207 }
4208
4209 return ret;
4210}
4211
4212static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4213 hdd_context_t *hdd_ctx,
4214 uint8_t *command,
4215 uint8_t command_len,
4216 hdd_priv_data_t *priv_data)
4217{
4218 int ret = 0;
4219 uint8_t *value = command;
4220 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4221
4222 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4223 value = value + command_len + 1;
4224
4225 /* Convert the value from ascii to integer */
4226 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4227 if (ret < 0) {
4228 /*
4229 * If the input value is greater than max value of datatype,
4230 * then also kstrtou8 fails
4231 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004232 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004233 ret = -EINVAL;
4234 goto exit;
4235 }
4236
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004237 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004238 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004239
4240 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4241 adapter->sessionId,
4242 nRoamRescanRssiDiff);
4243
4244exit:
4245 return ret;
4246}
4247
4248static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4249 hdd_context_t *hdd_ctx,
4250 uint8_t *command,
4251 uint8_t command_len,
4252 hdd_priv_data_t *priv_data)
4253{
4254 int ret = 0;
4255 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4256 char extra[32];
4257 uint8_t len = 0;
4258
4259 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304260 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004261 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004262 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004263 ret = -EFAULT;
4264 }
4265
4266 return ret;
4267}
4268
4269static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4270 hdd_context_t *hdd_ctx,
4271 uint8_t *command,
4272 uint8_t command_len,
4273 hdd_priv_data_t *priv_data)
4274{
4275 int ret = 0;
4276 uint8_t *value = command;
4277 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4278
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004279 if (!adapter->fast_roaming_allowed) {
4280 hdd_err("Roaming is always disabled on this interface");
4281 goto exit;
4282 }
4283
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004284 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4285 value = value + command_len + 1;
4286
4287 /* Convert the value from ascii to integer */
4288 ret = kstrtou8(value, 10, &lfrMode);
4289 if (ret < 0) {
4290 /*
4291 * If the input value is greater than max value of datatype,
4292 * then also kstrtou8 fails
4293 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004294 hdd_err("kstrtou8 failed range [%d - %d]",
4295 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004296 CFG_LFR_FEATURE_ENABLED_MAX);
4297 ret = -EINVAL;
4298 goto exit;
4299 }
4300
4301 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4302 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004303 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004304 lfrMode,
4305 CFG_LFR_FEATURE_ENABLED_MIN,
4306 CFG_LFR_FEATURE_ENABLED_MAX);
4307 ret = -EINVAL;
4308 goto exit;
4309 }
4310
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004311 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004312 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004313
4314 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4315 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4316 adapter->
4317 sessionId,
4318 lfrMode);
4319
4320exit:
4321 return ret;
4322}
4323
4324static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4325 hdd_context_t *hdd_ctx,
4326 uint8_t *command,
4327 uint8_t command_len,
4328 hdd_priv_data_t *priv_data)
4329{
4330 int ret = 0;
4331 uint8_t *value = command;
4332 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4333
4334 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4335 value = value + command_len + 1;
4336
4337 /* Convert the value from ascii to integer */
4338 ret = kstrtou8(value, 10, &ft);
4339 if (ret < 0) {
4340 /*
4341 * If the input value is greater than max value of datatype,
4342 * then also kstrtou8 fails
4343 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004344 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004345 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4346 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4347 ret = -EINVAL;
4348 goto exit;
4349 }
4350
4351 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4352 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004353 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004354 ft,
4355 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4356 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4357 ret = -EINVAL;
4358 goto exit;
4359 }
4360
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004361 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004362
4363 hdd_ctx->config->isFastTransitionEnabled = ft;
4364 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4365
4366exit:
4367 return ret;
4368}
4369
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4371 hdd_context_t *hdd_ctx,
4372 uint8_t *command,
4373 uint8_t command_len,
4374 hdd_priv_data_t *priv_data)
4375{
4376 int ret = 0;
4377 uint8_t *value = command;
4378 uint8_t channel = 0;
4379 tSirMacAddr targetApBssid;
4380 uint32_t roamId = 0;
4381 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004382 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004383 hdd_station_ctx_t *pHddStaCtx;
4384
Krunal Sonibe766b02016-03-10 13:00:44 -08004385 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386 hdd_warn("Unsupported in mode %s(%d)",
4387 hdd_device_mode_to_string(adapter->device_mode),
4388 adapter->device_mode);
4389 return -EINVAL;
4390 }
4391
4392 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4393
4394 /* if not associated, no need to proceed with reassoc */
4395 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004396 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004397 ret = -EINVAL;
4398 goto exit;
4399 }
4400
4401 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4402 &channel);
4403 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004404 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004405 goto exit;
4406 }
4407
4408 /*
4409 * if the target bssid is same as currently associated AP,
4410 * issue reassoc to same AP
4411 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004412 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004413 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304414 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004415 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304416 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004417 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304418 targetApBssid,
4419 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304420 } else {
4421 sme_get_modify_profile_fields(hdd_ctx->hHal,
4422 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304424 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4425 NULL, modProfileFields, &roamId, 1);
4426 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 return 0;
4428 }
4429
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304430 /* Check channel number is a valid channel number */
4431 if (QDF_STATUS_SUCCESS !=
4432 wlan_hdd_validate_operation_channel(adapter, channel)) {
4433 hdd_err("Invalid Channel [%d]", channel);
4434 return -EINVAL;
4435 }
4436
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004437 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004438 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004439 targetApBssid, (int)channel);
4440 goto exit;
4441 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004442 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443 handoffInfo.channel = channel;
4444 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004445 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004446 sizeof(tSirMacAddr));
4447 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4448 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004449exit:
4450 return ret;
4451}
4452
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004453static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4454 hdd_context_t *hdd_ctx,
4455 uint8_t *command,
4456 uint8_t command_len,
4457 hdd_priv_data_t *priv_data)
4458{
4459 int ret = 0;
4460 uint8_t *value = command;
4461 uint8_t roamScanControl = 0;
4462
4463 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4464 value = value + command_len + 1;
4465
4466 /* Convert the value from ascii to integer */
4467 ret = kstrtou8(value, 10, &roamScanControl);
4468 if (ret < 0) {
4469 /*
4470 * If the input value is greater than max value of datatype,
4471 * then also kstrtou8 fails
4472 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004473 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004474 ret = -EINVAL;
4475 goto exit;
4476 }
4477
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004478 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004479 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004480
4481 if (0 != roamScanControl) {
4482 ret = 0; /* return success but ignore param value "true" */
4483 goto exit;
4484 }
4485
4486 sme_set_roam_scan_control(hdd_ctx->hHal,
4487 adapter->sessionId,
4488 roamScanControl);
4489
4490exit:
4491 return ret;
4492}
4493
4494static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4495 hdd_context_t *hdd_ctx,
4496 uint8_t *command,
4497 uint8_t command_len,
4498 hdd_priv_data_t *priv_data)
4499{
4500 int ret = 0;
4501 uint8_t *value = command;
4502 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4503
4504 /*
4505 * Check if the features OKC/ESE/11R are supported simultaneously,
4506 * then this operation is not permitted (return FAILURE)
4507 */
4508 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4509 hdd_is_okc_mode_enabled(hdd_ctx) &&
4510 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004511 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512 ret = -EPERM;
4513 goto exit;
4514 }
4515
4516 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4517 value = value + command_len + 1;
4518
4519 /* Convert the value from ascii to integer */
4520 ret = kstrtou8(value, 10, &okcMode);
4521 if (ret < 0) {
4522 /*
4523 * If the input value is greater than max value of datatype,
4524 * then also kstrtou8 fails
4525 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004526 hdd_err("kstrtou8 failed range [%d - %d]",
4527 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004528 CFG_OKC_FEATURE_ENABLED_MAX);
4529 ret = -EINVAL;
4530 goto exit;
4531 }
4532
4533 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4534 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004535 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004536 okcMode,
4537 CFG_OKC_FEATURE_ENABLED_MIN,
4538 CFG_OKC_FEATURE_ENABLED_MAX);
4539 ret = -EINVAL;
4540 goto exit;
4541 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004542 hdd_debug("Received Command to change okc mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004543 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004544
4545 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4546
4547exit:
4548 return ret;
4549}
4550
4551static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4552 hdd_context_t *hdd_ctx,
4553 uint8_t *command,
4554 uint8_t command_len,
4555 hdd_priv_data_t *priv_data)
4556{
4557 int ret = 0;
4558 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4559 char extra[32];
4560 uint8_t len = 0;
4561
4562 len = scnprintf(extra, sizeof(extra), "%s %d",
4563 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304564 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004565 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004566 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004567 ret = -EFAULT;
4568 }
4569
4570 return ret;
4571}
4572
4573static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4574 hdd_context_t *hdd_ctx,
4575 uint8_t *command,
4576 uint8_t command_len,
4577 hdd_priv_data_t *priv_data)
4578{
4579 int ret = 0;
4580 char *bcMode;
4581
4582 bcMode = command + 11;
4583 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004584 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004585 hdd_ctx->btCoexModeSet = true;
4586 ret = wlan_hdd_scan_abort(adapter);
4587 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004588 hdd_err("Failed to abort existing scan status: %d",
4589 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004590 }
4591 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004592 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004593 hdd_ctx->btCoexModeSet = false;
4594 }
4595
4596 return ret;
4597}
4598
4599static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4600 hdd_context_t *hdd_ctx,
4601 uint8_t *command,
4602 uint8_t command_len,
4603 hdd_priv_data_t *priv_data)
4604{
4605 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4606 return 0;
4607}
4608
4609static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4610 hdd_context_t *hdd_ctx,
4611 uint8_t *command,
4612 uint8_t command_len,
4613 hdd_priv_data_t *priv_data)
4614{
4615 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4616 return 0;
4617}
4618
4619static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4620 hdd_context_t *hdd_ctx,
4621 uint8_t *command,
4622 uint8_t command_len,
4623 hdd_priv_data_t *priv_data)
4624{
4625 int ret = 0;
4626 struct hdd_config *pCfg =
4627 (WLAN_HDD_GET_CTX(adapter))->config;
4628 char extra[32];
4629 uint8_t len = 0;
4630
4631 memset(extra, 0, sizeof(extra));
4632 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304633 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004635 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004636 ret = -EFAULT;
4637 goto exit;
4638 }
4639 ret = len;
4640exit:
4641 return ret;
4642}
4643
4644static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4645 hdd_context_t *hdd_ctx,
4646 uint8_t *command,
4647 uint8_t command_len,
4648 hdd_priv_data_t *priv_data)
4649{
4650 return hdd_set_dwell_time(adapter, command);
4651}
4652
4653static int drv_cmd_miracast(hdd_adapter_t *adapter,
4654 hdd_context_t *hdd_ctx,
4655 uint8_t *command,
4656 uint8_t command_len,
4657 hdd_priv_data_t *priv_data)
4658{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304659 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004660 int ret = 0;
4661 tHalHandle hHal;
4662 uint8_t filterType = 0;
4663 hdd_context_t *pHddCtx = NULL;
4664 uint8_t *value;
4665
4666 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304667 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004668 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669
4670 hHal = pHddCtx->hHal;
4671 value = command + 9;
4672
4673 /* Convert the value from ascii to integer */
4674 ret = kstrtou8(value, 10, &filterType);
4675 if (ret < 0) {
4676 /*
4677 * If the input value is greater than max value of datatype,
4678 * then also kstrtou8 fails
4679 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004680 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004681 ret = -EINVAL;
4682 goto exit;
4683 }
4684 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4685 || (filterType >
4686 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004687 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004688 ret = -EINVAL;
4689 goto exit;
4690 }
4691 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4692 pHddCtx->miracast_value = filterType;
4693
4694 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304695 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004696 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004697 return -EBUSY;
4698 }
4699
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004700 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4701 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004702
4703exit:
4704 return ret;
4705}
4706
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004707/* Function header is left blank intentionally */
4708static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4709 int32_t *oui_length, int32_t limit)
4710{
4711 uint8_t len;
4712 uint8_t data;
4713
4714 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4715 command++;
4716 limit--;
4717 }
4718
4719 len = 2;
4720
4721 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4722 (limit > 1)) {
4723 sscanf(command, "%02x", (unsigned int *)&data);
4724 ie[len++] = data;
4725 command += 2;
4726 limit -= 2;
4727 }
4728
4729 *oui_length = len - 2;
4730
4731 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4732 command++;
4733 limit--;
4734 }
4735
4736 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4737 (limit > 1)) {
4738 sscanf(command, "%02x", (unsigned int *)&data);
4739 ie[len++] = data;
4740 command += 2;
4741 limit -= 2;
4742 }
4743
4744 ie[0] = IE_EID_VENDOR;
4745 ie[1] = len - 2;
4746
4747 return len;
4748}
4749
4750/**
4751 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4752 * @adapter: Pointer to adapter
4753 * @hdd_ctx: Pointer to HDD context
4754 * @command: Pointer to command string
4755 * @command_len : Command length
4756 * @priv_data : Pointer to priv data
4757 *
4758 * Return:
4759 * int status code
4760 */
4761static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4762 hdd_context_t *hdd_ctx,
4763 uint8_t *command,
4764 uint8_t command_len,
4765 hdd_priv_data_t *priv_data)
4766{
4767 int i = 0;
4768 int status;
4769 int ret = 0;
4770 uint8_t *ibss_ie;
4771 int32_t oui_length = 0;
4772 uint32_t ibss_ie_length;
4773 uint8_t *value = command;
4774 tSirModifyIE ibssModifyIE;
4775 tCsrRoamProfile *pRoamProfile;
4776 hdd_wext_state_t *pWextState;
4777
4778
Krunal Sonibe766b02016-03-10 13:00:44 -08004779 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004780 hdd_debug("Device_mode %s(%d) not IBSS",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004781 hdd_device_mode_to_string(adapter->device_mode),
4782 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004783 return ret;
4784 }
4785
4786 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4787
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004788 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004789
4790
4791 /* validate argument of command */
4792 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004793 hdd_err("No arguments in command length %zu",
4794 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004795 ret = -EFAULT;
4796 goto exit;
4797 }
4798
4799 /* moving to arguments of commands */
4800 value = value + command_len;
4801 command_len = strlen(value);
4802
4803 /* oui_data can't be less than 3 bytes */
4804 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004805 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4806 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004807 ret = -EFAULT;
4808 goto exit;
4809 }
4810
4811 ibss_ie = qdf_mem_malloc(command_len);
4812 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004813 hdd_err("Could not allocate memory for command length %d",
4814 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004815 ret = -ENOMEM;
4816 goto exit;
4817 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004818
4819 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4820 &oui_length,
4821 command_len);
4822 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004823 hdd_err("Could not parse command %s return length %d",
4824 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004825 ret = -EFAULT;
4826 qdf_mem_free(ibss_ie);
4827 goto exit;
4828 }
4829
4830 pRoamProfile = &pWextState->roamProfile;
4831
4832 qdf_copy_macaddr(&ibssModifyIE.bssid,
4833 pRoamProfile->BSSIDs.bssid);
4834
4835 ibssModifyIE.smeSessionId = adapter->sessionId;
4836 ibssModifyIE.notify = true;
4837 ibssModifyIE.ieID = IE_EID_VENDOR;
4838 ibssModifyIE.ieIDLen = ibss_ie_length;
4839 ibssModifyIE.ieBufferlength = ibss_ie_length;
4840 ibssModifyIE.pIEBuffer = ibss_ie;
4841 ibssModifyIE.oui_length = oui_length;
4842
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004843 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4844 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004845 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004846 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004847
4848 /* Probe Bcn modification */
4849 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4850 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4851
4852 /* Populating probe resp frame */
4853 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4854 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4855
4856 qdf_mem_free(ibss_ie);
4857
4858 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4859 adapter->sessionId);
4860 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004861 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004862 status);
4863 ret = -EINVAL;
4864 goto exit;
4865 }
4866
4867exit:
4868 return ret;
4869}
4870
4871static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4872 hdd_context_t *hdd_ctx,
4873 uint8_t *command,
4874 uint8_t command_len,
4875 hdd_priv_data_t *priv_data)
4876{
4877 int ret = 0;
4878 uint8_t *value = command;
4879 uint8_t ucRmcEnable = 0;
4880 int status;
4881
Krunal Sonibe766b02016-03-10 13:00:44 -08004882 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4883 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004884 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4885 hdd_device_mode_to_string(adapter->device_mode),
4886 adapter->device_mode);
4887 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004888 ret = -EINVAL;
4889 goto exit;
4890 }
4891
4892 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4893 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004894 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004895 ret = -EINVAL;
4896 goto exit;
4897 }
4898
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004899 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004900
4901 if (true == ucRmcEnable) {
4902 status = sme_enable_rmc((tHalHandle)
4903 (hdd_ctx->hHal),
4904 adapter->sessionId);
4905 } else if (false == ucRmcEnable) {
4906 status = sme_disable_rmc((tHalHandle)
4907 (hdd_ctx->hHal),
4908 adapter->sessionId);
4909 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004910 hdd_err("Invalid SETRMCENABLE command %d",
4911 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004912 ret = -EINVAL;
4913 goto exit;
4914 }
4915
4916 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004917 hdd_err("SETRMC %d failed status %d",
4918 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004919 ret = -EINVAL;
4920 goto exit;
4921 }
4922
4923exit:
4924 return ret;
4925}
4926
4927static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4928 hdd_context_t *hdd_ctx,
4929 uint8_t *command,
4930 uint8_t command_len,
4931 hdd_priv_data_t *priv_data)
4932{
4933 int ret = 0;
4934 uint8_t *value = command;
4935 uint32_t uActionPeriod = 0;
4936 int status;
4937
Krunal Sonibe766b02016-03-10 13:00:44 -08004938 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4939 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004940 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004941 hdd_device_mode_to_string(adapter->device_mode),
4942 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004943 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004944 ret = -EINVAL;
4945 goto exit;
4946 }
4947
4948 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4949 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004950 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004951 ret = -EINVAL;
4952 goto exit;
4953 }
4954
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004955 hdd_debug("uActionPeriod %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004956 uActionPeriod);
4957
4958 if (sme_cfg_set_int(hdd_ctx->hHal,
4959 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4960 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004961 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4962 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004963 ret = -EINVAL;
4964 goto exit;
4965 }
4966
4967 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4968 adapter->sessionId);
4969 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004970 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004971 status);
4972 ret = -EINVAL;
4973 goto exit;
4974 }
4975
4976exit:
4977 return ret;
4978}
4979
4980static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
4981 hdd_context_t *hdd_ctx,
4982 uint8_t *command,
4983 uint8_t command_len,
4984 hdd_priv_data_t *priv_data)
4985{
4986 int ret = 0;
4987 int status = QDF_STATUS_SUCCESS;
4988 hdd_station_ctx_t *pHddStaCtx = NULL;
4989 char *extra = NULL;
4990 int idx = 0;
4991 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004992 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004993 uint32_t numOfBytestoPrint = 0;
4994
Krunal Sonibe766b02016-03-10 13:00:44 -08004995 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004996 hdd_warn("Unsupported in mode %s(%d)",
4997 hdd_device_mode_to_string(adapter->device_mode),
4998 adapter->device_mode);
4999 return -EINVAL;
5000 }
5001
5002 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005003 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005004
5005 /* Handle the command */
5006 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5007 if (QDF_STATUS_SUCCESS == status) {
5008 /*
5009 * The variable extra needed to be allocated on the heap since
5010 * amount of memory required to copy the data for 32 devices
5011 * exceeds the size of 1024 bytes of default stack size. On
5012 * 64 bit devices, the default max stack size of 2048 bytes
5013 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005014 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005015
5016 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005017 hdd_err("memory allocation failed");
5018 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005019 goto exit;
5020 }
5021
5022 /* Copy number of stations */
5023 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005024 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005025 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005026 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5027 idx++) {
5028 int8_t rssi;
5029 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005030
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005031 qdf_mem_copy(mac_addr,
5032 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5033 mac_addr, sizeof(mac_addr));
5034
5035 tx_rate =
5036 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5037 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305038 /*
5039 * Only lower 3 bytes are rate info. Mask of the MSByte
5040 */
5041 tx_rate &= 0x00FFFFFF;
5042
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005043 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5044 rssi;
5045
5046 length += scnprintf((extra + length),
5047 WLAN_MAX_BUF_SIZE - length,
5048 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5049 mac_addr[0], mac_addr[1], mac_addr[2],
5050 mac_addr[3], mac_addr[4], mac_addr[5],
5051 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005052 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005053 * cdf_trace_msg has limitation of 512 bytes for the
5054 * print buffer. Hence printing the data in two chunks.
5055 * The first chunk will have the data for 16 devices
5056 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005057 */
5058 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5059 numOfBytestoPrint = length;
5060 }
5061
5062 /*
5063 * Copy the data back into buffer, if the data to copy is
5064 * more than 512 bytes than we will split the data and do
5065 * it in two shots
5066 */
5067 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005068 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005069 ret = -EFAULT;
5070 goto exit;
5071 }
5072
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005073 /* This overwrites the last space, which we already copied */
5074 extra[numOfBytestoPrint - 1] = '\0';
5075 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005076
5077 if (length > numOfBytestoPrint) {
5078 if (copy_to_user
5079 (priv_data->buf + numOfBytestoPrint,
5080 extra + numOfBytestoPrint,
5081 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005082 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005083 ret = -EFAULT;
5084 goto exit;
5085 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005086 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005087 }
5088
5089 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005090 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005091 } else {
5092 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005093 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5094 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005095 ret = -EINVAL;
5096 goto exit;
5097 }
5098 ret = 0;
5099
5100exit:
5101 return ret;
5102}
5103
5104/* Peer Info <Peer Addr> command */
5105static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5106 hdd_context_t *hdd_ctx,
5107 uint8_t *command,
5108 uint8_t command_len,
5109 hdd_priv_data_t *priv_data)
5110{
5111 int ret = 0;
5112 uint8_t *value = command;
5113 QDF_STATUS status;
5114 hdd_station_ctx_t *pHddStaCtx = NULL;
5115 char extra[128] = { 0 };
5116 uint32_t length = 0;
5117 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005118 struct qdf_mac_addr peerMacAddr;
5119
Krunal Sonibe766b02016-03-10 13:00:44 -08005120 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005121 hdd_warn("Unsupported in mode %s(%d)",
5122 hdd_device_mode_to_string(adapter->device_mode),
5123 adapter->device_mode);
5124 return -EINVAL;
5125 }
5126
5127 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5128
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005129 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005130
5131 /* if there are no peers, no need to continue with the command */
5132 if (eConnectionState_IbssConnected !=
5133 pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005134 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005135 ret = -EINVAL;
5136 goto exit;
5137 }
5138
5139 /* Parse the incoming command buffer */
5140 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5141 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005142 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005143 ret = -EINVAL;
5144 goto exit;
5145 }
5146
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005147 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005148 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005149
Naveen Rawatc45d1622016-07-05 12:20:09 -07005150 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005151 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005152 ret = -EINVAL;
5153 goto exit;
5154 }
5155
5156 /* Handle the command */
5157 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5158 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005159 uint32_t txRate =
5160 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305161 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5162 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005163
5164 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005165 (int)txRate,
5166 (int)pHddStaCtx->ibss_peer_info.
5167 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005168
5169 /* Copy the data back into buffer */
5170 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005171 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005172 ret = -EFAULT;
5173 goto exit;
5174 }
5175 } else {
5176 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005177 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5178 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005179 ret = -EINVAL;
5180 goto exit;
5181 }
5182
5183 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005184 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005185 ret = 0;
5186
5187exit:
5188 return ret;
5189}
5190
5191static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5192 hdd_context_t *hdd_ctx,
5193 uint8_t *command,
5194 uint8_t command_len,
5195 hdd_priv_data_t *priv_data)
5196{
5197 int ret = 0;
5198 uint8_t *value = command;
5199 uint32_t uRate = 0;
5200 tTxrateinfoflags txFlags = 0;
5201 tSirRateUpdateInd rateUpdateParams = {0};
5202 int status;
5203 struct hdd_config *pConfig = hdd_ctx->config;
5204
Krunal Sonibe766b02016-03-10 13:00:44 -08005205 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5206 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005207 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5208 hdd_device_mode_to_string(adapter->device_mode),
5209 adapter->device_mode);
5210 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005211 ret = -EINVAL;
5212 goto exit;
5213 }
5214
5215 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5216 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005217 hdd_err("Invalid SETRMCTXRATE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005218 ret = -EINVAL;
5219 goto exit;
5220 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005221 hdd_debug("uRate %d", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005222 /* -1 implies ignore this param */
5223 rateUpdateParams.ucastDataRate = -1;
5224
5225 /*
5226 * Fill the user specifieed RMC rate param
5227 * and the derived tx flags.
5228 */
5229 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5230 rateUpdateParams.reliableMcastDataRate = uRate;
5231 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5232 rateUpdateParams.dev_mode = adapter->device_mode;
5233 rateUpdateParams.bcastDataRate = -1;
5234 memcpy(rateUpdateParams.bssid.bytes,
5235 adapter->macAddressCurrent.bytes,
5236 sizeof(rateUpdateParams.bssid));
5237 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5238 &rateUpdateParams);
5239
5240exit:
5241 return ret;
5242}
5243
5244static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5245 hdd_context_t *hdd_ctx,
5246 uint8_t *command,
5247 uint8_t command_len,
5248 hdd_priv_data_t *priv_data)
5249{
5250 int ret = 0;
5251 char *value;
5252 uint8_t tx_fail_count = 0;
5253 uint16_t pid = 0;
5254
5255 value = command;
5256
5257 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5258
5259 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005260 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005261 goto exit;
5262 }
5263
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005264 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005265
5266 if (0 == tx_fail_count) {
5267 /* Disable TX Fail Indication */
5268 if (QDF_STATUS_SUCCESS ==
5269 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5270 tx_fail_count,
5271 NULL)) {
5272 cesium_pid = 0;
5273 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005274 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005275 ret = -EINVAL;
5276 }
5277 } else {
5278 if (QDF_STATUS_SUCCESS ==
5279 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5280 tx_fail_count,
5281 (void *)hdd_tx_fail_ind_callback)) {
5282 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005283 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005284 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005285 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005286 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005287 ret = -EINVAL;
5288 }
5289 }
5290
5291exit:
5292 return ret;
5293}
5294
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005295#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005296static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5297 hdd_context_t *hdd_ctx,
5298 uint8_t *command,
5299 uint8_t command_len,
5300 hdd_priv_data_t *priv_data)
5301{
5302 int ret = 0;
5303 uint8_t *value = command;
5304 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5305 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305306 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005307
5308 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5309 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005310 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005311 goto exit;
5312 }
5313 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005314 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005315 numChannels,
5316 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5317 ret = -EINVAL;
5318 goto exit;
5319 }
5320 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5321 adapter->sessionId,
5322 ChannelList,
5323 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305324 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005325 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005326 ret = -EINVAL;
5327 goto exit;
5328 }
5329
5330exit:
5331 return ret;
5332}
5333
5334static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5335 hdd_context_t *hdd_ctx,
5336 uint8_t *command,
5337 uint8_t command_len,
5338 hdd_priv_data_t *priv_data)
5339{
5340 int ret = 0;
5341 uint8_t *value = command;
5342 char extra[128] = { 0 };
5343 int len = 0;
5344 uint8_t tid = 0;
5345 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005346 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005347
Krunal Sonibe766b02016-03-10 13:00:44 -08005348 if ((QDF_STA_MODE != adapter->device_mode) &&
5349 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005350 hdd_warn("Unsupported in mode %s(%d)",
5351 hdd_device_mode_to_string(adapter->device_mode),
5352 adapter->device_mode);
5353 return -EINVAL;
5354 }
5355
5356 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5357
5358 /* if not associated, return error */
5359 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005360 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005361 ret = -EINVAL;
5362 goto exit;
5363 }
5364
5365 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5366 value = value + command_len + 1;
5367
5368 /* Convert the value from ascii to integer */
5369 ret = kstrtou8(value, 10, &tid);
5370 if (ret < 0) {
5371 /*
5372 * If the input value is greater than max value of datatype,
5373 * then also kstrtou8 fails
5374 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005375 hdd_err("kstrtou8 failed range [%d - %d]",
5376 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005377 TID_MAX_VALUE);
5378 ret = -EINVAL;
5379 goto exit;
5380 }
5381 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005382 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005383 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5384 ret = -EINVAL;
5385 goto exit;
5386 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005387 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005388 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005389 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5390 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005391 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005392 goto exit;
5393 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005394 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005395 "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005396 tsm_metrics.UplinkPktQueueDly,
5397 tsm_metrics.UplinkPktQueueDlyHist[0],
5398 tsm_metrics.UplinkPktQueueDlyHist[1],
5399 tsm_metrics.UplinkPktQueueDlyHist[2],
5400 tsm_metrics.UplinkPktQueueDlyHist[3],
5401 tsm_metrics.UplinkPktTxDly,
5402 tsm_metrics.UplinkPktLoss,
5403 tsm_metrics.UplinkPktCount,
5404 tsm_metrics.RoamingCount,
5405 tsm_metrics.RoamingDly);
5406 /*
5407 * Output TSM stats is of the format
5408 * GETTSMSTATS [PktQueueDly]
5409 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5410 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5411 */
5412 len = scnprintf(extra,
5413 sizeof(extra),
5414 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5415 command,
5416 tsm_metrics.UplinkPktQueueDly,
5417 tsm_metrics.UplinkPktQueueDlyHist[0],
5418 tsm_metrics.UplinkPktQueueDlyHist[1],
5419 tsm_metrics.UplinkPktQueueDlyHist[2],
5420 tsm_metrics.UplinkPktQueueDlyHist[3],
5421 tsm_metrics.UplinkPktTxDly,
5422 tsm_metrics.UplinkPktLoss,
5423 tsm_metrics.UplinkPktCount,
5424 tsm_metrics.RoamingCount,
5425 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305426 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005427 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005428 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005429 ret = -EFAULT;
5430 goto exit;
5431 }
5432
5433exit:
5434 return ret;
5435}
5436
5437static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5438 hdd_context_t *hdd_ctx,
5439 uint8_t *command,
5440 uint8_t command_len,
5441 hdd_priv_data_t *priv_data)
5442{
5443 int ret;
5444 uint8_t *value = command;
5445 uint8_t *cckmIe = NULL;
5446 uint8_t cckmIeLen = 0;
5447
5448 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5449 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005450 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005451 goto exit;
5452 }
5453
5454 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005455 hdd_err("CCKM Ie input length is more than max[%d]",
5456 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005457 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305458 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005459 cckmIe = NULL;
5460 }
5461 ret = -EINVAL;
5462 goto exit;
5463 }
5464
5465 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5466 cckmIe, cckmIeLen);
5467 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305468 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005469 cckmIe = NULL;
5470 }
5471
5472exit:
5473 return ret;
5474}
5475
5476static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5477 hdd_context_t *hdd_ctx,
5478 uint8_t *command,
5479 uint8_t command_len,
5480 hdd_priv_data_t *priv_data)
5481{
5482 int ret;
5483 uint8_t *value = command;
5484 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305485 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005486
Krunal Sonibe766b02016-03-10 13:00:44 -08005487 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005488 hdd_warn("Unsupported in mode %s(%d)",
5489 hdd_device_mode_to_string(adapter->device_mode),
5490 adapter->device_mode);
5491 return -EINVAL;
5492 }
5493
5494 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5495 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005496 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005497 goto exit;
5498 }
5499
5500 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005501 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005502 hdd_indicate_ese_bcn_report_no_results(adapter,
5503 eseBcnReq.bcnReq[0].measurementToken,
5504 0x02, /* BIT(1) set for measurement done */
5505 0); /* no BSS */
5506 goto exit;
5507 }
5508
5509 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5510 adapter->sessionId,
5511 &eseBcnReq);
5512
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305513 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005514 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005515 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005516 ret = -EBUSY;
5517 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305518 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005519 hdd_err("sme_set_ese_beacon_request failed (%d)",
5520 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005521 ret = -EINVAL;
5522 goto exit;
5523 }
5524
5525exit:
5526 return ret;
5527}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005528
5529/**
5530 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5531 * @adapter: Pointer to the HDD adapter
5532 * @hdd_ctx: Pointer to the HDD context
5533 * @command: Driver command string
5534 * @command_len: Driver command string length
5535 * @priv_data: Private data coming with the driver command. Unused here
5536 *
5537 * This function handles driver command that sets the ESE PLM request
5538 *
5539 * Return: 0 on success; negative errno otherwise
5540 */
5541static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5542 hdd_context_t *hdd_ctx,
5543 uint8_t *command,
5544 uint8_t command_len,
5545 hdd_priv_data_t *priv_data)
5546{
5547 int ret = 0;
5548 uint8_t *value = command;
5549 QDF_STATUS status = QDF_STATUS_SUCCESS;
5550 tpSirPlmReq pPlmRequest = NULL;
5551
5552 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5553 if (NULL == pPlmRequest) {
5554 ret = -ENOMEM;
5555 goto exit;
5556 }
5557
5558 status = hdd_parse_plm_cmd(value, pPlmRequest);
5559 if (QDF_STATUS_SUCCESS != status) {
5560 qdf_mem_free(pPlmRequest);
5561 pPlmRequest = NULL;
5562 ret = -EINVAL;
5563 goto exit;
5564 }
5565 pPlmRequest->sessionId = adapter->sessionId;
5566
5567 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5568 if (QDF_STATUS_SUCCESS != status) {
5569 qdf_mem_free(pPlmRequest);
5570 pPlmRequest = NULL;
5571 ret = -EINVAL;
5572 goto exit;
5573 }
5574
5575exit:
5576 return ret;
5577}
5578
5579/**
5580 * drv_cmd_set_ccx_mode() - Set ESE mode
5581 * @adapter: Pointer to the HDD adapter
5582 * @hdd_ctx: Pointer to the HDD context
5583 * @command: Driver command string
5584 * @command_len: Driver command string length
5585 * @priv_data: Private data coming with the driver command. Unused here
5586 *
5587 * This function handles driver command that sets ESE mode
5588 *
5589 * Return: 0 on success; negative errno otherwise
5590 */
5591static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5592 hdd_context_t *hdd_ctx,
5593 uint8_t *command,
5594 uint8_t command_len,
5595 hdd_priv_data_t *priv_data)
5596{
5597 int ret = 0;
5598 uint8_t *value = command;
5599 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5600
5601 /*
5602 * Check if the features OKC/ESE/11R are supported simultaneously,
5603 * then this operation is not permitted (return FAILURE)
5604 */
5605 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5606 hdd_is_okc_mode_enabled(hdd_ctx) &&
5607 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5608 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5609 ret = -EPERM;
5610 goto exit;
5611 }
5612
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005613 if (!adapter->fast_roaming_allowed) {
5614 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5615 ret = -EPERM;
5616 goto exit;
5617 }
5618
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005619 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5620 value = value + command_len + 1;
5621
5622 /* Convert the value from ascii to integer */
5623 ret = kstrtou8(value, 10, &eseMode);
5624 if (ret < 0) {
5625 /*
5626 * If the input value is greater than max value of datatype,
5627 * then also kstrtou8 fails
5628 */
5629 hdd_err("kstrtou8 failed range [%d - %d]",
5630 CFG_ESE_FEATURE_ENABLED_MIN,
5631 CFG_ESE_FEATURE_ENABLED_MAX);
5632 ret = -EINVAL;
5633 goto exit;
5634 }
5635
5636 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5637 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5638 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5639 eseMode,
5640 CFG_ESE_FEATURE_ENABLED_MIN,
5641 CFG_ESE_FEATURE_ENABLED_MAX);
5642 ret = -EINVAL;
5643 goto exit;
5644 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005645 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005646
5647 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5648 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5649 adapter->sessionId,
5650 eseMode);
5651
5652exit:
5653 return ret;
5654}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005655#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005656
5657static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5658 hdd_context_t *hdd_ctx,
5659 uint8_t *command,
5660 uint8_t command_len,
5661 hdd_priv_data_t *priv_data)
5662{
5663 int ret = 0;
5664 uint8_t *value = command;
5665 int targetRate;
5666
5667 /* input value is in units of hundred kbps */
5668
5669 /* Move pointer to ahead of SETMCRATE<delimiter> */
5670 value = value + command_len + 1;
5671
5672 /* Convert the value from ascii to integer, decimal base */
5673 ret = kstrtouint(value, 10, &targetRate);
5674
5675 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5676 return ret;
5677}
5678
5679static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5680 hdd_context_t *hdd_ctx,
5681 uint8_t *command,
5682 uint8_t command_len,
5683 hdd_priv_data_t *priv_data)
5684{
5685 int ret = 0;
5686 int status;
5687 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305688 QDF_STATUS qdf_status;
5689 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005690 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305691 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5692 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005693 hdd_adapter_list_node_t *pAdapterNode = NULL;
5694 hdd_adapter_list_node_t *pNext = NULL;
5695
5696 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5697 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005698 hdd_err("Invalid MAXTXPOWER command");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005699 ret = -EINVAL;
5700 goto exit;
5701 }
5702
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305703 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005704 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305705 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005706 adapter = pAdapterNode->pAdapter;
5707 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305708 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005709 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305710 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005711 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005712
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005713 hdd_debug("Device mode %d max tx power %d selfMac: "
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005714 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005715 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005716 MAC_ADDR_ARRAY(selfMac.bytes),
5717 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005718
Srinivas Girigowda97215232015-09-24 12:26:28 -07005719 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5720 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305721 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005722 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005723 ret = -EINVAL;
5724 goto exit;
5725 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005726 hdd_debug("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305727 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005728 &pNext);
5729 pAdapterNode = pNext;
5730 }
5731
5732exit:
5733 return ret;
5734}
5735
5736static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5737 hdd_context_t *hdd_ctx,
5738 uint8_t *command,
5739 uint8_t command_len,
5740 hdd_priv_data_t *priv_data)
5741{
5742 int ret = 0;
5743 uint8_t *value = command;
5744 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5745
5746 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5747 value = value + command_len + 1;
5748
5749 /* Convert the value from ascii to integer */
5750 ret = kstrtou8(value, 10, &dfsScanMode);
5751 if (ret < 0) {
5752 /*
5753 * If the input value is greater than max value of datatype,
5754 * then also kstrtou8 fails
5755 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005756 hdd_err("kstrtou8 failed range [%d - %d]",
5757 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005758 CFG_ROAMING_DFS_CHANNEL_MAX);
5759 ret = -EINVAL;
5760 goto exit;
5761 }
5762
5763 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5764 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005765 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005766 dfsScanMode,
5767 CFG_ROAMING_DFS_CHANNEL_MIN,
5768 CFG_ROAMING_DFS_CHANNEL_MAX);
5769 ret = -EINVAL;
5770 goto exit;
5771 }
5772
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005773 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005774 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005775
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005776 /* When DFS scanning is disabled, the DFS channels need to be
5777 * removed from the operation of device.
5778 */
5779 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5780 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5781 if (ret < 0) {
5782 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005783 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005784 goto exit;
5785 }
5786
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005787 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5788 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5789 dfsScanMode);
5790
5791exit:
5792 return ret;
5793}
5794
5795static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5796 hdd_context_t *hdd_ctx,
5797 uint8_t *command,
5798 uint8_t command_len,
5799 hdd_priv_data_t *priv_data)
5800{
5801 int ret = 0;
5802 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5803 char extra[32];
5804 uint8_t len = 0;
5805
5806 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305807 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005808 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005809 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005810 ret = -EFAULT;
5811 }
5812
5813 return ret;
5814}
5815
5816static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5817 hdd_context_t *hdd_ctx,
5818 uint8_t *command,
5819 uint8_t command_len,
5820 hdd_priv_data_t *priv_data)
5821{
5822 int ret = 0;
5823 int value = wlan_hdd_get_link_status(adapter);
5824 char extra[32];
5825 uint8_t len;
5826
5827 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305828 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005829 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005830 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005831 ret = -EFAULT;
5832 }
5833
5834 return ret;
5835}
5836
5837#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5838static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5839 hdd_context_t *hdd_ctx,
5840 uint8_t *command,
5841 uint8_t command_len,
5842 hdd_priv_data_t *priv_data)
5843{
5844 uint8_t *value = command;
5845 int set_value;
5846
5847 /* Move pointer to ahead of ENABLEEXTWOW */
5848 value = value + command_len;
5849
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305850 if (!(sscanf(value, "%d", &set_value))) {
5851 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5852 ("No input identified"));
5853 return -EINVAL;
5854 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005855
5856 return hdd_enable_ext_wow_parser(adapter,
5857 adapter->sessionId,
5858 set_value);
5859}
5860
5861static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5862 hdd_context_t *hdd_ctx,
5863 uint8_t *command,
5864 uint8_t command_len,
5865 hdd_priv_data_t *priv_data)
5866{
5867 int ret;
5868 uint8_t *value = command;
5869
5870 /* Move pointer to ahead of SETAPP1PARAMS */
5871 value = value + command_len;
5872
5873 ret = hdd_set_app_type1_parser(adapter,
5874 value, strlen(value));
5875 if (ret >= 0)
5876 hdd_ctx->is_extwow_app_type1_param_set = true;
5877
5878 return ret;
5879}
5880
5881static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5882 hdd_context_t *hdd_ctx,
5883 uint8_t *command,
5884 uint8_t command_len,
5885 hdd_priv_data_t *priv_data)
5886{
5887 int ret;
5888 uint8_t *value = command;
5889
5890 /* Move pointer to ahead of SETAPP2PARAMS */
5891 value = value + command_len;
5892
5893 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5894 if (ret >= 0)
5895 hdd_ctx->is_extwow_app_type2_param_set = true;
5896
5897 return ret;
5898}
5899#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5900
5901#ifdef FEATURE_WLAN_TDLS
5902/**
5903 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5904 * @adapter: Pointer to the HDD adapter
5905 * @hdd_ctx: Pointer to the HDD context
5906 * @command: Driver command string
5907 * @command_len: Driver command string length
5908 * @priv_data: Private data coming with the driver command. Unused here
5909 *
5910 * This function handles driver command that sets the secondary tdls off channel
5911 * offset
5912 *
5913 * Return: 0 on success; negative errno otherwise
5914 */
5915static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5916 hdd_context_t *hdd_ctx,
5917 uint8_t *command,
5918 uint8_t command_len,
5919 hdd_priv_data_t *priv_data)
5920{
5921 int ret;
5922 uint8_t *value = command;
5923 int set_value;
5924
5925 /* Move pointer to point the string */
5926 value += command_len;
5927
5928 ret = sscanf(value, "%d", &set_value);
5929 if (ret != 1)
5930 return -EINVAL;
5931
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005932 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005933
5934 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5935
5936 return ret;
5937}
5938
5939/**
5940 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5941 * @adapter: Pointer to the HDD adapter
5942 * @hdd_ctx: Pointer to the HDD context
5943 * @command: Driver command string
5944 * @command_len: Driver command string length
5945 * @priv_data: Private data coming with the driver command. Unused here
5946 *
5947 * This function handles driver command that sets tdls off channel mode
5948 *
5949 * Return: 0 on success; negative errno otherwise
5950 */
5951static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5952 hdd_context_t *hdd_ctx,
5953 uint8_t *command,
5954 uint8_t command_len,
5955 hdd_priv_data_t *priv_data)
5956{
5957 int ret;
5958 uint8_t *value = command;
5959 int set_value;
5960
5961 /* Move pointer to point the string */
5962 value += command_len;
5963
5964 ret = sscanf(value, "%d", &set_value);
5965 if (ret != 1)
5966 return -EINVAL;
5967
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005968 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005969
5970 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5971
5972 return ret;
5973}
5974
5975/**
5976 * drv_cmd_tdls_off_channel() - set tdls off channel number
5977 * @adapter: Pointer to the HDD adapter
5978 * @hdd_ctx: Pointer to the HDD context
5979 * @command: Driver command string
5980 * @command_len: Driver command string length
5981 * @priv_data: Private data coming with the driver command. Unused here
5982 *
5983 * This function handles driver command that sets tdls off channel number
5984 *
5985 * Return: 0 on success; negative errno otherwise
5986 */
5987static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5988 hdd_context_t *hdd_ctx,
5989 uint8_t *command,
5990 uint8_t command_len,
5991 hdd_priv_data_t *priv_data)
5992{
5993 int ret;
5994 uint8_t *value = command;
5995 int set_value;
5996
5997 /* Move pointer to point the string */
5998 value += command_len;
5999
6000 ret = sscanf(value, "%d", &set_value);
6001 if (ret != 1)
6002 return -EINVAL;
6003
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006004 if (CDS_IS_DFS_CH(set_value)) {
6005 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6006 set_value);
6007 return -EINVAL;
6008 }
6009
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006010 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006011
6012 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6013
6014 return ret;
6015}
6016
6017/**
6018 * drv_cmd_tdls_scan() - set tdls scan type
6019 * @adapter: Pointer to the HDD adapter
6020 * @hdd_ctx: Pointer to the HDD context
6021 * @command: Driver command string
6022 * @command_len: Driver command string length
6023 * @priv_data: Private data coming with the driver command. Unused here
6024 *
6025 * This function handles driver command that sets tdls scan type
6026 *
6027 * Return: 0 on success; negative errno otherwise
6028 */
6029static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6030 hdd_context_t *hdd_ctx,
6031 uint8_t *command,
6032 uint8_t command_len,
6033 hdd_priv_data_t *priv_data)
6034{
6035 int ret;
6036 uint8_t *value = command;
6037 int set_value;
6038
6039 /* Move pointer to point the string */
6040 value += command_len;
6041
6042 ret = sscanf(value, "%d", &set_value);
6043 if (ret != 1)
6044 return -EINVAL;
6045
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006046 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006047
6048 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6049
6050 return ret;
6051}
6052#endif
6053
6054static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6055 hdd_context_t *hdd_ctx,
6056 uint8_t *command,
6057 uint8_t command_len,
6058 hdd_priv_data_t *priv_data)
6059{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006060 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006061 int8_t rssi = 0;
6062 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006063
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006064 uint8_t len = 0;
6065
6066 wlan_hdd_get_rssi(adapter, &rssi);
6067
6068 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306069 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006070
6071 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006072 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006073 ret = -EFAULT;
6074 }
6075
6076 return ret;
6077}
6078
6079static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6080 hdd_context_t *hdd_ctx,
6081 uint8_t *command,
6082 uint8_t command_len,
6083 hdd_priv_data_t *priv_data)
6084{
6085 int ret;
6086 uint32_t link_speed = 0;
6087 char extra[32];
6088 uint8_t len = 0;
6089
6090 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6091 if (0 != ret)
6092 return ret;
6093
6094 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306095 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006096 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006097 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006098 ret = -EFAULT;
6099 }
6100
6101 return ret;
6102}
6103
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006104/**
6105 * hdd_set_rx_filter() - set RX filter
6106 * @adapter: Pointer to adapter
6107 * @action: Filter action
6108 * @pattern: Address pattern
6109 *
6110 * Address pattern is most significant byte of address for example
6111 * 0x01 for IPV4 multicast address
6112 * 0x33 for IPV6 multicast address
6113 * 0xFF for broadcast address
6114 *
6115 * Return: 0 for success, non-zero for failure
6116 */
6117static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6118 uint8_t pattern)
6119{
6120 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006121 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006122 tHalHandle handle;
6123 tSirRcvFltMcAddrList *filter;
6124 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6125
6126 ret = wlan_hdd_validate_context(hdd_ctx);
6127 if (0 != ret)
6128 return ret;
6129
6130 handle = hdd_ctx->hHal;
6131
6132 if (NULL == handle) {
6133 hdd_err("HAL Handle is NULL");
6134 return -EINVAL;
6135 }
6136
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306137 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006138 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306139 return -EINVAL;
6140 }
6141
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006142 /*
6143 * If action is false it means start dropping packets
6144 * Set addr_filter_pattern which will be used when sending
6145 * MC/BC address list to target
6146 */
6147 if (!action)
6148 adapter->addr_filter_pattern = pattern;
6149 else
6150 adapter->addr_filter_pattern = 0;
6151
Krunal Sonibe766b02016-03-10 13:00:44 -08006152 if (((adapter->device_mode == QDF_STA_MODE) ||
6153 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006154 adapter->mc_addr_list.mc_cnt &&
6155 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6156
6157
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306158 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006159 if (NULL == filter) {
6160 hdd_err("Could not allocate Memory");
6161 return -ENOMEM;
6162 }
6163 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006164 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006165 if (!memcmp(adapter->mc_addr_list.addr[i],
6166 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006167 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006168 adapter->mc_addr_list.addr[i],
6169 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006170
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006171 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006172 MAC_ADDRESS_STR,
6173 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006174 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6175 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006176 }
6177 }
Frank Liuf95e8132016-09-29 19:01:30 +08006178 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006179 /* Set rx filter */
6180 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306181 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006182 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006183 hdd_debug("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006184 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6185 }
6186
6187 return 0;
6188}
6189
6190/**
6191 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6192 * @command: Pointer to input string driver command
6193 * @adapter: Pointer to adapter
6194 * @action: Action to enable/disable filtering
6195 *
6196 * If action == false
6197 * Start filtering out data packets based on type
6198 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6199 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6200 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6201 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6202 *
6203 * if action == true
6204 * Stop filtering data packets based on type
6205 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6206 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6207 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6208 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6209 *
6210 * Current implementation only supports IPV4 address filtering by
6211 * selectively allowing IPV4 multicast data packest based on
6212 * address list received in .ndo_set_rx_mode
6213 *
6214 * Return: 0 for success, non-zero for failure
6215 */
6216static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6217 hdd_adapter_t *adapter,
6218 bool action)
6219{
6220 int ret = 0;
6221 uint8_t *value;
6222 uint8_t type;
6223
6224 value = command;
6225 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6226 if (!action)
6227 value = command + 16;
6228 else
6229 value = command + 13;
6230 ret = kstrtou8(value, 10, &type);
6231 if (ret < 0) {
6232 hdd_err("kstrtou8 failed invalid input value %d", type);
6233 return -EINVAL;
6234 }
6235
6236 switch (type) {
6237 case 2:
6238 /* Set rx filter for IPV4 multicast data packets */
6239 ret = hdd_set_rx_filter(adapter, action, 0x01);
6240 break;
6241 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006242 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006243 break;
6244 }
6245
6246 return ret;
6247}
6248
6249/**
6250 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6251 * @adapter: Pointer to network adapter
6252 * @hdd_ctx: Pointer to hdd context
6253 * @command: Pointer to input command
6254 * @command_len: Command length
6255 * @priv_data: Pointer to private data in command
6256 */
6257static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6258 hdd_context_t *hdd_ctx,
6259 uint8_t *command,
6260 uint8_t command_len,
6261 hdd_priv_data_t *priv_data)
6262{
6263 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6264}
6265
6266/**
6267 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6268 * @adapter: Pointer to network adapter
6269 * @hdd_ctx: Pointer to hdd context
6270 * @command: Pointer to input command
6271 * @command_len: Command length
6272 * @priv_data: Pointer to private data in command
6273 */
6274static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6275 hdd_context_t *hdd_ctx,
6276 uint8_t *command,
6277 uint8_t command_len,
6278 hdd_priv_data_t *priv_data)
6279{
6280 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6281}
6282
Archana Ramachandran393f3792015-11-13 17:13:21 -08006283/**
6284 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6285 * command
6286 * @value: Pointer to SETANTENNAMODE command
6287 * @mode: Pointer to antenna mode
6288 * @reason: Pointer to reason for set antenna mode
6289 *
6290 * This function parses the SETANTENNAMODE command passed in the format
6291 * SETANTENNAMODE<space>mode
6292 *
6293 * Return: 0 for success non-zero for failure
6294 */
6295static int hdd_parse_setantennamode_command(const uint8_t *value)
6296{
6297 const uint8_t *in_ptr = value;
6298 int tmp, v;
6299 char arg1[32];
6300
6301 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6302
6303 /* no argument after the command */
6304 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006305 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006306 return -EINVAL;
6307 }
6308
6309 /* no space after the command */
6310 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006311 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006312 return -EINVAL;
6313 }
6314
6315 /* remove empty spaces */
6316 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6317 in_ptr++;
6318
6319 /* no argument followed by spaces */
6320 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006321 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006322 return -EINVAL;
6323 }
6324
6325 /* get the argument i.e. antenna mode */
6326 v = sscanf(in_ptr, "%31s ", arg1);
6327 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006328 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006329 return -EINVAL;
6330 }
6331
6332 v = kstrtos32(arg1, 10, &tmp);
6333 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006334 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006335 return -EINVAL;
6336 }
6337
6338 return tmp;
6339}
6340
6341/**
6342 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6343 * mask is 2x2 mode
6344 * @hdd_ctx: Pointer to hdd contex
6345 *
6346 * Return: true if supported chain mask 2x2 else false
6347 */
6348static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6349{
6350 /*
6351 * Revisit and the update logic to determine the number
6352 * of TX/RX chains supported in the system when
6353 * antenna sharing per band chain mask support is
6354 * brought in
6355 */
6356 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6357}
6358
6359/**
6360 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6361 * chain mask is 1x1
6362 * @hdd_ctx: Pointer to hdd contex
6363 *
6364 * Return: true if supported chain mask 1x1 else false
6365 */
6366static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6367{
6368 /*
6369 * Revisit and update the logic to determine the number
6370 * of TX/RX chains supported in the system when
6371 * antenna sharing per band chain mask support is
6372 * brought in
6373 */
6374 return (!hdd_ctx->config->enable2x2) ? true : false;
6375}
6376
6377/**
6378 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6379 * handler
6380 * @adapter: Pointer to network adapter
6381 * @hdd_ctx: Pointer to hdd context
6382 * @command: Pointer to input command
6383 * @command_len: Command length
6384 * @priv_data: Pointer to private data in command
6385 */
6386static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6387 hdd_context_t *hdd_ctx,
6388 uint8_t *command,
6389 uint8_t command_len,
6390 hdd_priv_data_t *priv_data)
6391{
6392 struct sir_antenna_mode_param params;
6393 QDF_STATUS status;
6394 int ret = 0;
6395 int mode;
6396 uint8_t *value = command;
6397 uint8_t smps_mode;
6398 uint8_t smps_enable;
6399
6400 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6401 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6402 hdd_err("Operation invalid in non sta or concurrent mode");
6403 ret = -EPERM;
6404 goto exit;
6405 }
6406
6407 mode = hdd_parse_setantennamode_command(value);
6408 if (mode < 0) {
6409 hdd_err("Invalid SETANTENNA command");
6410 ret = mode;
6411 goto exit;
6412 }
6413
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006414 hdd_debug("Processing antenna mode switch to: %d", mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006415
6416 if (hdd_ctx->current_antenna_mode == mode) {
6417 hdd_err("System already in the requested mode");
6418 ret = 0;
6419 goto exit;
6420 }
6421
6422 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6423 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6424 hdd_err("System does not support 2x2 mode");
6425 ret = -EPERM;
6426 goto exit;
6427 }
6428
6429 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6430 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6431 hdd_err("System only supports 1x1 mode");
6432 ret = 0;
6433 goto exit;
6434 }
6435
6436 switch (mode) {
6437 case HDD_ANTENNA_MODE_1X1:
6438 params.num_rx_chains = 1;
6439 params.num_tx_chains = 1;
6440 break;
6441 case HDD_ANTENNA_MODE_2X2:
6442 params.num_rx_chains = 2;
6443 params.num_tx_chains = 2;
6444 break;
6445 default:
6446 hdd_err("unsupported antenna mode");
6447 ret = -EINVAL;
6448 goto exit;
6449 }
6450
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006451 /* Check TDLS status and update antenna mode */
6452 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006453 policy_mgr_is_sta_active_connection_exists(
6454 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006455 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6456 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006457 if (0 != ret)
6458 goto exit;
6459 }
6460
Archana Ramachandran393f3792015-11-13 17:13:21 -08006461 params.set_antenna_mode_resp =
6462 (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006463 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006464 params.num_rx_chains,
6465 params.num_tx_chains);
6466
6467
6468 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6469 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6470 if (QDF_STATUS_SUCCESS != status) {
6471 hdd_err("set antenna mode failed status : %d", status);
6472 ret = -EFAULT;
6473 goto exit;
6474 }
6475
6476 ret = wait_for_completion_timeout(
6477 &hdd_ctx->set_antenna_mode_cmpl,
6478 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6479 if (!ret) {
6480 ret = -EFAULT;
6481 hdd_err("send set antenna mode timed out");
6482 goto exit;
6483 }
6484
6485 /* Update SME SMPS config */
6486 if (HDD_ANTENNA_MODE_1X1 == mode) {
6487 smps_enable = true;
6488 smps_mode = HDD_SMPS_MODE_STATIC;
6489 } else {
6490 smps_enable = false;
6491 smps_mode = HDD_SMPS_MODE_DISABLED;
6492 }
6493
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006494 hdd_debug("Update SME SMPS enable: %d mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006495 smps_enable, smps_mode);
6496 status = sme_update_mimo_power_save(
6497 hdd_ctx->hHal, smps_enable, smps_mode, false);
6498 if (QDF_STATUS_SUCCESS != status) {
6499 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6500 smps_enable, smps_mode, status);
6501 ret = -EFAULT;
6502 goto exit;
6503 }
6504
Archana Ramachandran393f3792015-11-13 17:13:21 -08006505 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006506 /* Update the user requested nss in the mac context.
6507 * This will be used in tdls protocol engine to form tdls
6508 * Management frames.
6509 */
6510 sme_update_user_configured_nss(
6511 hdd_ctx->hHal,
6512 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006513
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006514 hdd_debug("Successfully switched to mode: %d x %d",
Archana Ramachandran5041b252016-04-25 14:29:25 -07006515 hdd_ctx->current_antenna_mode,
6516 hdd_ctx->current_antenna_mode);
6517 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006518exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006519#ifdef FEATURE_WLAN_TDLS
6520 /* Reset tdls NSS flags */
6521 if (hdd_ctx->tdls_nss_switch_in_progress &&
6522 hdd_ctx->tdls_nss_teardown_complete) {
6523 hdd_ctx->tdls_nss_switch_in_progress = false;
6524 hdd_ctx->tdls_nss_teardown_complete = false;
6525 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006526 hdd_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
Kabilan Kannanff89f742016-08-15 18:14:10 -07006527 hdd_ctx->tdls_nss_switch_in_progress,
6528 hdd_ctx->tdls_nss_teardown_complete);
6529#endif
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006530 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006531 ret, hdd_ctx->current_antenna_mode);
6532 return ret;
6533
6534}
6535
6536/**
6537 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6538 * handler
6539 * @adapter: Pointer to hdd adapter
6540 * @hdd_ctx: Pointer to hdd context
6541 * @command: Pointer to input command
6542 * @command_len: length of the command
6543 * @priv_data: private data coming with the driver command
6544 *
6545 * Return: 0 for success non-zero for failure
6546 */
6547static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6548 hdd_context_t *hdd_ctx,
6549 uint8_t *command,
6550 uint8_t command_len,
6551 hdd_priv_data_t *priv_data)
6552{
6553 uint32_t antenna_mode = 0;
6554 char extra[32];
6555 uint8_t len = 0;
6556
6557 antenna_mode = hdd_ctx->current_antenna_mode;
6558 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6559 antenna_mode);
6560 len = QDF_MIN(priv_data->total_len, len + 1);
6561 if (copy_to_user(priv_data->buf, &extra, len)) {
6562 hdd_err("Failed to copy data to user buffer");
6563 return -EFAULT;
6564 }
6565
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006566 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006567
6568 return 0;
6569}
6570
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006571/*
6572 * dummy (no-op) hdd driver command handler
6573 */
6574static int drv_cmd_dummy(hdd_adapter_t *adapter,
6575 hdd_context_t *hdd_ctx,
6576 uint8_t *command,
6577 uint8_t command_len,
6578 hdd_priv_data_t *priv_data)
6579{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006580 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006581 adapter->dev->name, command);
6582 return 0;
6583}
6584
6585/*
6586 * handler for any unsupported wlan hdd driver command
6587 */
6588static int drv_cmd_invalid(hdd_adapter_t *adapter,
6589 hdd_context_t *hdd_ctx,
6590 uint8_t *command,
6591 uint8_t command_len,
6592 hdd_priv_data_t *priv_data)
6593{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306594 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006595 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6596 adapter->sessionId, 0));
6597
6598 hdd_warn("%s: Unsupported driver command \"%s\"",
6599 adapter->dev->name, command);
6600
6601 return -ENOTSUPP;
6602}
6603
6604/**
6605 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6606 * @adapter: HDD adapter
6607 * @hdd_ctx: HDD context
6608 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6609 * @command_len: command len
6610 * @priv_data: private data
6611 *
6612 * Return: status
6613 */
6614static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6615 hdd_context_t *hdd_ctx,
6616 uint8_t *command,
6617 uint8_t command_len,
6618 hdd_priv_data_t *priv_data)
6619{
6620 uint8_t *value;
6621 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306622 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006623 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006624 int ret = 0;
6625
6626 /*
6627 * this command would be called by user-space when it detects WLAN
6628 * ON after airplane mode is set. When APM is set, WLAN turns off.
6629 * But it can be turned back on. Otherwise; when APM is turned back
6630 * off, WLAN would turn back on. So at that point the command is
6631 * expected to come down. 0 means disable, 1 means enable. The
6632 * constraint is removed when parameter 1 is set or different
6633 * country code is set
6634 */
6635
6636 value = command + command_len + 1;
6637
6638 ret = kstrtou8(value, 10, &fcc_constraint);
6639 if ((ret < 0) || (fcc_constraint > 1)) {
6640 /*
6641 * If the input value is greater than max value of datatype,
6642 * then also it is a failure
6643 */
6644 hdd_err("value out of range");
6645 return -EINVAL;
6646 }
Sandeep Puligillad0004212017-02-26 18:34:56 -08006647#ifndef NAPIER_SCAN
6648 /* This code will be removed*/
Amar Singhal83a047a2016-05-19 15:56:11 -07006649 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
Sandeep Puligillad0004212017-02-26 18:34:56 -08006650#else
6651 scan_pending = ucfg_scan_get_pdev_status(hdd_ctx->hdd_pdev);
6652#endif
Amar Singhal83a047a2016-05-19 15:56:11 -07006653 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6654 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306655 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006656 hdd_err("sme disable fn. returned err");
6657 ret = -EPERM;
6658 }
6659
6660 return ret;
6661}
6662
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306663/**
6664 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6665 * command
6666 * @value: Pointer to the command
6667 * @chan_number: Pointer to the channel number
6668 * @chan_bw: Pointer to the channel bandwidth
6669 *
6670 * Parses and provides the channel number and channel width from the input
6671 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6672 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6673 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6674 *
6675 * Return: 0 for success, non-zero for failure
6676 */
6677static int hdd_parse_set_channel_switch_command(uint8_t *value,
6678 uint32_t *chan_number,
6679 uint32_t *chan_bw)
6680{
6681 const uint8_t *in_ptr = value;
6682 int ret;
6683
6684 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6685
6686 /* no argument after the command */
6687 if (NULL == in_ptr) {
6688 hdd_err("No argument after the command");
6689 return -EINVAL;
6690 }
6691
6692 /* no space after the command */
6693 if (SPACE_ASCII_VALUE != *in_ptr) {
6694 hdd_err("No space after the command ");
6695 return -EINVAL;
6696 }
6697
6698 /* remove empty spaces and move the next argument */
6699 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6700 in_ptr++;
6701
6702 /* no argument followed by spaces */
6703 if ('\0' == *in_ptr) {
6704 hdd_err("No argument followed by spaces");
6705 return -EINVAL;
6706 }
6707
6708 /* get the two arguments: channel number and bandwidth */
6709 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6710 if (ret != 2) {
6711 hdd_err("Arguments retrieval from cmd string failed");
6712 return -EINVAL;
6713 }
6714
6715 return 0;
6716}
6717
6718/**
6719 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6720 * @adapter: HDD adapter
6721 * @hdd_ctx: HDD context
6722 * @command: Pointer to the input command CHANNEL_SWITCH
6723 * @command_len: Command len
6724 * @priv_data: Private data
6725 *
6726 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6727 * of SAP/P2P-GO
6728 *
6729 * Return: 0 for success, non-zero for failure
6730 */
6731static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
6732 hdd_context_t *hdd_ctx,
6733 uint8_t *command,
6734 uint8_t command_len,
6735 hdd_priv_data_t *priv_data)
6736{
6737 struct net_device *dev = adapter->dev;
6738 int status;
6739 uint32_t chan_number = 0, chan_bw = 0;
6740 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006741 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306742
Krunal Sonibe766b02016-03-10 13:00:44 -08006743 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6744 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306745 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6746 adapter->device_mode);
6747 return -EINVAL;
6748 }
6749
6750 status = hdd_parse_set_channel_switch_command(value,
6751 &chan_number, &chan_bw);
6752 if (status) {
6753 hdd_err("Invalid CHANNEL_SWITCH command");
6754 return status;
6755 }
6756
6757 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6758 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6759 return -EINVAL;
6760 }
6761
6762 if (chan_bw == 80)
6763 width = CH_WIDTH_80MHZ;
6764 else if (chan_bw == 40)
6765 width = CH_WIDTH_40MHZ;
6766 else
6767 width = CH_WIDTH_20MHZ;
6768
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006769 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306770
6771 status = hdd_softap_set_channel_change(dev, chan_number, width);
6772 if (status) {
6773 hdd_err("Set channel change fail");
6774 return status;
6775 }
6776
6777 return 0;
6778}
6779
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006780/*
6781 * The following table contains all supported WLAN HDD
6782 * IOCTL driver commands and the handler for each of them.
6783 */
6784static const hdd_drv_cmd_t hdd_drv_cmds[] = {
6785 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
6786 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
6787 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
6788 {"SETBAND", drv_cmd_set_band},
6789 {"SETWMMPS", drv_cmd_set_wmmps},
6790 {"COUNTRY", drv_cmd_country},
6791 {"SETSUSPENDMODE", drv_cmd_dummy},
6792 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
6793 {"BTCOEXSCAN", drv_cmd_dummy},
6794 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006795 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
6796 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
6797 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
6798 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
6799 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
6800 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006801 {"SETROAMMODE", drv_cmd_set_roam_mode},
6802 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006803 {"SETROAMDELTA", drv_cmd_set_roam_delta},
6804 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006805 {"GETBAND", drv_cmd_get_band},
6806 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
6807 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
6808 {"GETCCXMODE", drv_cmd_get_ccx_mode},
6809 {"GETOKCMODE", drv_cmd_get_okc_mode},
6810 {"GETFASTROAM", drv_cmd_get_fast_roam},
6811 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
6812 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
6813 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
6814 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
6815 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
6816 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
6817 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
6818 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
6819 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
6820 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
6821 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
6822 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
6823 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
6824 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
6825 {"REASSOC", drv_cmd_reassoc},
6826 {"SETWESMODE", drv_cmd_set_wes_mode},
6827 {"GETWESMODE", drv_cmd_get_wes_mode},
6828 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
6829 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
6830 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
6831 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006832 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006833 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
6834 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006835 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006836 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006837 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
6838 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
6839 {"SCAN-ACTIVE", drv_cmd_scan_active},
6840 {"SCAN-PASSIVE", drv_cmd_scan_passive},
6841 {"GETDWELLTIME", drv_cmd_get_dwell_time},
6842 {"SETDWELLTIME", drv_cmd_set_dwell_time},
6843 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08006844 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
6845 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
6846 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
6847 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
6848 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
6849 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
6850 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006851#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006852 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
6853 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
6854 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006855 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
6856 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
6857 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006858#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006859 {"SETMCRATE", drv_cmd_set_mc_rate},
6860 {"MAXTXPOWER", drv_cmd_max_tx_power},
6861 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
6862 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
6863 {"GETLINKSTATUS", drv_cmd_get_link_status},
6864#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6865 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
6866 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
6867 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
6868#endif
6869#ifdef FEATURE_WLAN_TDLS
6870 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
6871 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
6872 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
6873 {"TDLSSCAN", drv_cmd_tdls_scan},
6874#endif
6875 {"RSSI", drv_cmd_get_rssi},
6876 {"LINKSPEED", drv_cmd_get_linkspeed},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006877 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
6878 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
6879 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306880 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08006881 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
6882 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006883};
6884
6885/**
6886 * hdd_drv_cmd_process() - chooses and runs the proper
6887 * handler based on the input command
6888 * @adapter: Pointer to the hdd adapter
6889 * @cmd: Pointer to the driver command
6890 * @priv_data: Pointer to the data associated with the command
6891 *
6892 * This function parses the input hdd driver command and runs
6893 * the proper handler
6894 *
6895 * Return: 0 for success non-zero for failure
6896 */
6897static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
6898 uint8_t *cmd,
6899 hdd_priv_data_t *priv_data)
6900{
6901 hdd_context_t *hdd_ctx;
6902 int i;
6903 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6904 uint8_t *cmd_i = NULL;
6905 hdd_drv_cmd_handler_t handler = NULL;
6906 int len = 0;
6907
6908 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006909 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006910 return -EINVAL;
6911 }
6912
6913 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
6914
6915 for (i = 0; i < cmd_num_total; i++) {
6916
6917 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6918 handler = hdd_drv_cmds[i].handler;
6919 len = strlen(cmd_i);
6920
6921 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006922 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006923 return -EINVAL;
6924 }
6925
6926 if (strncasecmp(cmd, cmd_i, len) == 0)
6927 return handler(adapter, hdd_ctx,
6928 cmd, len, priv_data);
6929 }
6930
6931 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6932}
6933
6934/**
6935 * hdd_driver_command() - top level wlan hdd driver command handler
6936 * @adapter: Pointer to the hdd adapter
6937 * @priv_data: Pointer to the raw command data
6938 *
6939 * This function is the top level wlan hdd driver command handler. It
6940 * handles the command with the help of hdd_drv_cmd_process()
6941 *
6942 * Return: 0 for success non-zero for failure
6943 */
6944static int hdd_driver_command(hdd_adapter_t *adapter,
6945 hdd_priv_data_t *priv_data)
6946{
6947 uint8_t *command = NULL;
6948 int ret = 0;
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306949 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006950
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306951 ENTER();
6952
Anurag Chouhan6d760662016-02-20 16:05:43 +05306953 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006954 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006955 return -EINVAL;
6956 }
6957
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306958 ret = wlan_hdd_validate_context(hdd_ctx);
6959 if (ret)
6960 return ret;
6961
6962 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
6963 hdd_err("Driver module is closed; command can not be processed");
6964 return -EINVAL;
6965 }
6966
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006967 /*
6968 * Note that valid pointers are provided by caller
6969 */
6970
6971 /* copy to local struct to avoid numerous changes to legacy code */
6972 if (priv_data->total_len <= 0 ||
6973 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006974 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006975 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006976 ret = -EINVAL;
6977 goto exit;
6978 }
6979
6980 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006981 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006982 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006983 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006984 ret = -ENOMEM;
6985 goto exit;
6986 }
6987
6988 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6989 ret = -EFAULT;
6990 goto exit;
6991 }
6992
6993 /* Make sure the command is NUL-terminated */
6994 command[priv_data->total_len] = '\0';
6995
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006996 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006997 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6998
6999exit:
7000 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007001 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307002 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007003 return ret;
7004}
7005
7006#ifdef CONFIG_COMPAT
7007static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7008{
7009 struct {
7010 compat_uptr_t buf;
7011 int used_len;
7012 int total_len;
7013 } compat_priv_data;
7014 hdd_priv_data_t priv_data;
7015 int ret = 0;
7016
7017 /*
7018 * Note that adapter and ifr have already been verified by caller,
7019 * and HDD context has also been validated
7020 */
7021 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7022 sizeof(compat_priv_data))) {
7023 ret = -EFAULT;
7024 goto exit;
7025 }
7026 priv_data.buf = compat_ptr(compat_priv_data.buf);
7027 priv_data.used_len = compat_priv_data.used_len;
7028 priv_data.total_len = compat_priv_data.total_len;
7029 ret = hdd_driver_command(adapter, &priv_data);
7030exit:
7031 return ret;
7032}
7033#else /* CONFIG_COMPAT */
7034static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7035{
7036 /* will never be invoked */
7037 return 0;
7038}
7039#endif /* CONFIG_COMPAT */
7040
7041static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7042{
7043 hdd_priv_data_t priv_data;
7044 int ret = 0;
7045
7046 /*
7047 * Note that adapter and ifr have already been verified by caller,
7048 * and HDD context has also been validated
7049 */
7050 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7051 ret = -EFAULT;
7052 else
7053 ret = hdd_driver_command(adapter, &priv_data);
7054
7055 return ret;
7056}
7057
7058/**
7059 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7060 * @dev: device upon which the ioctl was received
7061 * @ifr: ioctl request information
7062 * @cmd: ioctl command
7063 *
7064 * This function does initial processing of wlan device ioctls.
7065 * Currently two flavors of ioctls are supported. The primary ioctl
7066 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7067 * for Android "DRIVER" commands. The other ioctl that is
7068 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7069 * for FTM on some platforms. This function simply verifies that the
7070 * driver is in a sane state, and that the ioctl is one of the
7071 * supported flavors, in which case flavor-specific handlers are
7072 * dispatched.
7073 *
7074 * Return: 0 on success, non-zero on error
7075 */
7076static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7077{
7078 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7079 hdd_context_t *hdd_ctx;
7080 int ret;
7081
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007082 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307083
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007084 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007085 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007086 ret = -ENODEV;
7087 goto exit;
7088 }
7089
7090 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007091 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007092 ret = -EINVAL;
7093 goto exit;
7094 }
7095#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307096 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007097 if (SIOCIOCTLTX99 == cmd) {
7098 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7099 goto exit;
7100 }
7101 }
7102#endif
7103
7104 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7105 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307106 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007107 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007108
7109 switch (cmd) {
7110 case (SIOCDEVPRIVATE + 1):
7111 if (is_compat_task())
7112 ret = hdd_driver_compat_ioctl(adapter, ifr);
7113 else
7114 ret = hdd_driver_ioctl(adapter, ifr);
7115 break;
7116 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007117 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007118 ret = -EINVAL;
7119 break;
7120 }
7121exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307122 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007123 return ret;
7124}
7125
7126/**
7127 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7128 * @dev: device upon which the ioctl was received
7129 * @ifr: ioctl request information
7130 * @cmd: ioctl command
7131 *
7132 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7133 * which is where the ioctls are really handled.
7134 *
7135 * Return: 0 on success, non-zero on error
7136 */
7137int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7138{
7139 int ret;
7140
7141 cds_ssr_protect(__func__);
7142 ret = __hdd_ioctl(dev, ifr, cmd);
7143 cds_ssr_unprotect(__func__);
7144 return ret;
7145}