blob: 49c586cfdbeab17511bb02508e19a7cf200abb62 [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"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070035#include "wlan_hdd_regulatory.h"
Jeff Johnson253c0c22017-01-23 16:59:38 -080036#include "wlan_hdd_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080037#include "wlan_hdd_driver_ops.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080038#include "wlan_policy_mgr_api.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053039#include "wlan_hdd_hostapd.h"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080040#include "scheduler_api.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070041#include "wlan_reg_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080042#include "wlan_hdd_p2p.h"
43#include <linux/ctype.h>
44#include "wma.h"
45#include "wlan_hdd_napi.h"
46
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080047#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080048#include <sme_api.h>
49#include <sir_api.h>
50#endif
51#include "hif.h"
52
53#if defined(LINUX_QCMBR)
54#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
55#endif
56
57/*
58 * Size of Driver command strings from upper layer
59 */
60#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
61#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
62
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080063/*
64 * Ibss prop IE from command will be of size:
65 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
66 * OUI_DATA should be at least 3 bytes long
67 */
68#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080070#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071#define TID_MIN_VALUE 0
72#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080073#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080074
75/*
76 * Maximum buffer size used for returning the data back to user space
77 */
78#define WLAN_MAX_BUF_SIZE 1024
79#define WLAN_PRIV_DATA_MAX_LEN 8192
80
81/*
82 * Driver miracast parameters 0-Disabled
83 * 1-Source, 2-Sink
84 */
85#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
86#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
87
88/*
89 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
90 * we will split the printing.
91 */
92#define NUM_OF_STA_DATA_TO_PRINT 16
93
94/*
95 * Android DRIVER command structures
96 */
97struct android_wifi_reassoc_params {
98 unsigned char bssid[18];
99 int channel;
100};
101
102#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
103struct android_wifi_af_params {
104 unsigned char bssid[18];
105 int channel;
106 int dwell_time;
107 int len;
108 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
109};
110
111/*
112 * Define HDD driver command handling entry, each contains a command
113 * string and the handler.
114 */
115typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
116 hdd_context_t *hdd_ctx,
117 uint8_t *cmd,
118 uint8_t cmd_name_len,
119 hdd_priv_data_t *priv_data);
120
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700121struct hdd_drv_cmd {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800122 const char *cmd;
123 hdd_drv_cmd_handler_t handler;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700124};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800125
126#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
127#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
128#define WLAN_HDD_MAX_TCP_PORT 65535
129#endif
130
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800131static uint16_t cesium_pid;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800132
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
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700226 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800227 return 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700228 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800229 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800230
231 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
232 inPtr++;
233
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700234 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800235 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800236
Ashish Kumar Dhanotiya9cd0d7c2017-08-02 17:08:05 +0530237 v = sscanf(inPtr, "%31s ", buf);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700238 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800239 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700240
241 v = kstrtos32(buf, 10, &tempInt);
242 if (v < 0)
243 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800244
245 *pRmcEnable = tempInt;
246
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800247 hdd_debug("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800248
249 return 0;
250}
251
252/* Function header is left blank intentionally */
253static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
254 uint32_t *pActionPeriod)
255{
256 uint8_t *inPtr = pValue;
257 int tempInt;
258 int v = 0;
259 char buf[32];
260 *pActionPeriod = 0;
261
262 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
263
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700264 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800265 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700266 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800267 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800268
269 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
270 inPtr++;
271
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700272 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800273 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800274
Ashish Kumar Dhanotiya9cd0d7c2017-08-02 17:08:05 +0530275 v = sscanf(inPtr, "%31s ", buf);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700276 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800277 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700278
279 v = kstrtos32(buf, 10, &tempInt);
280 if (v < 0)
281 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800282
283 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700284 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800285 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800286
287 *pActionPeriod = tempInt;
288
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800289 hdd_debug("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800290
291 return 0;
292}
293
294/* Function header is left blank intentionally */
295static int hdd_parse_setrmcrate_command(uint8_t *pValue,
296 uint32_t *pRate,
297 tTxrateinfoflags *pTxFlags)
298{
299 uint8_t *inPtr = pValue;
300 int tempInt;
301 int v = 0;
302 char buf[32];
303 *pRate = 0;
304 *pTxFlags = 0;
305
306 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
307
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700308 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800309 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700310 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800311 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800312
313 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
314 inPtr++;
315
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700316 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800317 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800318
Ashish Kumar Dhanotiyabfe639f2017-06-12 18:34:34 +0530319 v = sscanf(inPtr, "%31s ", buf);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700320 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800321 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700322
323 v = kstrtos32(buf, 10, &tempInt);
324 if (v < 0)
325 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800326
327 switch (tempInt) {
328 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700329 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800330 return -EINVAL;
331 case 0:
332 case 6:
333 case 9:
334 case 12:
335 case 18:
336 case 24:
337 case 36:
338 case 48:
339 case 54:
340 *pTxFlags = eHAL_TX_RATE_LEGACY;
341 *pRate = tempInt * 10;
342 break;
343 case 65:
344 *pTxFlags = eHAL_TX_RATE_HT20;
345 *pRate = tempInt * 10;
346 break;
347 case 72:
348 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
349 *pRate = 722;
350 break;
351 }
352
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800353 hdd_debug("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800354
355 return 0;
356}
357
358/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700359 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
360 * @UserData: Adapter private data
361 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800362 *
363 * This is an asynchronous callback function from SME when the peer info
364 * is received
365 *
366 * Return: 0 for success non-zero for failure
367 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700368void
369hdd_get_ibss_peer_info_cb(void *pUserData,
370 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800371{
372 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800373 hdd_station_ctx_t *pStaCtx;
374 uint8_t i;
375
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800376 if ((NULL == adapter) ||
377 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800378 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800379 return;
380 }
381
382 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
383 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700384 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530385 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
386 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700387 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530388 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800389 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530390 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
391 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
392
393 for (i = 0; i < pPeerInfo->numPeers; i++)
394 pStaCtx->ibss_peer_info.peerInfoParams[i] =
395 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800396 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800397 hdd_debug("peerInfo %s: status %u, numPeers %u",
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530398 pPeerInfo ? "valid" : "null",
399 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
400 pPeerInfo ? pPeerInfo->numPeers : 0);
401 pStaCtx->ibss_peer_info.numPeers = 0;
402 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800403 }
404
405 complete(&adapter->ibss_peer_info_comp);
406}
407
408/**
409 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
410 * @adapter: Adapter context
411 *
412 * Request function to get IBSS peer info from lower layers
413 *
414 * Return: 0 for success non-zero for failure
415 */
416static
417QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
418{
419 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
420 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
421 unsigned long rc;
422
423 INIT_COMPLETION(adapter->ibss_peer_info_comp);
424
425 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700426 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800427 true, 0xFF);
428
429 if (QDF_STATUS_SUCCESS == retStatus) {
430 rc = wait_for_completion_timeout
431 (&adapter->ibss_peer_info_comp,
432 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
433
434 /* status will be 0 if timed out */
435 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700436 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800437 retStatus = QDF_STATUS_E_FAILURE;
438 return retStatus;
439 }
440 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700441 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800442 }
443
444 return retStatus;
445}
446
447/**
448 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
449 * @adapter: Adapter context
450 * @staIdx: Sta index for which the peer info is requested
451 *
452 * Request function to get IBSS peer info from lower layers
453 *
454 * Return: 0 for success non-zero for failure
455 */
456static QDF_STATUS
457hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
458{
459 unsigned long rc;
460 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
461 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
462
463 INIT_COMPLETION(adapter->ibss_peer_info_comp);
464
465 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700466 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800467 false, staIdx);
468
469 if (QDF_STATUS_SUCCESS == retStatus) {
470 rc = wait_for_completion_timeout(
471 &adapter->ibss_peer_info_comp,
472 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
473
474 /* status = 0 on timeout */
475 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700476 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800477 retStatus = QDF_STATUS_E_FAILURE;
478 return retStatus;
479 }
480 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700481 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800482 }
483
484 return retStatus;
485}
486
487/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700488static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800489hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
490{
491 uint8_t *inPtr = pValue;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700492
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800493 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
494
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700495 if (NULL == inPtr)
496 return QDF_STATUS_E_FAILURE;
497 else if (SPACE_ASCII_VALUE != *inPtr)
498 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800499
500 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
501 inPtr++;
502
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700503 if ('\0' == *inPtr)
504 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800505
506 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
507 inPtr[11] != ':' || inPtr[14] != ':') {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700508 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800509 }
510 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
511 (unsigned int *)&pPeerMacAddr->bytes[0],
512 (unsigned int *)&pPeerMacAddr->bytes[1],
513 (unsigned int *)&pPeerMacAddr->bytes[2],
514 (unsigned int *)&pPeerMacAddr->bytes[3],
515 (unsigned int *)&pPeerMacAddr->bytes[4],
516 (unsigned int *)&pPeerMacAddr->bytes[5]);
517
518 return QDF_STATUS_SUCCESS;
519}
520
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800521static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
522{
523 eCsrBand band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700524
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
526 switch (band) {
527 case eCSR_BAND_ALL:
528 *pBand = WLAN_HDD_UI_BAND_AUTO;
529 break;
530
531 case eCSR_BAND_24:
532 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
533 break;
534
535 case eCSR_BAND_5G:
536 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
537 break;
538
539 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700540 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800541 *pBand = -1;
542 break;
543 }
544}
545
546/**
547 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
548 * @data: input data
549 * @target_ap_bssid: pointer to bssid (output parameter)
550 * @channel: pointer to channel (output parameter)
551 *
552 * Return: 0 if parsing is successful; -EINVAL otherwise
553 */
554static int _hdd_parse_bssid_and_chan(const uint8_t **data,
555 uint8_t *bssid,
556 uint8_t *channel)
557{
558 const uint8_t *in_ptr;
559 int v = 0;
560 int temp_int;
561 uint8_t temp_buf[32];
562
563 /* 12 hexa decimal digits, 5 ':' and '\0' */
564 uint8_t mac_addr[18];
565
566 if (!data || !*data)
567 return -EINVAL;
568
569 in_ptr = *data;
570
571 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
572 /* no argument after the command */
573 if (NULL == in_ptr)
574 goto error;
575 /* no space after the command */
576 else if (SPACE_ASCII_VALUE != *in_ptr)
577 goto error;
578
579 /* remove empty spaces */
580 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
581 in_ptr++;
582
583 /* no argument followed by spaces */
584 if ('\0' == *in_ptr)
585 goto error;
586
587 v = sscanf(in_ptr, "%17s", mac_addr);
588 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700589 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
590 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800591 goto error;
592 }
593
594 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
595 hex_to_bin(mac_addr[1]);
596 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
597 hex_to_bin(mac_addr[4]);
598 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
599 hex_to_bin(mac_addr[7]);
600 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
601 hex_to_bin(mac_addr[10]);
602 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
603 hex_to_bin(mac_addr[13]);
604 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
605 hex_to_bin(mac_addr[16]);
606
607 /* point to the next argument */
608 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
609 /* no argument after the command */
610 if (NULL == in_ptr)
611 goto error;
612
613 /* remove empty spaces */
614 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
615 in_ptr++;
616
617 /* no argument followed by spaces */
618 if ('\0' == *in_ptr)
619 goto error;
620
621 /* get the next argument ie the channel number */
622 v = sscanf(in_ptr, "%31s ", temp_buf);
623 if (1 != v)
624 goto error;
625
626 v = kstrtos32(temp_buf, 10, &temp_int);
627 if ((v < 0) || (temp_int < 0) ||
628 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
629 return -EINVAL;
630
631 *channel = temp_int;
632 *data = in_ptr;
633 return 0;
634error:
635 *data = in_ptr;
636 return -EINVAL;
637}
638
639/**
640 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
641 * @pValue: Pointer to input data
642 * @pTargetApBssid: Pointer to target Ap bssid
643 * @pChannel: Pointer to the Target AP channel
644 * @pDwellTime: Pointer to the time to stay off-channel
645 * after transmitting action frame
646 * @pBuf: Pointer to data
647 * @pBufLen: Pointer to data length
648 *
649 * This function parses the send action frame data passed in the format
650 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
651 *
652 * Return: 0 for success non-zero for failure
653 */
654static int
655hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
656 uint8_t *pTargetApBssid,
657 uint8_t *pChannel, uint8_t *pDwellTime,
658 uint8_t **pBuf, uint8_t *pBufLen)
659{
660 const uint8_t *inPtr = pValue;
661 const uint8_t *dataEnd;
662 int tempInt;
663 int j = 0;
664 int i = 0;
665 int v = 0;
666 uint8_t tempBuf[32];
667 uint8_t tempByte = 0;
668
669 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
670 return -EINVAL;
671
672 /* point to the next argument */
673 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
674 /* no argument after the command */
675 if (NULL == inPtr)
676 return -EINVAL;
677 /* removing empty spaces */
678 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
679 inPtr++;
680
681 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700682 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800683 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800684
685 /* getting the next argument ie the dwell time */
686 v = sscanf(inPtr, "%31s ", tempBuf);
687 if (1 != v)
688 return -EINVAL;
689
690 v = kstrtos32(tempBuf, 10, &tempInt);
691 if (v < 0 || tempInt < 0)
692 return -EINVAL;
693
694 *pDwellTime = tempInt;
695
696 /* point to the next argument */
697 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
698 /* no argument after the command */
699 if (NULL == inPtr)
700 return -EINVAL;
701 /* removing empty spaces */
702 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
703 inPtr++;
704
705 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700706 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800707 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708
709 /* find the length of data */
710 dataEnd = inPtr;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700711 while (('\0' != *dataEnd))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800712 dataEnd++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700713
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800714 *pBufLen = dataEnd - inPtr;
715 if (*pBufLen <= 0)
716 return -EINVAL;
717
718 /*
719 * Allocate the number of bytes based on the number of input characters
720 * whether it is even or odd.
721 * if the number of input characters are even, then we need N/2 byte.
722 * if the number of input characters are odd, then we need do (N+1)/2
723 * to compensate rounding off.
724 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
725 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
726 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530727 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800728 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700729 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800730 return -ENOMEM;
731 }
732
733 /* the buffer received from the upper layer is character buffer,
734 * we need to prepare the buffer taking 2 characters in to a U8 hex
735 * decimal number for example 7f0000f0...form a buffer to contain 7f
736 * in 0th location, 00 in 1st and f0 in 3rd location
737 */
738 for (i = 0, j = 0; j < *pBufLen; j += 2) {
739 if (j + 1 == *pBufLen) {
740 tempByte = hex_to_bin(inPtr[j]);
741 } else {
742 tempByte =
743 (hex_to_bin(inPtr[j]) << 4) |
744 (hex_to_bin(inPtr[j + 1]));
745 }
746 (*pBuf)[i++] = tempByte;
747 }
748 *pBufLen = i;
749 return 0;
750}
751
752/**
753 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
754 * @pValue: Pointer to input data (its a NULL terminated string)
755 * @pTargetApBssid: Pointer to target Ap bssid
756 * @pChannel: Pointer to the Target AP channel
757 *
758 * This function parses the reasoc command data passed in the format
759 * REASSOC<space><bssid><space><channel>
760 *
761 * Return: 0 for success non-zero for failure
762 */
763static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
764 uint8_t *pTargetApBssid,
765 uint8_t *pChannel)
766{
767 const uint8_t *inPtr = pValue;
768
769 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
770 return -EINVAL;
771
772 return 0;
773}
774
Naveen Rawat05376ee2016-07-18 16:43:32 -0700775#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800776void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter,
777 const tSirMacAddr bssid, int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700778{
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800779 hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
780 tCsrRoamProfile *profile = &wext_state->roamProfile;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700781
Naveen Rawat4195c5e2017-05-22 17:07:45 -0700782 sme_fast_reassoc(WLAN_HDD_GET_HAL_CTX(adapter),
783 profile, bssid, channel, adapter->sessionId);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700784}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700785#endif
786
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787/**
788 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800789 * @adapter: Adapter upon which the command was received
790 * @bssid: BSSID with which to reassociate
791 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700792 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 *
794 * This function performs a userspace-directed reassoc operation
795 *
796 * Return: 0 for success non-zero for failure
797 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700798int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800799 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800800{
801 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700802 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800803 int ret = 0;
804
Naveen Rawat05376ee2016-07-18 16:43:32 -0700805 if (hdd_ctx == NULL) {
806 hdd_err("Invalid hdd ctx");
807 return -EINVAL;
808 }
809
Krunal Sonibe766b02016-03-10 13:00:44 -0800810 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800811 hdd_warn("Unsupported in mode %s(%d)",
812 hdd_device_mode_to_string(adapter->device_mode),
813 adapter->device_mode);
814 return -EINVAL;
815 }
816
817 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
818
819 /* if not associated, no need to proceed with reassoc */
820 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800821 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800822 ret = -EINVAL;
823 goto exit;
824 }
825
826 /*
827 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800828 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800829 */
830 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530831 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800832 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800833 channel = pHddStaCtx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834 }
835
836 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530837 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800838 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800839 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840 ret = -EINVAL;
841 goto exit;
842 }
843
844 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700845 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800846 hdd_wma_send_fastreassoc_cmd(adapter,
Naveen Rawat05376ee2016-07-18 16:43:32 -0700847 bssid, (int)channel);
848 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800849 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800850
851 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700852 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530853 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
855 &handoffInfo);
856 }
857exit:
858 return ret;
859}
860
861/**
862 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
863 * @adapter: Adapter upon which the command was received
864 * @command: ASCII text command that was received
865 *
866 * This function parses the v1 REASSOC command with the format
867 *
868 * REASSOC xx:xx:xx:xx:xx:xx CH
869 *
870 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
871 * BSSID and CH is the ASCII representation of the channel. For
872 * example
873 *
874 * REASSOC 00:0a:0b:11:22:33 48
875 *
876 * Return: 0 for success non-zero for failure
877 */
878static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
879{
880 uint8_t channel = 0;
881 tSirMacAddr bssid;
882 int ret;
883
884 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700885 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700886 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700887 else
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700888 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700889
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800890 return ret;
891}
892
893/**
894 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
895 * @adapter: Adapter upon which the command was received
896 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700897 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898 *
899 * This function parses the v2 REASSOC command with the format
900 *
901 * REASSOC <android_wifi_reassoc_params>
902 *
903 * Return: 0 for success non-zero for failure
904 */
905static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
906{
907 struct android_wifi_reassoc_params params;
908 tSirMacAddr bssid;
909 int ret;
910
911 /* The params are located after "REASSOC " */
912 memcpy(&params, command + 8, sizeof(params));
913
914 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700915 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916 ret = -EINVAL;
917 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700918 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800919 }
920 return ret;
921}
922
923/**
924 * hdd_parse_reassoc() - parse the REASSOC command
925 * @adapter: Adapter upon which the command was received
926 * @command: Command that was received
927 *
928 * There are two different versions of the REASSOC command. Version 1
929 * of the command contains a parameter list that is ASCII characters
930 * whereas version 2 contains a combination of ASCII and binary
931 * payload. Determine if a version 1 or a version 2 command is being
932 * parsed by examining the parameters, and then dispatch the parser
933 * that is appropriate for the command.
934 *
935 * Return: 0 for success non-zero for failure
936 */
937static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
938{
939 int ret;
940
941 /* both versions start with "REASSOC "
942 * v1 has a bssid and channel # as an ASCII string
943 * REASSOC xx:xx:xx:xx:xx:xx CH
944 * v2 has a C struct
945 * REASSOC <binary c struct>
946 *
947 * The first field in the v2 struct is also the bssid in ASCII.
948 * But in the case of a v2 message the BSSID is NUL-terminated.
949 * Hence we can peek at that offset to see if this is V1 or V2
950 * REASSOC xx:xx:xx:xx:xx:xx*
951 * 1111111111222222
952 * 01234567890123456789012345
953 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700954 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800955 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700956 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800957 ret = hdd_parse_reassoc_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800958
959 return ret;
960}
961
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962/**
963 * hdd_sendactionframe() - send a userspace-supplied action frame
964 * @adapter: Adapter upon which the command was received
965 * @bssid: BSSID target of the action frame
966 * @channel: Channel upon which to send the frame
967 * @dwell_time: Amount of time to dwell when the frame is sent
968 * @payload_len:Length of the payload
969 * @payload: Payload of the frame
970 *
971 * This function sends a userspace-supplied action frame
972 *
973 * Return: 0 for success non-zero for failure
974 */
975static int
976hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
977 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700978 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800979{
980 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700981 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800982 uint8_t *frame;
983 struct ieee80211_hdr_3addr *hdr;
984 u64 cookie;
985 hdd_station_ctx_t *pHddStaCtx;
986 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800987 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
988 (tpSirMacVendorSpecificFrameHdr) payload;
989#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
990 struct cfg80211_mgmt_tx_params params;
991#endif
992
Krunal Sonibe766b02016-03-10 13:00:44 -0800993 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994 hdd_warn("Unsupported in mode %s(%d)",
995 hdd_device_mode_to_string(adapter->device_mode),
996 adapter->device_mode);
997 return -EINVAL;
998 }
999
1000 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1001 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1002
1003 /* if not associated, no need to send action frame */
1004 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001005 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006 ret = -EINVAL;
1007 goto exit;
1008 }
1009
1010 /*
1011 * if the target bssid is different from currently associated AP,
1012 * then no need to send action frame
1013 */
1014 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301015 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001016 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001017 ret = -EINVAL;
1018 goto exit;
1019 }
1020
1021 chan.center_freq = sme_chn_to_freq(channel);
1022 /* Check if it is specific action frame */
1023 if (pVendorSpecific->category ==
1024 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1025 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001026
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301027 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 /*
1029 * if the channel number is different from operating
1030 * channel then no need to send action frame
1031 */
1032 if (channel != 0) {
1033 if (channel !=
1034 pHddStaCtx->conn_info.operationChannel) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001035 hdd_warn("channel(%d) is different from operating channel(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001036 channel,
1037 pHddStaCtx->conn_info.
1038 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 ret = -EINVAL;
1040 goto exit;
1041 }
1042 /*
1043 * If channel number is specified and same
1044 * as home channel, ensure that action frame
1045 * is sent immediately by cancelling
1046 * roaming scans. Otherwise large dwell times
1047 * may cause long delays in sending action
1048 * frames.
1049 */
1050 sme_abort_roam_scan(hdd_ctx->hHal,
1051 adapter->sessionId);
1052 } else {
1053 /*
1054 * 0 is accepted as current home channel,
1055 * delayed transmission of action frame is ok.
1056 */
1057 chan.center_freq =
1058 sme_chn_to_freq(pHddStaCtx->conn_info.
1059 operationChannel);
1060 }
1061 }
1062 }
1063 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001064 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 ret = -EINVAL;
1066 goto exit;
1067 }
1068
1069 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301070 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001071 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001072 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073 ret = -ENOMEM;
1074 goto exit;
1075 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076
1077 hdr = (struct ieee80211_hdr_3addr *)frame;
1078 hdr->frame_control =
1079 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301080 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1081 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301082 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301083 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1084 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001085
1086#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1087 params.chan = &chan;
1088 params.offchan = 0;
1089 params.wait = dwell_time;
1090 params.buf = frame;
1091 params.len = frame_len;
1092 params.no_cck = 1;
1093 params.dont_wait_for_ack = 1;
1094 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1095#else
1096 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001097 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001099
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001100 dwell_time, frame, frame_len, 1, 1, &cookie);
1101#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1102
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301103 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001104exit:
1105 return ret;
1106}
1107
1108/**
1109 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1110 * SENDACTIONFRAME command
1111 * @adapter: Adapter upon which the command was received
1112 * @command: ASCII text command that was received
1113 *
1114 * This function parses the v1 SENDACTIONFRAME command with the format
1115 *
1116 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1117 *
1118 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1119 * BSSID, CH is the ASCII representation of the channel, DW is the
1120 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1121 * payload. For example
1122 *
1123 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1124 *
1125 * Return: 0 for success non-zero for failure
1126 */
1127static int
1128hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1129{
1130 uint8_t channel = 0;
1131 uint8_t dwell_time = 0;
1132 uint8_t payload_len = 0;
1133 uint8_t *payload = NULL;
1134 tSirMacAddr bssid;
1135 int ret;
1136
1137 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1138 &dwell_time, &payload,
1139 &payload_len);
1140 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001141 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142 } else {
1143 ret = hdd_sendactionframe(adapter, bssid, channel,
1144 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301145 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001146 }
1147
1148 return ret;
1149}
1150
1151/**
1152 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1153 * SENDACTIONFRAME command
1154 * @adapter: Adapter upon which the command was received
1155 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001156 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001157 *
1158 * This function parses the v2 SENDACTIONFRAME command with the format
1159 *
1160 * SENDACTIONFRAME <android_wifi_af_params>
1161 *
1162 * Return: 0 for success non-zero for failure
1163 */
1164static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001165hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1166 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001167{
1168 struct android_wifi_af_params *params;
1169 tSirMacAddr bssid;
1170 int ret;
1171
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001172 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001173 total_len -= 16;
1174 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001175
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001176 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1177 (params->len > total_len)) {
1178 hdd_err("Invalid payload length: %d", params->len);
1179 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001180 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001181
1182 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1183 hdd_err("MAC address parsing failed");
1184 return -EINVAL;
1185 }
1186
1187 if (params->channel < 0 ||
1188 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1189 hdd_err("Invalid channel: %d", params->channel);
1190 return -EINVAL;
1191 }
1192
1193 if (params->dwell_time < 0) {
1194 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1195 return -EINVAL;
1196 }
1197
1198 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1199 params->dwell_time, params->len, params->data);
1200
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001201 return ret;
1202}
1203
1204/**
1205 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1206 * @adapter: Adapter upon which the command was received
1207 * @command: Command that was received
1208 *
1209 * There are two different versions of the SENDACTIONFRAME command.
1210 * Version 1 of the command contains a parameter list that is ASCII
1211 * characters whereas version 2 contains a combination of ASCII and
1212 * binary payload. Determine if a version 1 or a version 2 command is
1213 * being parsed by examining the parameters, and then dispatch the
1214 * parser that is appropriate for the version of the command.
1215 *
1216 * Return: 0 for success non-zero for failure
1217 */
1218static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001219hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1220 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001221{
1222 int ret;
1223
1224 /*
1225 * both versions start with "SENDACTIONFRAME "
1226 * v1 has a bssid and other parameters as an ASCII string
1227 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1228 * v2 has a C struct
1229 * SENDACTIONFRAME <binary c struct>
1230 *
1231 * The first field in the v2 struct is also the bssid in ASCII.
1232 * But in the case of a v2 message the BSSID is NUL-terminated.
1233 * Hence we can peek at that offset to see if this is V1 or V2
1234 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1235 * 111111111122222222223333
1236 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001237 * For both the commands, a valid command must have atleast
1238 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001239 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001240 if (total_len < 34) {
1241 hdd_err("Invalid command (total_len=%d)", total_len);
1242 return -EINVAL;
1243 }
1244
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001245 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001246 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001247 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001248 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249
1250 return ret;
1251}
1252
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253/**
1254 * hdd_parse_channellist() - HDD Parse channel list
1255 * @pValue: Pointer to input channel list
1256 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001257 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001258 * @pNumChannels: Pointer to number of roam scan channels
1259 *
1260 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001261 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1262 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001263 * if the Number of channels (N) does not match with the actual number
1264 * of channels passed then take the minimum of N and count of
1265 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1266 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1267 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1268 * removing duplicate channels from the list
1269 *
1270 * Return: 0 for success non-zero for failure
1271 */
1272static int
1273hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1274 uint8_t *pNumChannels)
1275{
1276 const uint8_t *inPtr = pValue;
1277 int tempInt;
1278 int j = 0;
1279 int v = 0;
1280 char buf[32];
1281
1282 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1283 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001284 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001285 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001286 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001287 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001288
1289 /* remove empty spaces */
1290 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1291 inPtr++;
1292
1293 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001294 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001295 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001296
1297 /* get the first argument ie the number of channels */
1298 v = sscanf(inPtr, "%31s ", buf);
1299 if (1 != v)
1300 return -EINVAL;
1301
1302 v = kstrtos32(buf, 10, &tempInt);
1303 if ((v < 0) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001304 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001306
1307 *pNumChannels = tempInt;
1308
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001309 hdd_debug("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001310
1311 for (j = 0; j < (*pNumChannels); j++) {
1312 /*
1313 * inPtr pointing to the beginning of first space after number
1314 * of channels
1315 */
1316 inPtr = strpbrk(inPtr, " ");
1317 /* no channel list after the number of channels argument */
1318 if (NULL == inPtr) {
1319 if (0 != j) {
1320 *pNumChannels = j;
1321 return 0;
1322 } else {
1323 return -EINVAL;
1324 }
1325 }
1326
1327 /* remove empty space */
1328 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1329 inPtr++;
1330
1331 /*
1332 * no channel list after the number of channels
1333 * argument and spaces
1334 */
1335 if ('\0' == *inPtr) {
1336 if (0 != j) {
1337 *pNumChannels = j;
1338 return 0;
1339 } else {
1340 return -EINVAL;
1341 }
1342 }
1343
1344 v = sscanf(inPtr, "%31s ", buf);
1345 if (1 != v)
1346 return -EINVAL;
1347
1348 v = kstrtos32(buf, 10, &tempInt);
1349 if ((v < 0) ||
1350 (tempInt <= 0) ||
1351 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1352 return -EINVAL;
1353 }
1354 pChannelList[j] = tempInt;
1355
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001356 hdd_debug("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001357 pChannelList[j]);
1358 }
1359
1360 return 0;
1361}
1362
1363/**
1364 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1365 * SETROAMSCANCHANNELS command
1366 * @adapter: Adapter upon which the command was received
1367 * @command: ASCII text command that was received
1368 *
1369 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1370 *
1371 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1372 *
1373 * Where "N" is the ASCII representation of the number of channels and
1374 * C1 thru Cn is the ASCII representation of the channels. For example
1375 *
1376 * SETROAMSCANCHANNELS 4 36 40 44 48
1377 *
1378 * Return: 0 for success non-zero for failure
1379 */
1380static int
1381hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1382 const char *command)
1383{
1384 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1385 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301386 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001387 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1388 int ret;
1389
1390 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1391 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001392 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001393 goto exit;
1394 }
1395
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301396 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001397 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1398 adapter->sessionId, num_chan));
1399
1400 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001401 hdd_err("number of channels (%d) supported exceeded max (%d)",
1402 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001403 ret = -EINVAL;
1404 goto exit;
1405 }
1406
1407 status =
1408 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1409 adapter->sessionId,
1410 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301411 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001412 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001413 ret = -EINVAL;
1414 goto exit;
1415 }
1416exit:
1417 return ret;
1418}
1419
1420/**
1421 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1422 * SETROAMSCANCHANNELS command
1423 * @adapter: Adapter upon which the command was received
1424 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001425 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426 *
1427 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1428 *
1429 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1430 *
1431 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1432 * what follows the space is an array of u08 parameters. For example
1433 *
1434 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1435 *
1436 * Return: 0 for success non-zero for failure
1437 */
1438static int
1439hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1440 const char *command)
1441{
1442 const uint8_t *value;
1443 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1444 uint8_t channel;
1445 uint8_t num_chan;
1446 int i;
1447 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301448 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449 int ret = 0;
1450
1451 /* array of values begins after "SETROAMSCANCHANNELS " */
1452 value = command + 20;
1453
1454 num_chan = *value++;
1455 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001456 hdd_err("number of channels (%d) supported exceeded max (%d)",
1457 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001458 ret = -EINVAL;
1459 goto exit;
1460 }
1461
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301462 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001463 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1464 adapter->sessionId, num_chan));
1465
1466 for (i = 0; i < num_chan; i++) {
1467 channel = *value++;
1468 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001469 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001470 i, channel);
1471 ret = -EINVAL;
1472 goto exit;
1473 }
1474 channel_list[i] = channel;
1475 }
1476 status =
1477 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1478 adapter->sessionId,
1479 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301480 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001481 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001482 ret = -EINVAL;
1483 goto exit;
1484 }
1485exit:
1486 return ret;
1487}
1488
1489/**
1490 * hdd_parse_set_roam_scan_channels() - parse the
1491 * SETROAMSCANCHANNELS command
1492 * @adapter: Adapter upon which the command was received
1493 * @command: Command that was received
1494 *
1495 * There are two different versions of the SETROAMSCANCHANNELS command.
1496 * Version 1 of the command contains a parameter list that is ASCII
1497 * characters whereas version 2 contains a binary payload. Determine
1498 * if a version 1 or a version 2 command is being parsed by examining
1499 * the parameters, and then dispatch the parser that is appropriate for
1500 * the command.
1501 *
1502 * Return: 0 for success non-zero for failure
1503 */
1504static int
1505hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1506{
1507 const char *cursor;
1508 char ch;
1509 bool v1;
1510 int ret;
1511
1512 /* start after "SETROAMSCANCHANNELS " */
1513 cursor = command + 20;
1514
1515 /* assume we have a version 1 command until proven otherwise */
1516 v1 = true;
1517
1518 /* v1 params will only contain ASCII digits and space */
1519 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001520 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001521 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001522 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001523
1524 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001525 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001526 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001527 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001528
1529 return ret;
1530}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001531
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001532#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001533/**
1534 * hdd_parse_plm_cmd() - HDD Parse Plm command
1535 * @pValue: Pointer to input data
1536 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1537 *
1538 * This function parses the plm command passed in the format
1539 * CCXPLMREQ<space><enable><space><dialog_token><space>
1540 * <meas_token><space><num_of_bursts><space><burst_int><space>
1541 * <measu duration><space><burst_len><space><desired_tx_pwr>
1542 * <space><multcast_addr><space><number_of_channels>
1543 * <space><channel_numbers>
1544 *
1545 * Return: 0 for success non-zero for failure
1546 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001547static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001548{
1549 uint8_t *cmdPtr = NULL;
1550 int count, content = 0, ret = 0;
1551 char buf[32];
1552
1553 /* move to argument list */
1554 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1555 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301556 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001557
1558 /* no space after the command */
1559 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301560 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001561
1562 /* remove empty spaces */
1563 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1564 cmdPtr++;
1565
1566 /* START/STOP PLM req */
1567 ret = sscanf(cmdPtr, "%31s ", buf);
1568 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301569 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001570
1571 ret = kstrtos32(buf, 10, &content);
1572 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301573 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574
1575 pPlmRequest->enable = content;
1576 cmdPtr = strpbrk(cmdPtr, " ");
1577
1578 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301579 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580
1581 /* remove empty spaces */
1582 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1583 cmdPtr++;
1584
1585 /* Dialog token of radio meas req containing meas reqIE */
1586 ret = sscanf(cmdPtr, "%31s ", buf);
1587 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301588 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001589
1590 ret = kstrtos32(buf, 10, &content);
1591 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301592 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001593
1594 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001595 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001596 cmdPtr = strpbrk(cmdPtr, " ");
1597
1598 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301599 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001600
1601 /* remove empty spaces */
1602 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1603 cmdPtr++;
1604
1605 /* measurement token of meas req IE */
1606 ret = sscanf(cmdPtr, "%31s ", buf);
1607 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301608 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001609
1610 ret = kstrtos32(buf, 10, &content);
1611 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301612 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613
1614 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001615 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001616
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001617 hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001618 if (pPlmRequest->enable) {
1619
1620 cmdPtr = strpbrk(cmdPtr, " ");
1621
1622 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301623 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001624
1625 /* remove empty spaces */
1626 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1627 cmdPtr++;
1628
1629 /* total number of bursts after which STA stops sending */
1630 ret = sscanf(cmdPtr, "%31s ", buf);
1631 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301632 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001633
1634 ret = kstrtos32(buf, 10, &content);
1635 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301636 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001637
1638 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301639 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001640
1641 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001642 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001643 cmdPtr = strpbrk(cmdPtr, " ");
1644
1645 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301646 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647
1648 /* remove empty spaces */
1649 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1650 cmdPtr++;
1651
1652 /* burst interval in seconds */
1653 ret = sscanf(cmdPtr, "%31s ", buf);
1654 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301655 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001656
1657 ret = kstrtos32(buf, 10, &content);
1658 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301659 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001660
1661 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301662 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001663
1664 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001665 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666 cmdPtr = strpbrk(cmdPtr, " ");
1667
1668 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301669 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670
1671 /* remove empty spaces */
1672 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1673 cmdPtr++;
1674
1675 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1676 ret = sscanf(cmdPtr, "%31s ", buf);
1677 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301678 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001679
1680 ret = kstrtos32(buf, 10, &content);
1681 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301682 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001683
1684 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301685 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686
1687 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001688 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 cmdPtr = strpbrk(cmdPtr, " ");
1690
1691 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301692 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693
1694 /* remove empty spaces */
1695 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1696 cmdPtr++;
1697
1698 /* burst length of PLM bursts */
1699 ret = sscanf(cmdPtr, "%31s ", buf);
1700 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301701 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
1703 ret = kstrtos32(buf, 10, &content);
1704 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301705 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001706
1707 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301708 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709
1710 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001711 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001712 cmdPtr = strpbrk(cmdPtr, " ");
1713
1714 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301715 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716
1717 /* remove empty spaces */
1718 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1719 cmdPtr++;
1720
1721 /* desired tx power for transmission of PLM bursts */
1722 ret = sscanf(cmdPtr, "%31s ", buf);
1723 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301724 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725
1726 ret = kstrtos32(buf, 10, &content);
1727 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301728 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729
1730 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301731 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732
1733 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001734 hdd_debug("desiredTxPwr %d",
1735 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736
Anurag Chouhan6d760662016-02-20 16:05:43 +05301737 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738 cmdPtr = strpbrk(cmdPtr, " ");
1739
1740 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301741 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742
1743 /* remove empty spaces */
1744 while ((SPACE_ASCII_VALUE == *cmdPtr)
1745 && ('\0' != *cmdPtr))
1746 cmdPtr++;
1747
1748 ret = sscanf(cmdPtr, "%31s ", buf);
1749 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301750 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001751
1752 ret = kstrtos32(buf, 16, &content);
1753 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301754 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001755
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001756 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757 }
1758
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001759 hdd_debug("MC addr " MAC_ADDRESS_STR,
1760 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001761
1762 cmdPtr = strpbrk(cmdPtr, " ");
1763
1764 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301765 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766
1767 /* remove empty spaces */
1768 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1769 cmdPtr++;
1770
1771 /* number of channels */
1772 ret = sscanf(cmdPtr, "%31s ", buf);
1773 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301774 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775
1776 ret = kstrtos32(buf, 10, &content);
1777 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301778 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779
1780 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301781 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001782
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001783 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001785 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786
1787 /* Channel numbers */
1788 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1789 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, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001804 if (ret < 0 || content <= 0 ||
1805 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301806 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807
1808 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001809 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001810 }
1811 }
1812 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301813 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001814}
1815#endif
1816
1817#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1818static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1819{
1820 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1821 int rc;
1822
1823 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301824 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001826 hdd_ctx->ext_wow_should_suspend = is_success;
1827 complete(&hdd_ctx->ready_to_extwow);
1828}
1829
1830static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1831 tpSirExtWoWParams arg_params)
1832{
1833 tSirExtWoWParams params;
Jeff Johnson17d62672017-03-27 08:00:11 -07001834 QDF_STATUS qdf_ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1836 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1837 int rc;
1838
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301839 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001840
1841 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1842
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301843 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844 &wlan_hdd_ready_to_extwow,
1845 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301846 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001847 hdd_err("sme_configure_ext_wow returned failure %d",
1848 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001849 return -EPERM;
1850 }
1851
1852 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1853 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1854 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001855 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001856 return -EPERM;
1857 }
1858
Jeff Johnson17d62672017-03-27 08:00:11 -07001859 if (!hdd_ctx->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001860 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001861 return -EPERM;
1862 }
1863
Jeff Johnson17d62672017-03-27 08:00:11 -07001864 if (hdd_ctx->config->extWowGotoSuspend) {
1865 hdd_info("Received ready to ExtWoW. Going to suspend");
1866
1867 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1868 if (rc < 0) {
1869 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1870 rc);
1871 return rc;
1872 }
1873 rc = wlan_hdd_bus_suspend();
1874 if (rc) {
1875 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1876 rc);
1877 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1878 return rc;
1879 }
1880 }
1881
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001882 return 0;
1883}
1884
1885static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1886 int value)
1887{
1888 tSirExtWoWParams params;
1889 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1890 int rc;
1891
1892 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301893 if (rc)
1894 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895
1896 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1897 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001898 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001899 return -EINVAL;
1900 }
1901
1902 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1903 hdd_ctx->is_extwow_app_type1_param_set)
1904 params.type = value;
1905 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1906 hdd_ctx->is_extwow_app_type2_param_set)
1907 params.type = value;
1908 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1909 hdd_ctx->is_extwow_app_type1_param_set &&
1910 hdd_ctx->is_extwow_app_type2_param_set)
1911 params.type = value;
1912 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001913 hdd_err("Set app params before enable it value %d",
1914 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915 return -EINVAL;
1916 }
1917
1918 params.vdev_id = vdev_id;
1919 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1920 (hdd_ctx->config->extWowApp2WakeupPinNumber
1921 << 8);
1922
1923 return hdd_enable_ext_wow(adapter, &params);
1924}
1925
1926static int hdd_set_app_type1_params(tHalHandle hHal,
1927 tpSirAppType1Params arg_params)
1928{
1929 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301930 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001931
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301932 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301934 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1935 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001936 hdd_err("sme_configure_app_type1_params returned failure %d",
1937 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001938 return -EPERM;
1939 }
1940
1941 return 0;
1942}
1943
1944static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
1945 char *arg, int len)
1946{
1947 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1948 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1949 char id[20], password[20];
1950 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001951 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001952
1953 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301954 if (rc)
1955 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001956
1957 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001958 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001959 return -EINVAL;
1960 }
1961
1962 memset(&params, 0, sizeof(tSirAppType1Params));
1963 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05301964 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965
1966 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301967 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001968 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301969 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001971 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001972 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001973 params.identification_id, params.id_length,
1974 params.password, params.pass_length);
1975
1976 return hdd_set_app_type1_params(hHal, &params);
1977}
1978
1979static int hdd_set_app_type2_params(tHalHandle hHal,
1980 tpSirAppType2Params arg_params)
1981{
1982 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301983 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301985 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301987 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
1988 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001989 hdd_err("sme_configure_app_type2_params returned failure %d",
1990 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 return -EPERM;
1992 }
1993
1994 return 0;
1995}
1996
1997static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
1998 char *arg, int len)
1999{
2000 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2001 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2002 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302003 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004 tSirAppType2Params params;
2005 int ret;
2006
2007 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302008 if (ret)
2009 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002010
2011 memset(&params, 0, sizeof(tSirAppType2Params));
2012
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302013 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 -08002014 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2015 (unsigned int *)&params.ip_device_ip,
2016 (unsigned int *)&params.ip_server_ip,
2017 (unsigned int *)&params.tcp_seq,
2018 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302019 (uint16_t *)&params.tcp_src_port,
2020 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021 (unsigned int *)&params.keepalive_init,
2022 (unsigned int *)&params.keepalive_min,
2023 (unsigned int *)&params.keepalive_max,
2024 (unsigned int *)&params.keepalive_inc,
2025 (unsigned int *)&params.tcp_tx_timeout_val,
2026 (unsigned int *)&params.tcp_rx_timeout_val);
2027
2028 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002029 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002030 return -EINVAL;
2031 }
2032
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002033 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
2034 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2035 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002036 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037 return -EINVAL;
2038 }
2039
2040 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2041 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002042 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043 return -EINVAL;
2044 }
2045
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302046 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302047 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048
2049 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302050 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051
2052 params.vdev_id = adapter->sessionId;
2053 params.tcp_src_port = (params.tcp_src_port != 0) ?
2054 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2055 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2056 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2057 params.keepalive_init = (params.keepalive_init != 0) ?
2058 params.keepalive_init : hdd_ctx->config->
2059 extWowApp2KAInitPingInterval;
2060 params.keepalive_min =
2061 (params.keepalive_min != 0) ?
2062 params.keepalive_min :
2063 hdd_ctx->config->extWowApp2KAMinPingInterval;
2064 params.keepalive_max =
2065 (params.keepalive_max != 0) ?
2066 params.keepalive_max :
2067 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2068 params.keepalive_inc =
2069 (params.keepalive_inc != 0) ?
2070 params.keepalive_inc :
2071 hdd_ctx->config->extWowApp2KAIncPingInterval;
2072 params.tcp_tx_timeout_val =
2073 (params.tcp_tx_timeout_val != 0) ?
2074 params.tcp_tx_timeout_val :
2075 hdd_ctx->config->extWowApp2TcpTxTimeout;
2076 params.tcp_rx_timeout_val =
2077 (params.tcp_rx_timeout_val != 0) ?
2078 params.tcp_rx_timeout_val :
2079 hdd_ctx->config->extWowApp2TcpRxTimeout;
2080
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002081 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002082 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2084 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2085 params.keepalive_init, params.keepalive_min,
2086 params.keepalive_max, params.keepalive_inc,
2087 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2088
2089 return hdd_set_app_type2_params(hHal, &params);
2090}
2091#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2092
2093/**
2094 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2095 * @pValue: Pointer to MAXTXPOWER command
2096 * @pDbm: Pointer to tx power
2097 *
2098 * This function parses the MAXTXPOWER command passed in the format
2099 * MAXTXPOWER<space>X(Tx power in dbm)
2100 *
2101 * For example input commands:
2102 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2103 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2104 *
2105 * Return: 0 for success non-zero for failure
2106 */
2107static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2108{
2109 uint8_t *inPtr = pValue;
2110 int tempInt;
2111 int v = 0;
2112 *pTxPower = 0;
2113
2114 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2115 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002116 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002117 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002118 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002119 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002120
2121 /* remove empty spaces */
2122 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2123 inPtr++;
2124
2125 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002126 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002127 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002128
2129 v = kstrtos32(inPtr, 10, &tempInt);
2130
2131 /* Range checking for passed parameter */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002132 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002133 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002134
2135 *pTxPower = tempInt;
2136
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002137 hdd_debug("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002138
2139 return 0;
2140} /* End of hdd_parse_setmaxtxpower_command */
2141
2142static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2143 char *extra, uint8_t n, uint8_t *len)
2144{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002146 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002147 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002148 }
2149
2150 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2151 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2152 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002153 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002154 }
2155 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002156 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2157 (int)pCfg->nActiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002158 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002159 }
2160 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2162 (int)pCfg->nPassiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002163 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002164 }
2165 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2167 (int)pCfg->nPassiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002168 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002169 }
2170 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002171 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2172 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002173 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002174 }
2175
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002176 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002177}
2178
2179static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2180{
2181 tHalHandle hHal;
2182 struct hdd_config *pCfg;
2183 uint8_t *value = command;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302184 tSmeConfigParams *sme_config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002185 int val = 0, temp = 0;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302186 int retval = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002187
2188 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2189 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2190 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002191 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002192 return -EINVAL;
2193 }
2194
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302195 sme_config = qdf_mem_malloc(sizeof(*sme_config));
2196 if (!sme_config) {
2197 hdd_err("failed to allocate memory for sme_config");
2198 return -ENOMEM;
2199 }
2200 qdf_mem_zero(sme_config, sizeof(*sme_config));
2201 sme_get_config_param(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002202
2203 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2204 value = value + 24;
2205 temp = kstrtou32(value, 10, &val);
2206 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2207 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002208 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302209 retval = -EFAULT;
2210 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211 }
2212 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302213 sme_config->csrConfig.nActiveMaxChnTime = val;
2214 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002215 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2216 value = value + 24;
2217 temp = kstrtou32(value, 10, &val);
2218 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2219 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002220 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302221 retval = -EFAULT;
2222 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002223 }
2224 pCfg->nActiveMinChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302225 sme_config->csrConfig.nActiveMinChnTime = val;
2226 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002227 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2228 value = value + 25;
2229 temp = kstrtou32(value, 10, &val);
2230 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2231 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002232 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302233 retval = -EFAULT;
2234 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002235 }
2236 pCfg->nPassiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302237 sme_config->csrConfig.nPassiveMaxChnTime = val;
2238 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002239 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2240 value = value + 25;
2241 temp = kstrtou32(value, 10, &val);
2242 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2243 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002244 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302245 retval = -EFAULT;
2246 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002247 }
2248 pCfg->nPassiveMinChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302249 sme_config->csrConfig.nPassiveMinChnTime = val;
2250 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002251 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2252 value = value + 13;
2253 temp = kstrtou32(value, 10, &val);
2254 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2255 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002256 hdd_err("argument passed for SETDWELLTIME is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302257 retval = -EFAULT;
2258 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002259 }
2260 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302261 sme_config->csrConfig.nActiveMaxChnTime = val;
2262 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002263 } else {
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302264 retval = -EINVAL;
2265 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002266 }
2267
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302268free:
2269 qdf_mem_free(sme_config);
2270 return retval;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002271}
2272
Jeff Johnson253c0c22017-01-23 16:59:38 -08002273struct link_status_priv {
2274 uint8_t link_status;
2275};
2276
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002277static void hdd_get_link_status_cb(uint8_t status, void *context)
2278{
Jeff Johnson253c0c22017-01-23 16:59:38 -08002279 struct hdd_request *request;
2280 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002281
Jeff Johnson253c0c22017-01-23 16:59:38 -08002282 request = hdd_request_get(context);
2283 if (!request) {
2284 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002285 return;
2286 }
2287
Jeff Johnson253c0c22017-01-23 16:59:38 -08002288 priv = hdd_request_priv(request);
2289 priv->link_status = status;
2290 hdd_request_complete(request);
2291 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002292}
2293
2294/**
2295 * wlan_hdd_get_link_status() - get link status
2296 * @pAdapter: pointer to the adapter
2297 *
2298 * This function sends a request to query the link status and waits
2299 * on a timer to invoke the callback. if the callback is invoked then
2300 * latest link status shall be returned or otherwise cached value
2301 * will be returned.
2302 *
2303 * Return: On success, link status shall be returned.
2304 * On error or not associated, link status 0 will be returned.
2305 */
2306static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2307{
2308
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002309 hdd_station_ctx_t *pHddStaCtx =
2310 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302311 QDF_STATUS hstatus;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002312 int ret;
2313 void *cookie;
2314 struct hdd_request *request;
2315 struct link_status_priv *priv;
2316 static const struct hdd_request_params params = {
2317 .priv_size = sizeof(*priv),
2318 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2319 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002320
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05302321 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002322 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2323 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002324 return 0;
2325 }
2326
Krunal Sonibe766b02016-03-10 13:00:44 -08002327 if ((QDF_STA_MODE != adapter->device_mode) &&
2328 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329 hdd_warn("Unsupported in mode %s(%d)",
2330 hdd_device_mode_to_string(adapter->device_mode),
2331 adapter->device_mode);
2332 return 0;
2333 }
2334
2335 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2336 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2337 /* If not associated, then expected link status return
2338 * value is 0
2339 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002340 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002341 return 0;
2342 }
2343
Jeff Johnson253c0c22017-01-23 16:59:38 -08002344 request = hdd_request_alloc(&params);
2345 if (!request) {
2346 hdd_err("Request allocation failure");
2347 return 0;
2348 }
2349 cookie = hdd_request_cookie(request);
2350
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002351 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2352 hdd_get_link_status_cb,
Jeff Johnson253c0c22017-01-23 16:59:38 -08002353 cookie, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302354 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002355 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002356 /* return a cached value */
2357 } else {
2358 /* request is sent -- wait for the response */
Jeff Johnson253c0c22017-01-23 16:59:38 -08002359 ret = hdd_request_wait_for_response(request);
2360 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002361 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002362 /* return a cached value */
2363 } else {
2364 /* update the adapter with the fresh results */
2365 priv = hdd_request_priv(request);
2366 adapter->linkStatus = priv->link_status;
2367 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002368 }
2369
Jeff Johnson253c0c22017-01-23 16:59:38 -08002370 /*
2371 * either we never sent a request, we sent a request and
2372 * received a response or we sent a request and timed out.
2373 * regardless we are done with the request.
2374 */
2375 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002376
2377 /* either callback updated adapter stats or it has cached data */
2378 return adapter->linkStatus;
2379}
2380
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002381static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2382{
2383 int payload_len;
2384 struct sk_buff *skb;
2385 struct nlmsghdr *nlh;
2386 uint8_t *data;
2387
2388 payload_len = ETH_ALEN;
2389
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002390 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002391 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002392 return;
2393 }
2394
2395 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2396 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002397 hdd_err("nlmsg_new() failed for msg size[%d]",
2398 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002399 return;
2400 }
2401
2402 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2403
2404 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002405 hdd_err("nlmsg_put() failed for msg size[%d]",
2406 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002407
2408 kfree_skb(skb);
2409 return;
2410 }
2411
2412 data = nlmsg_data(nlh);
2413 memcpy(data, MacAddr, ETH_ALEN);
2414
2415 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002416 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2417 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002418 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002419}
2420
2421
2422/**
2423 * hdd_ParseuserParams - return a pointer to the next argument
2424 * @pValue: Input argument string
2425 * @ppArg: Output pointer to the next argument
2426 *
2427 * This function parses argument stream and finds the pointer
2428 * to the next argument
2429 *
2430 * Return: 0 if the next argument found; -EINVAL otherwise
2431 */
2432static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2433{
2434 uint8_t *pVal;
2435
2436 pVal = strnchr(pValue, strlen(pValue), ' ');
2437
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002438 if (NULL == pVal) /* no argument remains */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002439 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002440 else if (SPACE_ASCII_VALUE != *pVal)/* no space after the current arg */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002441 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002442
2443 pVal++;
2444
2445 /* remove empty spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002446 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002447 pVal++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002448
2449 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002450 if ('\0' == *pVal)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002451 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002452
2453 *ppArg = pVal;
2454
2455 return 0;
2456}
2457
2458/**
2459 * hdd_parse_ibsstx_fail_event_params - Parse params
2460 * for SETIBSSTXFAILEVENT
2461 * @pValue: Input ibss tx fail event argument
2462 * @tx_fail_count: (Output parameter) Tx fail counter
2463 * @pid: (Output parameter) PID
2464 *
2465 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2466 */
2467static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2468 uint8_t *tx_fail_count,
2469 uint16_t *pid)
2470{
2471 uint8_t *param = NULL;
2472 int ret;
2473
2474 ret = hdd_parse_user_params(pValue, &param);
2475
2476 if (0 == ret && NULL != param) {
2477 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2478 ret = -EINVAL;
2479 goto done;
2480 }
2481 } else {
2482 goto done;
2483 }
2484
2485 if (0 == *tx_fail_count) {
2486 *pid = 0;
2487 goto done;
2488 }
2489
2490 pValue = param;
2491 pValue++;
2492
2493 ret = hdd_parse_user_params(pValue, &param);
2494
2495 if (0 == ret) {
2496 if (1 != sscanf(param, "%hu", pid)) {
2497 ret = -EINVAL;
2498 goto done;
2499 }
2500 } else {
2501 goto done;
2502 }
2503
2504done:
2505 return ret;
2506}
2507
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002508#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002509/**
2510 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2511 * @pValue: Pointer to data
2512 * @pEseBcnReq: Output pointer to store parsed ie information
2513 *
2514 * This function parses the ese beacon request passed in the format
2515 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2516 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2517 * <space>Scan Mode N<space>Meas Duration N
2518 *
2519 * If the Number of bcn req fields (N) does not match with the
2520 * actual number of fields passed then take N.
2521 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2522 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2523 * This function does not take care of removing duplicate channels from the
2524 * list
2525 *
2526 * Return: 0 for success non-zero for failure
2527 */
2528static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2529 tCsrEseBeaconReq *pEseBcnReq)
2530{
2531 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002532 uint8_t input = 0;
2533 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002534 int j = 0, i = 0, v = 0;
2535 char buf[32];
2536
2537 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002538 if (NULL == inPtr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002539 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002540 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002541 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002542
2543 /* remove empty spaces */
2544 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2545 inPtr++;
2546
2547 /* no argument followed by spaces */
2548 if ('\0' == *inPtr)
2549 return -EINVAL;
2550
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002551 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002552 v = sscanf(inPtr, "%31s ", buf);
2553 if (1 != v)
2554 return -EINVAL;
2555
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002556 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002557 if (v < 0)
2558 return -EINVAL;
2559
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002560 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2561 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002562
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002563 hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002564
2565 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2566 for (i = 0; i < 4; i++) {
2567 /*
2568 * inPtr pointing to the beginning of 1st space
2569 * after number of ie fields
2570 */
2571 inPtr = strpbrk(inPtr, " ");
2572 /* no ie data after the number of ie fields argument */
2573 if (NULL == inPtr)
2574 return -EINVAL;
2575
2576 /* remove empty space */
2577 while ((SPACE_ASCII_VALUE == *inPtr)
2578 && ('\0' != *inPtr))
2579 inPtr++;
2580
2581 /*
2582 * no ie data after the number of ie fields
2583 * argument and spaces
2584 */
2585 if ('\0' == *inPtr)
2586 return -EINVAL;
2587
2588 v = sscanf(inPtr, "%31s ", buf);
2589 if (1 != v)
2590 return -EINVAL;
2591
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002592 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002593 if (v < 0)
2594 return -EINVAL;
2595
2596 switch (i) {
2597 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002598 if (!tempInt) {
2599 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002600 tempInt);
2601 return -EINVAL;
2602 }
2603 pEseBcnReq->bcnReq[j].measurementToken =
2604 tempInt;
2605 break;
2606
2607 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002608 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002609 (tempInt >
2610 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002611 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612 tempInt);
2613 return -EINVAL;
2614 }
2615 pEseBcnReq->bcnReq[j].channel = tempInt;
2616 break;
2617
2618 case 2: /* Scan mode */
2619 if ((tempInt < eSIR_PASSIVE_SCAN)
2620 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002621 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002622 tempInt);
2623 return -EINVAL;
2624 }
2625 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2626 break;
2627
2628 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002629 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002630 && (pEseBcnReq->bcnReq[j].scanMode !=
2631 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002632 (pEseBcnReq->bcnReq[j].scanMode ==
2633 eSIR_BEACON_TABLE)) {
2634 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002635 tempInt);
2636 return -EINVAL;
2637 }
2638 pEseBcnReq->bcnReq[j].measurementDuration =
2639 tempInt;
2640 break;
2641 }
2642 }
2643 }
2644
2645 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002646 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002647 j,
2648 pEseBcnReq->bcnReq[j].measurementToken,
2649 pEseBcnReq->bcnReq[j].channel,
2650 pEseBcnReq->bcnReq[j].scanMode,
2651 pEseBcnReq->bcnReq[j].measurementDuration);
2652 }
2653
2654 return 0;
2655}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002656
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002657/**
2658 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2659 * @pValue: Pointer to input data
2660 * @pCckmIe: Pointer to output cckm Ie
2661 * @pCckmIeLen: Pointer to output cckm ie length
2662 *
2663 * This function parses the SETCCKM IE command
2664 * SETCCKMIE<space><ie data>
2665 *
2666 * Return: 0 for success non-zero for failure
2667 */
2668static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2669 uint8_t *pCckmIeLen)
2670{
2671 uint8_t *inPtr = pValue;
2672 uint8_t *dataEnd;
2673 int j = 0;
2674 int i = 0;
2675 uint8_t tempByte = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002676
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002677 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2678 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002679 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002680 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002681 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002682 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002683
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002684 /* remove empty spaces */
2685 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2686 inPtr++;
2687 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002688 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002689 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002690
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002691 /* find the length of data */
2692 dataEnd = inPtr;
2693 while (('\0' != *dataEnd)) {
2694 dataEnd++;
2695 ++(*pCckmIeLen);
2696 }
2697 if (*pCckmIeLen <= 0)
2698 return -EINVAL;
2699 /*
2700 * Allocate the number of bytes based on the number of input characters
2701 * whether it is even or odd.
2702 * if the number of input characters are even, then we need N / 2 byte.
2703 * if the number of input characters are odd, then we need do
2704 * (N + 1) / 2 to compensate rounding off.
2705 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2706 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2707 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302708 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002709 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002710 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002711 return -ENOMEM;
2712 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002713 /*
2714 * the buffer received from the upper layer is character buffer,
2715 * we need to prepare the buffer taking 2 characters in to a U8 hex
2716 * decimal number for example 7f0000f0...form a buffer to contain
2717 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2718 */
2719 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2720 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2721 (hex_to_bin(inPtr[j + 1]));
2722 (*pCckmIe)[i++] = tempByte;
2723 }
2724 *pCckmIeLen = i;
2725 return 0;
2726}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002727#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002728
2729int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2730{
2731 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302732 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002733 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2734 struct hdd_config *pConfig = NULL;
2735
2736 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002737 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002738 return -EINVAL;
2739 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002740 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2741 (QDF_SAP_MODE != pAdapter->device_mode) &&
2742 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002743 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2744 hdd_device_mode_to_string(pAdapter->device_mode),
2745 pAdapter->device_mode);
2746 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002747 return -EINVAL;
2748 }
2749 pConfig = pHddCtx->config;
2750 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2751 rateUpdate.dev_mode = pAdapter->device_mode;
2752 rateUpdate.mcastDataRate24GHz = targetRate;
2753 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2754 rateUpdate.mcastDataRate5GHz = targetRate;
2755 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302756 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002757 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002758 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2759 hdd_device_mode_to_string(pAdapter->device_mode),
2760 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002761 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302762 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002763 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002764 return -EFAULT;
2765 }
2766 return 0;
2767}
2768
2769static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2770 hdd_context_t *hdd_ctx,
2771 uint8_t *command,
2772 uint8_t command_len,
2773 hdd_priv_data_t *priv_data)
2774{
2775 int ret = 0;
2776
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302777 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002778 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2779 adapter->sessionId,
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002780 (unsigned int)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002781 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2782 + 3) << 16 | *(hdd_ctx->
2783 p2pDeviceAddress.bytes + 4) << 8 |
2784 *(hdd_ctx->p2pDeviceAddress.bytes +
2785 5))));
2786
2787 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2788 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002789 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002790 ret = -EFAULT;
2791 }
2792
2793 return ret;
2794}
2795
2796/**
2797 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2798 * @adapter: Adapter on which the command was received
2799 * @hdd_ctx: HDD global context
2800 * @command: Entire driver command received from userspace
2801 * @command_len: Length of @command
2802 * @priv_data: Pointer to ioctl private data structure
2803 *
2804 * This is a trivial command hander function which simply forwards the
2805 * command to the actual command processor within the P2P module.
2806 *
2807 * Return: 0 on success, non-zero on failure
2808 */
2809static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2810 hdd_context_t *hdd_ctx,
2811 uint8_t *command,
2812 uint8_t command_len,
2813 hdd_priv_data_t *priv_data)
2814{
2815 return hdd_set_p2p_noa(adapter->dev, command);
2816}
2817
2818/**
2819 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2820 * @adapter: Adapter on which the command was received
2821 * @hdd_ctx: HDD global context
2822 * @command: Entire driver command received from userspace
2823 * @command_len: Length of @command
2824 * @priv_data: Pointer to ioctl private data structure
2825 *
2826 * This is a trivial command hander function which simply forwards the
2827 * command to the actual command processor within the P2P module.
2828 *
2829 * Return: 0 on success, non-zero on failure
2830 */
2831static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2832 hdd_context_t *hdd_ctx,
2833 uint8_t *command,
2834 uint8_t command_len,
2835 hdd_priv_data_t *priv_data)
2836{
2837 return hdd_set_p2p_opps(adapter->dev, command);
2838}
2839
2840static int drv_cmd_set_band(hdd_adapter_t *adapter,
2841 hdd_context_t *hdd_ctx,
2842 uint8_t *command,
2843 uint8_t command_len,
2844 hdd_priv_data_t *priv_data)
2845{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002846 int err;
2847 uint8_t band;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002848
2849 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002850 * Parse the band value passed from userspace. The first 8 bytes
2851 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002852 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002853 err = kstrtou8(command + command_len + 1, 10, &band);
2854 if (err) {
2855 hdd_err("error %d parsing userspace band parameter", err);
2856 return err;
2857 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002858
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002859 return hdd_reg_set_band(adapter->dev, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002860}
2861
2862static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2863 hdd_context_t *hdd_ctx,
2864 uint8_t *command,
2865 uint8_t command_len,
2866 hdd_priv_data_t *priv_data)
2867{
2868 return hdd_wmmps_helper(adapter, command);
2869}
2870
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002871static inline int drv_cmd_country(hdd_adapter_t *adapter,
2872 hdd_context_t *hdd_ctx,
2873 uint8_t *command,
2874 uint8_t command_len,
2875 hdd_priv_data_t *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002876{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002877 return hdd_reg_set_country(hdd_ctx, command + command_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002878}
2879
2880static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
2881 hdd_context_t *hdd_ctx,
2882 uint8_t *command,
2883 uint8_t command_len,
2884 hdd_priv_data_t *priv_data)
2885{
2886 int ret = 0;
2887 uint8_t *value = command;
2888 int8_t rssi = 0;
2889 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302890 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002891
2892 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2893 value = value + command_len + 1;
2894
2895 /* Convert the value from ascii to integer */
2896 ret = kstrtos8(value, 10, &rssi);
2897 if (ret < 0) {
2898 /*
2899 * If the input value is greater than max value of datatype,
2900 * then also kstrtou8 fails
2901 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002902 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2903 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2904 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002905 ret = -EINVAL;
2906 goto exit;
2907 }
2908
2909 lookUpThreshold = abs(rssi);
2910
2911 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
2912 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002913 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002914 lookUpThreshold,
2915 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2916 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
2917 ret = -EINVAL;
2918 goto exit;
2919 }
2920
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302921 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002922 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
2923 adapter->sessionId, lookUpThreshold));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002924 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002925 lookUpThreshold);
2926
2927 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
2928 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
2929 adapter->sessionId,
2930 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302931 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002932 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002933 ret = -EPERM;
2934 goto exit;
2935 }
2936
2937exit:
2938 return ret;
2939}
2940
2941static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
2942 hdd_context_t *hdd_ctx,
2943 uint8_t *command,
2944 uint8_t command_len,
2945 hdd_priv_data_t *priv_data)
2946{
2947 int ret = 0;
2948 uint8_t lookUpThreshold =
2949 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
2950 int rssi = (-1) * lookUpThreshold;
2951 char extra[32];
2952 uint8_t len = 0;
2953
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302954 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002955 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
2956 adapter->sessionId, lookUpThreshold));
2957
2958 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05302959 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002960 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002961 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002962 ret = -EFAULT;
2963 }
2964
2965 return ret;
2966}
2967
2968static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
2969 hdd_context_t *hdd_ctx,
2970 uint8_t *command,
2971 uint8_t command_len,
2972 hdd_priv_data_t *priv_data)
2973{
2974 int ret = 0;
2975 uint8_t *value = command;
2976 uint8_t roamScanPeriod = 0;
2977 uint16_t neighborEmptyScanRefreshPeriod =
2978 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
2979
2980 /* input refresh period is in terms of seconds */
2981
2982 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
2983 value = value + command_len + 1;
2984
2985 /* Convert the value from ascii to integer */
2986 ret = kstrtou8(value, 10, &roamScanPeriod);
2987 if (ret < 0) {
2988 /*
2989 * If the input value is greater than max value of datatype,
2990 * then also kstrtou8 fails
2991 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002992 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2993 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
2994 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002995 ret = -EINVAL;
2996 goto exit;
2997 }
2998
2999 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3000 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003001 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3002 roamScanPeriod,
3003 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3004 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003005 ret = -EINVAL;
3006 goto exit;
3007 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303008 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003009 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3010 adapter->sessionId, roamScanPeriod));
3011 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3012
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003013 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014 roamScanPeriod);
3015
3016 hdd_ctx->config->nEmptyScanRefreshPeriod =
3017 neighborEmptyScanRefreshPeriod;
3018 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3019 adapter->sessionId,
3020 neighborEmptyScanRefreshPeriod);
3021
3022exit:
3023 return ret;
3024}
3025
3026static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3027 hdd_context_t *hdd_ctx,
3028 uint8_t *command,
3029 uint8_t command_len,
3030 hdd_priv_data_t *priv_data)
3031{
3032 int ret = 0;
3033 uint16_t nEmptyScanRefreshPeriod =
3034 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3035 char extra[32];
3036 uint8_t len = 0;
3037
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303038 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003039 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3040 adapter->sessionId,
3041 nEmptyScanRefreshPeriod));
3042 len = scnprintf(extra, sizeof(extra), "%s %d",
3043 "GETROAMSCANPERIOD",
3044 (nEmptyScanRefreshPeriod / 1000));
3045 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303046 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003047 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003048 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003049 ret = -EFAULT;
3050 }
3051
3052 return ret;
3053}
3054
3055static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3056 hdd_context_t *hdd_ctx,
3057 uint8_t *command,
3058 uint8_t command_len,
3059 hdd_priv_data_t *priv_data)
3060{
3061 int ret = 0;
3062 uint8_t *value = command;
3063 uint8_t roamScanRefreshPeriod = 0;
3064 uint16_t neighborScanRefreshPeriod =
3065 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3066
3067 /* input refresh period is in terms of seconds */
3068 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3069 value = value + command_len + 1;
3070
3071 /* Convert the value from ascii to integer */
3072 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3073 if (ret < 0) {
3074 /*
3075 * If the input value is greater than max value of datatype,
3076 * then also kstrtou8 fails
3077 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003078 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3079 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3080 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003081 ret = -EINVAL;
3082 goto exit;
3083 }
3084
3085 if ((roamScanRefreshPeriod <
3086 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3087 || (roamScanRefreshPeriod >
3088 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003089 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3090 roamScanRefreshPeriod,
3091 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3092 / 1000),
3093 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3094 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003095 ret = -EINVAL;
3096 goto exit;
3097 }
3098 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3099
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003100 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101 roamScanRefreshPeriod);
3102
3103 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3104 neighborScanRefreshPeriod;
3105 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3106 adapter->sessionId,
3107 neighborScanRefreshPeriod);
3108
3109exit:
3110 return ret;
3111}
3112
3113static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3114 hdd_context_t *hdd_ctx,
3115 uint8_t *command,
3116 uint8_t command_len,
3117 hdd_priv_data_t *priv_data)
3118{
3119 int ret = 0;
3120 uint16_t value =
3121 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3122 char extra[32];
3123 uint8_t len = 0;
3124
3125 len = scnprintf(extra, sizeof(extra), "%s %d",
3126 "GETROAMSCANREFRESHPERIOD",
3127 (value / 1000));
3128 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303129 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003130 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003131 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003132 ret = -EFAULT;
3133 }
3134
3135 return ret;
3136}
3137
3138static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3139 hdd_context_t *hdd_ctx,
3140 uint8_t *command,
3141 uint8_t command_len,
3142 hdd_priv_data_t *priv_data)
3143{
3144 int ret = 0;
3145 uint8_t *value = command;
3146 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3147
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003148 if (!adapter->fast_roaming_allowed) {
3149 hdd_err("Roaming is always disabled on this interface");
3150 goto exit;
3151 }
3152
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003153 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3154 value = value + SIZE_OF_SETROAMMODE + 1;
3155
3156 /* Convert the value from ascii to integer */
3157 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3158 if (ret < 0) {
3159 /*
3160 * If the input value is greater than max value of datatype,
3161 * then also kstrtou8 fails
3162 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003163 hdd_err("kstrtou8 failed range [%d - %d]",
3164 CFG_LFR_FEATURE_ENABLED_MIN,
3165 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003166 ret = -EINVAL;
3167 goto exit;
3168 }
3169 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3170 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003171 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3172 roamMode,
3173 CFG_LFR_FEATURE_ENABLED_MIN,
3174 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003175 ret = -EINVAL;
3176 goto exit;
3177 }
3178
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003179 hdd_debug("Received Command to Set Roam Mode = %d",
3180 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003181 /*
3182 * Note that
3183 * SETROAMMODE 0 is to enable LFR while
3184 * SETROAMMODE 1 is to disable LFR, but
3185 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3186 * enable/disable. So, we have to invert the value
3187 * to call sme_update_is_fast_roam_ini_feature_enabled.
3188 */
3189 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3190 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3191 else
3192 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3193
3194 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3195 if (roamMode) {
3196 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3197 sme_update_roam_scan_offload_enabled(
3198 (tHalHandle)(hdd_ctx->hHal),
3199 hdd_ctx->config->isRoamOffloadScanEnabled);
3200 sme_update_is_fast_roam_ini_feature_enabled(
3201 hdd_ctx->hHal,
3202 adapter->sessionId,
3203 roamMode);
3204 } else {
3205 sme_update_is_fast_roam_ini_feature_enabled(
3206 hdd_ctx->hHal,
3207 adapter->sessionId,
3208 roamMode);
3209 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3210 sme_update_roam_scan_offload_enabled(
3211 (tHalHandle)(hdd_ctx->hHal),
3212 hdd_ctx->config->isRoamOffloadScanEnabled);
3213 }
3214
3215
3216exit:
3217 return ret;
3218}
3219
3220static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3221 hdd_context_t *hdd_ctx,
3222 uint8_t *command,
3223 uint8_t command_len,
3224 hdd_priv_data_t *priv_data)
3225{
3226 int ret = 0;
3227 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3228 char extra[32];
3229 uint8_t len = 0;
3230
3231 /*
3232 * roamMode value shall be inverted because the sementics is different.
3233 */
3234 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3235 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3236 else
3237 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3238
3239 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303240 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003241 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003242 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003243 ret = -EFAULT;
3244 }
3245
3246 return ret;
3247}
3248
3249static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3250 hdd_context_t *hdd_ctx,
3251 uint8_t *command,
3252 uint8_t command_len,
3253 hdd_priv_data_t *priv_data)
3254{
3255 int ret = 0;
3256 uint8_t *value = command;
3257 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3258
3259 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3260 value = value + command_len + 1;
3261
3262 /* Convert the value from ascii to integer */
3263 ret = kstrtou8(value, 10, &roamRssiDiff);
3264 if (ret < 0) {
3265 /*
3266 * If the input value is greater than max value of datatype,
3267 * then also kstrtou8 fails
3268 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003269 hdd_err("kstrtou8 failed range [%d - %d]",
3270 CFG_ROAM_RSSI_DIFF_MIN,
3271 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272 ret = -EINVAL;
3273 goto exit;
3274 }
3275
3276 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3277 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003278 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3279 roamRssiDiff,
3280 CFG_ROAM_RSSI_DIFF_MIN,
3281 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003282 ret = -EINVAL;
3283 goto exit;
3284 }
3285
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003286 hdd_debug("Received Command to Set roam rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003287 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003288
3289 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3290 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3291 adapter->sessionId,
3292 roamRssiDiff);
3293
3294exit:
3295 return ret;
3296}
3297
3298static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3299 hdd_context_t *hdd_ctx,
3300 uint8_t *command,
3301 uint8_t command_len,
3302 hdd_priv_data_t *priv_data)
3303{
3304 int ret = 0;
3305 uint8_t roamRssiDiff =
3306 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3307 char extra[32];
3308 uint8_t len = 0;
3309
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303310 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003311 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3312 adapter->sessionId, roamRssiDiff));
3313
3314 len = scnprintf(extra, sizeof(extra), "%s %d",
3315 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303316 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003317
3318 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003319 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003320 ret = -EFAULT;
3321 }
3322
3323 return ret;
3324}
3325
3326static int drv_cmd_get_band(hdd_adapter_t *adapter,
3327 hdd_context_t *hdd_ctx,
3328 uint8_t *command,
3329 uint8_t command_len,
3330 hdd_priv_data_t *priv_data)
3331{
3332 int ret = 0;
3333 int band = -1;
3334 char extra[32];
3335 uint8_t len = 0;
3336
3337 hdd_get_band_helper(hdd_ctx, &band);
3338
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303339 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003340 TRACE_CODE_HDD_GETBAND_IOCTL,
3341 adapter->sessionId, band));
3342
3343 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303344 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003345
3346 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003347 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003348 ret = -EFAULT;
3349 }
3350
3351 return ret;
3352}
3353
3354static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3355 hdd_context_t *hdd_ctx,
3356 uint8_t *command,
3357 uint8_t command_len,
3358 hdd_priv_data_t *priv_data)
3359{
3360 return hdd_parse_set_roam_scan_channels(adapter, command);
3361}
3362
3363static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3364 hdd_context_t *hdd_ctx,
3365 uint8_t *command,
3366 uint8_t command_len,
3367 hdd_priv_data_t *priv_data)
3368{
3369 int ret = 0;
3370 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3371 uint8_t numChannels = 0;
3372 uint8_t j = 0;
3373 char extra[128] = { 0 };
3374 int len;
3375
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303376 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003377 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3378 ChannelList,
3379 &numChannels,
3380 adapter->sessionId)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003381 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003382 ret = -EFAULT;
3383 goto exit;
3384 }
3385
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303386 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003387 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3388 adapter->sessionId, numChannels));
3389 /*
3390 * output channel list is of the format
3391 * [Number of roam scan channels][Channel1][Channel2]...
3392 * copy the number of channels in the 0th index
3393 */
3394 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3395 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303396 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003397 len += scnprintf(extra + len, sizeof(extra) - len,
3398 " %d", ChannelList[j]);
3399
Anurag Chouhan6d760662016-02-20 16:05:43 +05303400 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003401 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003402 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403 ret = -EFAULT;
3404 goto exit;
3405 }
3406
3407exit:
3408 return ret;
3409}
3410
3411static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3412 hdd_context_t *hdd_ctx,
3413 uint8_t *command,
3414 uint8_t command_len,
3415 hdd_priv_data_t *priv_data)
3416{
3417 int ret = 0;
3418 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3419 char extra[32];
3420 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003421 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003422
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003423 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003424 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003425 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003426 * then this operation is not permitted (return FAILURE)
3427 */
3428 if (eseMode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003429 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003430 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003431 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003432 ret = -EPERM;
3433 goto exit;
3434 }
3435
3436 len = scnprintf(extra, sizeof(extra), "%s %d",
3437 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303438 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003439 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003440 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003441 ret = -EFAULT;
3442 goto exit;
3443 }
3444
3445exit:
3446 return ret;
3447}
3448
3449static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3450 hdd_context_t *hdd_ctx,
3451 uint8_t *command,
3452 uint8_t command_len,
3453 hdd_priv_data_t *priv_data)
3454{
3455 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003456 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457 char extra[32];
3458 uint8_t len = 0;
3459
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003460 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003461 /*
3462 * Check if the features OKC/ESE/11R are supported simultaneously,
3463 * then this operation is not permitted (return FAILURE)
3464 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003465 if (pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003466 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3467 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003468 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003469 ret = -EPERM;
3470 goto exit;
3471 }
3472
3473 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003474 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303475 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003476
3477 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003478 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479 ret = -EFAULT;
3480 goto exit;
3481 }
3482
3483exit:
3484 return ret;
3485}
3486
3487static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3488 hdd_context_t *hdd_ctx,
3489 uint8_t *command,
3490 uint8_t command_len,
3491 hdd_priv_data_t *priv_data)
3492{
3493 int ret = 0;
3494 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3495 char extra[32];
3496 uint8_t len = 0;
3497
3498 len = scnprintf(extra, sizeof(extra), "%s %d",
3499 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303500 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003501
3502 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003503 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003504 ret = -EFAULT;
3505 }
3506
3507 return ret;
3508}
3509
3510static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3511 hdd_context_t *hdd_ctx,
3512 uint8_t *command,
3513 uint8_t command_len,
3514 hdd_priv_data_t *priv_data)
3515{
3516 int ret = 0;
3517 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3518 char extra[32];
3519 uint8_t len = 0;
3520
3521 len = scnprintf(extra, sizeof(extra), "%s %d",
3522 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303523 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524
3525 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003526 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003527 ret = -EFAULT;
3528 }
3529
3530 return ret;
3531}
3532
3533static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3534 hdd_context_t *hdd_ctx,
3535 uint8_t *command,
3536 uint8_t command_len,
3537 hdd_priv_data_t *priv_data)
3538{
3539 int ret = 0;
3540 uint8_t *value = command;
3541 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3542
3543 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3544 value = value + command_len + 1;
3545
3546 /* Convert the value from ascii to integer */
3547 ret = kstrtou8(value, 10, &minTime);
3548 if (ret < 0) {
3549 /*
3550 * If the input value is greater than max value of datatype,
3551 * then also kstrtou8 fails
3552 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003553 hdd_err("kstrtou8 failed range [%d - %d]",
3554 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3555 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003556 ret = -EINVAL;
3557 goto exit;
3558 }
3559
3560 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3561 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003562 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3563 minTime,
3564 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3565 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003566 ret = -EINVAL;
3567 goto exit;
3568 }
3569
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303570 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003571 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3572 adapter->sessionId, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003573 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003574 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003575
3576 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3577 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3578 minTime,
3579 adapter->sessionId);
3580
3581exit:
3582 return ret;
3583}
3584
3585static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3586 hdd_context_t *hdd_ctx,
3587 uint8_t *command,
3588 uint8_t command_len,
3589 hdd_priv_data_t *priv_data)
3590{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003591 return hdd_parse_sendactionframe(adapter, command,
3592 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003593}
3594
3595static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3596 hdd_context_t *hdd_ctx,
3597 uint8_t *command,
3598 uint8_t command_len,
3599 hdd_priv_data_t *priv_data)
3600{
3601 int ret = 0;
3602 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3603 adapter->sessionId);
3604 char extra[32];
3605 uint8_t len = 0;
3606
3607 /* value is interms of msec */
3608 len = scnprintf(extra, sizeof(extra), "%s %d",
3609 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303610 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003611
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303612 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3614 adapter->sessionId, val));
3615
3616 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003617 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003618 ret = -EFAULT;
3619 }
3620
3621 return ret;
3622}
3623
3624static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3625 hdd_context_t *hdd_ctx,
3626 uint8_t *command,
3627 uint8_t command_len,
3628 hdd_priv_data_t *priv_data)
3629{
3630 int ret = 0;
3631 uint8_t *value = command;
3632 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3633
3634 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3635 value = value + command_len + 1;
3636
3637 /* Convert the value from ascii to integer */
3638 ret = kstrtou16(value, 10, &maxTime);
3639 if (ret < 0) {
3640 /*
3641 * If the input value is greater than max value of datatype,
3642 * then also kstrtou8 fails
3643 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003644 hdd_err("kstrtou16 failed range [%d - %d]",
3645 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3646 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003647 ret = -EINVAL;
3648 goto exit;
3649 }
3650
3651 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3652 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003653 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3654 maxTime,
3655 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3656 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003657 ret = -EINVAL;
3658 goto exit;
3659 }
3660
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003661 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003662 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003663
3664 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3665 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3666 adapter->sessionId,
3667 maxTime);
3668
3669exit:
3670 return ret;
3671}
3672
3673static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3674 hdd_context_t *hdd_ctx,
3675 uint8_t *command,
3676 uint8_t command_len,
3677 hdd_priv_data_t *priv_data)
3678{
3679 int ret = 0;
3680 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3681 adapter->sessionId);
3682 char extra[32];
3683 uint8_t len = 0;
3684
3685 /* value is interms of msec */
3686 len = scnprintf(extra, sizeof(extra), "%s %d",
3687 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303688 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003689
3690 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003691 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003692 ret = -EFAULT;
3693 }
3694
3695 return ret;
3696}
3697
3698static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3699 hdd_context_t *hdd_ctx,
3700 uint8_t *command,
3701 uint8_t command_len,
3702 hdd_priv_data_t *priv_data)
3703{
3704 int ret = 0;
3705 uint8_t *value = command;
3706 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3707
3708 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3709 value = value + command_len + 1;
3710
3711 /* Convert the value from ascii to integer */
3712 ret = kstrtou16(value, 10, &val);
3713 if (ret < 0) {
3714 /*
3715 * If the input value is greater than max value of datatype,
3716 * then also kstrtou8 fails
3717 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003718 hdd_err("kstrtou16 failed range [%d - %d]",
3719 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3720 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003721 ret = -EINVAL;
3722 goto exit;
3723 }
3724
3725 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3726 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003727 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3728 val,
3729 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3730 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731 ret = -EINVAL;
3732 goto exit;
3733 }
3734
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003735 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003736 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003737
3738 hdd_ctx->config->nNeighborScanPeriod = val;
3739 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3740 adapter->sessionId, val);
3741
3742exit:
3743 return ret;
3744}
3745
3746static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3747 hdd_context_t *hdd_ctx,
3748 uint8_t *command,
3749 uint8_t command_len,
3750 hdd_priv_data_t *priv_data)
3751{
3752 int ret = 0;
3753 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3754 adapter->
3755 sessionId);
3756 char extra[32];
3757 uint8_t len = 0;
3758
3759 /* value is interms of msec */
3760 len = scnprintf(extra, sizeof(extra), "%s %d",
3761 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303762 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003763
3764 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003765 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003766 ret = -EFAULT;
3767 }
3768
3769 return ret;
3770}
3771
3772static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3773 hdd_context_t *hdd_ctx,
3774 uint8_t *command,
3775 uint8_t command_len,
3776 hdd_priv_data_t *priv_data)
3777{
3778 int ret = 0;
3779 uint8_t *value = command;
3780 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3781
3782 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3783 value = value + command_len + 1;
3784
3785 /* Convert the value from ascii to integer */
3786 ret = kstrtou8(value, 10, &val);
3787 if (ret < 0) {
3788 /*
3789 * If the input value is greater than max value of datatype,
3790 * then also kstrtou8 fails
3791 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003792 hdd_err("kstrtou8 failed range [%d - %d]",
3793 CFG_ROAM_INTRA_BAND_MIN,
3794 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003795 ret = -EINVAL;
3796 goto exit;
3797 }
3798
3799 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3800 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003801 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3802 val,
3803 CFG_ROAM_INTRA_BAND_MIN,
3804 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003805 ret = -EINVAL;
3806 goto exit;
3807 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003808 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003809 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003810
3811 hdd_ctx->config->nRoamIntraBand = val;
3812 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3813
3814exit:
3815 return ret;
3816}
3817
3818static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3819 hdd_context_t *hdd_ctx,
3820 uint8_t *command,
3821 uint8_t command_len,
3822 hdd_priv_data_t *priv_data)
3823{
3824 int ret = 0;
3825 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3826 char extra[32];
3827 uint8_t len = 0;
3828
3829 /* value is interms of msec */
3830 len = scnprintf(extra, sizeof(extra), "%s %d",
3831 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303832 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003833 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003834 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003835 ret = -EFAULT;
3836 }
3837
3838 return ret;
3839}
3840
3841static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3842 hdd_context_t *hdd_ctx,
3843 uint8_t *command,
3844 uint8_t command_len,
3845 hdd_priv_data_t *priv_data)
3846{
3847 int ret = 0;
3848 uint8_t *value = command;
3849 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3850
3851 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3852 value = value + command_len + 1;
3853
3854 /* Convert the value from ascii to integer */
3855 ret = kstrtou8(value, 10, &nProbes);
3856 if (ret < 0) {
3857 /*
3858 * If the input value is greater than max value of datatype,
3859 * then also kstrtou8 fails
3860 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003861 hdd_err("kstrtou8 failed range [%d - %d]",
3862 CFG_ROAM_SCAN_N_PROBES_MIN,
3863 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003864 ret = -EINVAL;
3865 goto exit;
3866 }
3867
3868 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3869 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003870 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3871 nProbes,
3872 CFG_ROAM_SCAN_N_PROBES_MIN,
3873 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003874 ret = -EINVAL;
3875 goto exit;
3876 }
3877
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003878 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003879 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003880
3881 hdd_ctx->config->nProbes = nProbes;
3882 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3883 adapter->sessionId, nProbes);
3884
3885exit:
3886 return ret;
3887}
3888
3889static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3890 hdd_context_t *hdd_ctx,
3891 uint8_t *command,
3892 uint8_t command_len,
3893 hdd_priv_data_t *priv_data)
3894{
3895 int ret = 0;
3896 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3897 char extra[32];
3898 uint8_t len = 0;
3899
3900 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303901 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003902 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003903 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003904 ret = -EFAULT;
3905 }
3906
3907 return ret;
3908}
3909
3910static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
3911 hdd_context_t *hdd_ctx,
3912 uint8_t *command,
3913 uint8_t command_len,
3914 hdd_priv_data_t *priv_data)
3915{
3916 int ret = 0;
3917 uint8_t *value = command;
3918 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3919
3920 /* input value is in units of msec */
3921
3922 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3923 value = value + command_len + 1;
3924
3925 /* Convert the value from ascii to integer */
3926 ret = kstrtou16(value, 10, &homeAwayTime);
3927 if (ret < 0) {
3928 /*
3929 * If the input value is greater than max value of datatype,
3930 * then also kstrtou8 fails
3931 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003932 hdd_err("kstrtou8 failed range [%d - %d]",
3933 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3934 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003935 ret = -EINVAL;
3936 goto exit;
3937 }
3938
3939 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
3940 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003941 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003942 homeAwayTime,
3943 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3944 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
3945 ret = -EINVAL;
3946 goto exit;
3947 }
3948
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003949 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003950 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003951
3952 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
3953 homeAwayTime) {
3954 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
3955 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
3956 adapter->sessionId,
3957 homeAwayTime,
3958 true);
3959 }
3960
3961exit:
3962 return ret;
3963}
3964
3965static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
3966 hdd_context_t *hdd_ctx,
3967 uint8_t *command,
3968 uint8_t command_len,
3969 hdd_priv_data_t *priv_data)
3970{
3971 int ret = 0;
3972 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
3973 char extra[32];
3974 uint8_t len = 0;
3975
3976 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303977 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003978
3979 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003980 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003981 ret = -EFAULT;
3982 }
3983
3984 return ret;
3985}
3986
3987static int drv_cmd_reassoc(hdd_adapter_t *adapter,
3988 hdd_context_t *hdd_ctx,
3989 uint8_t *command,
3990 uint8_t command_len,
3991 hdd_priv_data_t *priv_data)
3992{
3993 return hdd_parse_reassoc(adapter, command);
3994}
3995
3996static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
3997 hdd_context_t *hdd_ctx,
3998 uint8_t *command,
3999 uint8_t command_len,
4000 hdd_priv_data_t *priv_data)
4001{
4002 int ret = 0;
4003 uint8_t *value = command;
4004 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4005
4006 /* Move pointer to ahead of SETWESMODE<delimiter> */
4007 value = value + command_len + 1;
4008
4009 /* Convert the value from ascii to integer */
4010 ret = kstrtou8(value, 10, &wesMode);
4011 if (ret < 0) {
4012 /*
4013 * If the input value is greater than max value of datatype,
4014 * then also kstrtou8 fails
4015 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004016 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004017 CFG_ENABLE_WES_MODE_NAME_MIN,
4018 CFG_ENABLE_WES_MODE_NAME_MAX);
4019 ret = -EINVAL;
4020 goto exit;
4021 }
4022
4023 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4024 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004025 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004026 wesMode,
4027 CFG_ENABLE_WES_MODE_NAME_MIN,
4028 CFG_ENABLE_WES_MODE_NAME_MAX);
4029 ret = -EINVAL;
4030 goto exit;
4031 }
4032
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004033 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004034 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004035
4036 hdd_ctx->config->isWESModeEnabled = wesMode;
4037 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4038
4039exit:
4040 return ret;
4041}
4042
4043static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4044 hdd_context_t *hdd_ctx,
4045 uint8_t *command,
4046 uint8_t command_len,
4047 hdd_priv_data_t *priv_data)
4048{
4049 int ret = 0;
4050 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4051 char extra[32];
4052 uint8_t len = 0;
4053
4054 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304055 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004056 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004057 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004058 ret = -EFAULT;
4059 }
4060
4061 return ret;
4062}
4063
4064static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4065 hdd_context_t *hdd_ctx,
4066 uint8_t *command,
4067 uint8_t command_len,
4068 hdd_priv_data_t *priv_data)
4069{
4070 int ret = 0;
4071 uint8_t *value = command;
4072 uint8_t nOpportunisticThresholdDiff =
4073 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4074
4075 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4076 value = value + command_len + 1;
4077
4078 /* Convert the value from ascii to integer */
4079 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4080 if (ret < 0) {
4081 /*
4082 * If the input value is greater than max value of datatype,
4083 * then also kstrtou8 fails
4084 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004085 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004086 ret = -EINVAL;
4087 goto exit;
4088 }
4089
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004090 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004091 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004092
4093 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4094 adapter->sessionId,
4095 nOpportunisticThresholdDiff);
4096
4097exit:
4098 return ret;
4099}
4100
4101static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4102 hdd_context_t *hdd_ctx,
4103 uint8_t *command,
4104 uint8_t command_len,
4105 hdd_priv_data_t *priv_data)
4106{
4107 int ret = 0;
4108 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4109 hdd_ctx->hHal);
4110 char extra[32];
4111 uint8_t len = 0;
4112
4113 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304114 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004116 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004117 ret = -EFAULT;
4118 }
4119
4120 return ret;
4121}
4122
4123static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4124 hdd_context_t *hdd_ctx,
4125 uint8_t *command,
4126 uint8_t command_len,
4127 hdd_priv_data_t *priv_data)
4128{
4129 int ret = 0;
4130 uint8_t *value = command;
4131 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4132
4133 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4134 value = value + command_len + 1;
4135
4136 /* Convert the value from ascii to integer */
4137 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4138 if (ret < 0) {
4139 /*
4140 * If the input value is greater than max value of datatype,
4141 * then also kstrtou8 fails
4142 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004143 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004144 ret = -EINVAL;
4145 goto exit;
4146 }
4147
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004148 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004149 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004150
4151 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4152 adapter->sessionId,
4153 nRoamRescanRssiDiff);
4154
4155exit:
4156 return ret;
4157}
4158
4159static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4160 hdd_context_t *hdd_ctx,
4161 uint8_t *command,
4162 uint8_t command_len,
4163 hdd_priv_data_t *priv_data)
4164{
4165 int ret = 0;
4166 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4167 char extra[32];
4168 uint8_t len = 0;
4169
4170 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304171 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004172 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004173 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004174 ret = -EFAULT;
4175 }
4176
4177 return ret;
4178}
4179
4180static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4181 hdd_context_t *hdd_ctx,
4182 uint8_t *command,
4183 uint8_t command_len,
4184 hdd_priv_data_t *priv_data)
4185{
4186 int ret = 0;
4187 uint8_t *value = command;
4188 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4189
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004190 if (!adapter->fast_roaming_allowed) {
4191 hdd_err("Roaming is always disabled on this interface");
4192 goto exit;
4193 }
4194
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004195 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4196 value = value + command_len + 1;
4197
4198 /* Convert the value from ascii to integer */
4199 ret = kstrtou8(value, 10, &lfrMode);
4200 if (ret < 0) {
4201 /*
4202 * If the input value is greater than max value of datatype,
4203 * then also kstrtou8 fails
4204 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004205 hdd_err("kstrtou8 failed range [%d - %d]",
4206 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004207 CFG_LFR_FEATURE_ENABLED_MAX);
4208 ret = -EINVAL;
4209 goto exit;
4210 }
4211
4212 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4213 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004214 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004215 lfrMode,
4216 CFG_LFR_FEATURE_ENABLED_MIN,
4217 CFG_LFR_FEATURE_ENABLED_MAX);
4218 ret = -EINVAL;
4219 goto exit;
4220 }
4221
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004222 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004223 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004224
4225 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4226 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4227 adapter->
4228 sessionId,
4229 lfrMode);
4230
4231exit:
4232 return ret;
4233}
4234
4235static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4236 hdd_context_t *hdd_ctx,
4237 uint8_t *command,
4238 uint8_t command_len,
4239 hdd_priv_data_t *priv_data)
4240{
4241 int ret = 0;
4242 uint8_t *value = command;
4243 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4244
4245 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4246 value = value + command_len + 1;
4247
4248 /* Convert the value from ascii to integer */
4249 ret = kstrtou8(value, 10, &ft);
4250 if (ret < 0) {
4251 /*
4252 * If the input value is greater than max value of datatype,
4253 * then also kstrtou8 fails
4254 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004255 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004256 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4257 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4258 ret = -EINVAL;
4259 goto exit;
4260 }
4261
4262 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4263 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004264 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004265 ft,
4266 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4267 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4268 ret = -EINVAL;
4269 goto exit;
4270 }
4271
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004272 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004273
4274 hdd_ctx->config->isFastTransitionEnabled = ft;
4275 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4276
4277exit:
4278 return ret;
4279}
4280
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004281static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4282 hdd_context_t *hdd_ctx,
4283 uint8_t *command,
4284 uint8_t command_len,
4285 hdd_priv_data_t *priv_data)
4286{
4287 int ret = 0;
4288 uint8_t *value = command;
4289 uint8_t channel = 0;
4290 tSirMacAddr targetApBssid;
4291 uint32_t roamId = 0;
4292 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004294 hdd_station_ctx_t *pHddStaCtx;
4295
Krunal Sonibe766b02016-03-10 13:00:44 -08004296 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004297 hdd_warn("Unsupported in mode %s(%d)",
4298 hdd_device_mode_to_string(adapter->device_mode),
4299 adapter->device_mode);
4300 return -EINVAL;
4301 }
4302
4303 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4304
4305 /* if not associated, no need to proceed with reassoc */
4306 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004307 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004308 ret = -EINVAL;
4309 goto exit;
4310 }
4311
4312 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4313 &channel);
4314 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004315 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004316 goto exit;
4317 }
4318
4319 /*
4320 * if the target bssid is same as currently associated AP,
4321 * issue reassoc to same AP
4322 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004323 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004324 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304325 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004326 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304327 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004328 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304329 targetApBssid,
4330 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304331 } else {
4332 sme_get_modify_profile_fields(hdd_ctx->hHal,
4333 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304335 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4336 NULL, modProfileFields, &roamId, 1);
4337 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004338 return 0;
4339 }
4340
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304341 /* Check channel number is a valid channel number */
Selvaraj, Sridhar64b0a9c2017-05-11 16:50:15 +05304342 if (channel && (QDF_STATUS_SUCCESS !=
4343 wlan_hdd_validate_operation_channel(adapter, channel))) {
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304344 hdd_err("Invalid Channel [%d]", channel);
4345 return -EINVAL;
4346 }
4347
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004348 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004349 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004350 targetApBssid, (int)channel);
4351 goto exit;
4352 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004353 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004354 handoffInfo.channel = channel;
4355 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004356 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004357 sizeof(tSirMacAddr));
4358 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4359 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004360exit:
4361 return ret;
4362}
4363
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004364static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4365 hdd_context_t *hdd_ctx,
4366 uint8_t *command,
4367 uint8_t command_len,
4368 hdd_priv_data_t *priv_data)
4369{
4370 int ret = 0;
4371 uint8_t *value = command;
4372 uint8_t roamScanControl = 0;
4373
4374 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4375 value = value + command_len + 1;
4376
4377 /* Convert the value from ascii to integer */
4378 ret = kstrtou8(value, 10, &roamScanControl);
4379 if (ret < 0) {
4380 /*
4381 * If the input value is greater than max value of datatype,
4382 * then also kstrtou8 fails
4383 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004384 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004385 ret = -EINVAL;
4386 goto exit;
4387 }
4388
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004389 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004390 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004391
4392 if (0 != roamScanControl) {
4393 ret = 0; /* return success but ignore param value "true" */
4394 goto exit;
4395 }
4396
4397 sme_set_roam_scan_control(hdd_ctx->hHal,
4398 adapter->sessionId,
4399 roamScanControl);
4400
4401exit:
4402 return ret;
4403}
4404
4405static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4406 hdd_context_t *hdd_ctx,
4407 uint8_t *command,
4408 uint8_t command_len,
4409 hdd_priv_data_t *priv_data)
4410{
4411 int ret = 0;
4412 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004413 uint32_t okc_mode;
4414 struct pmkid_mode_bits pmkid_modes;
4415
4416 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417
4418 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004419 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004420 * then this operation is not permitted (return FAILURE)
4421 */
4422 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004423 pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004424 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004425 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004426 ret = -EPERM;
4427 goto exit;
4428 }
4429
4430 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4431 value = value + command_len + 1;
4432
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004433 /* get the current configured value */
4434 okc_mode = hdd_ctx->config->pmkid_modes & CFG_PMKID_MODES_OKC;
4435
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004436 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004437 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004438 if (ret < 0) {
4439 /*
4440 * If the input value is greater than max value of datatype,
4441 * then also kstrtou8 fails
4442 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004443 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004444 ret = -EINVAL;
4445 goto exit;
4446 }
4447
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004448 if ((okc_mode < 0) ||
4449 (okc_mode > 1)) {
4450 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4451 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004452 ret = -EINVAL;
4453 goto exit;
4454 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004455 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004456 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004457
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004458 if (okc_mode)
4459 hdd_ctx->config->pmkid_modes |= CFG_PMKID_MODES_OKC;
4460 else
4461 hdd_ctx->config->pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004462
4463exit:
4464 return ret;
4465}
4466
4467static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4468 hdd_context_t *hdd_ctx,
4469 uint8_t *command,
4470 uint8_t command_len,
4471 hdd_priv_data_t *priv_data)
4472{
4473 int ret = 0;
4474 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4475 char extra[32];
4476 uint8_t len = 0;
4477
4478 len = scnprintf(extra, sizeof(extra), "%s %d",
4479 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304480 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004481 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004482 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004483 ret = -EFAULT;
4484 }
4485
4486 return ret;
4487}
4488
4489static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4490 hdd_context_t *hdd_ctx,
4491 uint8_t *command,
4492 uint8_t command_len,
4493 hdd_priv_data_t *priv_data)
4494{
4495 int ret = 0;
4496 char *bcMode;
4497
4498 bcMode = command + 11;
4499 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004500 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004501 hdd_ctx->btCoexModeSet = true;
4502 ret = wlan_hdd_scan_abort(adapter);
4503 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004504 hdd_err("Failed to abort existing scan status: %d",
4505 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004506 }
4507 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004508 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004509 hdd_ctx->btCoexModeSet = false;
4510 }
4511
4512 return ret;
4513}
4514
4515static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4516 hdd_context_t *hdd_ctx,
4517 uint8_t *command,
4518 uint8_t command_len,
4519 hdd_priv_data_t *priv_data)
4520{
4521 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4522 return 0;
4523}
4524
4525static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4526 hdd_context_t *hdd_ctx,
4527 uint8_t *command,
4528 uint8_t command_len,
4529 hdd_priv_data_t *priv_data)
4530{
4531 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4532 return 0;
4533}
4534
4535static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4536 hdd_context_t *hdd_ctx,
4537 uint8_t *command,
4538 uint8_t command_len,
4539 hdd_priv_data_t *priv_data)
4540{
4541 int ret = 0;
4542 struct hdd_config *pCfg =
4543 (WLAN_HDD_GET_CTX(adapter))->config;
4544 char extra[32];
4545 uint8_t len = 0;
4546
4547 memset(extra, 0, sizeof(extra));
4548 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304549 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004550 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004551 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004552 ret = -EFAULT;
4553 goto exit;
4554 }
4555 ret = len;
4556exit:
4557 return ret;
4558}
4559
4560static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4561 hdd_context_t *hdd_ctx,
4562 uint8_t *command,
4563 uint8_t command_len,
4564 hdd_priv_data_t *priv_data)
4565{
4566 return hdd_set_dwell_time(adapter, command);
4567}
4568
4569static int drv_cmd_miracast(hdd_adapter_t *adapter,
4570 hdd_context_t *hdd_ctx,
4571 uint8_t *command,
4572 uint8_t command_len,
4573 hdd_priv_data_t *priv_data)
4574{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304575 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004576 int ret = 0;
4577 tHalHandle hHal;
4578 uint8_t filterType = 0;
4579 hdd_context_t *pHddCtx = NULL;
4580 uint8_t *value;
4581
4582 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304583 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004584 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004585
4586 hHal = pHddCtx->hHal;
4587 value = command + 9;
4588
4589 /* Convert the value from ascii to integer */
4590 ret = kstrtou8(value, 10, &filterType);
4591 if (ret < 0) {
4592 /*
4593 * If the input value is greater than max value of datatype,
4594 * then also kstrtou8 fails
4595 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004596 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004597 ret = -EINVAL;
4598 goto exit;
4599 }
4600 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4601 || (filterType >
4602 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004603 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004604 ret = -EINVAL;
4605 goto exit;
4606 }
4607 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4608 pHddCtx->miracast_value = filterType;
4609
4610 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304611 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004612 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 return -EBUSY;
4614 }
4615
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004616 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4617 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004618
4619exit:
4620 return ret;
4621}
4622
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004623/* Function header is left blank intentionally */
4624static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4625 int32_t *oui_length, int32_t limit)
4626{
4627 uint8_t len;
4628 uint8_t data;
4629
4630 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4631 command++;
4632 limit--;
4633 }
4634
4635 len = 2;
4636
4637 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4638 (limit > 1)) {
4639 sscanf(command, "%02x", (unsigned int *)&data);
4640 ie[len++] = data;
4641 command += 2;
4642 limit -= 2;
4643 }
4644
4645 *oui_length = len - 2;
4646
4647 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4648 command++;
4649 limit--;
4650 }
4651
4652 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4653 (limit > 1)) {
4654 sscanf(command, "%02x", (unsigned int *)&data);
4655 ie[len++] = data;
4656 command += 2;
4657 limit -= 2;
4658 }
4659
4660 ie[0] = IE_EID_VENDOR;
4661 ie[1] = len - 2;
4662
4663 return len;
4664}
4665
4666/**
4667 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4668 * @adapter: Pointer to adapter
4669 * @hdd_ctx: Pointer to HDD context
4670 * @command: Pointer to command string
4671 * @command_len : Command length
4672 * @priv_data : Pointer to priv data
4673 *
4674 * Return:
4675 * int status code
4676 */
4677static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4678 hdd_context_t *hdd_ctx,
4679 uint8_t *command,
4680 uint8_t command_len,
4681 hdd_priv_data_t *priv_data)
4682{
4683 int i = 0;
4684 int status;
4685 int ret = 0;
4686 uint8_t *ibss_ie;
4687 int32_t oui_length = 0;
4688 uint32_t ibss_ie_length;
4689 uint8_t *value = command;
4690 tSirModifyIE ibssModifyIE;
4691 tCsrRoamProfile *pRoamProfile;
4692 hdd_wext_state_t *pWextState;
4693
4694
Krunal Sonibe766b02016-03-10 13:00:44 -08004695 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004696 hdd_debug("Device_mode %s(%d) not IBSS",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004697 hdd_device_mode_to_string(adapter->device_mode),
4698 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004699 return ret;
4700 }
4701
4702 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4703
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004704 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004705
4706
4707 /* validate argument of command */
4708 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004709 hdd_err("No arguments in command length %zu",
4710 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004711 ret = -EFAULT;
4712 goto exit;
4713 }
4714
4715 /* moving to arguments of commands */
4716 value = value + command_len;
4717 command_len = strlen(value);
4718
4719 /* oui_data can't be less than 3 bytes */
4720 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004721 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4722 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004723 ret = -EFAULT;
4724 goto exit;
4725 }
4726
4727 ibss_ie = qdf_mem_malloc(command_len);
4728 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004729 hdd_err("Could not allocate memory for command length %d",
4730 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004731 ret = -ENOMEM;
4732 goto exit;
4733 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004734
4735 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4736 &oui_length,
4737 command_len);
4738 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004739 hdd_err("Could not parse command %s return length %d",
4740 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004741 ret = -EFAULT;
4742 qdf_mem_free(ibss_ie);
4743 goto exit;
4744 }
4745
4746 pRoamProfile = &pWextState->roamProfile;
4747
4748 qdf_copy_macaddr(&ibssModifyIE.bssid,
4749 pRoamProfile->BSSIDs.bssid);
4750
4751 ibssModifyIE.smeSessionId = adapter->sessionId;
4752 ibssModifyIE.notify = true;
4753 ibssModifyIE.ieID = IE_EID_VENDOR;
4754 ibssModifyIE.ieIDLen = ibss_ie_length;
4755 ibssModifyIE.ieBufferlength = ibss_ie_length;
4756 ibssModifyIE.pIEBuffer = ibss_ie;
4757 ibssModifyIE.oui_length = oui_length;
4758
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004759 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4760 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004761 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004762 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004763
4764 /* Probe Bcn modification */
4765 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4766 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4767
4768 /* Populating probe resp frame */
4769 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4770 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4771
4772 qdf_mem_free(ibss_ie);
4773
4774 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4775 adapter->sessionId);
4776 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004777 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004778 status);
4779 ret = -EINVAL;
4780 goto exit;
4781 }
4782
4783exit:
4784 return ret;
4785}
4786
4787static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4788 hdd_context_t *hdd_ctx,
4789 uint8_t *command,
4790 uint8_t command_len,
4791 hdd_priv_data_t *priv_data)
4792{
4793 int ret = 0;
4794 uint8_t *value = command;
4795 uint8_t ucRmcEnable = 0;
4796 int status;
4797
Krunal Sonibe766b02016-03-10 13:00:44 -08004798 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4799 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004800 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4801 hdd_device_mode_to_string(adapter->device_mode),
4802 adapter->device_mode);
4803 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004804 ret = -EINVAL;
4805 goto exit;
4806 }
4807
4808 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4809 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004810 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004811 ret = -EINVAL;
4812 goto exit;
4813 }
4814
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004815 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004816
4817 if (true == ucRmcEnable) {
4818 status = sme_enable_rmc((tHalHandle)
4819 (hdd_ctx->hHal),
4820 adapter->sessionId);
4821 } else if (false == ucRmcEnable) {
4822 status = sme_disable_rmc((tHalHandle)
4823 (hdd_ctx->hHal),
4824 adapter->sessionId);
4825 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004826 hdd_err("Invalid SETRMCENABLE command %d",
4827 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004828 ret = -EINVAL;
4829 goto exit;
4830 }
4831
4832 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004833 hdd_err("SETRMC %d failed status %d",
4834 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004835 ret = -EINVAL;
4836 goto exit;
4837 }
4838
4839exit:
4840 return ret;
4841}
4842
4843static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4844 hdd_context_t *hdd_ctx,
4845 uint8_t *command,
4846 uint8_t command_len,
4847 hdd_priv_data_t *priv_data)
4848{
4849 int ret = 0;
4850 uint8_t *value = command;
4851 uint32_t uActionPeriod = 0;
4852 int status;
4853
Krunal Sonibe766b02016-03-10 13:00:44 -08004854 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4855 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004856 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004857 hdd_device_mode_to_string(adapter->device_mode),
4858 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004859 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004860 ret = -EINVAL;
4861 goto exit;
4862 }
4863
4864 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4865 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004866 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004867 ret = -EINVAL;
4868 goto exit;
4869 }
4870
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004871 hdd_debug("uActionPeriod %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004872 uActionPeriod);
4873
4874 if (sme_cfg_set_int(hdd_ctx->hHal,
4875 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4876 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004877 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4878 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004879 ret = -EINVAL;
4880 goto exit;
4881 }
4882
4883 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4884 adapter->sessionId);
4885 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004886 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004887 status);
4888 ret = -EINVAL;
4889 goto exit;
4890 }
4891
4892exit:
4893 return ret;
4894}
4895
4896static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
4897 hdd_context_t *hdd_ctx,
4898 uint8_t *command,
4899 uint8_t command_len,
4900 hdd_priv_data_t *priv_data)
4901{
4902 int ret = 0;
4903 int status = QDF_STATUS_SUCCESS;
4904 hdd_station_ctx_t *pHddStaCtx = NULL;
4905 char *extra = NULL;
4906 int idx = 0;
4907 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004908 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004909 uint32_t numOfBytestoPrint = 0;
4910
Krunal Sonibe766b02016-03-10 13:00:44 -08004911 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004912 hdd_warn("Unsupported in mode %s(%d)",
4913 hdd_device_mode_to_string(adapter->device_mode),
4914 adapter->device_mode);
4915 return -EINVAL;
4916 }
4917
4918 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004919 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004920
4921 /* Handle the command */
4922 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
4923 if (QDF_STATUS_SUCCESS == status) {
4924 /*
4925 * The variable extra needed to be allocated on the heap since
4926 * amount of memory required to copy the data for 32 devices
4927 * exceeds the size of 1024 bytes of default stack size. On
4928 * 64 bit devices, the default max stack size of 2048 bytes
4929 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004930 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004931
4932 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004933 hdd_err("memory allocation failed");
4934 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004935 goto exit;
4936 }
4937
4938 /* Copy number of stations */
4939 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004940 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004941 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004942 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
4943 idx++) {
4944 int8_t rssi;
4945 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004946
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004947 qdf_mem_copy(mac_addr,
4948 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4949 mac_addr, sizeof(mac_addr));
4950
4951 tx_rate =
4952 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4953 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05304954 /*
4955 * Only lower 3 bytes are rate info. Mask of the MSByte
4956 */
4957 tx_rate &= 0x00FFFFFF;
4958
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004959 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4960 rssi;
4961
4962 length += scnprintf((extra + length),
4963 WLAN_MAX_BUF_SIZE - length,
4964 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
4965 mac_addr[0], mac_addr[1], mac_addr[2],
4966 mac_addr[3], mac_addr[4], mac_addr[5],
4967 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004968 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004969 * cdf_trace_msg has limitation of 512 bytes for the
4970 * print buffer. Hence printing the data in two chunks.
4971 * The first chunk will have the data for 16 devices
4972 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004973 */
4974 if (idx < NUM_OF_STA_DATA_TO_PRINT)
4975 numOfBytestoPrint = length;
4976 }
4977
4978 /*
4979 * Copy the data back into buffer, if the data to copy is
4980 * more than 512 bytes than we will split the data and do
4981 * it in two shots
4982 */
4983 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004984 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004985 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05304986 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004987 }
4988
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07004989 /* This overwrites the last space, which we already copied */
4990 extra[numOfBytestoPrint - 1] = '\0';
4991 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004992
4993 if (length > numOfBytestoPrint) {
4994 if (copy_to_user
4995 (priv_data->buf + numOfBytestoPrint,
4996 extra + numOfBytestoPrint,
4997 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004998 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004999 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305000 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005001 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005002 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005003 }
5004
5005 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005006 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005007 } else {
5008 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005009 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5010 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005011 ret = -EINVAL;
5012 goto exit;
5013 }
5014 ret = 0;
5015
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305016mem_free:
5017 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005018exit:
5019 return ret;
5020}
5021
5022/* Peer Info <Peer Addr> command */
5023static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5024 hdd_context_t *hdd_ctx,
5025 uint8_t *command,
5026 uint8_t command_len,
5027 hdd_priv_data_t *priv_data)
5028{
5029 int ret = 0;
5030 uint8_t *value = command;
5031 QDF_STATUS status;
5032 hdd_station_ctx_t *pHddStaCtx = NULL;
5033 char extra[128] = { 0 };
5034 uint32_t length = 0;
5035 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005036 struct qdf_mac_addr peerMacAddr;
5037
Krunal Sonibe766b02016-03-10 13:00:44 -08005038 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005039 hdd_warn("Unsupported in mode %s(%d)",
5040 hdd_device_mode_to_string(adapter->device_mode),
5041 adapter->device_mode);
5042 return -EINVAL;
5043 }
5044
5045 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5046
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005047 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005048
5049 /* if there are no peers, no need to continue with the command */
5050 if (eConnectionState_IbssConnected !=
5051 pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005052 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005053 ret = -EINVAL;
5054 goto exit;
5055 }
5056
5057 /* Parse the incoming command buffer */
5058 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5059 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005060 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005061 ret = -EINVAL;
5062 goto exit;
5063 }
5064
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005065 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005066 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005067
Naveen Rawatc45d1622016-07-05 12:20:09 -07005068 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005069 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005070 ret = -EINVAL;
5071 goto exit;
5072 }
5073
5074 /* Handle the command */
5075 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5076 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005077 uint32_t txRate =
5078 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305079 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5080 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005081
5082 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005083 (int)txRate,
5084 (int)pHddStaCtx->ibss_peer_info.
5085 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005086
5087 /* Copy the data back into buffer */
5088 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005089 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005090 ret = -EFAULT;
5091 goto exit;
5092 }
5093 } else {
5094 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005095 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5096 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005097 ret = -EINVAL;
5098 goto exit;
5099 }
5100
5101 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005102 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005103 ret = 0;
5104
5105exit:
5106 return ret;
5107}
5108
5109static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5110 hdd_context_t *hdd_ctx,
5111 uint8_t *command,
5112 uint8_t command_len,
5113 hdd_priv_data_t *priv_data)
5114{
5115 int ret = 0;
5116 uint8_t *value = command;
5117 uint32_t uRate = 0;
5118 tTxrateinfoflags txFlags = 0;
5119 tSirRateUpdateInd rateUpdateParams = {0};
5120 int status;
5121 struct hdd_config *pConfig = hdd_ctx->config;
5122
Krunal Sonibe766b02016-03-10 13:00:44 -08005123 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5124 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005125 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5126 hdd_device_mode_to_string(adapter->device_mode),
5127 adapter->device_mode);
5128 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005129 ret = -EINVAL;
5130 goto exit;
5131 }
5132
5133 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5134 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005135 hdd_err("Invalid SETRMCTXRATE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005136 ret = -EINVAL;
5137 goto exit;
5138 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005139 hdd_debug("uRate %d", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005140 /* -1 implies ignore this param */
5141 rateUpdateParams.ucastDataRate = -1;
5142
5143 /*
5144 * Fill the user specifieed RMC rate param
5145 * and the derived tx flags.
5146 */
5147 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5148 rateUpdateParams.reliableMcastDataRate = uRate;
5149 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5150 rateUpdateParams.dev_mode = adapter->device_mode;
5151 rateUpdateParams.bcastDataRate = -1;
5152 memcpy(rateUpdateParams.bssid.bytes,
5153 adapter->macAddressCurrent.bytes,
5154 sizeof(rateUpdateParams.bssid));
5155 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5156 &rateUpdateParams);
5157
5158exit:
5159 return ret;
5160}
5161
5162static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5163 hdd_context_t *hdd_ctx,
5164 uint8_t *command,
5165 uint8_t command_len,
5166 hdd_priv_data_t *priv_data)
5167{
5168 int ret = 0;
5169 char *value;
5170 uint8_t tx_fail_count = 0;
5171 uint16_t pid = 0;
5172
5173 value = command;
5174
5175 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5176
5177 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005178 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005179 goto exit;
5180 }
5181
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005182 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005183
5184 if (0 == tx_fail_count) {
5185 /* Disable TX Fail Indication */
5186 if (QDF_STATUS_SUCCESS ==
5187 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5188 tx_fail_count,
5189 NULL)) {
5190 cesium_pid = 0;
5191 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005192 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005193 ret = -EINVAL;
5194 }
5195 } else {
5196 if (QDF_STATUS_SUCCESS ==
5197 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5198 tx_fail_count,
5199 (void *)hdd_tx_fail_ind_callback)) {
5200 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005201 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005202 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005203 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005204 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005205 ret = -EINVAL;
5206 }
5207 }
5208
5209exit:
5210 return ret;
5211}
5212
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005213#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005214static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5215 hdd_context_t *hdd_ctx,
5216 uint8_t *command,
5217 uint8_t command_len,
5218 hdd_priv_data_t *priv_data)
5219{
5220 int ret = 0;
5221 uint8_t *value = command;
5222 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5223 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305224 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005225
5226 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5227 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005228 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005229 goto exit;
5230 }
5231 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005232 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005233 numChannels,
5234 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5235 ret = -EINVAL;
5236 goto exit;
5237 }
5238 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5239 adapter->sessionId,
5240 ChannelList,
5241 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305242 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005243 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005244 ret = -EINVAL;
5245 goto exit;
5246 }
5247
5248exit:
5249 return ret;
5250}
5251
5252static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5253 hdd_context_t *hdd_ctx,
5254 uint8_t *command,
5255 uint8_t command_len,
5256 hdd_priv_data_t *priv_data)
5257{
5258 int ret = 0;
5259 uint8_t *value = command;
5260 char extra[128] = { 0 };
5261 int len = 0;
5262 uint8_t tid = 0;
5263 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005264 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005265
Krunal Sonibe766b02016-03-10 13:00:44 -08005266 if ((QDF_STA_MODE != adapter->device_mode) &&
5267 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005268 hdd_warn("Unsupported in mode %s(%d)",
5269 hdd_device_mode_to_string(adapter->device_mode),
5270 adapter->device_mode);
5271 return -EINVAL;
5272 }
5273
5274 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5275
5276 /* if not associated, return error */
5277 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005278 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005279 ret = -EINVAL;
5280 goto exit;
5281 }
5282
5283 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5284 value = value + command_len + 1;
5285
5286 /* Convert the value from ascii to integer */
5287 ret = kstrtou8(value, 10, &tid);
5288 if (ret < 0) {
5289 /*
5290 * If the input value is greater than max value of datatype,
5291 * then also kstrtou8 fails
5292 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005293 hdd_err("kstrtou8 failed range [%d - %d]",
5294 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005295 TID_MAX_VALUE);
5296 ret = -EINVAL;
5297 goto exit;
5298 }
5299 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005300 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005301 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5302 ret = -EINVAL;
5303 goto exit;
5304 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005305 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005306 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005307 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5308 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005309 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005310 goto exit;
5311 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005312 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005313 "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 -08005314 tsm_metrics.UplinkPktQueueDly,
5315 tsm_metrics.UplinkPktQueueDlyHist[0],
5316 tsm_metrics.UplinkPktQueueDlyHist[1],
5317 tsm_metrics.UplinkPktQueueDlyHist[2],
5318 tsm_metrics.UplinkPktQueueDlyHist[3],
5319 tsm_metrics.UplinkPktTxDly,
5320 tsm_metrics.UplinkPktLoss,
5321 tsm_metrics.UplinkPktCount,
5322 tsm_metrics.RoamingCount,
5323 tsm_metrics.RoamingDly);
5324 /*
5325 * Output TSM stats is of the format
5326 * GETTSMSTATS [PktQueueDly]
5327 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5328 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5329 */
5330 len = scnprintf(extra,
5331 sizeof(extra),
5332 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5333 command,
5334 tsm_metrics.UplinkPktQueueDly,
5335 tsm_metrics.UplinkPktQueueDlyHist[0],
5336 tsm_metrics.UplinkPktQueueDlyHist[1],
5337 tsm_metrics.UplinkPktQueueDlyHist[2],
5338 tsm_metrics.UplinkPktQueueDlyHist[3],
5339 tsm_metrics.UplinkPktTxDly,
5340 tsm_metrics.UplinkPktLoss,
5341 tsm_metrics.UplinkPktCount,
5342 tsm_metrics.RoamingCount,
5343 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305344 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005345 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005346 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005347 ret = -EFAULT;
5348 goto exit;
5349 }
5350
5351exit:
5352 return ret;
5353}
5354
5355static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5356 hdd_context_t *hdd_ctx,
5357 uint8_t *command,
5358 uint8_t command_len,
5359 hdd_priv_data_t *priv_data)
5360{
5361 int ret;
5362 uint8_t *value = command;
5363 uint8_t *cckmIe = NULL;
5364 uint8_t cckmIeLen = 0;
5365
5366 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5367 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005368 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005369 goto exit;
5370 }
5371
5372 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005373 hdd_err("CCKM Ie input length is more than max[%d]",
5374 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005375 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305376 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005377 cckmIe = NULL;
5378 }
5379 ret = -EINVAL;
5380 goto exit;
5381 }
5382
5383 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5384 cckmIe, cckmIeLen);
5385 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305386 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005387 cckmIe = NULL;
5388 }
5389
5390exit:
5391 return ret;
5392}
5393
5394static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5395 hdd_context_t *hdd_ctx,
5396 uint8_t *command,
5397 uint8_t command_len,
5398 hdd_priv_data_t *priv_data)
5399{
5400 int ret;
5401 uint8_t *value = command;
5402 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305403 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005404
Krunal Sonibe766b02016-03-10 13:00:44 -08005405 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005406 hdd_warn("Unsupported in mode %s(%d)",
5407 hdd_device_mode_to_string(adapter->device_mode),
5408 adapter->device_mode);
5409 return -EINVAL;
5410 }
5411
5412 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5413 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005414 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005415 goto exit;
5416 }
5417
5418 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005419 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005420 hdd_indicate_ese_bcn_report_no_results(adapter,
5421 eseBcnReq.bcnReq[0].measurementToken,
5422 0x02, /* BIT(1) set for measurement done */
5423 0); /* no BSS */
5424 goto exit;
5425 }
5426
5427 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5428 adapter->sessionId,
5429 &eseBcnReq);
5430
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305431 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005432 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005433 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005434 ret = -EBUSY;
5435 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305436 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005437 hdd_err("sme_set_ese_beacon_request failed (%d)",
5438 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005439 ret = -EINVAL;
5440 goto exit;
5441 }
5442
5443exit:
5444 return ret;
5445}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005446
5447/**
5448 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5449 * @adapter: Pointer to the HDD adapter
5450 * @hdd_ctx: Pointer to the HDD context
5451 * @command: Driver command string
5452 * @command_len: Driver command string length
5453 * @priv_data: Private data coming with the driver command. Unused here
5454 *
5455 * This function handles driver command that sets the ESE PLM request
5456 *
5457 * Return: 0 on success; negative errno otherwise
5458 */
5459static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5460 hdd_context_t *hdd_ctx,
5461 uint8_t *command,
5462 uint8_t command_len,
5463 hdd_priv_data_t *priv_data)
5464{
5465 int ret = 0;
5466 uint8_t *value = command;
5467 QDF_STATUS status = QDF_STATUS_SUCCESS;
5468 tpSirPlmReq pPlmRequest = NULL;
5469
5470 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5471 if (NULL == pPlmRequest) {
5472 ret = -ENOMEM;
5473 goto exit;
5474 }
5475
5476 status = hdd_parse_plm_cmd(value, pPlmRequest);
5477 if (QDF_STATUS_SUCCESS != status) {
5478 qdf_mem_free(pPlmRequest);
5479 pPlmRequest = NULL;
5480 ret = -EINVAL;
5481 goto exit;
5482 }
5483 pPlmRequest->sessionId = adapter->sessionId;
5484
5485 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5486 if (QDF_STATUS_SUCCESS != status) {
5487 qdf_mem_free(pPlmRequest);
5488 pPlmRequest = NULL;
5489 ret = -EINVAL;
5490 goto exit;
5491 }
5492
5493exit:
5494 return ret;
5495}
5496
5497/**
5498 * drv_cmd_set_ccx_mode() - Set ESE mode
5499 * @adapter: Pointer to the HDD adapter
5500 * @hdd_ctx: Pointer to the HDD context
5501 * @command: Driver command string
5502 * @command_len: Driver command string length
5503 * @priv_data: Private data coming with the driver command. Unused here
5504 *
5505 * This function handles driver command that sets ESE mode
5506 *
5507 * Return: 0 on success; negative errno otherwise
5508 */
5509static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5510 hdd_context_t *hdd_ctx,
5511 uint8_t *command,
5512 uint8_t command_len,
5513 hdd_priv_data_t *priv_data)
5514{
5515 int ret = 0;
5516 uint8_t *value = command;
5517 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005518 struct pmkid_mode_bits pmkid_modes;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005519
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005520 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005521 /*
5522 * Check if the features OKC/ESE/11R are supported simultaneously,
5523 * then this operation is not permitted (return FAILURE)
5524 */
5525 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005526 pmkid_modes.fw_okc &&
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005527 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5528 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5529 ret = -EPERM;
5530 goto exit;
5531 }
5532
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005533 if (!adapter->fast_roaming_allowed) {
5534 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5535 ret = -EPERM;
5536 goto exit;
5537 }
5538
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005539 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5540 value = value + command_len + 1;
5541
5542 /* Convert the value from ascii to integer */
5543 ret = kstrtou8(value, 10, &eseMode);
5544 if (ret < 0) {
5545 /*
5546 * If the input value is greater than max value of datatype,
5547 * then also kstrtou8 fails
5548 */
5549 hdd_err("kstrtou8 failed range [%d - %d]",
5550 CFG_ESE_FEATURE_ENABLED_MIN,
5551 CFG_ESE_FEATURE_ENABLED_MAX);
5552 ret = -EINVAL;
5553 goto exit;
5554 }
5555
5556 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5557 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5558 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5559 eseMode,
5560 CFG_ESE_FEATURE_ENABLED_MIN,
5561 CFG_ESE_FEATURE_ENABLED_MAX);
5562 ret = -EINVAL;
5563 goto exit;
5564 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005565 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005566
5567 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5568 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5569 adapter->sessionId,
5570 eseMode);
5571
5572exit:
5573 return ret;
5574}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005575#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005576
5577static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5578 hdd_context_t *hdd_ctx,
5579 uint8_t *command,
5580 uint8_t command_len,
5581 hdd_priv_data_t *priv_data)
5582{
5583 int ret = 0;
5584 uint8_t *value = command;
5585 int targetRate;
5586
5587 /* input value is in units of hundred kbps */
5588
5589 /* Move pointer to ahead of SETMCRATE<delimiter> */
5590 value = value + command_len + 1;
5591
5592 /* Convert the value from ascii to integer, decimal base */
5593 ret = kstrtouint(value, 10, &targetRate);
5594
5595 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5596 return ret;
5597}
5598
5599static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5600 hdd_context_t *hdd_ctx,
5601 uint8_t *command,
5602 uint8_t command_len,
5603 hdd_priv_data_t *priv_data)
5604{
5605 int ret = 0;
5606 int status;
5607 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305608 QDF_STATUS qdf_status;
5609 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005610 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305611 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5612 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005613 hdd_adapter_list_node_t *pAdapterNode = NULL;
5614 hdd_adapter_list_node_t *pNext = NULL;
5615
5616 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5617 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005618 hdd_err("Invalid MAXTXPOWER command");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005619 ret = -EINVAL;
5620 goto exit;
5621 }
5622
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305623 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005624 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305625 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005626 adapter = pAdapterNode->pAdapter;
5627 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305628 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005629 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305630 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005631 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005632
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005633 hdd_debug("Device mode %d max tx power %d selfMac: "
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005634 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005635 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005636 MAC_ADDR_ARRAY(selfMac.bytes),
5637 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005638
Srinivas Girigowda97215232015-09-24 12:26:28 -07005639 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5640 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305641 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005642 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005643 ret = -EINVAL;
5644 goto exit;
5645 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005646 hdd_debug("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305647 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005648 &pNext);
5649 pAdapterNode = pNext;
5650 }
5651
5652exit:
5653 return ret;
5654}
5655
5656static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5657 hdd_context_t *hdd_ctx,
5658 uint8_t *command,
5659 uint8_t command_len,
5660 hdd_priv_data_t *priv_data)
5661{
5662 int ret = 0;
5663 uint8_t *value = command;
5664 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5665
5666 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5667 value = value + command_len + 1;
5668
5669 /* Convert the value from ascii to integer */
5670 ret = kstrtou8(value, 10, &dfsScanMode);
5671 if (ret < 0) {
5672 /*
5673 * If the input value is greater than max value of datatype,
5674 * then also kstrtou8 fails
5675 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005676 hdd_err("kstrtou8 failed range [%d - %d]",
5677 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005678 CFG_ROAMING_DFS_CHANNEL_MAX);
5679 ret = -EINVAL;
5680 goto exit;
5681 }
5682
5683 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5684 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005685 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005686 dfsScanMode,
5687 CFG_ROAMING_DFS_CHANNEL_MIN,
5688 CFG_ROAMING_DFS_CHANNEL_MAX);
5689 ret = -EINVAL;
5690 goto exit;
5691 }
5692
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005693 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005694 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005695
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005696 /* When DFS scanning is disabled, the DFS channels need to be
5697 * removed from the operation of device.
5698 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005699 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5700 dfsScanMode != CFG_ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005701 if (ret < 0) {
5702 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005703 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005704 goto exit;
5705 }
5706
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005707 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5708 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5709 dfsScanMode);
5710
5711exit:
5712 return ret;
5713}
5714
5715static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5716 hdd_context_t *hdd_ctx,
5717 uint8_t *command,
5718 uint8_t command_len,
5719 hdd_priv_data_t *priv_data)
5720{
5721 int ret = 0;
5722 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5723 char extra[32];
5724 uint8_t len = 0;
5725
5726 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305727 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005728 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005729 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005730 ret = -EFAULT;
5731 }
5732
5733 return ret;
5734}
5735
5736static int drv_cmd_get_link_status(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 int value = wlan_hdd_get_link_status(adapter);
5744 char extra[32];
5745 uint8_t len;
5746
5747 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305748 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005749 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005750 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005751 ret = -EFAULT;
5752 }
5753
5754 return ret;
5755}
5756
5757#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5758static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5759 hdd_context_t *hdd_ctx,
5760 uint8_t *command,
5761 uint8_t command_len,
5762 hdd_priv_data_t *priv_data)
5763{
5764 uint8_t *value = command;
5765 int set_value;
5766
5767 /* Move pointer to ahead of ENABLEEXTWOW */
5768 value = value + command_len;
5769
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305770 if (!(sscanf(value, "%d", &set_value))) {
5771 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5772 ("No input identified"));
5773 return -EINVAL;
5774 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005775
5776 return hdd_enable_ext_wow_parser(adapter,
5777 adapter->sessionId,
5778 set_value);
5779}
5780
5781static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5782 hdd_context_t *hdd_ctx,
5783 uint8_t *command,
5784 uint8_t command_len,
5785 hdd_priv_data_t *priv_data)
5786{
5787 int ret;
5788 uint8_t *value = command;
5789
5790 /* Move pointer to ahead of SETAPP1PARAMS */
5791 value = value + command_len;
5792
5793 ret = hdd_set_app_type1_parser(adapter,
5794 value, strlen(value));
5795 if (ret >= 0)
5796 hdd_ctx->is_extwow_app_type1_param_set = true;
5797
5798 return ret;
5799}
5800
5801static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5802 hdd_context_t *hdd_ctx,
5803 uint8_t *command,
5804 uint8_t command_len,
5805 hdd_priv_data_t *priv_data)
5806{
5807 int ret;
5808 uint8_t *value = command;
5809
5810 /* Move pointer to ahead of SETAPP2PARAMS */
5811 value = value + command_len;
5812
5813 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5814 if (ret >= 0)
5815 hdd_ctx->is_extwow_app_type2_param_set = true;
5816
5817 return ret;
5818}
5819#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5820
5821#ifdef FEATURE_WLAN_TDLS
5822/**
5823 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5824 * @adapter: Pointer to the HDD adapter
5825 * @hdd_ctx: Pointer to the HDD context
5826 * @command: Driver command string
5827 * @command_len: Driver command string length
5828 * @priv_data: Private data coming with the driver command. Unused here
5829 *
5830 * This function handles driver command that sets the secondary tdls off channel
5831 * offset
5832 *
5833 * Return: 0 on success; negative errno otherwise
5834 */
5835static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5836 hdd_context_t *hdd_ctx,
5837 uint8_t *command,
5838 uint8_t command_len,
5839 hdd_priv_data_t *priv_data)
5840{
5841 int ret;
5842 uint8_t *value = command;
5843 int set_value;
5844
5845 /* Move pointer to point the string */
5846 value += command_len;
5847
5848 ret = sscanf(value, "%d", &set_value);
5849 if (ret != 1)
5850 return -EINVAL;
5851
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005852 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005853
5854 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5855
5856 return ret;
5857}
5858
5859/**
5860 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5861 * @adapter: Pointer to the HDD adapter
5862 * @hdd_ctx: Pointer to the HDD context
5863 * @command: Driver command string
5864 * @command_len: Driver command string length
5865 * @priv_data: Private data coming with the driver command. Unused here
5866 *
5867 * This function handles driver command that sets tdls off channel mode
5868 *
5869 * Return: 0 on success; negative errno otherwise
5870 */
5871static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5872 hdd_context_t *hdd_ctx,
5873 uint8_t *command,
5874 uint8_t command_len,
5875 hdd_priv_data_t *priv_data)
5876{
5877 int ret;
5878 uint8_t *value = command;
5879 int set_value;
5880
5881 /* Move pointer to point the string */
5882 value += command_len;
5883
5884 ret = sscanf(value, "%d", &set_value);
5885 if (ret != 1)
5886 return -EINVAL;
5887
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005888 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005889
5890 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5891
5892 return ret;
5893}
5894
5895/**
5896 * drv_cmd_tdls_off_channel() - set tdls off channel number
5897 * @adapter: Pointer to the HDD adapter
5898 * @hdd_ctx: Pointer to the HDD context
5899 * @command: Driver command string
5900 * @command_len: Driver command string length
5901 * @priv_data: Private data coming with the driver command. Unused here
5902 *
5903 * This function handles driver command that sets tdls off channel number
5904 *
5905 * Return: 0 on success; negative errno otherwise
5906 */
5907static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5908 hdd_context_t *hdd_ctx,
5909 uint8_t *command,
5910 uint8_t command_len,
5911 hdd_priv_data_t *priv_data)
5912{
5913 int ret;
5914 uint8_t *value = command;
5915 int set_value;
5916
5917 /* Move pointer to point the string */
5918 value += command_len;
5919
5920 ret = sscanf(value, "%d", &set_value);
5921 if (ret != 1)
5922 return -EINVAL;
5923
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -07005924 if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, set_value)) {
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005925 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5926 set_value);
5927 return -EINVAL;
5928 }
5929
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005930 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005931
5932 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5933
5934 return ret;
5935}
5936
5937/**
5938 * drv_cmd_tdls_scan() - set tdls scan type
5939 * @adapter: Pointer to the HDD adapter
5940 * @hdd_ctx: Pointer to the HDD context
5941 * @command: Driver command string
5942 * @command_len: Driver command string length
5943 * @priv_data: Private data coming with the driver command. Unused here
5944 *
5945 * This function handles driver command that sets tdls scan type
5946 *
5947 * Return: 0 on success; negative errno otherwise
5948 */
5949static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
5950 hdd_context_t *hdd_ctx,
5951 uint8_t *command,
5952 uint8_t command_len,
5953 hdd_priv_data_t *priv_data)
5954{
5955 int ret;
5956 uint8_t *value = command;
5957 int set_value;
5958
5959 /* Move pointer to point the string */
5960 value += command_len;
5961
5962 ret = sscanf(value, "%d", &set_value);
5963 if (ret != 1)
5964 return -EINVAL;
5965
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005966 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005967
5968 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
5969
5970 return ret;
5971}
5972#endif
5973
5974static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
5975 hdd_context_t *hdd_ctx,
5976 uint8_t *command,
5977 uint8_t command_len,
5978 hdd_priv_data_t *priv_data)
5979{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005980 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005981 int8_t rssi = 0;
5982 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005983
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005984 uint8_t len = 0;
5985
5986 wlan_hdd_get_rssi(adapter, &rssi);
5987
5988 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305989 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005990
5991 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005992 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005993 ret = -EFAULT;
5994 }
5995
5996 return ret;
5997}
5998
5999static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6000 hdd_context_t *hdd_ctx,
6001 uint8_t *command,
6002 uint8_t command_len,
6003 hdd_priv_data_t *priv_data)
6004{
6005 int ret;
6006 uint32_t link_speed = 0;
6007 char extra[32];
6008 uint8_t len = 0;
6009
6010 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6011 if (0 != ret)
6012 return ret;
6013
6014 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306015 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006016 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006017 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006018 ret = -EFAULT;
6019 }
6020
6021 return ret;
6022}
6023
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006024/**
6025 * hdd_set_rx_filter() - set RX filter
6026 * @adapter: Pointer to adapter
6027 * @action: Filter action
6028 * @pattern: Address pattern
6029 *
6030 * Address pattern is most significant byte of address for example
6031 * 0x01 for IPV4 multicast address
6032 * 0x33 for IPV6 multicast address
6033 * 0xFF for broadcast address
6034 *
6035 * Return: 0 for success, non-zero for failure
6036 */
6037static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6038 uint8_t pattern)
6039{
6040 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006041 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006042 tHalHandle handle;
6043 tSirRcvFltMcAddrList *filter;
6044 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6045
6046 ret = wlan_hdd_validate_context(hdd_ctx);
6047 if (0 != ret)
6048 return ret;
6049
6050 handle = hdd_ctx->hHal;
6051
6052 if (NULL == handle) {
6053 hdd_err("HAL Handle is NULL");
6054 return -EINVAL;
6055 }
6056
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306057 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006058 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306059 return -EINVAL;
6060 }
6061
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006062 /*
6063 * If action is false it means start dropping packets
6064 * Set addr_filter_pattern which will be used when sending
6065 * MC/BC address list to target
6066 */
6067 if (!action)
6068 adapter->addr_filter_pattern = pattern;
6069 else
6070 adapter->addr_filter_pattern = 0;
6071
Krunal Sonibe766b02016-03-10 13:00:44 -08006072 if (((adapter->device_mode == QDF_STA_MODE) ||
6073 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006074 adapter->mc_addr_list.mc_cnt &&
6075 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6076
6077
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306078 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006079 if (NULL == filter) {
6080 hdd_err("Could not allocate Memory");
6081 return -ENOMEM;
6082 }
6083 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006084 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006085 if (!memcmp(adapter->mc_addr_list.addr[i],
6086 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006087 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006088 adapter->mc_addr_list.addr[i],
6089 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006090
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006091 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092 MAC_ADDRESS_STR,
6093 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006094 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6095 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006096 }
SaidiReddy Yenuga0b2c9f42017-02-03 12:26:38 +05306097 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
6098 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006099 }
Frank Liuf95e8132016-09-29 19:01:30 +08006100 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006101 /* Set rx filter */
6102 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306103 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006104 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006105 hdd_debug("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006106 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6107 }
6108
6109 return 0;
6110}
6111
6112/**
6113 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6114 * @command: Pointer to input string driver command
6115 * @adapter: Pointer to adapter
6116 * @action: Action to enable/disable filtering
6117 *
6118 * If action == false
6119 * Start filtering out data packets based on type
6120 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6121 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6122 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6123 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6124 *
6125 * if action == true
6126 * Stop filtering data packets based on type
6127 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6128 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6129 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6130 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6131 *
6132 * Current implementation only supports IPV4 address filtering by
6133 * selectively allowing IPV4 multicast data packest based on
6134 * address list received in .ndo_set_rx_mode
6135 *
6136 * Return: 0 for success, non-zero for failure
6137 */
6138static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6139 hdd_adapter_t *adapter,
6140 bool action)
6141{
6142 int ret = 0;
6143 uint8_t *value;
6144 uint8_t type;
6145
6146 value = command;
6147 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6148 if (!action)
6149 value = command + 16;
6150 else
6151 value = command + 13;
6152 ret = kstrtou8(value, 10, &type);
6153 if (ret < 0) {
6154 hdd_err("kstrtou8 failed invalid input value %d", type);
6155 return -EINVAL;
6156 }
6157
6158 switch (type) {
6159 case 2:
6160 /* Set rx filter for IPV4 multicast data packets */
6161 ret = hdd_set_rx_filter(adapter, action, 0x01);
6162 break;
6163 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006164 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006165 break;
6166 }
6167
6168 return ret;
6169}
6170
6171/**
6172 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6173 * @adapter: Pointer to network adapter
6174 * @hdd_ctx: Pointer to hdd context
6175 * @command: Pointer to input command
6176 * @command_len: Command length
6177 * @priv_data: Pointer to private data in command
6178 */
6179static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6180 hdd_context_t *hdd_ctx,
6181 uint8_t *command,
6182 uint8_t command_len,
6183 hdd_priv_data_t *priv_data)
6184{
6185 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6186}
6187
6188/**
6189 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6190 * @adapter: Pointer to network adapter
6191 * @hdd_ctx: Pointer to hdd context
6192 * @command: Pointer to input command
6193 * @command_len: Command length
6194 * @priv_data: Pointer to private data in command
6195 */
6196static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6197 hdd_context_t *hdd_ctx,
6198 uint8_t *command,
6199 uint8_t command_len,
6200 hdd_priv_data_t *priv_data)
6201{
6202 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6203}
6204
Archana Ramachandran393f3792015-11-13 17:13:21 -08006205/**
6206 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6207 * command
6208 * @value: Pointer to SETANTENNAMODE command
6209 * @mode: Pointer to antenna mode
6210 * @reason: Pointer to reason for set antenna mode
6211 *
6212 * This function parses the SETANTENNAMODE command passed in the format
6213 * SETANTENNAMODE<space>mode
6214 *
6215 * Return: 0 for success non-zero for failure
6216 */
6217static int hdd_parse_setantennamode_command(const uint8_t *value)
6218{
6219 const uint8_t *in_ptr = value;
6220 int tmp, v;
6221 char arg1[32];
6222
6223 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6224
6225 /* no argument after the command */
6226 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006227 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006228 return -EINVAL;
6229 }
6230
6231 /* no space after the command */
6232 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006233 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006234 return -EINVAL;
6235 }
6236
6237 /* remove empty spaces */
6238 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6239 in_ptr++;
6240
6241 /* no argument followed by spaces */
6242 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006243 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006244 return -EINVAL;
6245 }
6246
6247 /* get the argument i.e. antenna mode */
6248 v = sscanf(in_ptr, "%31s ", arg1);
6249 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006250 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006251 return -EINVAL;
6252 }
6253
6254 v = kstrtos32(arg1, 10, &tmp);
6255 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006256 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006257 return -EINVAL;
6258 }
6259
6260 return tmp;
6261}
6262
6263/**
6264 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6265 * mask is 2x2 mode
6266 * @hdd_ctx: Pointer to hdd contex
6267 *
6268 * Return: true if supported chain mask 2x2 else false
6269 */
6270static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6271{
6272 /*
6273 * Revisit and the update logic to determine the number
6274 * of TX/RX chains supported in the system when
6275 * antenna sharing per band chain mask support is
6276 * brought in
6277 */
6278 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6279}
6280
6281/**
6282 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6283 * chain mask is 1x1
6284 * @hdd_ctx: Pointer to hdd contex
6285 *
6286 * Return: true if supported chain mask 1x1 else false
6287 */
6288static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6289{
6290 /*
6291 * Revisit and update the logic to determine the number
6292 * of TX/RX chains supported in the system when
6293 * antenna sharing per band chain mask support is
6294 * brought in
6295 */
6296 return (!hdd_ctx->config->enable2x2) ? true : false;
6297}
6298
Nitesh Shahe50711f2017-04-26 16:30:45 +05306299QDF_STATUS hdd_update_smps_antenna_mode(hdd_context_t *hdd_ctx, int mode)
6300{
6301 QDF_STATUS status;
6302 uint8_t smps_mode;
6303 uint8_t smps_enable;
6304
6305 /* Update SME SMPS config */
6306 if (HDD_ANTENNA_MODE_1X1 == mode) {
6307 smps_enable = true;
6308 smps_mode = HDD_SMPS_MODE_STATIC;
6309 } else {
6310 smps_enable = false;
6311 smps_mode = HDD_SMPS_MODE_DISABLED;
6312 }
6313
6314 hdd_debug("Update SME SMPS enable: %d mode: %d",
6315 smps_enable, smps_mode);
6316 status = sme_update_mimo_power_save(
6317 hdd_ctx->hHal, smps_enable, smps_mode, false);
6318 if (QDF_STATUS_SUCCESS != status) {
6319 hdd_err("Update SMPS config failed enable: %d mode: %d"
6320 "status: %d",
6321 smps_enable, smps_mode, status);
6322 return QDF_STATUS_E_FAILURE;
6323 }
6324
6325 hdd_ctx->current_antenna_mode = mode;
6326 /*
6327 * Update the user requested nss in the mac context.
6328 * This will be used in tdls protocol engine to form tdls
6329 * Management frames.
6330 */
6331 sme_update_user_configured_nss(
6332 hdd_ctx->hHal,
6333 hdd_ctx->current_antenna_mode);
6334
6335 hdd_debug("Successfully switched to mode: %d x %d",
6336 hdd_ctx->current_antenna_mode,
6337 hdd_ctx->current_antenna_mode);
6338
6339 return QDF_STATUS_SUCCESS;
6340}
6341
Archana Ramachandran393f3792015-11-13 17:13:21 -08006342/**
6343 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6344 * handler
6345 * @adapter: Pointer to network adapter
6346 * @hdd_ctx: Pointer to hdd context
6347 * @command: Pointer to input command
6348 * @command_len: Command length
6349 * @priv_data: Pointer to private data in command
6350 */
6351static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6352 hdd_context_t *hdd_ctx,
6353 uint8_t *command,
6354 uint8_t command_len,
6355 hdd_priv_data_t *priv_data)
6356{
6357 struct sir_antenna_mode_param params;
6358 QDF_STATUS status;
6359 int ret = 0;
6360 int mode;
6361 uint8_t *value = command;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006362
6363 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6364 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6365 hdd_err("Operation invalid in non sta or concurrent mode");
6366 ret = -EPERM;
6367 goto exit;
6368 }
6369
6370 mode = hdd_parse_setantennamode_command(value);
6371 if (mode < 0) {
6372 hdd_err("Invalid SETANTENNA command");
6373 ret = mode;
6374 goto exit;
6375 }
6376
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006377 hdd_debug("Processing antenna mode switch to: %d", mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006378
6379 if (hdd_ctx->current_antenna_mode == mode) {
6380 hdd_err("System already in the requested mode");
6381 ret = 0;
6382 goto exit;
6383 }
6384
6385 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6386 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6387 hdd_err("System does not support 2x2 mode");
6388 ret = -EPERM;
6389 goto exit;
6390 }
6391
6392 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6393 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6394 hdd_err("System only supports 1x1 mode");
6395 ret = 0;
6396 goto exit;
6397 }
6398
6399 switch (mode) {
6400 case HDD_ANTENNA_MODE_1X1:
6401 params.num_rx_chains = 1;
6402 params.num_tx_chains = 1;
6403 break;
6404 case HDD_ANTENNA_MODE_2X2:
6405 params.num_rx_chains = 2;
6406 params.num_tx_chains = 2;
6407 break;
6408 default:
6409 hdd_err("unsupported antenna mode");
6410 ret = -EINVAL;
6411 goto exit;
6412 }
6413
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006414 /* Check TDLS status and update antenna mode */
6415 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006416 policy_mgr_is_sta_active_connection_exists(
6417 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006418 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6419 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006420 if (0 != ret)
6421 goto exit;
6422 }
6423
Archana Ramachandran393f3792015-11-13 17:13:21 -08006424 params.set_antenna_mode_resp =
6425 (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006426 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006427 params.num_rx_chains,
6428 params.num_tx_chains);
6429
6430
6431 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6432 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6433 if (QDF_STATUS_SUCCESS != status) {
6434 hdd_err("set antenna mode failed status : %d", status);
6435 ret = -EFAULT;
6436 goto exit;
6437 }
6438
6439 ret = wait_for_completion_timeout(
6440 &hdd_ctx->set_antenna_mode_cmpl,
6441 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6442 if (!ret) {
6443 ret = -EFAULT;
6444 hdd_err("send set antenna mode timed out");
6445 goto exit;
6446 }
6447
Nitesh Shahe50711f2017-04-26 16:30:45 +05306448 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006449 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006450 ret = -EFAULT;
6451 goto exit;
6452 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006453 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006454exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006455#ifdef FEATURE_WLAN_TDLS
6456 /* Reset tdls NSS flags */
6457 if (hdd_ctx->tdls_nss_switch_in_progress &&
6458 hdd_ctx->tdls_nss_teardown_complete) {
6459 hdd_ctx->tdls_nss_switch_in_progress = false;
6460 hdd_ctx->tdls_nss_teardown_complete = false;
6461 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006462 hdd_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
Kabilan Kannanff89f742016-08-15 18:14:10 -07006463 hdd_ctx->tdls_nss_switch_in_progress,
6464 hdd_ctx->tdls_nss_teardown_complete);
6465#endif
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006466 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006467 ret, hdd_ctx->current_antenna_mode);
6468 return ret;
6469
6470}
6471
6472/**
6473 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6474 * handler
6475 * @adapter: Pointer to hdd adapter
6476 * @hdd_ctx: Pointer to hdd context
6477 * @command: Pointer to input command
6478 * @command_len: length of the command
6479 * @priv_data: private data coming with the driver command
6480 *
6481 * Return: 0 for success non-zero for failure
6482 */
6483static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6484 hdd_context_t *hdd_ctx,
6485 uint8_t *command,
6486 uint8_t command_len,
6487 hdd_priv_data_t *priv_data)
6488{
6489 uint32_t antenna_mode = 0;
6490 char extra[32];
6491 uint8_t len = 0;
6492
6493 antenna_mode = hdd_ctx->current_antenna_mode;
6494 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6495 antenna_mode);
6496 len = QDF_MIN(priv_data->total_len, len + 1);
6497 if (copy_to_user(priv_data->buf, &extra, len)) {
6498 hdd_err("Failed to copy data to user buffer");
6499 return -EFAULT;
6500 }
6501
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006502 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006503
6504 return 0;
6505}
6506
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006507/*
6508 * dummy (no-op) hdd driver command handler
6509 */
6510static int drv_cmd_dummy(hdd_adapter_t *adapter,
6511 hdd_context_t *hdd_ctx,
6512 uint8_t *command,
6513 uint8_t command_len,
6514 hdd_priv_data_t *priv_data)
6515{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006516 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006517 adapter->dev->name, command);
6518 return 0;
6519}
6520
6521/*
6522 * handler for any unsupported wlan hdd driver command
6523 */
6524static int drv_cmd_invalid(hdd_adapter_t *adapter,
6525 hdd_context_t *hdd_ctx,
6526 uint8_t *command,
6527 uint8_t command_len,
6528 hdd_priv_data_t *priv_data)
6529{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306530 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006531 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6532 adapter->sessionId, 0));
6533
6534 hdd_warn("%s: Unsupported driver command \"%s\"",
6535 adapter->dev->name, command);
6536
6537 return -ENOTSUPP;
6538}
6539
6540/**
6541 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6542 * @adapter: HDD adapter
6543 * @hdd_ctx: HDD context
6544 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6545 * @command_len: command len
6546 * @priv_data: private data
6547 *
6548 * Return: status
6549 */
6550static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6551 hdd_context_t *hdd_ctx,
6552 uint8_t *command,
6553 uint8_t command_len,
6554 hdd_priv_data_t *priv_data)
6555{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306556 QDF_STATUS status;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006557 uint8_t fcc_constraint;
6558 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006559
6560 /*
6561 * this command would be called by user-space when it detects WLAN
6562 * ON after airplane mode is set. When APM is set, WLAN turns off.
6563 * But it can be turned back on. Otherwise; when APM is turned back
6564 * off, WLAN would turn back on. So at that point the command is
6565 * expected to come down. 0 means disable, 1 means enable. The
6566 * constraint is removed when parameter 1 is set or different
6567 * country code is set
6568 */
6569
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006570 err = kstrtou8(command + command_len + 1, 10, &fcc_constraint);
6571 if (err) {
6572 hdd_err("error %d parsing userspace fcc parameter", err);
6573 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006574 }
6575
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006576 status = ucfg_reg_set_fcc_constraint(hdd_ctx->hdd_pdev,
6577 fcc_constraint);
6578
6579 if (QDF_IS_STATUS_ERROR(status))
6580 hdd_err("Failed to %s tx power for channels 12/13",
6581 fcc_constraint ? "reduce" : "restore");
6582
6583 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006584}
6585
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306586/**
6587 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6588 * command
6589 * @value: Pointer to the command
6590 * @chan_number: Pointer to the channel number
6591 * @chan_bw: Pointer to the channel bandwidth
6592 *
6593 * Parses and provides the channel number and channel width from the input
6594 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6595 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6596 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6597 *
6598 * Return: 0 for success, non-zero for failure
6599 */
6600static int hdd_parse_set_channel_switch_command(uint8_t *value,
6601 uint32_t *chan_number,
6602 uint32_t *chan_bw)
6603{
6604 const uint8_t *in_ptr = value;
6605 int ret;
6606
6607 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6608
6609 /* no argument after the command */
6610 if (NULL == in_ptr) {
6611 hdd_err("No argument after the command");
6612 return -EINVAL;
6613 }
6614
6615 /* no space after the command */
6616 if (SPACE_ASCII_VALUE != *in_ptr) {
6617 hdd_err("No space after the command ");
6618 return -EINVAL;
6619 }
6620
6621 /* remove empty spaces and move the next argument */
6622 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6623 in_ptr++;
6624
6625 /* no argument followed by spaces */
6626 if ('\0' == *in_ptr) {
6627 hdd_err("No argument followed by spaces");
6628 return -EINVAL;
6629 }
6630
6631 /* get the two arguments: channel number and bandwidth */
6632 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6633 if (ret != 2) {
6634 hdd_err("Arguments retrieval from cmd string failed");
6635 return -EINVAL;
6636 }
6637
6638 return 0;
6639}
6640
6641/**
6642 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6643 * @adapter: HDD adapter
6644 * @hdd_ctx: HDD context
6645 * @command: Pointer to the input command CHANNEL_SWITCH
6646 * @command_len: Command len
6647 * @priv_data: Private data
6648 *
6649 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6650 * of SAP/P2P-GO
6651 *
6652 * Return: 0 for success, non-zero for failure
6653 */
6654static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
6655 hdd_context_t *hdd_ctx,
6656 uint8_t *command,
6657 uint8_t command_len,
6658 hdd_priv_data_t *priv_data)
6659{
6660 struct net_device *dev = adapter->dev;
6661 int status;
6662 uint32_t chan_number = 0, chan_bw = 0;
6663 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006664 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306665
Krunal Sonibe766b02016-03-10 13:00:44 -08006666 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6667 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306668 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6669 adapter->device_mode);
6670 return -EINVAL;
6671 }
6672
6673 status = hdd_parse_set_channel_switch_command(value,
6674 &chan_number, &chan_bw);
6675 if (status) {
6676 hdd_err("Invalid CHANNEL_SWITCH command");
6677 return status;
6678 }
6679
6680 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6681 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6682 return -EINVAL;
6683 }
6684
6685 if (chan_bw == 80)
6686 width = CH_WIDTH_80MHZ;
6687 else if (chan_bw == 40)
6688 width = CH_WIDTH_40MHZ;
6689 else
6690 width = CH_WIDTH_20MHZ;
6691
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006692 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306693
6694 status = hdd_softap_set_channel_change(dev, chan_number, width);
6695 if (status) {
6696 hdd_err("Set channel change fail");
6697 return status;
6698 }
6699
6700 return 0;
6701}
6702
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006703/*
6704 * The following table contains all supported WLAN HDD
6705 * IOCTL driver commands and the handler for each of them.
6706 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07006707static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006708 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
6709 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
6710 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
6711 {"SETBAND", drv_cmd_set_band},
6712 {"SETWMMPS", drv_cmd_set_wmmps},
6713 {"COUNTRY", drv_cmd_country},
6714 {"SETSUSPENDMODE", drv_cmd_dummy},
6715 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
6716 {"BTCOEXSCAN", drv_cmd_dummy},
6717 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006718 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
6719 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
6720 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
6721 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
6722 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
6723 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006724 {"SETROAMMODE", drv_cmd_set_roam_mode},
6725 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006726 {"SETROAMDELTA", drv_cmd_set_roam_delta},
6727 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006728 {"GETBAND", drv_cmd_get_band},
6729 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
6730 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
6731 {"GETCCXMODE", drv_cmd_get_ccx_mode},
6732 {"GETOKCMODE", drv_cmd_get_okc_mode},
6733 {"GETFASTROAM", drv_cmd_get_fast_roam},
6734 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
6735 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
6736 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
6737 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
6738 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
6739 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
6740 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
6741 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
6742 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
6743 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
6744 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
6745 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
6746 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
6747 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
6748 {"REASSOC", drv_cmd_reassoc},
6749 {"SETWESMODE", drv_cmd_set_wes_mode},
6750 {"GETWESMODE", drv_cmd_get_wes_mode},
6751 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
6752 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
6753 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
6754 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006755 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006756 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
6757 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006758 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006759 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006760 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
6761 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
6762 {"SCAN-ACTIVE", drv_cmd_scan_active},
6763 {"SCAN-PASSIVE", drv_cmd_scan_passive},
6764 {"GETDWELLTIME", drv_cmd_get_dwell_time},
6765 {"SETDWELLTIME", drv_cmd_set_dwell_time},
6766 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08006767 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
6768 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
6769 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
6770 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
6771 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
6772 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
6773 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006774#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006775 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
6776 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
6777 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006778 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
6779 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
6780 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006781#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006782 {"SETMCRATE", drv_cmd_set_mc_rate},
6783 {"MAXTXPOWER", drv_cmd_max_tx_power},
6784 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
6785 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
6786 {"GETLINKSTATUS", drv_cmd_get_link_status},
6787#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6788 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
6789 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
6790 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
6791#endif
6792#ifdef FEATURE_WLAN_TDLS
6793 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
6794 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
6795 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
6796 {"TDLSSCAN", drv_cmd_tdls_scan},
6797#endif
6798 {"RSSI", drv_cmd_get_rssi},
6799 {"LINKSPEED", drv_cmd_get_linkspeed},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006800 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
6801 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
6802 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306803 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08006804 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
6805 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Hanumanth Reddy Pothula0161e1d2017-02-14 17:36:13 +05306806 {"STOP", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006807};
6808
6809/**
6810 * hdd_drv_cmd_process() - chooses and runs the proper
6811 * handler based on the input command
6812 * @adapter: Pointer to the hdd adapter
6813 * @cmd: Pointer to the driver command
6814 * @priv_data: Pointer to the data associated with the command
6815 *
6816 * This function parses the input hdd driver command and runs
6817 * the proper handler
6818 *
6819 * Return: 0 for success non-zero for failure
6820 */
6821static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
6822 uint8_t *cmd,
6823 hdd_priv_data_t *priv_data)
6824{
6825 hdd_context_t *hdd_ctx;
6826 int i;
6827 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6828 uint8_t *cmd_i = NULL;
6829 hdd_drv_cmd_handler_t handler = NULL;
6830 int len = 0;
6831
6832 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006833 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006834 return -EINVAL;
6835 }
6836
6837 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
6838
6839 for (i = 0; i < cmd_num_total; i++) {
6840
6841 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6842 handler = hdd_drv_cmds[i].handler;
6843 len = strlen(cmd_i);
6844
6845 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006846 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006847 return -EINVAL;
6848 }
6849
6850 if (strncasecmp(cmd, cmd_i, len) == 0)
6851 return handler(adapter, hdd_ctx,
6852 cmd, len, priv_data);
6853 }
6854
6855 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6856}
6857
6858/**
6859 * hdd_driver_command() - top level wlan hdd driver command handler
6860 * @adapter: Pointer to the hdd adapter
6861 * @priv_data: Pointer to the raw command data
6862 *
6863 * This function is the top level wlan hdd driver command handler. It
6864 * handles the command with the help of hdd_drv_cmd_process()
6865 *
6866 * Return: 0 for success non-zero for failure
6867 */
6868static int hdd_driver_command(hdd_adapter_t *adapter,
6869 hdd_priv_data_t *priv_data)
6870{
6871 uint8_t *command = NULL;
6872 int ret = 0;
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306873 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006874
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306875 ENTER();
6876
Anurag Chouhan6d760662016-02-20 16:05:43 +05306877 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006878 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006879 return -EINVAL;
6880 }
6881
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306882 ret = wlan_hdd_validate_context(hdd_ctx);
6883 if (ret)
6884 return ret;
6885
6886 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
6887 hdd_err("Driver module is closed; command can not be processed");
6888 return -EINVAL;
6889 }
6890
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006891 /*
6892 * Note that valid pointers are provided by caller
6893 */
6894
6895 /* copy to local struct to avoid numerous changes to legacy code */
6896 if (priv_data->total_len <= 0 ||
6897 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006898 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006899 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006900 ret = -EINVAL;
6901 goto exit;
6902 }
6903
6904 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006905 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006906 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006907 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006908 ret = -ENOMEM;
6909 goto exit;
6910 }
6911
6912 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6913 ret = -EFAULT;
6914 goto exit;
6915 }
6916
6917 /* Make sure the command is NUL-terminated */
6918 command[priv_data->total_len] = '\0';
6919
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006920 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006921 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6922
6923exit:
6924 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006925 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306926 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006927 return ret;
6928}
6929
6930#ifdef CONFIG_COMPAT
6931static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6932{
6933 struct {
6934 compat_uptr_t buf;
6935 int used_len;
6936 int total_len;
6937 } compat_priv_data;
6938 hdd_priv_data_t priv_data;
6939 int ret = 0;
6940
6941 /*
6942 * Note that adapter and ifr have already been verified by caller,
6943 * and HDD context has also been validated
6944 */
6945 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
6946 sizeof(compat_priv_data))) {
6947 ret = -EFAULT;
6948 goto exit;
6949 }
6950 priv_data.buf = compat_ptr(compat_priv_data.buf);
6951 priv_data.used_len = compat_priv_data.used_len;
6952 priv_data.total_len = compat_priv_data.total_len;
6953 ret = hdd_driver_command(adapter, &priv_data);
6954exit:
6955 return ret;
6956}
6957#else /* CONFIG_COMPAT */
6958static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6959{
6960 /* will never be invoked */
6961 return 0;
6962}
6963#endif /* CONFIG_COMPAT */
6964
6965static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6966{
6967 hdd_priv_data_t priv_data;
6968 int ret = 0;
6969
6970 /*
6971 * Note that adapter and ifr have already been verified by caller,
6972 * and HDD context has also been validated
6973 */
6974 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
6975 ret = -EFAULT;
6976 else
6977 ret = hdd_driver_command(adapter, &priv_data);
6978
6979 return ret;
6980}
6981
6982/**
6983 * __hdd_ioctl() - ioctl handler for wlan network interfaces
6984 * @dev: device upon which the ioctl was received
6985 * @ifr: ioctl request information
6986 * @cmd: ioctl command
6987 *
6988 * This function does initial processing of wlan device ioctls.
6989 * Currently two flavors of ioctls are supported. The primary ioctl
6990 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
6991 * for Android "DRIVER" commands. The other ioctl that is
6992 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
6993 * for FTM on some platforms. This function simply verifies that the
6994 * driver is in a sane state, and that the ioctl is one of the
6995 * supported flavors, in which case flavor-specific handlers are
6996 * dispatched.
6997 *
6998 * Return: 0 on success, non-zero on error
6999 */
7000static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7001{
7002 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7003 hdd_context_t *hdd_ctx;
7004 int ret;
7005
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007006 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307007
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007008 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007009 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007010 ret = -ENODEV;
7011 goto exit;
7012 }
7013
7014 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007015 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007016 ret = -EINVAL;
7017 goto exit;
7018 }
7019#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307020 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007021 if (SIOCIOCTLTX99 == cmd) {
7022 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7023 goto exit;
7024 }
7025 }
7026#endif
7027
7028 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7029 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307030 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007031 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007032
7033 switch (cmd) {
7034 case (SIOCDEVPRIVATE + 1):
7035 if (is_compat_task())
7036 ret = hdd_driver_compat_ioctl(adapter, ifr);
7037 else
7038 ret = hdd_driver_ioctl(adapter, ifr);
7039 break;
7040 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007041 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007042 ret = -EINVAL;
7043 break;
7044 }
7045exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307046 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007047 return ret;
7048}
7049
7050/**
7051 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7052 * @dev: device upon which the ioctl was received
7053 * @ifr: ioctl request information
7054 * @cmd: ioctl command
7055 *
7056 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7057 * which is where the ioctls are really handled.
7058 *
7059 * Return: 0 on success, non-zero on error
7060 */
7061int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7062{
7063 int ret;
7064
7065 cds_ssr_protect(__func__);
7066 ret = __hdd_ioctl(dev, ifr, cmd);
7067 cds_ssr_unprotect(__func__);
7068 return ret;
7069}