blob: 281bcbec69ead5a57e31e331a831e5311fd4409b [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
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700237 v = sscanf(inPtr, "%32s ", buf);
238 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
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700275 v = sscanf(inPtr, "%32s ", buf);
276 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
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700319 v = sscanf(inPtr, "%32s ", buf);
320 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 QDF_STATUS status;
780 hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
781 tCsrRoamProfile *profile = &wext_state->roamProfile;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700782 struct wma_roam_invoke_cmd *fastreassoc;
Rajeev Kumarea95edd2017-01-11 20:49:36 -0800783 struct scheduler_msg msg = {0};
Naveen Rawat05376ee2016-07-18 16:43:32 -0700784
785 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
786 if (NULL == fastreassoc) {
787 hdd_err("qdf_mem_malloc failed for fastreassoc");
788 return;
789 }
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800790 fastreassoc->vdev_id = adapter->sessionId;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700791 fastreassoc->channel = channel;
792 fastreassoc->bssid[0] = bssid[0];
793 fastreassoc->bssid[1] = bssid[1];
794 fastreassoc->bssid[2] = bssid[2];
795 fastreassoc->bssid[3] = bssid[3];
796 fastreassoc->bssid[4] = bssid[4];
797 fastreassoc->bssid[5] = bssid[5];
798
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800799 status = sme_get_beacon_frm(WLAN_HDD_GET_HAL_CTX(adapter), profile,
800 bssid, &fastreassoc->frame_buf,
801 &fastreassoc->frame_len);
802
803 if (QDF_STATUS_SUCCESS != status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800804 hdd_warn("sme_get_beacon_frm failed");
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800805 fastreassoc->frame_buf = NULL;
806 fastreassoc->frame_len = 0;
807 }
808
Naveen Rawat05376ee2016-07-18 16:43:32 -0700809 msg.type = SIR_HAL_ROAM_INVOKE;
810 msg.reserved = 0;
811 msg.bodyptr = fastreassoc;
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800812 status = scheduler_post_msg(QDF_MODULE_ID_WMA, &msg);
813 if (QDF_STATUS_SUCCESS != status) {
Naveen Rawat05376ee2016-07-18 16:43:32 -0700814 hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA");
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800815 qdf_mem_free(fastreassoc);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700816 }
817}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700818#endif
819
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820/**
821 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800822 * @adapter: Adapter upon which the command was received
823 * @bssid: BSSID with which to reassociate
824 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700825 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800826 *
827 * This function performs a userspace-directed reassoc operation
828 *
829 * Return: 0 for success non-zero for failure
830 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700831int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800832 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833{
834 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700835 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800836 int ret = 0;
837
Naveen Rawat05376ee2016-07-18 16:43:32 -0700838 if (hdd_ctx == NULL) {
839 hdd_err("Invalid hdd ctx");
840 return -EINVAL;
841 }
842
Krunal Sonibe766b02016-03-10 13:00:44 -0800843 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800844 hdd_warn("Unsupported in mode %s(%d)",
845 hdd_device_mode_to_string(adapter->device_mode),
846 adapter->device_mode);
847 return -EINVAL;
848 }
849
850 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
851
852 /* if not associated, no need to proceed with reassoc */
853 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800854 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800855 ret = -EINVAL;
856 goto exit;
857 }
858
859 /*
860 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800861 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800862 */
863 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530864 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800865 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800866 channel = pHddStaCtx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800867 }
868
869 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530870 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800871 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800872 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873 ret = -EINVAL;
874 goto exit;
875 }
876
877 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700878 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800879 hdd_wma_send_fastreassoc_cmd(adapter,
Naveen Rawat05376ee2016-07-18 16:43:32 -0700880 bssid, (int)channel);
881 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800883
884 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700885 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530886 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800887 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
888 &handoffInfo);
889 }
890exit:
891 return ret;
892}
893
894/**
895 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
896 * @adapter: Adapter upon which the command was received
897 * @command: ASCII text command that was received
898 *
899 * This function parses the v1 REASSOC command with the format
900 *
901 * REASSOC xx:xx:xx:xx:xx:xx CH
902 *
903 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
904 * BSSID and CH is the ASCII representation of the channel. For
905 * example
906 *
907 * REASSOC 00:0a:0b:11:22:33 48
908 *
909 * Return: 0 for success non-zero for failure
910 */
911static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
912{
913 uint8_t channel = 0;
914 tSirMacAddr bssid;
915 int ret;
916
917 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700918 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700919 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700920 else
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700921 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700922
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800923 return ret;
924}
925
926/**
927 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
928 * @adapter: Adapter upon which the command was received
929 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700930 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931 *
932 * This function parses the v2 REASSOC command with the format
933 *
934 * REASSOC <android_wifi_reassoc_params>
935 *
936 * Return: 0 for success non-zero for failure
937 */
938static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
939{
940 struct android_wifi_reassoc_params params;
941 tSirMacAddr bssid;
942 int ret;
943
944 /* The params are located after "REASSOC " */
945 memcpy(&params, command + 8, sizeof(params));
946
947 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700948 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949 ret = -EINVAL;
950 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700951 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800952 }
953 return ret;
954}
955
956/**
957 * hdd_parse_reassoc() - parse the REASSOC command
958 * @adapter: Adapter upon which the command was received
959 * @command: Command that was received
960 *
961 * There are two different versions of the REASSOC command. Version 1
962 * of the command contains a parameter list that is ASCII characters
963 * whereas version 2 contains a combination of ASCII and binary
964 * payload. Determine if a version 1 or a version 2 command is being
965 * parsed by examining the parameters, and then dispatch the parser
966 * that is appropriate for the command.
967 *
968 * Return: 0 for success non-zero for failure
969 */
970static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
971{
972 int ret;
973
974 /* both versions start with "REASSOC "
975 * v1 has a bssid and channel # as an ASCII string
976 * REASSOC xx:xx:xx:xx:xx:xx CH
977 * v2 has a C struct
978 * REASSOC <binary c struct>
979 *
980 * The first field in the v2 struct is also the bssid in ASCII.
981 * But in the case of a v2 message the BSSID is NUL-terminated.
982 * Hence we can peek at that offset to see if this is V1 or V2
983 * REASSOC xx:xx:xx:xx:xx:xx*
984 * 1111111111222222
985 * 01234567890123456789012345
986 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700987 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800988 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700989 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990 ret = hdd_parse_reassoc_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800991
992 return ret;
993}
994
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800995/**
996 * hdd_sendactionframe() - send a userspace-supplied action frame
997 * @adapter: Adapter upon which the command was received
998 * @bssid: BSSID target of the action frame
999 * @channel: Channel upon which to send the frame
1000 * @dwell_time: Amount of time to dwell when the frame is sent
1001 * @payload_len:Length of the payload
1002 * @payload: Payload of the frame
1003 *
1004 * This function sends a userspace-supplied action frame
1005 *
1006 * Return: 0 for success non-zero for failure
1007 */
1008static int
1009hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1010 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001011 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001012{
1013 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001014 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001015 uint8_t *frame;
1016 struct ieee80211_hdr_3addr *hdr;
1017 u64 cookie;
1018 hdd_station_ctx_t *pHddStaCtx;
1019 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001020 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1021 (tpSirMacVendorSpecificFrameHdr) payload;
1022#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1023 struct cfg80211_mgmt_tx_params params;
1024#endif
1025
Krunal Sonibe766b02016-03-10 13:00:44 -08001026 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 hdd_warn("Unsupported in mode %s(%d)",
1028 hdd_device_mode_to_string(adapter->device_mode),
1029 adapter->device_mode);
1030 return -EINVAL;
1031 }
1032
1033 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1034 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1035
1036 /* if not associated, no need to send action frame */
1037 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001038 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 ret = -EINVAL;
1040 goto exit;
1041 }
1042
1043 /*
1044 * if the target bssid is different from currently associated AP,
1045 * then no need to send action frame
1046 */
1047 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301048 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001049 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001050 ret = -EINVAL;
1051 goto exit;
1052 }
1053
1054 chan.center_freq = sme_chn_to_freq(channel);
1055 /* Check if it is specific action frame */
1056 if (pVendorSpecific->category ==
1057 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1058 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001059
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301060 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001061 /*
1062 * if the channel number is different from operating
1063 * channel then no need to send action frame
1064 */
1065 if (channel != 0) {
1066 if (channel !=
1067 pHddStaCtx->conn_info.operationChannel) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001068 hdd_warn("channel(%d) is different from operating channel(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001069 channel,
1070 pHddStaCtx->conn_info.
1071 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001072 ret = -EINVAL;
1073 goto exit;
1074 }
1075 /*
1076 * If channel number is specified and same
1077 * as home channel, ensure that action frame
1078 * is sent immediately by cancelling
1079 * roaming scans. Otherwise large dwell times
1080 * may cause long delays in sending action
1081 * frames.
1082 */
1083 sme_abort_roam_scan(hdd_ctx->hHal,
1084 adapter->sessionId);
1085 } else {
1086 /*
1087 * 0 is accepted as current home channel,
1088 * delayed transmission of action frame is ok.
1089 */
1090 chan.center_freq =
1091 sme_chn_to_freq(pHddStaCtx->conn_info.
1092 operationChannel);
1093 }
1094 }
1095 }
1096 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001097 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098 ret = -EINVAL;
1099 goto exit;
1100 }
1101
1102 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301103 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001104 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001105 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106 ret = -ENOMEM;
1107 goto exit;
1108 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109
1110 hdr = (struct ieee80211_hdr_3addr *)frame;
1111 hdr->frame_control =
1112 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301113 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1114 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301115 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301116 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1117 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118
1119#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1120 params.chan = &chan;
1121 params.offchan = 0;
1122 params.wait = dwell_time;
1123 params.buf = frame;
1124 params.len = frame_len;
1125 params.no_cck = 1;
1126 params.dont_wait_for_ack = 1;
1127 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1128#else
1129 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001131 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001132
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133 dwell_time, frame, frame_len, 1, 1, &cookie);
1134#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1135
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301136 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001137exit:
1138 return ret;
1139}
1140
1141/**
1142 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1143 * SENDACTIONFRAME command
1144 * @adapter: Adapter upon which the command was received
1145 * @command: ASCII text command that was received
1146 *
1147 * This function parses the v1 SENDACTIONFRAME command with the format
1148 *
1149 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1150 *
1151 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1152 * BSSID, CH is the ASCII representation of the channel, DW is the
1153 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1154 * payload. For example
1155 *
1156 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1157 *
1158 * Return: 0 for success non-zero for failure
1159 */
1160static int
1161hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1162{
1163 uint8_t channel = 0;
1164 uint8_t dwell_time = 0;
1165 uint8_t payload_len = 0;
1166 uint8_t *payload = NULL;
1167 tSirMacAddr bssid;
1168 int ret;
1169
1170 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1171 &dwell_time, &payload,
1172 &payload_len);
1173 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001174 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001175 } else {
1176 ret = hdd_sendactionframe(adapter, bssid, channel,
1177 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301178 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001179 }
1180
1181 return ret;
1182}
1183
1184/**
1185 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1186 * SENDACTIONFRAME command
1187 * @adapter: Adapter upon which the command was received
1188 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001189 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190 *
1191 * This function parses the v2 SENDACTIONFRAME command with the format
1192 *
1193 * SENDACTIONFRAME <android_wifi_af_params>
1194 *
1195 * Return: 0 for success non-zero for failure
1196 */
1197static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001198hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1199 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001200{
1201 struct android_wifi_af_params *params;
1202 tSirMacAddr bssid;
1203 int ret;
1204
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001205 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001206 total_len -= 16;
1207 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001208
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001209 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1210 (params->len > total_len)) {
1211 hdd_err("Invalid payload length: %d", params->len);
1212 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001213 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001214
1215 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1216 hdd_err("MAC address parsing failed");
1217 return -EINVAL;
1218 }
1219
1220 if (params->channel < 0 ||
1221 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1222 hdd_err("Invalid channel: %d", params->channel);
1223 return -EINVAL;
1224 }
1225
1226 if (params->dwell_time < 0) {
1227 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1228 return -EINVAL;
1229 }
1230
1231 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1232 params->dwell_time, params->len, params->data);
1233
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001234 return ret;
1235}
1236
1237/**
1238 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1239 * @adapter: Adapter upon which the command was received
1240 * @command: Command that was received
1241 *
1242 * There are two different versions of the SENDACTIONFRAME command.
1243 * Version 1 of the command contains a parameter list that is ASCII
1244 * characters whereas version 2 contains a combination of ASCII and
1245 * binary payload. Determine if a version 1 or a version 2 command is
1246 * being parsed by examining the parameters, and then dispatch the
1247 * parser that is appropriate for the version of the command.
1248 *
1249 * Return: 0 for success non-zero for failure
1250 */
1251static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001252hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1253 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254{
1255 int ret;
1256
1257 /*
1258 * both versions start with "SENDACTIONFRAME "
1259 * v1 has a bssid and other parameters as an ASCII string
1260 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1261 * v2 has a C struct
1262 * SENDACTIONFRAME <binary c struct>
1263 *
1264 * The first field in the v2 struct is also the bssid in ASCII.
1265 * But in the case of a v2 message the BSSID is NUL-terminated.
1266 * Hence we can peek at that offset to see if this is V1 or V2
1267 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1268 * 111111111122222222223333
1269 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001270 * For both the commands, a valid command must have atleast
1271 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001272 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001273 if (total_len < 34) {
1274 hdd_err("Invalid command (total_len=%d)", total_len);
1275 return -EINVAL;
1276 }
1277
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001278 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001280 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001281 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001282
1283 return ret;
1284}
1285
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001286/**
1287 * hdd_parse_channellist() - HDD Parse channel list
1288 * @pValue: Pointer to input channel list
1289 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001290 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001291 * @pNumChannels: Pointer to number of roam scan channels
1292 *
1293 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001294 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1295 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001296 * if the Number of channels (N) does not match with the actual number
1297 * of channels passed then take the minimum of N and count of
1298 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1299 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1300 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1301 * removing duplicate channels from the list
1302 *
1303 * Return: 0 for success non-zero for failure
1304 */
1305static int
1306hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1307 uint8_t *pNumChannels)
1308{
1309 const uint8_t *inPtr = pValue;
1310 int tempInt;
1311 int j = 0;
1312 int v = 0;
1313 char buf[32];
1314
1315 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1316 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001317 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001318 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001319 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001320 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001321
1322 /* remove empty spaces */
1323 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1324 inPtr++;
1325
1326 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001327 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001328 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001329
1330 /* get the first argument ie the number of channels */
1331 v = sscanf(inPtr, "%31s ", buf);
1332 if (1 != v)
1333 return -EINVAL;
1334
1335 v = kstrtos32(buf, 10, &tempInt);
1336 if ((v < 0) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001337 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001338 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001339
1340 *pNumChannels = tempInt;
1341
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001342 hdd_debug("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001343
1344 for (j = 0; j < (*pNumChannels); j++) {
1345 /*
1346 * inPtr pointing to the beginning of first space after number
1347 * of channels
1348 */
1349 inPtr = strpbrk(inPtr, " ");
1350 /* no channel list after the number of channels argument */
1351 if (NULL == inPtr) {
1352 if (0 != j) {
1353 *pNumChannels = j;
1354 return 0;
1355 } else {
1356 return -EINVAL;
1357 }
1358 }
1359
1360 /* remove empty space */
1361 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1362 inPtr++;
1363
1364 /*
1365 * no channel list after the number of channels
1366 * argument and spaces
1367 */
1368 if ('\0' == *inPtr) {
1369 if (0 != j) {
1370 *pNumChannels = j;
1371 return 0;
1372 } else {
1373 return -EINVAL;
1374 }
1375 }
1376
1377 v = sscanf(inPtr, "%31s ", buf);
1378 if (1 != v)
1379 return -EINVAL;
1380
1381 v = kstrtos32(buf, 10, &tempInt);
1382 if ((v < 0) ||
1383 (tempInt <= 0) ||
1384 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1385 return -EINVAL;
1386 }
1387 pChannelList[j] = tempInt;
1388
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001389 hdd_debug("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001390 pChannelList[j]);
1391 }
1392
1393 return 0;
1394}
1395
1396/**
1397 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1398 * SETROAMSCANCHANNELS command
1399 * @adapter: Adapter upon which the command was received
1400 * @command: ASCII text command that was received
1401 *
1402 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1403 *
1404 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1405 *
1406 * Where "N" is the ASCII representation of the number of channels and
1407 * C1 thru Cn is the ASCII representation of the channels. For example
1408 *
1409 * SETROAMSCANCHANNELS 4 36 40 44 48
1410 *
1411 * Return: 0 for success non-zero for failure
1412 */
1413static int
1414hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1415 const char *command)
1416{
1417 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1418 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301419 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001420 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1421 int ret;
1422
1423 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1424 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001425 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426 goto exit;
1427 }
1428
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301429 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001430 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1431 adapter->sessionId, num_chan));
1432
1433 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001434 hdd_err("number of channels (%d) supported exceeded max (%d)",
1435 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436 ret = -EINVAL;
1437 goto exit;
1438 }
1439
1440 status =
1441 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1442 adapter->sessionId,
1443 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301444 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001445 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446 ret = -EINVAL;
1447 goto exit;
1448 }
1449exit:
1450 return ret;
1451}
1452
1453/**
1454 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1455 * SETROAMSCANCHANNELS command
1456 * @adapter: Adapter upon which the command was received
1457 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001458 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001459 *
1460 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1461 *
1462 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1463 *
1464 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1465 * what follows the space is an array of u08 parameters. For example
1466 *
1467 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1468 *
1469 * Return: 0 for success non-zero for failure
1470 */
1471static int
1472hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1473 const char *command)
1474{
1475 const uint8_t *value;
1476 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1477 uint8_t channel;
1478 uint8_t num_chan;
1479 int i;
1480 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301481 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001482 int ret = 0;
1483
1484 /* array of values begins after "SETROAMSCANCHANNELS " */
1485 value = command + 20;
1486
1487 num_chan = *value++;
1488 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001489 hdd_err("number of channels (%d) supported exceeded max (%d)",
1490 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001491 ret = -EINVAL;
1492 goto exit;
1493 }
1494
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301495 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1497 adapter->sessionId, num_chan));
1498
1499 for (i = 0; i < num_chan; i++) {
1500 channel = *value++;
1501 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001502 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001503 i, channel);
1504 ret = -EINVAL;
1505 goto exit;
1506 }
1507 channel_list[i] = channel;
1508 }
1509 status =
1510 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1511 adapter->sessionId,
1512 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301513 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001514 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001515 ret = -EINVAL;
1516 goto exit;
1517 }
1518exit:
1519 return ret;
1520}
1521
1522/**
1523 * hdd_parse_set_roam_scan_channels() - parse the
1524 * SETROAMSCANCHANNELS command
1525 * @adapter: Adapter upon which the command was received
1526 * @command: Command that was received
1527 *
1528 * There are two different versions of the SETROAMSCANCHANNELS command.
1529 * Version 1 of the command contains a parameter list that is ASCII
1530 * characters whereas version 2 contains a binary payload. Determine
1531 * if a version 1 or a version 2 command is being parsed by examining
1532 * the parameters, and then dispatch the parser that is appropriate for
1533 * the command.
1534 *
1535 * Return: 0 for success non-zero for failure
1536 */
1537static int
1538hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1539{
1540 const char *cursor;
1541 char ch;
1542 bool v1;
1543 int ret;
1544
1545 /* start after "SETROAMSCANCHANNELS " */
1546 cursor = command + 20;
1547
1548 /* assume we have a version 1 command until proven otherwise */
1549 v1 = true;
1550
1551 /* v1 params will only contain ASCII digits and space */
1552 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001553 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001554 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001556
1557 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001558 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001559 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001560 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001561
1562 return ret;
1563}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001564
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001565#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001566/**
1567 * hdd_parse_plm_cmd() - HDD Parse Plm command
1568 * @pValue: Pointer to input data
1569 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1570 *
1571 * This function parses the plm command passed in the format
1572 * CCXPLMREQ<space><enable><space><dialog_token><space>
1573 * <meas_token><space><num_of_bursts><space><burst_int><space>
1574 * <measu duration><space><burst_len><space><desired_tx_pwr>
1575 * <space><multcast_addr><space><number_of_channels>
1576 * <space><channel_numbers>
1577 *
1578 * Return: 0 for success non-zero for failure
1579 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001580static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001581{
1582 uint8_t *cmdPtr = NULL;
1583 int count, content = 0, ret = 0;
1584 char buf[32];
1585
1586 /* move to argument list */
1587 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1588 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301589 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001590
1591 /* no space after the command */
1592 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301593 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001594
1595 /* remove empty spaces */
1596 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1597 cmdPtr++;
1598
1599 /* START/STOP PLM req */
1600 ret = sscanf(cmdPtr, "%31s ", buf);
1601 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301602 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603
1604 ret = kstrtos32(buf, 10, &content);
1605 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301606 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001607
1608 pPlmRequest->enable = content;
1609 cmdPtr = strpbrk(cmdPtr, " ");
1610
1611 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301612 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613
1614 /* remove empty spaces */
1615 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1616 cmdPtr++;
1617
1618 /* Dialog token of radio meas req containing meas reqIE */
1619 ret = sscanf(cmdPtr, "%31s ", buf);
1620 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301621 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622
1623 ret = kstrtos32(buf, 10, &content);
1624 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301625 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626
1627 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001628 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629 cmdPtr = strpbrk(cmdPtr, " ");
1630
1631 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301632 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001633
1634 /* remove empty spaces */
1635 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1636 cmdPtr++;
1637
1638 /* measurement token of meas req IE */
1639 ret = sscanf(cmdPtr, "%31s ", buf);
1640 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301641 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001642
1643 ret = kstrtos32(buf, 10, &content);
1644 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301645 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001646
1647 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001648 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001649
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001650 hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001651 if (pPlmRequest->enable) {
1652
1653 cmdPtr = strpbrk(cmdPtr, " ");
1654
1655 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301656 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001657
1658 /* remove empty spaces */
1659 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1660 cmdPtr++;
1661
1662 /* total number of bursts after which STA stops sending */
1663 ret = sscanf(cmdPtr, "%31s ", buf);
1664 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301665 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666
1667 ret = kstrtos32(buf, 10, &content);
1668 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301669 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670
1671 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301672 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001673
1674 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001675 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676 cmdPtr = strpbrk(cmdPtr, " ");
1677
1678 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301679 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001680
1681 /* remove empty spaces */
1682 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1683 cmdPtr++;
1684
1685 /* burst interval in seconds */
1686 ret = sscanf(cmdPtr, "%31s ", buf);
1687 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301688 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689
1690 ret = kstrtos32(buf, 10, &content);
1691 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301692 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693
1694 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301695 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001696
1697 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001698 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001699 cmdPtr = strpbrk(cmdPtr, " ");
1700
1701 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301702 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001703
1704 /* remove empty spaces */
1705 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1706 cmdPtr++;
1707
1708 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1709 ret = sscanf(cmdPtr, "%31s ", buf);
1710 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301711 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001712
1713 ret = kstrtos32(buf, 10, &content);
1714 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301715 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716
1717 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301718 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001719
1720 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001721 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 cmdPtr = strpbrk(cmdPtr, " ");
1723
1724 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301725 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001726
1727 /* remove empty spaces */
1728 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1729 cmdPtr++;
1730
1731 /* burst length of PLM bursts */
1732 ret = sscanf(cmdPtr, "%31s ", buf);
1733 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301734 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001735
1736 ret = kstrtos32(buf, 10, &content);
1737 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301738 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001739
1740 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301741 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742
1743 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001744 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001745 cmdPtr = strpbrk(cmdPtr, " ");
1746
1747 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301748 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749
1750 /* remove empty spaces */
1751 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1752 cmdPtr++;
1753
1754 /* desired tx power for transmission of PLM bursts */
1755 ret = sscanf(cmdPtr, "%31s ", buf);
1756 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301757 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758
1759 ret = kstrtos32(buf, 10, &content);
1760 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301761 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762
1763 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301764 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001765
1766 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001767 hdd_debug("desiredTxPwr %d",
1768 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769
Anurag Chouhan6d760662016-02-20 16:05:43 +05301770 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001771 cmdPtr = strpbrk(cmdPtr, " ");
1772
1773 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301774 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775
1776 /* remove empty spaces */
1777 while ((SPACE_ASCII_VALUE == *cmdPtr)
1778 && ('\0' != *cmdPtr))
1779 cmdPtr++;
1780
1781 ret = sscanf(cmdPtr, "%31s ", buf);
1782 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301783 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784
1785 ret = kstrtos32(buf, 16, &content);
1786 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301787 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001788
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001789 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001790 }
1791
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001792 hdd_debug("MC addr " MAC_ADDRESS_STR,
1793 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794
1795 cmdPtr = strpbrk(cmdPtr, " ");
1796
1797 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301798 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001799
1800 /* remove empty spaces */
1801 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1802 cmdPtr++;
1803
1804 /* number of channels */
1805 ret = sscanf(cmdPtr, "%31s ", buf);
1806 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301807 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808
1809 ret = kstrtos32(buf, 10, &content);
1810 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301811 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812
1813 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301814 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001815
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001816 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001818 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001819
1820 /* Channel numbers */
1821 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1822 cmdPtr = strpbrk(cmdPtr, " ");
1823
1824 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301825 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001826
1827 /* remove empty spaces */
1828 while ((SPACE_ASCII_VALUE == *cmdPtr)
1829 && ('\0' != *cmdPtr))
1830 cmdPtr++;
1831
1832 ret = sscanf(cmdPtr, "%31s ", buf);
1833 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301834 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835
1836 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001837 if (ret < 0 || content <= 0 ||
1838 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301839 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001840
1841 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001842 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001843 }
1844 }
1845 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301846 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001847}
1848#endif
1849
1850#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1851static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1852{
1853 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1854 int rc;
1855
1856 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301857 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001859 hdd_ctx->ext_wow_should_suspend = is_success;
1860 complete(&hdd_ctx->ready_to_extwow);
1861}
1862
1863static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1864 tpSirExtWoWParams arg_params)
1865{
1866 tSirExtWoWParams params;
Jeff Johnson17d62672017-03-27 08:00:11 -07001867 QDF_STATUS qdf_ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001868 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1869 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1870 int rc;
1871
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301872 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001873
1874 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1875
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301876 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 &wlan_hdd_ready_to_extwow,
1878 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301879 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001880 hdd_err("sme_configure_ext_wow returned failure %d",
1881 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001882 return -EPERM;
1883 }
1884
1885 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1886 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1887 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001888 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001889 return -EPERM;
1890 }
1891
Jeff Johnson17d62672017-03-27 08:00:11 -07001892 if (!hdd_ctx->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001893 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001894 return -EPERM;
1895 }
1896
Jeff Johnson17d62672017-03-27 08:00:11 -07001897 if (hdd_ctx->config->extWowGotoSuspend) {
1898 hdd_info("Received ready to ExtWoW. Going to suspend");
1899
1900 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1901 if (rc < 0) {
1902 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1903 rc);
1904 return rc;
1905 }
1906 rc = wlan_hdd_bus_suspend();
1907 if (rc) {
1908 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1909 rc);
1910 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1911 return rc;
1912 }
1913 }
1914
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915 return 0;
1916}
1917
1918static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1919 int value)
1920{
1921 tSirExtWoWParams params;
1922 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1923 int rc;
1924
1925 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301926 if (rc)
1927 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001928
1929 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1930 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001931 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001932 return -EINVAL;
1933 }
1934
1935 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1936 hdd_ctx->is_extwow_app_type1_param_set)
1937 params.type = value;
1938 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1939 hdd_ctx->is_extwow_app_type2_param_set)
1940 params.type = value;
1941 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1942 hdd_ctx->is_extwow_app_type1_param_set &&
1943 hdd_ctx->is_extwow_app_type2_param_set)
1944 params.type = value;
1945 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001946 hdd_err("Set app params before enable it value %d",
1947 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948 return -EINVAL;
1949 }
1950
1951 params.vdev_id = vdev_id;
1952 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1953 (hdd_ctx->config->extWowApp2WakeupPinNumber
1954 << 8);
1955
1956 return hdd_enable_ext_wow(adapter, &params);
1957}
1958
1959static int hdd_set_app_type1_params(tHalHandle hHal,
1960 tpSirAppType1Params arg_params)
1961{
1962 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301963 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001964
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301965 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001966
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301967 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1968 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001969 hdd_err("sme_configure_app_type1_params returned failure %d",
1970 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001971 return -EPERM;
1972 }
1973
1974 return 0;
1975}
1976
1977static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
1978 char *arg, int len)
1979{
1980 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1981 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1982 char id[20], password[20];
1983 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001984 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985
1986 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301987 if (rc)
1988 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001989
1990 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001991 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001992 return -EINVAL;
1993 }
1994
1995 memset(&params, 0, sizeof(tSirAppType1Params));
1996 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05301997 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998
1999 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302000 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002001 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302002 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002004 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002005 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 params.identification_id, params.id_length,
2007 params.password, params.pass_length);
2008
2009 return hdd_set_app_type1_params(hHal, &params);
2010}
2011
2012static int hdd_set_app_type2_params(tHalHandle hHal,
2013 tpSirAppType2Params arg_params)
2014{
2015 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302016 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302018 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002019
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302020 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2021 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002022 hdd_err("sme_configure_app_type2_params returned failure %d",
2023 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024 return -EPERM;
2025 }
2026
2027 return 0;
2028}
2029
2030static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2031 char *arg, int len)
2032{
2033 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2034 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2035 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302036 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037 tSirAppType2Params params;
2038 int ret;
2039
2040 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302041 if (ret)
2042 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043
2044 memset(&params, 0, sizeof(tSirAppType2Params));
2045
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302046 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 -08002047 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2048 (unsigned int *)&params.ip_device_ip,
2049 (unsigned int *)&params.ip_server_ip,
2050 (unsigned int *)&params.tcp_seq,
2051 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302052 (uint16_t *)&params.tcp_src_port,
2053 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002054 (unsigned int *)&params.keepalive_init,
2055 (unsigned int *)&params.keepalive_min,
2056 (unsigned int *)&params.keepalive_max,
2057 (unsigned int *)&params.keepalive_inc,
2058 (unsigned int *)&params.tcp_tx_timeout_val,
2059 (unsigned int *)&params.tcp_rx_timeout_val);
2060
2061 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002062 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002063 return -EINVAL;
2064 }
2065
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002066 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
2067 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2068 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002069 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002070 return -EINVAL;
2071 }
2072
2073 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2074 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002075 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 return -EINVAL;
2077 }
2078
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302079 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302080 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081
2082 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302083 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084
2085 params.vdev_id = adapter->sessionId;
2086 params.tcp_src_port = (params.tcp_src_port != 0) ?
2087 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2088 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2089 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2090 params.keepalive_init = (params.keepalive_init != 0) ?
2091 params.keepalive_init : hdd_ctx->config->
2092 extWowApp2KAInitPingInterval;
2093 params.keepalive_min =
2094 (params.keepalive_min != 0) ?
2095 params.keepalive_min :
2096 hdd_ctx->config->extWowApp2KAMinPingInterval;
2097 params.keepalive_max =
2098 (params.keepalive_max != 0) ?
2099 params.keepalive_max :
2100 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2101 params.keepalive_inc =
2102 (params.keepalive_inc != 0) ?
2103 params.keepalive_inc :
2104 hdd_ctx->config->extWowApp2KAIncPingInterval;
2105 params.tcp_tx_timeout_val =
2106 (params.tcp_tx_timeout_val != 0) ?
2107 params.tcp_tx_timeout_val :
2108 hdd_ctx->config->extWowApp2TcpTxTimeout;
2109 params.tcp_rx_timeout_val =
2110 (params.tcp_rx_timeout_val != 0) ?
2111 params.tcp_rx_timeout_val :
2112 hdd_ctx->config->extWowApp2TcpRxTimeout;
2113
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002114 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002115 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002116 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2117 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2118 params.keepalive_init, params.keepalive_min,
2119 params.keepalive_max, params.keepalive_inc,
2120 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2121
2122 return hdd_set_app_type2_params(hHal, &params);
2123}
2124#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2125
2126/**
2127 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2128 * @pValue: Pointer to MAXTXPOWER command
2129 * @pDbm: Pointer to tx power
2130 *
2131 * This function parses the MAXTXPOWER command passed in the format
2132 * MAXTXPOWER<space>X(Tx power in dbm)
2133 *
2134 * For example input commands:
2135 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2136 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2137 *
2138 * Return: 0 for success non-zero for failure
2139 */
2140static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2141{
2142 uint8_t *inPtr = pValue;
2143 int tempInt;
2144 int v = 0;
2145 *pTxPower = 0;
2146
2147 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2148 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002149 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002150 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002151 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002153
2154 /* remove empty spaces */
2155 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2156 inPtr++;
2157
2158 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002159 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002160 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161
2162 v = kstrtos32(inPtr, 10, &tempInt);
2163
2164 /* Range checking for passed parameter */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002165 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002167
2168 *pTxPower = tempInt;
2169
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002170 hdd_debug("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002171
2172 return 0;
2173} /* End of hdd_parse_setmaxtxpower_command */
2174
2175static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2176 char *extra, uint8_t n, uint8_t *len)
2177{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002178 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002179 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002180 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002181 }
2182
2183 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2184 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2185 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002186 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002187 }
2188 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002189 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2190 (int)pCfg->nActiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002191 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002192 }
2193 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2195 (int)pCfg->nPassiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002196 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002197 }
2198 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002199 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2200 (int)pCfg->nPassiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002201 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002202 }
2203 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002204 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2205 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002206 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002207 }
2208
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002209 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002210}
2211
2212static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2213{
2214 tHalHandle hHal;
2215 struct hdd_config *pCfg;
2216 uint8_t *value = command;
2217 tSmeConfigParams smeConfig;
2218 int val = 0, temp = 0;
2219
2220 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2221 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2222 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002223 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002224 return -EINVAL;
2225 }
2226
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302227 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002228 sme_get_config_param(hHal, &smeConfig);
2229
2230 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2231 value = value + 24;
2232 temp = kstrtou32(value, 10, &val);
2233 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2234 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002235 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002236 return -EFAULT;
2237 }
2238 pCfg->nActiveMaxChnTime = val;
2239 smeConfig.csrConfig.nActiveMaxChnTime = val;
2240 sme_update_config(hHal, &smeConfig);
2241 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2242 value = value + 24;
2243 temp = kstrtou32(value, 10, &val);
2244 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2245 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002246 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002247 return -EFAULT;
2248 }
2249 pCfg->nActiveMinChnTime = val;
2250 smeConfig.csrConfig.nActiveMinChnTime = val;
2251 sme_update_config(hHal, &smeConfig);
2252 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2253 value = value + 25;
2254 temp = kstrtou32(value, 10, &val);
2255 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2256 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002257 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002258 return -EFAULT;
2259 }
2260 pCfg->nPassiveMaxChnTime = val;
2261 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2262 sme_update_config(hHal, &smeConfig);
2263 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2264 value = value + 25;
2265 temp = kstrtou32(value, 10, &val);
2266 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2267 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002268 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002269 return -EFAULT;
2270 }
2271 pCfg->nPassiveMinChnTime = val;
2272 smeConfig.csrConfig.nPassiveMinChnTime = val;
2273 sme_update_config(hHal, &smeConfig);
2274 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2275 value = value + 13;
2276 temp = kstrtou32(value, 10, &val);
2277 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2278 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002279 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002280 return -EFAULT;
2281 }
2282 pCfg->nActiveMaxChnTime = val;
2283 smeConfig.csrConfig.nActiveMaxChnTime = val;
2284 sme_update_config(hHal, &smeConfig);
2285 } else {
2286 return -EINVAL;
2287 }
2288
2289 return 0;
2290}
2291
Jeff Johnson253c0c22017-01-23 16:59:38 -08002292struct link_status_priv {
2293 uint8_t link_status;
2294};
2295
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002296static void hdd_get_link_status_cb(uint8_t status, void *context)
2297{
Jeff Johnson253c0c22017-01-23 16:59:38 -08002298 struct hdd_request *request;
2299 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002300
Jeff Johnson253c0c22017-01-23 16:59:38 -08002301 request = hdd_request_get(context);
2302 if (!request) {
2303 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002304 return;
2305 }
2306
Jeff Johnson253c0c22017-01-23 16:59:38 -08002307 priv = hdd_request_priv(request);
2308 priv->link_status = status;
2309 hdd_request_complete(request);
2310 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002311}
2312
2313/**
2314 * wlan_hdd_get_link_status() - get link status
2315 * @pAdapter: pointer to the adapter
2316 *
2317 * This function sends a request to query the link status and waits
2318 * on a timer to invoke the callback. if the callback is invoked then
2319 * latest link status shall be returned or otherwise cached value
2320 * will be returned.
2321 *
2322 * Return: On success, link status shall be returned.
2323 * On error or not associated, link status 0 will be returned.
2324 */
2325static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2326{
2327
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002328 hdd_station_ctx_t *pHddStaCtx =
2329 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302330 QDF_STATUS hstatus;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002331 int ret;
2332 void *cookie;
2333 struct hdd_request *request;
2334 struct link_status_priv *priv;
2335 static const struct hdd_request_params params = {
2336 .priv_size = sizeof(*priv),
2337 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2338 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002340 if (cds_is_driver_recovering()) {
2341 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2342 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002343 return 0;
2344 }
2345
Krunal Sonibe766b02016-03-10 13:00:44 -08002346 if ((QDF_STA_MODE != adapter->device_mode) &&
2347 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002348 hdd_warn("Unsupported in mode %s(%d)",
2349 hdd_device_mode_to_string(adapter->device_mode),
2350 adapter->device_mode);
2351 return 0;
2352 }
2353
2354 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2355 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2356 /* If not associated, then expected link status return
2357 * value is 0
2358 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002359 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002360 return 0;
2361 }
2362
Jeff Johnson253c0c22017-01-23 16:59:38 -08002363 request = hdd_request_alloc(&params);
2364 if (!request) {
2365 hdd_err("Request allocation failure");
2366 return 0;
2367 }
2368 cookie = hdd_request_cookie(request);
2369
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002370 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2371 hdd_get_link_status_cb,
Jeff Johnson253c0c22017-01-23 16:59:38 -08002372 cookie, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302373 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002374 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002375 /* return a cached value */
2376 } else {
2377 /* request is sent -- wait for the response */
Jeff Johnson253c0c22017-01-23 16:59:38 -08002378 ret = hdd_request_wait_for_response(request);
2379 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002380 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002381 /* return a cached value */
2382 } else {
2383 /* update the adapter with the fresh results */
2384 priv = hdd_request_priv(request);
2385 adapter->linkStatus = priv->link_status;
2386 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002387 }
2388
Jeff Johnson253c0c22017-01-23 16:59:38 -08002389 /*
2390 * either we never sent a request, we sent a request and
2391 * received a response or we sent a request and timed out.
2392 * regardless we are done with the request.
2393 */
2394 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002395
2396 /* either callback updated adapter stats or it has cached data */
2397 return adapter->linkStatus;
2398}
2399
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002400static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2401{
2402 int payload_len;
2403 struct sk_buff *skb;
2404 struct nlmsghdr *nlh;
2405 uint8_t *data;
2406
2407 payload_len = ETH_ALEN;
2408
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002409 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002410 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002411 return;
2412 }
2413
2414 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2415 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002416 hdd_err("nlmsg_new() failed for msg size[%d]",
2417 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002418 return;
2419 }
2420
2421 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2422
2423 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002424 hdd_err("nlmsg_put() failed for msg size[%d]",
2425 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002426
2427 kfree_skb(skb);
2428 return;
2429 }
2430
2431 data = nlmsg_data(nlh);
2432 memcpy(data, MacAddr, ETH_ALEN);
2433
2434 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002435 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2436 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002437 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002438}
2439
2440
2441/**
2442 * hdd_ParseuserParams - return a pointer to the next argument
2443 * @pValue: Input argument string
2444 * @ppArg: Output pointer to the next argument
2445 *
2446 * This function parses argument stream and finds the pointer
2447 * to the next argument
2448 *
2449 * Return: 0 if the next argument found; -EINVAL otherwise
2450 */
2451static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2452{
2453 uint8_t *pVal;
2454
2455 pVal = strnchr(pValue, strlen(pValue), ' ');
2456
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002457 if (NULL == pVal) /* no argument remains */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002458 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002459 else if (SPACE_ASCII_VALUE != *pVal)/* no space after the current arg */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002460 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002461
2462 pVal++;
2463
2464 /* remove empty spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002465 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002466 pVal++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002467
2468 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002469 if ('\0' == *pVal)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002470 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002471
2472 *ppArg = pVal;
2473
2474 return 0;
2475}
2476
2477/**
2478 * hdd_parse_ibsstx_fail_event_params - Parse params
2479 * for SETIBSSTXFAILEVENT
2480 * @pValue: Input ibss tx fail event argument
2481 * @tx_fail_count: (Output parameter) Tx fail counter
2482 * @pid: (Output parameter) PID
2483 *
2484 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2485 */
2486static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2487 uint8_t *tx_fail_count,
2488 uint16_t *pid)
2489{
2490 uint8_t *param = NULL;
2491 int ret;
2492
2493 ret = hdd_parse_user_params(pValue, &param);
2494
2495 if (0 == ret && NULL != param) {
2496 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2497 ret = -EINVAL;
2498 goto done;
2499 }
2500 } else {
2501 goto done;
2502 }
2503
2504 if (0 == *tx_fail_count) {
2505 *pid = 0;
2506 goto done;
2507 }
2508
2509 pValue = param;
2510 pValue++;
2511
2512 ret = hdd_parse_user_params(pValue, &param);
2513
2514 if (0 == ret) {
2515 if (1 != sscanf(param, "%hu", pid)) {
2516 ret = -EINVAL;
2517 goto done;
2518 }
2519 } else {
2520 goto done;
2521 }
2522
2523done:
2524 return ret;
2525}
2526
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002527#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002528/**
2529 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2530 * @pValue: Pointer to data
2531 * @pEseBcnReq: Output pointer to store parsed ie information
2532 *
2533 * This function parses the ese beacon request passed in the format
2534 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2535 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2536 * <space>Scan Mode N<space>Meas Duration N
2537 *
2538 * If the Number of bcn req fields (N) does not match with the
2539 * actual number of fields passed then take N.
2540 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2541 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2542 * This function does not take care of removing duplicate channels from the
2543 * list
2544 *
2545 * Return: 0 for success non-zero for failure
2546 */
2547static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2548 tCsrEseBeaconReq *pEseBcnReq)
2549{
2550 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002551 uint8_t input = 0;
2552 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002553 int j = 0, i = 0, v = 0;
2554 char buf[32];
2555
2556 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002557 if (NULL == inPtr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002558 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002559 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002560 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002561
2562 /* remove empty spaces */
2563 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2564 inPtr++;
2565
2566 /* no argument followed by spaces */
2567 if ('\0' == *inPtr)
2568 return -EINVAL;
2569
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002570 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002571 v = sscanf(inPtr, "%31s ", buf);
2572 if (1 != v)
2573 return -EINVAL;
2574
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002575 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002576 if (v < 0)
2577 return -EINVAL;
2578
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002579 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2580 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002581
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002582 hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002583
2584 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2585 for (i = 0; i < 4; i++) {
2586 /*
2587 * inPtr pointing to the beginning of 1st space
2588 * after number of ie fields
2589 */
2590 inPtr = strpbrk(inPtr, " ");
2591 /* no ie data after the number of ie fields argument */
2592 if (NULL == inPtr)
2593 return -EINVAL;
2594
2595 /* remove empty space */
2596 while ((SPACE_ASCII_VALUE == *inPtr)
2597 && ('\0' != *inPtr))
2598 inPtr++;
2599
2600 /*
2601 * no ie data after the number of ie fields
2602 * argument and spaces
2603 */
2604 if ('\0' == *inPtr)
2605 return -EINVAL;
2606
2607 v = sscanf(inPtr, "%31s ", buf);
2608 if (1 != v)
2609 return -EINVAL;
2610
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002611 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612 if (v < 0)
2613 return -EINVAL;
2614
2615 switch (i) {
2616 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002617 if (!tempInt) {
2618 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002619 tempInt);
2620 return -EINVAL;
2621 }
2622 pEseBcnReq->bcnReq[j].measurementToken =
2623 tempInt;
2624 break;
2625
2626 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002627 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002628 (tempInt >
2629 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002630 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002631 tempInt);
2632 return -EINVAL;
2633 }
2634 pEseBcnReq->bcnReq[j].channel = tempInt;
2635 break;
2636
2637 case 2: /* Scan mode */
2638 if ((tempInt < eSIR_PASSIVE_SCAN)
2639 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002640 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002641 tempInt);
2642 return -EINVAL;
2643 }
2644 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2645 break;
2646
2647 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002648 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002649 && (pEseBcnReq->bcnReq[j].scanMode !=
2650 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002651 (pEseBcnReq->bcnReq[j].scanMode ==
2652 eSIR_BEACON_TABLE)) {
2653 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002654 tempInt);
2655 return -EINVAL;
2656 }
2657 pEseBcnReq->bcnReq[j].measurementDuration =
2658 tempInt;
2659 break;
2660 }
2661 }
2662 }
2663
2664 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002665 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002666 j,
2667 pEseBcnReq->bcnReq[j].measurementToken,
2668 pEseBcnReq->bcnReq[j].channel,
2669 pEseBcnReq->bcnReq[j].scanMode,
2670 pEseBcnReq->bcnReq[j].measurementDuration);
2671 }
2672
2673 return 0;
2674}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002675
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002676/**
2677 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2678 * @pValue: Pointer to input data
2679 * @pCckmIe: Pointer to output cckm Ie
2680 * @pCckmIeLen: Pointer to output cckm ie length
2681 *
2682 * This function parses the SETCCKM IE command
2683 * SETCCKMIE<space><ie data>
2684 *
2685 * Return: 0 for success non-zero for failure
2686 */
2687static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2688 uint8_t *pCckmIeLen)
2689{
2690 uint8_t *inPtr = pValue;
2691 uint8_t *dataEnd;
2692 int j = 0;
2693 int i = 0;
2694 uint8_t tempByte = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002695
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002696 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2697 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002698 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002699 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002700 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002701 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002702
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002703 /* remove empty spaces */
2704 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2705 inPtr++;
2706 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002707 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002708 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002709
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002710 /* find the length of data */
2711 dataEnd = inPtr;
2712 while (('\0' != *dataEnd)) {
2713 dataEnd++;
2714 ++(*pCckmIeLen);
2715 }
2716 if (*pCckmIeLen <= 0)
2717 return -EINVAL;
2718 /*
2719 * Allocate the number of bytes based on the number of input characters
2720 * whether it is even or odd.
2721 * if the number of input characters are even, then we need N / 2 byte.
2722 * if the number of input characters are odd, then we need do
2723 * (N + 1) / 2 to compensate rounding off.
2724 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2725 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2726 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302727 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002728 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002729 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002730 return -ENOMEM;
2731 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732 /*
2733 * the buffer received from the upper layer is character buffer,
2734 * we need to prepare the buffer taking 2 characters in to a U8 hex
2735 * decimal number for example 7f0000f0...form a buffer to contain
2736 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2737 */
2738 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2739 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2740 (hex_to_bin(inPtr[j + 1]));
2741 (*pCckmIe)[i++] = tempByte;
2742 }
2743 *pCckmIeLen = i;
2744 return 0;
2745}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002746#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002747
2748int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2749{
2750 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302751 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002752 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2753 struct hdd_config *pConfig = NULL;
2754
2755 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002756 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002757 return -EINVAL;
2758 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002759 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2760 (QDF_SAP_MODE != pAdapter->device_mode) &&
2761 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002762 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2763 hdd_device_mode_to_string(pAdapter->device_mode),
2764 pAdapter->device_mode);
2765 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002766 return -EINVAL;
2767 }
2768 pConfig = pHddCtx->config;
2769 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2770 rateUpdate.dev_mode = pAdapter->device_mode;
2771 rateUpdate.mcastDataRate24GHz = targetRate;
2772 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2773 rateUpdate.mcastDataRate5GHz = targetRate;
2774 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302775 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002776 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002777 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2778 hdd_device_mode_to_string(pAdapter->device_mode),
2779 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002780 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302781 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002782 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002783 return -EFAULT;
2784 }
2785 return 0;
2786}
2787
2788static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2789 hdd_context_t *hdd_ctx,
2790 uint8_t *command,
2791 uint8_t command_len,
2792 hdd_priv_data_t *priv_data)
2793{
2794 int ret = 0;
2795
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302796 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002797 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2798 adapter->sessionId,
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002799 (unsigned int)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002800 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2801 + 3) << 16 | *(hdd_ctx->
2802 p2pDeviceAddress.bytes + 4) << 8 |
2803 *(hdd_ctx->p2pDeviceAddress.bytes +
2804 5))));
2805
2806 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2807 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002808 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002809 ret = -EFAULT;
2810 }
2811
2812 return ret;
2813}
2814
2815/**
2816 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2817 * @adapter: Adapter on which the command was received
2818 * @hdd_ctx: HDD global context
2819 * @command: Entire driver command received from userspace
2820 * @command_len: Length of @command
2821 * @priv_data: Pointer to ioctl private data structure
2822 *
2823 * This is a trivial command hander function which simply forwards the
2824 * command to the actual command processor within the P2P module.
2825 *
2826 * Return: 0 on success, non-zero on failure
2827 */
2828static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2829 hdd_context_t *hdd_ctx,
2830 uint8_t *command,
2831 uint8_t command_len,
2832 hdd_priv_data_t *priv_data)
2833{
2834 return hdd_set_p2p_noa(adapter->dev, command);
2835}
2836
2837/**
2838 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2839 * @adapter: Adapter on which the command was received
2840 * @hdd_ctx: HDD global context
2841 * @command: Entire driver command received from userspace
2842 * @command_len: Length of @command
2843 * @priv_data: Pointer to ioctl private data structure
2844 *
2845 * This is a trivial command hander function which simply forwards the
2846 * command to the actual command processor within the P2P module.
2847 *
2848 * Return: 0 on success, non-zero on failure
2849 */
2850static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2851 hdd_context_t *hdd_ctx,
2852 uint8_t *command,
2853 uint8_t command_len,
2854 hdd_priv_data_t *priv_data)
2855{
2856 return hdd_set_p2p_opps(adapter->dev, command);
2857}
2858
2859static int drv_cmd_set_band(hdd_adapter_t *adapter,
2860 hdd_context_t *hdd_ctx,
2861 uint8_t *command,
2862 uint8_t command_len,
2863 hdd_priv_data_t *priv_data)
2864{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002865 int err;
2866 uint8_t band;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002867
2868 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002869 * Parse the band value passed from userspace. The first 8 bytes
2870 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002871 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002872 err = kstrtou8(command + command_len + 1, 10, &band);
2873 if (err) {
2874 hdd_err("error %d parsing userspace band parameter", err);
2875 return err;
2876 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002877
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002878 return hdd_reg_set_band(adapter->dev, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002879}
2880
2881static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2882 hdd_context_t *hdd_ctx,
2883 uint8_t *command,
2884 uint8_t command_len,
2885 hdd_priv_data_t *priv_data)
2886{
2887 return hdd_wmmps_helper(adapter, command);
2888}
2889
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002890static inline int drv_cmd_country(hdd_adapter_t *adapter,
2891 hdd_context_t *hdd_ctx,
2892 uint8_t *command,
2893 uint8_t command_len,
2894 hdd_priv_data_t *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002895{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002896 return hdd_reg_set_country(hdd_ctx, command + command_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002897}
2898
2899static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
2900 hdd_context_t *hdd_ctx,
2901 uint8_t *command,
2902 uint8_t command_len,
2903 hdd_priv_data_t *priv_data)
2904{
2905 int ret = 0;
2906 uint8_t *value = command;
2907 int8_t rssi = 0;
2908 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302909 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002910
2911 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2912 value = value + command_len + 1;
2913
2914 /* Convert the value from ascii to integer */
2915 ret = kstrtos8(value, 10, &rssi);
2916 if (ret < 0) {
2917 /*
2918 * If the input value is greater than max value of datatype,
2919 * then also kstrtou8 fails
2920 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002921 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2922 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2923 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002924 ret = -EINVAL;
2925 goto exit;
2926 }
2927
2928 lookUpThreshold = abs(rssi);
2929
2930 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
2931 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002932 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002933 lookUpThreshold,
2934 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2935 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
2936 ret = -EINVAL;
2937 goto exit;
2938 }
2939
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302940 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002941 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
2942 adapter->sessionId, lookUpThreshold));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002943 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002944 lookUpThreshold);
2945
2946 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
2947 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
2948 adapter->sessionId,
2949 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302950 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002951 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002952 ret = -EPERM;
2953 goto exit;
2954 }
2955
2956exit:
2957 return ret;
2958}
2959
2960static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
2961 hdd_context_t *hdd_ctx,
2962 uint8_t *command,
2963 uint8_t command_len,
2964 hdd_priv_data_t *priv_data)
2965{
2966 int ret = 0;
2967 uint8_t lookUpThreshold =
2968 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
2969 int rssi = (-1) * lookUpThreshold;
2970 char extra[32];
2971 uint8_t len = 0;
2972
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302973 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002974 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
2975 adapter->sessionId, lookUpThreshold));
2976
2977 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05302978 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002979 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002980 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002981 ret = -EFAULT;
2982 }
2983
2984 return ret;
2985}
2986
2987static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
2988 hdd_context_t *hdd_ctx,
2989 uint8_t *command,
2990 uint8_t command_len,
2991 hdd_priv_data_t *priv_data)
2992{
2993 int ret = 0;
2994 uint8_t *value = command;
2995 uint8_t roamScanPeriod = 0;
2996 uint16_t neighborEmptyScanRefreshPeriod =
2997 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
2998
2999 /* input refresh period is in terms of seconds */
3000
3001 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3002 value = value + command_len + 1;
3003
3004 /* Convert the value from ascii to integer */
3005 ret = kstrtou8(value, 10, &roamScanPeriod);
3006 if (ret < 0) {
3007 /*
3008 * If the input value is greater than max value of datatype,
3009 * then also kstrtou8 fails
3010 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003011 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3012 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3013 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014 ret = -EINVAL;
3015 goto exit;
3016 }
3017
3018 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3019 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003020 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3021 roamScanPeriod,
3022 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3023 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003024 ret = -EINVAL;
3025 goto exit;
3026 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303027 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003028 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3029 adapter->sessionId, roamScanPeriod));
3030 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3031
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003032 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003033 roamScanPeriod);
3034
3035 hdd_ctx->config->nEmptyScanRefreshPeriod =
3036 neighborEmptyScanRefreshPeriod;
3037 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3038 adapter->sessionId,
3039 neighborEmptyScanRefreshPeriod);
3040
3041exit:
3042 return ret;
3043}
3044
3045static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3046 hdd_context_t *hdd_ctx,
3047 uint8_t *command,
3048 uint8_t command_len,
3049 hdd_priv_data_t *priv_data)
3050{
3051 int ret = 0;
3052 uint16_t nEmptyScanRefreshPeriod =
3053 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3054 char extra[32];
3055 uint8_t len = 0;
3056
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303057 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003058 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3059 adapter->sessionId,
3060 nEmptyScanRefreshPeriod));
3061 len = scnprintf(extra, sizeof(extra), "%s %d",
3062 "GETROAMSCANPERIOD",
3063 (nEmptyScanRefreshPeriod / 1000));
3064 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303065 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003066 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003067 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003068 ret = -EFAULT;
3069 }
3070
3071 return ret;
3072}
3073
3074static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3075 hdd_context_t *hdd_ctx,
3076 uint8_t *command,
3077 uint8_t command_len,
3078 hdd_priv_data_t *priv_data)
3079{
3080 int ret = 0;
3081 uint8_t *value = command;
3082 uint8_t roamScanRefreshPeriod = 0;
3083 uint16_t neighborScanRefreshPeriod =
3084 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3085
3086 /* input refresh period is in terms of seconds */
3087 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3088 value = value + command_len + 1;
3089
3090 /* Convert the value from ascii to integer */
3091 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3092 if (ret < 0) {
3093 /*
3094 * If the input value is greater than max value of datatype,
3095 * then also kstrtou8 fails
3096 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003097 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3098 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3099 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003100 ret = -EINVAL;
3101 goto exit;
3102 }
3103
3104 if ((roamScanRefreshPeriod <
3105 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3106 || (roamScanRefreshPeriod >
3107 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003108 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3109 roamScanRefreshPeriod,
3110 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3111 / 1000),
3112 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3113 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003114 ret = -EINVAL;
3115 goto exit;
3116 }
3117 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3118
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003119 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003120 roamScanRefreshPeriod);
3121
3122 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3123 neighborScanRefreshPeriod;
3124 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3125 adapter->sessionId,
3126 neighborScanRefreshPeriod);
3127
3128exit:
3129 return ret;
3130}
3131
3132static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3133 hdd_context_t *hdd_ctx,
3134 uint8_t *command,
3135 uint8_t command_len,
3136 hdd_priv_data_t *priv_data)
3137{
3138 int ret = 0;
3139 uint16_t value =
3140 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3141 char extra[32];
3142 uint8_t len = 0;
3143
3144 len = scnprintf(extra, sizeof(extra), "%s %d",
3145 "GETROAMSCANREFRESHPERIOD",
3146 (value / 1000));
3147 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303148 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003149 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003150 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003151 ret = -EFAULT;
3152 }
3153
3154 return ret;
3155}
3156
3157static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3158 hdd_context_t *hdd_ctx,
3159 uint8_t *command,
3160 uint8_t command_len,
3161 hdd_priv_data_t *priv_data)
3162{
3163 int ret = 0;
3164 uint8_t *value = command;
3165 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3166
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003167 if (!adapter->fast_roaming_allowed) {
3168 hdd_err("Roaming is always disabled on this interface");
3169 goto exit;
3170 }
3171
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003172 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3173 value = value + SIZE_OF_SETROAMMODE + 1;
3174
3175 /* Convert the value from ascii to integer */
3176 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3177 if (ret < 0) {
3178 /*
3179 * If the input value is greater than max value of datatype,
3180 * then also kstrtou8 fails
3181 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003182 hdd_err("kstrtou8 failed range [%d - %d]",
3183 CFG_LFR_FEATURE_ENABLED_MIN,
3184 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003185 ret = -EINVAL;
3186 goto exit;
3187 }
3188 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3189 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003190 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3191 roamMode,
3192 CFG_LFR_FEATURE_ENABLED_MIN,
3193 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003194 ret = -EINVAL;
3195 goto exit;
3196 }
3197
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003198 hdd_debug("Received Command to Set Roam Mode = %d",
3199 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003200 /*
3201 * Note that
3202 * SETROAMMODE 0 is to enable LFR while
3203 * SETROAMMODE 1 is to disable LFR, but
3204 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3205 * enable/disable. So, we have to invert the value
3206 * to call sme_update_is_fast_roam_ini_feature_enabled.
3207 */
3208 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3209 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3210 else
3211 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3212
3213 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3214 if (roamMode) {
3215 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3216 sme_update_roam_scan_offload_enabled(
3217 (tHalHandle)(hdd_ctx->hHal),
3218 hdd_ctx->config->isRoamOffloadScanEnabled);
3219 sme_update_is_fast_roam_ini_feature_enabled(
3220 hdd_ctx->hHal,
3221 adapter->sessionId,
3222 roamMode);
3223 } else {
3224 sme_update_is_fast_roam_ini_feature_enabled(
3225 hdd_ctx->hHal,
3226 adapter->sessionId,
3227 roamMode);
3228 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3229 sme_update_roam_scan_offload_enabled(
3230 (tHalHandle)(hdd_ctx->hHal),
3231 hdd_ctx->config->isRoamOffloadScanEnabled);
3232 }
3233
3234
3235exit:
3236 return ret;
3237}
3238
3239static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3240 hdd_context_t *hdd_ctx,
3241 uint8_t *command,
3242 uint8_t command_len,
3243 hdd_priv_data_t *priv_data)
3244{
3245 int ret = 0;
3246 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3247 char extra[32];
3248 uint8_t len = 0;
3249
3250 /*
3251 * roamMode value shall be inverted because the sementics is different.
3252 */
3253 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3254 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3255 else
3256 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3257
3258 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303259 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003260 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003261 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003262 ret = -EFAULT;
3263 }
3264
3265 return ret;
3266}
3267
3268static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3269 hdd_context_t *hdd_ctx,
3270 uint8_t *command,
3271 uint8_t command_len,
3272 hdd_priv_data_t *priv_data)
3273{
3274 int ret = 0;
3275 uint8_t *value = command;
3276 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3277
3278 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3279 value = value + command_len + 1;
3280
3281 /* Convert the value from ascii to integer */
3282 ret = kstrtou8(value, 10, &roamRssiDiff);
3283 if (ret < 0) {
3284 /*
3285 * If the input value is greater than max value of datatype,
3286 * then also kstrtou8 fails
3287 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003288 hdd_err("kstrtou8 failed range [%d - %d]",
3289 CFG_ROAM_RSSI_DIFF_MIN,
3290 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003291 ret = -EINVAL;
3292 goto exit;
3293 }
3294
3295 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3296 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003297 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3298 roamRssiDiff,
3299 CFG_ROAM_RSSI_DIFF_MIN,
3300 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003301 ret = -EINVAL;
3302 goto exit;
3303 }
3304
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003305 hdd_debug("Received Command to Set roam rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003306 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003307
3308 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3309 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3310 adapter->sessionId,
3311 roamRssiDiff);
3312
3313exit:
3314 return ret;
3315}
3316
3317static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3318 hdd_context_t *hdd_ctx,
3319 uint8_t *command,
3320 uint8_t command_len,
3321 hdd_priv_data_t *priv_data)
3322{
3323 int ret = 0;
3324 uint8_t roamRssiDiff =
3325 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3326 char extra[32];
3327 uint8_t len = 0;
3328
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303329 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003330 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3331 adapter->sessionId, roamRssiDiff));
3332
3333 len = scnprintf(extra, sizeof(extra), "%s %d",
3334 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303335 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003336
3337 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003338 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003339 ret = -EFAULT;
3340 }
3341
3342 return ret;
3343}
3344
3345static int drv_cmd_get_band(hdd_adapter_t *adapter,
3346 hdd_context_t *hdd_ctx,
3347 uint8_t *command,
3348 uint8_t command_len,
3349 hdd_priv_data_t *priv_data)
3350{
3351 int ret = 0;
3352 int band = -1;
3353 char extra[32];
3354 uint8_t len = 0;
3355
3356 hdd_get_band_helper(hdd_ctx, &band);
3357
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303358 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003359 TRACE_CODE_HDD_GETBAND_IOCTL,
3360 adapter->sessionId, band));
3361
3362 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303363 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364
3365 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003366 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003367 ret = -EFAULT;
3368 }
3369
3370 return ret;
3371}
3372
3373static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3374 hdd_context_t *hdd_ctx,
3375 uint8_t *command,
3376 uint8_t command_len,
3377 hdd_priv_data_t *priv_data)
3378{
3379 return hdd_parse_set_roam_scan_channels(adapter, command);
3380}
3381
3382static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3383 hdd_context_t *hdd_ctx,
3384 uint8_t *command,
3385 uint8_t command_len,
3386 hdd_priv_data_t *priv_data)
3387{
3388 int ret = 0;
3389 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3390 uint8_t numChannels = 0;
3391 uint8_t j = 0;
3392 char extra[128] = { 0 };
3393 int len;
3394
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303395 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003396 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3397 ChannelList,
3398 &numChannels,
3399 adapter->sessionId)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003400 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003401 ret = -EFAULT;
3402 goto exit;
3403 }
3404
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303405 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003406 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3407 adapter->sessionId, numChannels));
3408 /*
3409 * output channel list is of the format
3410 * [Number of roam scan channels][Channel1][Channel2]...
3411 * copy the number of channels in the 0th index
3412 */
3413 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3414 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303415 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003416 len += scnprintf(extra + len, sizeof(extra) - len,
3417 " %d", ChannelList[j]);
3418
Anurag Chouhan6d760662016-02-20 16:05:43 +05303419 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003420 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003421 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003422 ret = -EFAULT;
3423 goto exit;
3424 }
3425
3426exit:
3427 return ret;
3428}
3429
3430static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3431 hdd_context_t *hdd_ctx,
3432 uint8_t *command,
3433 uint8_t command_len,
3434 hdd_priv_data_t *priv_data)
3435{
3436 int ret = 0;
3437 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3438 char extra[32];
3439 uint8_t len = 0;
3440
3441 /*
3442 * Check if the features OKC/ESE/11R are supported simultaneously,
3443 * then this operation is not permitted (return FAILURE)
3444 */
3445 if (eseMode &&
3446 hdd_is_okc_mode_enabled(hdd_ctx) &&
3447 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003448 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003449 ret = -EPERM;
3450 goto exit;
3451 }
3452
3453 len = scnprintf(extra, sizeof(extra), "%s %d",
3454 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303455 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003456 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003457 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003458 ret = -EFAULT;
3459 goto exit;
3460 }
3461
3462exit:
3463 return ret;
3464}
3465
3466static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3467 hdd_context_t *hdd_ctx,
3468 uint8_t *command,
3469 uint8_t command_len,
3470 hdd_priv_data_t *priv_data)
3471{
3472 int ret = 0;
3473 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3474 char extra[32];
3475 uint8_t len = 0;
3476
3477 /*
3478 * Check if the features OKC/ESE/11R are supported simultaneously,
3479 * then this operation is not permitted (return FAILURE)
3480 */
3481 if (okcMode &&
3482 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3483 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003484 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003485 ret = -EPERM;
3486 goto exit;
3487 }
3488
3489 len = scnprintf(extra, sizeof(extra), "%s %d",
3490 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303491 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003492
3493 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003494 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003495 ret = -EFAULT;
3496 goto exit;
3497 }
3498
3499exit:
3500 return ret;
3501}
3502
3503static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3504 hdd_context_t *hdd_ctx,
3505 uint8_t *command,
3506 uint8_t command_len,
3507 hdd_priv_data_t *priv_data)
3508{
3509 int ret = 0;
3510 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3511 char extra[32];
3512 uint8_t len = 0;
3513
3514 len = scnprintf(extra, sizeof(extra), "%s %d",
3515 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303516 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003517
3518 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003519 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003520 ret = -EFAULT;
3521 }
3522
3523 return ret;
3524}
3525
3526static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3527 hdd_context_t *hdd_ctx,
3528 uint8_t *command,
3529 uint8_t command_len,
3530 hdd_priv_data_t *priv_data)
3531{
3532 int ret = 0;
3533 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3534 char extra[32];
3535 uint8_t len = 0;
3536
3537 len = scnprintf(extra, sizeof(extra), "%s %d",
3538 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303539 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003540
3541 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003542 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003543 ret = -EFAULT;
3544 }
3545
3546 return ret;
3547}
3548
3549static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3550 hdd_context_t *hdd_ctx,
3551 uint8_t *command,
3552 uint8_t command_len,
3553 hdd_priv_data_t *priv_data)
3554{
3555 int ret = 0;
3556 uint8_t *value = command;
3557 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3558
3559 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3560 value = value + command_len + 1;
3561
3562 /* Convert the value from ascii to integer */
3563 ret = kstrtou8(value, 10, &minTime);
3564 if (ret < 0) {
3565 /*
3566 * If the input value is greater than max value of datatype,
3567 * then also kstrtou8 fails
3568 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003569 hdd_err("kstrtou8 failed range [%d - %d]",
3570 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3571 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003572 ret = -EINVAL;
3573 goto exit;
3574 }
3575
3576 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3577 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003578 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3579 minTime,
3580 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3581 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003582 ret = -EINVAL;
3583 goto exit;
3584 }
3585
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303586 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003587 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3588 adapter->sessionId, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003589 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003590 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003591
3592 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3593 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3594 minTime,
3595 adapter->sessionId);
3596
3597exit:
3598 return ret;
3599}
3600
3601static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3602 hdd_context_t *hdd_ctx,
3603 uint8_t *command,
3604 uint8_t command_len,
3605 hdd_priv_data_t *priv_data)
3606{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003607 return hdd_parse_sendactionframe(adapter, command,
3608 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003609}
3610
3611static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3612 hdd_context_t *hdd_ctx,
3613 uint8_t *command,
3614 uint8_t command_len,
3615 hdd_priv_data_t *priv_data)
3616{
3617 int ret = 0;
3618 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3619 adapter->sessionId);
3620 char extra[32];
3621 uint8_t len = 0;
3622
3623 /* value is interms of msec */
3624 len = scnprintf(extra, sizeof(extra), "%s %d",
3625 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303626 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003627
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303628 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003629 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3630 adapter->sessionId, val));
3631
3632 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003633 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003634 ret = -EFAULT;
3635 }
3636
3637 return ret;
3638}
3639
3640static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3641 hdd_context_t *hdd_ctx,
3642 uint8_t *command,
3643 uint8_t command_len,
3644 hdd_priv_data_t *priv_data)
3645{
3646 int ret = 0;
3647 uint8_t *value = command;
3648 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3649
3650 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3651 value = value + command_len + 1;
3652
3653 /* Convert the value from ascii to integer */
3654 ret = kstrtou16(value, 10, &maxTime);
3655 if (ret < 0) {
3656 /*
3657 * If the input value is greater than max value of datatype,
3658 * then also kstrtou8 fails
3659 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003660 hdd_err("kstrtou16 failed range [%d - %d]",
3661 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3662 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003663 ret = -EINVAL;
3664 goto exit;
3665 }
3666
3667 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3668 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003669 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3670 maxTime,
3671 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3672 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003673 ret = -EINVAL;
3674 goto exit;
3675 }
3676
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003677 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003678 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003679
3680 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3681 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3682 adapter->sessionId,
3683 maxTime);
3684
3685exit:
3686 return ret;
3687}
3688
3689static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3690 hdd_context_t *hdd_ctx,
3691 uint8_t *command,
3692 uint8_t command_len,
3693 hdd_priv_data_t *priv_data)
3694{
3695 int ret = 0;
3696 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3697 adapter->sessionId);
3698 char extra[32];
3699 uint8_t len = 0;
3700
3701 /* value is interms of msec */
3702 len = scnprintf(extra, sizeof(extra), "%s %d",
3703 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303704 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003705
3706 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003707 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708 ret = -EFAULT;
3709 }
3710
3711 return ret;
3712}
3713
3714static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3715 hdd_context_t *hdd_ctx,
3716 uint8_t *command,
3717 uint8_t command_len,
3718 hdd_priv_data_t *priv_data)
3719{
3720 int ret = 0;
3721 uint8_t *value = command;
3722 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3723
3724 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3725 value = value + command_len + 1;
3726
3727 /* Convert the value from ascii to integer */
3728 ret = kstrtou16(value, 10, &val);
3729 if (ret < 0) {
3730 /*
3731 * If the input value is greater than max value of datatype,
3732 * then also kstrtou8 fails
3733 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003734 hdd_err("kstrtou16 failed range [%d - %d]",
3735 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3736 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003737 ret = -EINVAL;
3738 goto exit;
3739 }
3740
3741 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3742 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003743 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3744 val,
3745 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3746 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003747 ret = -EINVAL;
3748 goto exit;
3749 }
3750
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003751 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003752 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003753
3754 hdd_ctx->config->nNeighborScanPeriod = val;
3755 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3756 adapter->sessionId, val);
3757
3758exit:
3759 return ret;
3760}
3761
3762static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3763 hdd_context_t *hdd_ctx,
3764 uint8_t *command,
3765 uint8_t command_len,
3766 hdd_priv_data_t *priv_data)
3767{
3768 int ret = 0;
3769 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3770 adapter->
3771 sessionId);
3772 char extra[32];
3773 uint8_t len = 0;
3774
3775 /* value is interms of msec */
3776 len = scnprintf(extra, sizeof(extra), "%s %d",
3777 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303778 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003779
3780 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003781 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003782 ret = -EFAULT;
3783 }
3784
3785 return ret;
3786}
3787
3788static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3789 hdd_context_t *hdd_ctx,
3790 uint8_t *command,
3791 uint8_t command_len,
3792 hdd_priv_data_t *priv_data)
3793{
3794 int ret = 0;
3795 uint8_t *value = command;
3796 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3797
3798 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3799 value = value + command_len + 1;
3800
3801 /* Convert the value from ascii to integer */
3802 ret = kstrtou8(value, 10, &val);
3803 if (ret < 0) {
3804 /*
3805 * If the input value is greater than max value of datatype,
3806 * then also kstrtou8 fails
3807 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003808 hdd_err("kstrtou8 failed range [%d - %d]",
3809 CFG_ROAM_INTRA_BAND_MIN,
3810 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003811 ret = -EINVAL;
3812 goto exit;
3813 }
3814
3815 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3816 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003817 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3818 val,
3819 CFG_ROAM_INTRA_BAND_MIN,
3820 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003821 ret = -EINVAL;
3822 goto exit;
3823 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003824 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003825 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826
3827 hdd_ctx->config->nRoamIntraBand = val;
3828 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3829
3830exit:
3831 return ret;
3832}
3833
3834static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3835 hdd_context_t *hdd_ctx,
3836 uint8_t *command,
3837 uint8_t command_len,
3838 hdd_priv_data_t *priv_data)
3839{
3840 int ret = 0;
3841 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3842 char extra[32];
3843 uint8_t len = 0;
3844
3845 /* value is interms of msec */
3846 len = scnprintf(extra, sizeof(extra), "%s %d",
3847 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303848 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003849 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003850 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003851 ret = -EFAULT;
3852 }
3853
3854 return ret;
3855}
3856
3857static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3858 hdd_context_t *hdd_ctx,
3859 uint8_t *command,
3860 uint8_t command_len,
3861 hdd_priv_data_t *priv_data)
3862{
3863 int ret = 0;
3864 uint8_t *value = command;
3865 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3866
3867 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3868 value = value + command_len + 1;
3869
3870 /* Convert the value from ascii to integer */
3871 ret = kstrtou8(value, 10, &nProbes);
3872 if (ret < 0) {
3873 /*
3874 * If the input value is greater than max value of datatype,
3875 * then also kstrtou8 fails
3876 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003877 hdd_err("kstrtou8 failed range [%d - %d]",
3878 CFG_ROAM_SCAN_N_PROBES_MIN,
3879 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003880 ret = -EINVAL;
3881 goto exit;
3882 }
3883
3884 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3885 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003886 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3887 nProbes,
3888 CFG_ROAM_SCAN_N_PROBES_MIN,
3889 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003890 ret = -EINVAL;
3891 goto exit;
3892 }
3893
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003894 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003895 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003896
3897 hdd_ctx->config->nProbes = nProbes;
3898 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3899 adapter->sessionId, nProbes);
3900
3901exit:
3902 return ret;
3903}
3904
3905static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3906 hdd_context_t *hdd_ctx,
3907 uint8_t *command,
3908 uint8_t command_len,
3909 hdd_priv_data_t *priv_data)
3910{
3911 int ret = 0;
3912 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3913 char extra[32];
3914 uint8_t len = 0;
3915
3916 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303917 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003919 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003920 ret = -EFAULT;
3921 }
3922
3923 return ret;
3924}
3925
3926static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
3927 hdd_context_t *hdd_ctx,
3928 uint8_t *command,
3929 uint8_t command_len,
3930 hdd_priv_data_t *priv_data)
3931{
3932 int ret = 0;
3933 uint8_t *value = command;
3934 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3935
3936 /* input value is in units of msec */
3937
3938 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3939 value = value + command_len + 1;
3940
3941 /* Convert the value from ascii to integer */
3942 ret = kstrtou16(value, 10, &homeAwayTime);
3943 if (ret < 0) {
3944 /*
3945 * If the input value is greater than max value of datatype,
3946 * then also kstrtou8 fails
3947 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003948 hdd_err("kstrtou8 failed range [%d - %d]",
3949 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3950 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003951 ret = -EINVAL;
3952 goto exit;
3953 }
3954
3955 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
3956 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003957 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003958 homeAwayTime,
3959 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3960 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
3961 ret = -EINVAL;
3962 goto exit;
3963 }
3964
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003965 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003966 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967
3968 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
3969 homeAwayTime) {
3970 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
3971 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
3972 adapter->sessionId,
3973 homeAwayTime,
3974 true);
3975 }
3976
3977exit:
3978 return ret;
3979}
3980
3981static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
3982 hdd_context_t *hdd_ctx,
3983 uint8_t *command,
3984 uint8_t command_len,
3985 hdd_priv_data_t *priv_data)
3986{
3987 int ret = 0;
3988 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
3989 char extra[32];
3990 uint8_t len = 0;
3991
3992 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303993 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003994
3995 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003996 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003997 ret = -EFAULT;
3998 }
3999
4000 return ret;
4001}
4002
4003static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4004 hdd_context_t *hdd_ctx,
4005 uint8_t *command,
4006 uint8_t command_len,
4007 hdd_priv_data_t *priv_data)
4008{
4009 return hdd_parse_reassoc(adapter, command);
4010}
4011
4012static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4013 hdd_context_t *hdd_ctx,
4014 uint8_t *command,
4015 uint8_t command_len,
4016 hdd_priv_data_t *priv_data)
4017{
4018 int ret = 0;
4019 uint8_t *value = command;
4020 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4021
4022 /* Move pointer to ahead of SETWESMODE<delimiter> */
4023 value = value + command_len + 1;
4024
4025 /* Convert the value from ascii to integer */
4026 ret = kstrtou8(value, 10, &wesMode);
4027 if (ret < 0) {
4028 /*
4029 * If the input value is greater than max value of datatype,
4030 * then also kstrtou8 fails
4031 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004032 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004033 CFG_ENABLE_WES_MODE_NAME_MIN,
4034 CFG_ENABLE_WES_MODE_NAME_MAX);
4035 ret = -EINVAL;
4036 goto exit;
4037 }
4038
4039 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4040 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004041 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004042 wesMode,
4043 CFG_ENABLE_WES_MODE_NAME_MIN,
4044 CFG_ENABLE_WES_MODE_NAME_MAX);
4045 ret = -EINVAL;
4046 goto exit;
4047 }
4048
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004049 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004050 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004051
4052 hdd_ctx->config->isWESModeEnabled = wesMode;
4053 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4054
4055exit:
4056 return ret;
4057}
4058
4059static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4060 hdd_context_t *hdd_ctx,
4061 uint8_t *command,
4062 uint8_t command_len,
4063 hdd_priv_data_t *priv_data)
4064{
4065 int ret = 0;
4066 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4067 char extra[32];
4068 uint8_t len = 0;
4069
4070 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304071 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004072 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004073 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004074 ret = -EFAULT;
4075 }
4076
4077 return ret;
4078}
4079
4080static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4081 hdd_context_t *hdd_ctx,
4082 uint8_t *command,
4083 uint8_t command_len,
4084 hdd_priv_data_t *priv_data)
4085{
4086 int ret = 0;
4087 uint8_t *value = command;
4088 uint8_t nOpportunisticThresholdDiff =
4089 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4090
4091 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4092 value = value + command_len + 1;
4093
4094 /* Convert the value from ascii to integer */
4095 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4096 if (ret < 0) {
4097 /*
4098 * If the input value is greater than max value of datatype,
4099 * then also kstrtou8 fails
4100 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004101 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004102 ret = -EINVAL;
4103 goto exit;
4104 }
4105
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004106 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004107 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004108
4109 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4110 adapter->sessionId,
4111 nOpportunisticThresholdDiff);
4112
4113exit:
4114 return ret;
4115}
4116
4117static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4118 hdd_context_t *hdd_ctx,
4119 uint8_t *command,
4120 uint8_t command_len,
4121 hdd_priv_data_t *priv_data)
4122{
4123 int ret = 0;
4124 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4125 hdd_ctx->hHal);
4126 char extra[32];
4127 uint8_t len = 0;
4128
4129 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304130 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004131 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004132 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004133 ret = -EFAULT;
4134 }
4135
4136 return ret;
4137}
4138
4139static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4140 hdd_context_t *hdd_ctx,
4141 uint8_t *command,
4142 uint8_t command_len,
4143 hdd_priv_data_t *priv_data)
4144{
4145 int ret = 0;
4146 uint8_t *value = command;
4147 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4148
4149 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4150 value = value + command_len + 1;
4151
4152 /* Convert the value from ascii to integer */
4153 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4154 if (ret < 0) {
4155 /*
4156 * If the input value is greater than max value of datatype,
4157 * then also kstrtou8 fails
4158 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004159 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004160 ret = -EINVAL;
4161 goto exit;
4162 }
4163
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004164 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004165 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004166
4167 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4168 adapter->sessionId,
4169 nRoamRescanRssiDiff);
4170
4171exit:
4172 return ret;
4173}
4174
4175static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4176 hdd_context_t *hdd_ctx,
4177 uint8_t *command,
4178 uint8_t command_len,
4179 hdd_priv_data_t *priv_data)
4180{
4181 int ret = 0;
4182 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4183 char extra[32];
4184 uint8_t len = 0;
4185
4186 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304187 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004188 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004189 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190 ret = -EFAULT;
4191 }
4192
4193 return ret;
4194}
4195
4196static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4197 hdd_context_t *hdd_ctx,
4198 uint8_t *command,
4199 uint8_t command_len,
4200 hdd_priv_data_t *priv_data)
4201{
4202 int ret = 0;
4203 uint8_t *value = command;
4204 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4205
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004206 if (!adapter->fast_roaming_allowed) {
4207 hdd_err("Roaming is always disabled on this interface");
4208 goto exit;
4209 }
4210
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004211 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4212 value = value + command_len + 1;
4213
4214 /* Convert the value from ascii to integer */
4215 ret = kstrtou8(value, 10, &lfrMode);
4216 if (ret < 0) {
4217 /*
4218 * If the input value is greater than max value of datatype,
4219 * then also kstrtou8 fails
4220 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004221 hdd_err("kstrtou8 failed range [%d - %d]",
4222 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004223 CFG_LFR_FEATURE_ENABLED_MAX);
4224 ret = -EINVAL;
4225 goto exit;
4226 }
4227
4228 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4229 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004230 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004231 lfrMode,
4232 CFG_LFR_FEATURE_ENABLED_MIN,
4233 CFG_LFR_FEATURE_ENABLED_MAX);
4234 ret = -EINVAL;
4235 goto exit;
4236 }
4237
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004238 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004239 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004240
4241 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4242 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4243 adapter->
4244 sessionId,
4245 lfrMode);
4246
4247exit:
4248 return ret;
4249}
4250
4251static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4252 hdd_context_t *hdd_ctx,
4253 uint8_t *command,
4254 uint8_t command_len,
4255 hdd_priv_data_t *priv_data)
4256{
4257 int ret = 0;
4258 uint8_t *value = command;
4259 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4260
4261 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4262 value = value + command_len + 1;
4263
4264 /* Convert the value from ascii to integer */
4265 ret = kstrtou8(value, 10, &ft);
4266 if (ret < 0) {
4267 /*
4268 * If the input value is greater than max value of datatype,
4269 * then also kstrtou8 fails
4270 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004271 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004272 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4273 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4274 ret = -EINVAL;
4275 goto exit;
4276 }
4277
4278 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4279 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004280 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004281 ft,
4282 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4283 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4284 ret = -EINVAL;
4285 goto exit;
4286 }
4287
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004288 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004289
4290 hdd_ctx->config->isFastTransitionEnabled = ft;
4291 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4292
4293exit:
4294 return ret;
4295}
4296
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004297static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4298 hdd_context_t *hdd_ctx,
4299 uint8_t *command,
4300 uint8_t command_len,
4301 hdd_priv_data_t *priv_data)
4302{
4303 int ret = 0;
4304 uint8_t *value = command;
4305 uint8_t channel = 0;
4306 tSirMacAddr targetApBssid;
4307 uint32_t roamId = 0;
4308 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004309 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004310 hdd_station_ctx_t *pHddStaCtx;
4311
Krunal Sonibe766b02016-03-10 13:00:44 -08004312 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004313 hdd_warn("Unsupported in mode %s(%d)",
4314 hdd_device_mode_to_string(adapter->device_mode),
4315 adapter->device_mode);
4316 return -EINVAL;
4317 }
4318
4319 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4320
4321 /* if not associated, no need to proceed with reassoc */
4322 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004323 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004324 ret = -EINVAL;
4325 goto exit;
4326 }
4327
4328 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4329 &channel);
4330 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004331 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004332 goto exit;
4333 }
4334
4335 /*
4336 * if the target bssid is same as currently associated AP,
4337 * issue reassoc to same AP
4338 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004339 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304341 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004342 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304343 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004344 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304345 targetApBssid,
4346 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304347 } else {
4348 sme_get_modify_profile_fields(hdd_ctx->hHal,
4349 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004350 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304351 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4352 NULL, modProfileFields, &roamId, 1);
4353 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004354 return 0;
4355 }
4356
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304357 /* Check channel number is a valid channel number */
4358 if (QDF_STATUS_SUCCESS !=
4359 wlan_hdd_validate_operation_channel(adapter, channel)) {
4360 hdd_err("Invalid Channel [%d]", channel);
4361 return -EINVAL;
4362 }
4363
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004364 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004365 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004366 targetApBssid, (int)channel);
4367 goto exit;
4368 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004369 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370 handoffInfo.channel = channel;
4371 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004372 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004373 sizeof(tSirMacAddr));
4374 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4375 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004376exit:
4377 return ret;
4378}
4379
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004380static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4381 hdd_context_t *hdd_ctx,
4382 uint8_t *command,
4383 uint8_t command_len,
4384 hdd_priv_data_t *priv_data)
4385{
4386 int ret = 0;
4387 uint8_t *value = command;
4388 uint8_t roamScanControl = 0;
4389
4390 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4391 value = value + command_len + 1;
4392
4393 /* Convert the value from ascii to integer */
4394 ret = kstrtou8(value, 10, &roamScanControl);
4395 if (ret < 0) {
4396 /*
4397 * If the input value is greater than max value of datatype,
4398 * then also kstrtou8 fails
4399 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004400 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004401 ret = -EINVAL;
4402 goto exit;
4403 }
4404
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004405 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004406 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004407
4408 if (0 != roamScanControl) {
4409 ret = 0; /* return success but ignore param value "true" */
4410 goto exit;
4411 }
4412
4413 sme_set_roam_scan_control(hdd_ctx->hHal,
4414 adapter->sessionId,
4415 roamScanControl);
4416
4417exit:
4418 return ret;
4419}
4420
4421static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4422 hdd_context_t *hdd_ctx,
4423 uint8_t *command,
4424 uint8_t command_len,
4425 hdd_priv_data_t *priv_data)
4426{
4427 int ret = 0;
4428 uint8_t *value = command;
4429 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4430
4431 /*
4432 * Check if the features OKC/ESE/11R are supported simultaneously,
4433 * then this operation is not permitted (return FAILURE)
4434 */
4435 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4436 hdd_is_okc_mode_enabled(hdd_ctx) &&
4437 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004438 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004439 ret = -EPERM;
4440 goto exit;
4441 }
4442
4443 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4444 value = value + command_len + 1;
4445
4446 /* Convert the value from ascii to integer */
4447 ret = kstrtou8(value, 10, &okcMode);
4448 if (ret < 0) {
4449 /*
4450 * If the input value is greater than max value of datatype,
4451 * then also kstrtou8 fails
4452 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004453 hdd_err("kstrtou8 failed range [%d - %d]",
4454 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004455 CFG_OKC_FEATURE_ENABLED_MAX);
4456 ret = -EINVAL;
4457 goto exit;
4458 }
4459
4460 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4461 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004462 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004463 okcMode,
4464 CFG_OKC_FEATURE_ENABLED_MIN,
4465 CFG_OKC_FEATURE_ENABLED_MAX);
4466 ret = -EINVAL;
4467 goto exit;
4468 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004469 hdd_debug("Received Command to change okc mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004470 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471
4472 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4473
4474exit:
4475 return ret;
4476}
4477
4478static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4479 hdd_context_t *hdd_ctx,
4480 uint8_t *command,
4481 uint8_t command_len,
4482 hdd_priv_data_t *priv_data)
4483{
4484 int ret = 0;
4485 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4486 char extra[32];
4487 uint8_t len = 0;
4488
4489 len = scnprintf(extra, sizeof(extra), "%s %d",
4490 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304491 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004492 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004493 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494 ret = -EFAULT;
4495 }
4496
4497 return ret;
4498}
4499
4500static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4501 hdd_context_t *hdd_ctx,
4502 uint8_t *command,
4503 uint8_t command_len,
4504 hdd_priv_data_t *priv_data)
4505{
4506 int ret = 0;
4507 char *bcMode;
4508
4509 bcMode = command + 11;
4510 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004511 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512 hdd_ctx->btCoexModeSet = true;
4513 ret = wlan_hdd_scan_abort(adapter);
4514 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004515 hdd_err("Failed to abort existing scan status: %d",
4516 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004517 }
4518 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004519 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004520 hdd_ctx->btCoexModeSet = false;
4521 }
4522
4523 return ret;
4524}
4525
4526static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4527 hdd_context_t *hdd_ctx,
4528 uint8_t *command,
4529 uint8_t command_len,
4530 hdd_priv_data_t *priv_data)
4531{
4532 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4533 return 0;
4534}
4535
4536static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4537 hdd_context_t *hdd_ctx,
4538 uint8_t *command,
4539 uint8_t command_len,
4540 hdd_priv_data_t *priv_data)
4541{
4542 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4543 return 0;
4544}
4545
4546static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4547 hdd_context_t *hdd_ctx,
4548 uint8_t *command,
4549 uint8_t command_len,
4550 hdd_priv_data_t *priv_data)
4551{
4552 int ret = 0;
4553 struct hdd_config *pCfg =
4554 (WLAN_HDD_GET_CTX(adapter))->config;
4555 char extra[32];
4556 uint8_t len = 0;
4557
4558 memset(extra, 0, sizeof(extra));
4559 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304560 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004561 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004562 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563 ret = -EFAULT;
4564 goto exit;
4565 }
4566 ret = len;
4567exit:
4568 return ret;
4569}
4570
4571static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4572 hdd_context_t *hdd_ctx,
4573 uint8_t *command,
4574 uint8_t command_len,
4575 hdd_priv_data_t *priv_data)
4576{
4577 return hdd_set_dwell_time(adapter, command);
4578}
4579
4580static int drv_cmd_miracast(hdd_adapter_t *adapter,
4581 hdd_context_t *hdd_ctx,
4582 uint8_t *command,
4583 uint8_t command_len,
4584 hdd_priv_data_t *priv_data)
4585{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304586 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004587 int ret = 0;
4588 tHalHandle hHal;
4589 uint8_t filterType = 0;
4590 hdd_context_t *pHddCtx = NULL;
4591 uint8_t *value;
4592
4593 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304594 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004595 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004596
4597 hHal = pHddCtx->hHal;
4598 value = command + 9;
4599
4600 /* Convert the value from ascii to integer */
4601 ret = kstrtou8(value, 10, &filterType);
4602 if (ret < 0) {
4603 /*
4604 * If the input value is greater than max value of datatype,
4605 * then also kstrtou8 fails
4606 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004607 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004608 ret = -EINVAL;
4609 goto exit;
4610 }
4611 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4612 || (filterType >
4613 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004614 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615 ret = -EINVAL;
4616 goto exit;
4617 }
4618 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4619 pHddCtx->miracast_value = filterType;
4620
4621 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304622 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004623 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004624 return -EBUSY;
4625 }
4626
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004627 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4628 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004629
4630exit:
4631 return ret;
4632}
4633
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004634/* Function header is left blank intentionally */
4635static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4636 int32_t *oui_length, int32_t limit)
4637{
4638 uint8_t len;
4639 uint8_t data;
4640
4641 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4642 command++;
4643 limit--;
4644 }
4645
4646 len = 2;
4647
4648 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4649 (limit > 1)) {
4650 sscanf(command, "%02x", (unsigned int *)&data);
4651 ie[len++] = data;
4652 command += 2;
4653 limit -= 2;
4654 }
4655
4656 *oui_length = len - 2;
4657
4658 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4659 command++;
4660 limit--;
4661 }
4662
4663 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4664 (limit > 1)) {
4665 sscanf(command, "%02x", (unsigned int *)&data);
4666 ie[len++] = data;
4667 command += 2;
4668 limit -= 2;
4669 }
4670
4671 ie[0] = IE_EID_VENDOR;
4672 ie[1] = len - 2;
4673
4674 return len;
4675}
4676
4677/**
4678 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4679 * @adapter: Pointer to adapter
4680 * @hdd_ctx: Pointer to HDD context
4681 * @command: Pointer to command string
4682 * @command_len : Command length
4683 * @priv_data : Pointer to priv data
4684 *
4685 * Return:
4686 * int status code
4687 */
4688static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4689 hdd_context_t *hdd_ctx,
4690 uint8_t *command,
4691 uint8_t command_len,
4692 hdd_priv_data_t *priv_data)
4693{
4694 int i = 0;
4695 int status;
4696 int ret = 0;
4697 uint8_t *ibss_ie;
4698 int32_t oui_length = 0;
4699 uint32_t ibss_ie_length;
4700 uint8_t *value = command;
4701 tSirModifyIE ibssModifyIE;
4702 tCsrRoamProfile *pRoamProfile;
4703 hdd_wext_state_t *pWextState;
4704
4705
Krunal Sonibe766b02016-03-10 13:00:44 -08004706 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004707 hdd_debug("Device_mode %s(%d) not IBSS",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004708 hdd_device_mode_to_string(adapter->device_mode),
4709 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004710 return ret;
4711 }
4712
4713 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4714
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004715 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004716
4717
4718 /* validate argument of command */
4719 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004720 hdd_err("No arguments in command length %zu",
4721 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004722 ret = -EFAULT;
4723 goto exit;
4724 }
4725
4726 /* moving to arguments of commands */
4727 value = value + command_len;
4728 command_len = strlen(value);
4729
4730 /* oui_data can't be less than 3 bytes */
4731 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004732 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4733 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004734 ret = -EFAULT;
4735 goto exit;
4736 }
4737
4738 ibss_ie = qdf_mem_malloc(command_len);
4739 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004740 hdd_err("Could not allocate memory for command length %d",
4741 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004742 ret = -ENOMEM;
4743 goto exit;
4744 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004745
4746 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4747 &oui_length,
4748 command_len);
4749 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004750 hdd_err("Could not parse command %s return length %d",
4751 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004752 ret = -EFAULT;
4753 qdf_mem_free(ibss_ie);
4754 goto exit;
4755 }
4756
4757 pRoamProfile = &pWextState->roamProfile;
4758
4759 qdf_copy_macaddr(&ibssModifyIE.bssid,
4760 pRoamProfile->BSSIDs.bssid);
4761
4762 ibssModifyIE.smeSessionId = adapter->sessionId;
4763 ibssModifyIE.notify = true;
4764 ibssModifyIE.ieID = IE_EID_VENDOR;
4765 ibssModifyIE.ieIDLen = ibss_ie_length;
4766 ibssModifyIE.ieBufferlength = ibss_ie_length;
4767 ibssModifyIE.pIEBuffer = ibss_ie;
4768 ibssModifyIE.oui_length = oui_length;
4769
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004770 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4771 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004772 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004773 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004774
4775 /* Probe Bcn modification */
4776 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4777 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4778
4779 /* Populating probe resp frame */
4780 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4781 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4782
4783 qdf_mem_free(ibss_ie);
4784
4785 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4786 adapter->sessionId);
4787 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004788 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004789 status);
4790 ret = -EINVAL;
4791 goto exit;
4792 }
4793
4794exit:
4795 return ret;
4796}
4797
4798static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4799 hdd_context_t *hdd_ctx,
4800 uint8_t *command,
4801 uint8_t command_len,
4802 hdd_priv_data_t *priv_data)
4803{
4804 int ret = 0;
4805 uint8_t *value = command;
4806 uint8_t ucRmcEnable = 0;
4807 int status;
4808
Krunal Sonibe766b02016-03-10 13:00:44 -08004809 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4810 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004811 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4812 hdd_device_mode_to_string(adapter->device_mode),
4813 adapter->device_mode);
4814 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004815 ret = -EINVAL;
4816 goto exit;
4817 }
4818
4819 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4820 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004821 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004822 ret = -EINVAL;
4823 goto exit;
4824 }
4825
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004826 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004827
4828 if (true == ucRmcEnable) {
4829 status = sme_enable_rmc((tHalHandle)
4830 (hdd_ctx->hHal),
4831 adapter->sessionId);
4832 } else if (false == ucRmcEnable) {
4833 status = sme_disable_rmc((tHalHandle)
4834 (hdd_ctx->hHal),
4835 adapter->sessionId);
4836 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004837 hdd_err("Invalid SETRMCENABLE command %d",
4838 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004839 ret = -EINVAL;
4840 goto exit;
4841 }
4842
4843 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004844 hdd_err("SETRMC %d failed status %d",
4845 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004846 ret = -EINVAL;
4847 goto exit;
4848 }
4849
4850exit:
4851 return ret;
4852}
4853
4854static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4855 hdd_context_t *hdd_ctx,
4856 uint8_t *command,
4857 uint8_t command_len,
4858 hdd_priv_data_t *priv_data)
4859{
4860 int ret = 0;
4861 uint8_t *value = command;
4862 uint32_t uActionPeriod = 0;
4863 int status;
4864
Krunal Sonibe766b02016-03-10 13:00:44 -08004865 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4866 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004867 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004868 hdd_device_mode_to_string(adapter->device_mode),
4869 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004870 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004871 ret = -EINVAL;
4872 goto exit;
4873 }
4874
4875 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4876 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004877 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004878 ret = -EINVAL;
4879 goto exit;
4880 }
4881
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004882 hdd_debug("uActionPeriod %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004883 uActionPeriod);
4884
4885 if (sme_cfg_set_int(hdd_ctx->hHal,
4886 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4887 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004888 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4889 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004890 ret = -EINVAL;
4891 goto exit;
4892 }
4893
4894 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4895 adapter->sessionId);
4896 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004897 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004898 status);
4899 ret = -EINVAL;
4900 goto exit;
4901 }
4902
4903exit:
4904 return ret;
4905}
4906
4907static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
4908 hdd_context_t *hdd_ctx,
4909 uint8_t *command,
4910 uint8_t command_len,
4911 hdd_priv_data_t *priv_data)
4912{
4913 int ret = 0;
4914 int status = QDF_STATUS_SUCCESS;
4915 hdd_station_ctx_t *pHddStaCtx = NULL;
4916 char *extra = NULL;
4917 int idx = 0;
4918 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004919 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004920 uint32_t numOfBytestoPrint = 0;
4921
Krunal Sonibe766b02016-03-10 13:00:44 -08004922 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004923 hdd_warn("Unsupported in mode %s(%d)",
4924 hdd_device_mode_to_string(adapter->device_mode),
4925 adapter->device_mode);
4926 return -EINVAL;
4927 }
4928
4929 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004930 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004931
4932 /* Handle the command */
4933 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
4934 if (QDF_STATUS_SUCCESS == status) {
4935 /*
4936 * The variable extra needed to be allocated on the heap since
4937 * amount of memory required to copy the data for 32 devices
4938 * exceeds the size of 1024 bytes of default stack size. On
4939 * 64 bit devices, the default max stack size of 2048 bytes
4940 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004941 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004942
4943 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004944 hdd_err("memory allocation failed");
4945 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004946 goto exit;
4947 }
4948
4949 /* Copy number of stations */
4950 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004951 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004952 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004953 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
4954 idx++) {
4955 int8_t rssi;
4956 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004957
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004958 qdf_mem_copy(mac_addr,
4959 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4960 mac_addr, sizeof(mac_addr));
4961
4962 tx_rate =
4963 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4964 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05304965 /*
4966 * Only lower 3 bytes are rate info. Mask of the MSByte
4967 */
4968 tx_rate &= 0x00FFFFFF;
4969
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004970 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4971 rssi;
4972
4973 length += scnprintf((extra + length),
4974 WLAN_MAX_BUF_SIZE - length,
4975 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
4976 mac_addr[0], mac_addr[1], mac_addr[2],
4977 mac_addr[3], mac_addr[4], mac_addr[5],
4978 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004979 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004980 * cdf_trace_msg has limitation of 512 bytes for the
4981 * print buffer. Hence printing the data in two chunks.
4982 * The first chunk will have the data for 16 devices
4983 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004984 */
4985 if (idx < NUM_OF_STA_DATA_TO_PRINT)
4986 numOfBytestoPrint = length;
4987 }
4988
4989 /*
4990 * Copy the data back into buffer, if the data to copy is
4991 * more than 512 bytes than we will split the data and do
4992 * it in two shots
4993 */
4994 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004995 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004996 ret = -EFAULT;
4997 goto exit;
4998 }
4999
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005000 /* This overwrites the last space, which we already copied */
5001 extra[numOfBytestoPrint - 1] = '\0';
5002 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005003
5004 if (length > numOfBytestoPrint) {
5005 if (copy_to_user
5006 (priv_data->buf + numOfBytestoPrint,
5007 extra + numOfBytestoPrint,
5008 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005009 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005010 ret = -EFAULT;
5011 goto exit;
5012 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005013 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005014 }
5015
5016 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005017 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005018 } else {
5019 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005020 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5021 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005022 ret = -EINVAL;
5023 goto exit;
5024 }
5025 ret = 0;
5026
5027exit:
5028 return ret;
5029}
5030
5031/* Peer Info <Peer Addr> command */
5032static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5033 hdd_context_t *hdd_ctx,
5034 uint8_t *command,
5035 uint8_t command_len,
5036 hdd_priv_data_t *priv_data)
5037{
5038 int ret = 0;
5039 uint8_t *value = command;
5040 QDF_STATUS status;
5041 hdd_station_ctx_t *pHddStaCtx = NULL;
5042 char extra[128] = { 0 };
5043 uint32_t length = 0;
5044 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005045 struct qdf_mac_addr peerMacAddr;
5046
Krunal Sonibe766b02016-03-10 13:00:44 -08005047 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005048 hdd_warn("Unsupported in mode %s(%d)",
5049 hdd_device_mode_to_string(adapter->device_mode),
5050 adapter->device_mode);
5051 return -EINVAL;
5052 }
5053
5054 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5055
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005056 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005057
5058 /* if there are no peers, no need to continue with the command */
5059 if (eConnectionState_IbssConnected !=
5060 pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005061 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005062 ret = -EINVAL;
5063 goto exit;
5064 }
5065
5066 /* Parse the incoming command buffer */
5067 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5068 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005069 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005070 ret = -EINVAL;
5071 goto exit;
5072 }
5073
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005074 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005075 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005076
Naveen Rawatc45d1622016-07-05 12:20:09 -07005077 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005078 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005079 ret = -EINVAL;
5080 goto exit;
5081 }
5082
5083 /* Handle the command */
5084 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5085 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005086 uint32_t txRate =
5087 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305088 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5089 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005090
5091 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005092 (int)txRate,
5093 (int)pHddStaCtx->ibss_peer_info.
5094 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005095
5096 /* Copy the data back into buffer */
5097 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005098 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005099 ret = -EFAULT;
5100 goto exit;
5101 }
5102 } else {
5103 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005104 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5105 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005106 ret = -EINVAL;
5107 goto exit;
5108 }
5109
5110 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005111 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005112 ret = 0;
5113
5114exit:
5115 return ret;
5116}
5117
5118static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5119 hdd_context_t *hdd_ctx,
5120 uint8_t *command,
5121 uint8_t command_len,
5122 hdd_priv_data_t *priv_data)
5123{
5124 int ret = 0;
5125 uint8_t *value = command;
5126 uint32_t uRate = 0;
5127 tTxrateinfoflags txFlags = 0;
5128 tSirRateUpdateInd rateUpdateParams = {0};
5129 int status;
5130 struct hdd_config *pConfig = hdd_ctx->config;
5131
Krunal Sonibe766b02016-03-10 13:00:44 -08005132 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5133 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005134 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5135 hdd_device_mode_to_string(adapter->device_mode),
5136 adapter->device_mode);
5137 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005138 ret = -EINVAL;
5139 goto exit;
5140 }
5141
5142 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5143 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005144 hdd_err("Invalid SETRMCTXRATE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005145 ret = -EINVAL;
5146 goto exit;
5147 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005148 hdd_debug("uRate %d", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005149 /* -1 implies ignore this param */
5150 rateUpdateParams.ucastDataRate = -1;
5151
5152 /*
5153 * Fill the user specifieed RMC rate param
5154 * and the derived tx flags.
5155 */
5156 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5157 rateUpdateParams.reliableMcastDataRate = uRate;
5158 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5159 rateUpdateParams.dev_mode = adapter->device_mode;
5160 rateUpdateParams.bcastDataRate = -1;
5161 memcpy(rateUpdateParams.bssid.bytes,
5162 adapter->macAddressCurrent.bytes,
5163 sizeof(rateUpdateParams.bssid));
5164 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5165 &rateUpdateParams);
5166
5167exit:
5168 return ret;
5169}
5170
5171static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5172 hdd_context_t *hdd_ctx,
5173 uint8_t *command,
5174 uint8_t command_len,
5175 hdd_priv_data_t *priv_data)
5176{
5177 int ret = 0;
5178 char *value;
5179 uint8_t tx_fail_count = 0;
5180 uint16_t pid = 0;
5181
5182 value = command;
5183
5184 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5185
5186 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005187 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005188 goto exit;
5189 }
5190
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005191 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005192
5193 if (0 == tx_fail_count) {
5194 /* Disable TX Fail Indication */
5195 if (QDF_STATUS_SUCCESS ==
5196 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5197 tx_fail_count,
5198 NULL)) {
5199 cesium_pid = 0;
5200 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005201 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005202 ret = -EINVAL;
5203 }
5204 } else {
5205 if (QDF_STATUS_SUCCESS ==
5206 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5207 tx_fail_count,
5208 (void *)hdd_tx_fail_ind_callback)) {
5209 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005210 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005211 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005212 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005213 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005214 ret = -EINVAL;
5215 }
5216 }
5217
5218exit:
5219 return ret;
5220}
5221
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005222#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005223static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5224 hdd_context_t *hdd_ctx,
5225 uint8_t *command,
5226 uint8_t command_len,
5227 hdd_priv_data_t *priv_data)
5228{
5229 int ret = 0;
5230 uint8_t *value = command;
5231 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5232 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305233 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005234
5235 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5236 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005237 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005238 goto exit;
5239 }
5240 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005241 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005242 numChannels,
5243 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5244 ret = -EINVAL;
5245 goto exit;
5246 }
5247 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5248 adapter->sessionId,
5249 ChannelList,
5250 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305251 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005252 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005253 ret = -EINVAL;
5254 goto exit;
5255 }
5256
5257exit:
5258 return ret;
5259}
5260
5261static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5262 hdd_context_t *hdd_ctx,
5263 uint8_t *command,
5264 uint8_t command_len,
5265 hdd_priv_data_t *priv_data)
5266{
5267 int ret = 0;
5268 uint8_t *value = command;
5269 char extra[128] = { 0 };
5270 int len = 0;
5271 uint8_t tid = 0;
5272 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005273 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005274
Krunal Sonibe766b02016-03-10 13:00:44 -08005275 if ((QDF_STA_MODE != adapter->device_mode) &&
5276 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005277 hdd_warn("Unsupported in mode %s(%d)",
5278 hdd_device_mode_to_string(adapter->device_mode),
5279 adapter->device_mode);
5280 return -EINVAL;
5281 }
5282
5283 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5284
5285 /* if not associated, return error */
5286 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005287 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005288 ret = -EINVAL;
5289 goto exit;
5290 }
5291
5292 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5293 value = value + command_len + 1;
5294
5295 /* Convert the value from ascii to integer */
5296 ret = kstrtou8(value, 10, &tid);
5297 if (ret < 0) {
5298 /*
5299 * If the input value is greater than max value of datatype,
5300 * then also kstrtou8 fails
5301 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005302 hdd_err("kstrtou8 failed range [%d - %d]",
5303 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005304 TID_MAX_VALUE);
5305 ret = -EINVAL;
5306 goto exit;
5307 }
5308 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005309 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005310 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5311 ret = -EINVAL;
5312 goto exit;
5313 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005314 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005315 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005316 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5317 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005318 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005319 goto exit;
5320 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005321 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005322 "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 -08005323 tsm_metrics.UplinkPktQueueDly,
5324 tsm_metrics.UplinkPktQueueDlyHist[0],
5325 tsm_metrics.UplinkPktQueueDlyHist[1],
5326 tsm_metrics.UplinkPktQueueDlyHist[2],
5327 tsm_metrics.UplinkPktQueueDlyHist[3],
5328 tsm_metrics.UplinkPktTxDly,
5329 tsm_metrics.UplinkPktLoss,
5330 tsm_metrics.UplinkPktCount,
5331 tsm_metrics.RoamingCount,
5332 tsm_metrics.RoamingDly);
5333 /*
5334 * Output TSM stats is of the format
5335 * GETTSMSTATS [PktQueueDly]
5336 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5337 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5338 */
5339 len = scnprintf(extra,
5340 sizeof(extra),
5341 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5342 command,
5343 tsm_metrics.UplinkPktQueueDly,
5344 tsm_metrics.UplinkPktQueueDlyHist[0],
5345 tsm_metrics.UplinkPktQueueDlyHist[1],
5346 tsm_metrics.UplinkPktQueueDlyHist[2],
5347 tsm_metrics.UplinkPktQueueDlyHist[3],
5348 tsm_metrics.UplinkPktTxDly,
5349 tsm_metrics.UplinkPktLoss,
5350 tsm_metrics.UplinkPktCount,
5351 tsm_metrics.RoamingCount,
5352 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305353 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005354 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005355 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005356 ret = -EFAULT;
5357 goto exit;
5358 }
5359
5360exit:
5361 return ret;
5362}
5363
5364static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5365 hdd_context_t *hdd_ctx,
5366 uint8_t *command,
5367 uint8_t command_len,
5368 hdd_priv_data_t *priv_data)
5369{
5370 int ret;
5371 uint8_t *value = command;
5372 uint8_t *cckmIe = NULL;
5373 uint8_t cckmIeLen = 0;
5374
5375 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5376 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005377 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005378 goto exit;
5379 }
5380
5381 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005382 hdd_err("CCKM Ie input length is more than max[%d]",
5383 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005384 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305385 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005386 cckmIe = NULL;
5387 }
5388 ret = -EINVAL;
5389 goto exit;
5390 }
5391
5392 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5393 cckmIe, cckmIeLen);
5394 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305395 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005396 cckmIe = NULL;
5397 }
5398
5399exit:
5400 return ret;
5401}
5402
5403static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5404 hdd_context_t *hdd_ctx,
5405 uint8_t *command,
5406 uint8_t command_len,
5407 hdd_priv_data_t *priv_data)
5408{
5409 int ret;
5410 uint8_t *value = command;
5411 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305412 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005413
Krunal Sonibe766b02016-03-10 13:00:44 -08005414 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005415 hdd_warn("Unsupported in mode %s(%d)",
5416 hdd_device_mode_to_string(adapter->device_mode),
5417 adapter->device_mode);
5418 return -EINVAL;
5419 }
5420
5421 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5422 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005423 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005424 goto exit;
5425 }
5426
5427 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005428 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005429 hdd_indicate_ese_bcn_report_no_results(adapter,
5430 eseBcnReq.bcnReq[0].measurementToken,
5431 0x02, /* BIT(1) set for measurement done */
5432 0); /* no BSS */
5433 goto exit;
5434 }
5435
5436 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5437 adapter->sessionId,
5438 &eseBcnReq);
5439
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305440 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005441 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005442 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005443 ret = -EBUSY;
5444 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305445 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005446 hdd_err("sme_set_ese_beacon_request failed (%d)",
5447 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005448 ret = -EINVAL;
5449 goto exit;
5450 }
5451
5452exit:
5453 return ret;
5454}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005455
5456/**
5457 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5458 * @adapter: Pointer to the HDD adapter
5459 * @hdd_ctx: Pointer to the HDD context
5460 * @command: Driver command string
5461 * @command_len: Driver command string length
5462 * @priv_data: Private data coming with the driver command. Unused here
5463 *
5464 * This function handles driver command that sets the ESE PLM request
5465 *
5466 * Return: 0 on success; negative errno otherwise
5467 */
5468static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5469 hdd_context_t *hdd_ctx,
5470 uint8_t *command,
5471 uint8_t command_len,
5472 hdd_priv_data_t *priv_data)
5473{
5474 int ret = 0;
5475 uint8_t *value = command;
5476 QDF_STATUS status = QDF_STATUS_SUCCESS;
5477 tpSirPlmReq pPlmRequest = NULL;
5478
5479 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5480 if (NULL == pPlmRequest) {
5481 ret = -ENOMEM;
5482 goto exit;
5483 }
5484
5485 status = hdd_parse_plm_cmd(value, pPlmRequest);
5486 if (QDF_STATUS_SUCCESS != status) {
5487 qdf_mem_free(pPlmRequest);
5488 pPlmRequest = NULL;
5489 ret = -EINVAL;
5490 goto exit;
5491 }
5492 pPlmRequest->sessionId = adapter->sessionId;
5493
5494 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5495 if (QDF_STATUS_SUCCESS != status) {
5496 qdf_mem_free(pPlmRequest);
5497 pPlmRequest = NULL;
5498 ret = -EINVAL;
5499 goto exit;
5500 }
5501
5502exit:
5503 return ret;
5504}
5505
5506/**
5507 * drv_cmd_set_ccx_mode() - Set ESE mode
5508 * @adapter: Pointer to the HDD adapter
5509 * @hdd_ctx: Pointer to the HDD context
5510 * @command: Driver command string
5511 * @command_len: Driver command string length
5512 * @priv_data: Private data coming with the driver command. Unused here
5513 *
5514 * This function handles driver command that sets ESE mode
5515 *
5516 * Return: 0 on success; negative errno otherwise
5517 */
5518static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5519 hdd_context_t *hdd_ctx,
5520 uint8_t *command,
5521 uint8_t command_len,
5522 hdd_priv_data_t *priv_data)
5523{
5524 int ret = 0;
5525 uint8_t *value = command;
5526 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5527
5528 /*
5529 * Check if the features OKC/ESE/11R are supported simultaneously,
5530 * then this operation is not permitted (return FAILURE)
5531 */
5532 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5533 hdd_is_okc_mode_enabled(hdd_ctx) &&
5534 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5535 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5536 ret = -EPERM;
5537 goto exit;
5538 }
5539
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005540 if (!adapter->fast_roaming_allowed) {
5541 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5542 ret = -EPERM;
5543 goto exit;
5544 }
5545
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005546 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5547 value = value + command_len + 1;
5548
5549 /* Convert the value from ascii to integer */
5550 ret = kstrtou8(value, 10, &eseMode);
5551 if (ret < 0) {
5552 /*
5553 * If the input value is greater than max value of datatype,
5554 * then also kstrtou8 fails
5555 */
5556 hdd_err("kstrtou8 failed range [%d - %d]",
5557 CFG_ESE_FEATURE_ENABLED_MIN,
5558 CFG_ESE_FEATURE_ENABLED_MAX);
5559 ret = -EINVAL;
5560 goto exit;
5561 }
5562
5563 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5564 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5565 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5566 eseMode,
5567 CFG_ESE_FEATURE_ENABLED_MIN,
5568 CFG_ESE_FEATURE_ENABLED_MAX);
5569 ret = -EINVAL;
5570 goto exit;
5571 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005572 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005573
5574 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5575 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5576 adapter->sessionId,
5577 eseMode);
5578
5579exit:
5580 return ret;
5581}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005582#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005583
5584static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5585 hdd_context_t *hdd_ctx,
5586 uint8_t *command,
5587 uint8_t command_len,
5588 hdd_priv_data_t *priv_data)
5589{
5590 int ret = 0;
5591 uint8_t *value = command;
5592 int targetRate;
5593
5594 /* input value is in units of hundred kbps */
5595
5596 /* Move pointer to ahead of SETMCRATE<delimiter> */
5597 value = value + command_len + 1;
5598
5599 /* Convert the value from ascii to integer, decimal base */
5600 ret = kstrtouint(value, 10, &targetRate);
5601
5602 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5603 return ret;
5604}
5605
5606static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5607 hdd_context_t *hdd_ctx,
5608 uint8_t *command,
5609 uint8_t command_len,
5610 hdd_priv_data_t *priv_data)
5611{
5612 int ret = 0;
5613 int status;
5614 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305615 QDF_STATUS qdf_status;
5616 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005617 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305618 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5619 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005620 hdd_adapter_list_node_t *pAdapterNode = NULL;
5621 hdd_adapter_list_node_t *pNext = NULL;
5622
5623 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5624 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005625 hdd_err("Invalid MAXTXPOWER command");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005626 ret = -EINVAL;
5627 goto exit;
5628 }
5629
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305630 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005631 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305632 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005633 adapter = pAdapterNode->pAdapter;
5634 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305635 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005636 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305637 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005638 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005639
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005640 hdd_debug("Device mode %d max tx power %d selfMac: "
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005641 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005642 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005643 MAC_ADDR_ARRAY(selfMac.bytes),
5644 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005645
Srinivas Girigowda97215232015-09-24 12:26:28 -07005646 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5647 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305648 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005649 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005650 ret = -EINVAL;
5651 goto exit;
5652 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005653 hdd_debug("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305654 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005655 &pNext);
5656 pAdapterNode = pNext;
5657 }
5658
5659exit:
5660 return ret;
5661}
5662
5663static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5664 hdd_context_t *hdd_ctx,
5665 uint8_t *command,
5666 uint8_t command_len,
5667 hdd_priv_data_t *priv_data)
5668{
5669 int ret = 0;
5670 uint8_t *value = command;
5671 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5672
5673 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5674 value = value + command_len + 1;
5675
5676 /* Convert the value from ascii to integer */
5677 ret = kstrtou8(value, 10, &dfsScanMode);
5678 if (ret < 0) {
5679 /*
5680 * If the input value is greater than max value of datatype,
5681 * then also kstrtou8 fails
5682 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005683 hdd_err("kstrtou8 failed range [%d - %d]",
5684 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005685 CFG_ROAMING_DFS_CHANNEL_MAX);
5686 ret = -EINVAL;
5687 goto exit;
5688 }
5689
5690 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5691 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005692 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005693 dfsScanMode,
5694 CFG_ROAMING_DFS_CHANNEL_MIN,
5695 CFG_ROAMING_DFS_CHANNEL_MAX);
5696 ret = -EINVAL;
5697 goto exit;
5698 }
5699
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005700 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005701 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005702
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005703 /* When DFS scanning is disabled, the DFS channels need to be
5704 * removed from the operation of device.
5705 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005706 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5707 dfsScanMode != CFG_ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005708 if (ret < 0) {
5709 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005710 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005711 goto exit;
5712 }
5713
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005714 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5715 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5716 dfsScanMode);
5717
5718exit:
5719 return ret;
5720}
5721
5722static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5723 hdd_context_t *hdd_ctx,
5724 uint8_t *command,
5725 uint8_t command_len,
5726 hdd_priv_data_t *priv_data)
5727{
5728 int ret = 0;
5729 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5730 char extra[32];
5731 uint8_t len = 0;
5732
5733 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305734 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005735 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005736 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005737 ret = -EFAULT;
5738 }
5739
5740 return ret;
5741}
5742
5743static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5744 hdd_context_t *hdd_ctx,
5745 uint8_t *command,
5746 uint8_t command_len,
5747 hdd_priv_data_t *priv_data)
5748{
5749 int ret = 0;
5750 int value = wlan_hdd_get_link_status(adapter);
5751 char extra[32];
5752 uint8_t len;
5753
5754 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305755 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005756 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005757 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005758 ret = -EFAULT;
5759 }
5760
5761 return ret;
5762}
5763
5764#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5765static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5766 hdd_context_t *hdd_ctx,
5767 uint8_t *command,
5768 uint8_t command_len,
5769 hdd_priv_data_t *priv_data)
5770{
5771 uint8_t *value = command;
5772 int set_value;
5773
5774 /* Move pointer to ahead of ENABLEEXTWOW */
5775 value = value + command_len;
5776
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305777 if (!(sscanf(value, "%d", &set_value))) {
5778 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5779 ("No input identified"));
5780 return -EINVAL;
5781 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005782
5783 return hdd_enable_ext_wow_parser(adapter,
5784 adapter->sessionId,
5785 set_value);
5786}
5787
5788static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5789 hdd_context_t *hdd_ctx,
5790 uint8_t *command,
5791 uint8_t command_len,
5792 hdd_priv_data_t *priv_data)
5793{
5794 int ret;
5795 uint8_t *value = command;
5796
5797 /* Move pointer to ahead of SETAPP1PARAMS */
5798 value = value + command_len;
5799
5800 ret = hdd_set_app_type1_parser(adapter,
5801 value, strlen(value));
5802 if (ret >= 0)
5803 hdd_ctx->is_extwow_app_type1_param_set = true;
5804
5805 return ret;
5806}
5807
5808static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5809 hdd_context_t *hdd_ctx,
5810 uint8_t *command,
5811 uint8_t command_len,
5812 hdd_priv_data_t *priv_data)
5813{
5814 int ret;
5815 uint8_t *value = command;
5816
5817 /* Move pointer to ahead of SETAPP2PARAMS */
5818 value = value + command_len;
5819
5820 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5821 if (ret >= 0)
5822 hdd_ctx->is_extwow_app_type2_param_set = true;
5823
5824 return ret;
5825}
5826#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5827
5828#ifdef FEATURE_WLAN_TDLS
5829/**
5830 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5831 * @adapter: Pointer to the HDD adapter
5832 * @hdd_ctx: Pointer to the HDD context
5833 * @command: Driver command string
5834 * @command_len: Driver command string length
5835 * @priv_data: Private data coming with the driver command. Unused here
5836 *
5837 * This function handles driver command that sets the secondary tdls off channel
5838 * offset
5839 *
5840 * Return: 0 on success; negative errno otherwise
5841 */
5842static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5843 hdd_context_t *hdd_ctx,
5844 uint8_t *command,
5845 uint8_t command_len,
5846 hdd_priv_data_t *priv_data)
5847{
5848 int ret;
5849 uint8_t *value = command;
5850 int set_value;
5851
5852 /* Move pointer to point the string */
5853 value += command_len;
5854
5855 ret = sscanf(value, "%d", &set_value);
5856 if (ret != 1)
5857 return -EINVAL;
5858
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005859 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005860
5861 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5862
5863 return ret;
5864}
5865
5866/**
5867 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5868 * @adapter: Pointer to the HDD adapter
5869 * @hdd_ctx: Pointer to the HDD context
5870 * @command: Driver command string
5871 * @command_len: Driver command string length
5872 * @priv_data: Private data coming with the driver command. Unused here
5873 *
5874 * This function handles driver command that sets tdls off channel mode
5875 *
5876 * Return: 0 on success; negative errno otherwise
5877 */
5878static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5879 hdd_context_t *hdd_ctx,
5880 uint8_t *command,
5881 uint8_t command_len,
5882 hdd_priv_data_t *priv_data)
5883{
5884 int ret;
5885 uint8_t *value = command;
5886 int set_value;
5887
5888 /* Move pointer to point the string */
5889 value += command_len;
5890
5891 ret = sscanf(value, "%d", &set_value);
5892 if (ret != 1)
5893 return -EINVAL;
5894
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005895 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005896
5897 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5898
5899 return ret;
5900}
5901
5902/**
5903 * drv_cmd_tdls_off_channel() - set tdls off channel number
5904 * @adapter: Pointer to the HDD adapter
5905 * @hdd_ctx: Pointer to the HDD context
5906 * @command: Driver command string
5907 * @command_len: Driver command string length
5908 * @priv_data: Private data coming with the driver command. Unused here
5909 *
5910 * This function handles driver command that sets tdls off channel number
5911 *
5912 * Return: 0 on success; negative errno otherwise
5913 */
5914static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5915 hdd_context_t *hdd_ctx,
5916 uint8_t *command,
5917 uint8_t command_len,
5918 hdd_priv_data_t *priv_data)
5919{
5920 int ret;
5921 uint8_t *value = command;
5922 int set_value;
5923
5924 /* Move pointer to point the string */
5925 value += command_len;
5926
5927 ret = sscanf(value, "%d", &set_value);
5928 if (ret != 1)
5929 return -EINVAL;
5930
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -07005931 if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, set_value)) {
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005932 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5933 set_value);
5934 return -EINVAL;
5935 }
5936
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005937 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005938
5939 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5940
5941 return ret;
5942}
5943
5944/**
5945 * drv_cmd_tdls_scan() - set tdls scan type
5946 * @adapter: Pointer to the HDD adapter
5947 * @hdd_ctx: Pointer to the HDD context
5948 * @command: Driver command string
5949 * @command_len: Driver command string length
5950 * @priv_data: Private data coming with the driver command. Unused here
5951 *
5952 * This function handles driver command that sets tdls scan type
5953 *
5954 * Return: 0 on success; negative errno otherwise
5955 */
5956static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
5957 hdd_context_t *hdd_ctx,
5958 uint8_t *command,
5959 uint8_t command_len,
5960 hdd_priv_data_t *priv_data)
5961{
5962 int ret;
5963 uint8_t *value = command;
5964 int set_value;
5965
5966 /* Move pointer to point the string */
5967 value += command_len;
5968
5969 ret = sscanf(value, "%d", &set_value);
5970 if (ret != 1)
5971 return -EINVAL;
5972
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005973 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005974
5975 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
5976
5977 return ret;
5978}
5979#endif
5980
5981static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
5982 hdd_context_t *hdd_ctx,
5983 uint8_t *command,
5984 uint8_t command_len,
5985 hdd_priv_data_t *priv_data)
5986{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005987 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005988 int8_t rssi = 0;
5989 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005990
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005991 uint8_t len = 0;
5992
5993 wlan_hdd_get_rssi(adapter, &rssi);
5994
5995 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305996 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005997
5998 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005999 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006000 ret = -EFAULT;
6001 }
6002
6003 return ret;
6004}
6005
6006static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6007 hdd_context_t *hdd_ctx,
6008 uint8_t *command,
6009 uint8_t command_len,
6010 hdd_priv_data_t *priv_data)
6011{
6012 int ret;
6013 uint32_t link_speed = 0;
6014 char extra[32];
6015 uint8_t len = 0;
6016
6017 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6018 if (0 != ret)
6019 return ret;
6020
6021 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306022 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006023 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006024 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006025 ret = -EFAULT;
6026 }
6027
6028 return ret;
6029}
6030
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006031/**
6032 * hdd_set_rx_filter() - set RX filter
6033 * @adapter: Pointer to adapter
6034 * @action: Filter action
6035 * @pattern: Address pattern
6036 *
6037 * Address pattern is most significant byte of address for example
6038 * 0x01 for IPV4 multicast address
6039 * 0x33 for IPV6 multicast address
6040 * 0xFF for broadcast address
6041 *
6042 * Return: 0 for success, non-zero for failure
6043 */
6044static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6045 uint8_t pattern)
6046{
6047 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006048 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006049 tHalHandle handle;
6050 tSirRcvFltMcAddrList *filter;
6051 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6052
6053 ret = wlan_hdd_validate_context(hdd_ctx);
6054 if (0 != ret)
6055 return ret;
6056
6057 handle = hdd_ctx->hHal;
6058
6059 if (NULL == handle) {
6060 hdd_err("HAL Handle is NULL");
6061 return -EINVAL;
6062 }
6063
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306064 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006065 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306066 return -EINVAL;
6067 }
6068
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006069 /*
6070 * If action is false it means start dropping packets
6071 * Set addr_filter_pattern which will be used when sending
6072 * MC/BC address list to target
6073 */
6074 if (!action)
6075 adapter->addr_filter_pattern = pattern;
6076 else
6077 adapter->addr_filter_pattern = 0;
6078
Krunal Sonibe766b02016-03-10 13:00:44 -08006079 if (((adapter->device_mode == QDF_STA_MODE) ||
6080 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006081 adapter->mc_addr_list.mc_cnt &&
6082 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6083
6084
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306085 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006086 if (NULL == filter) {
6087 hdd_err("Could not allocate Memory");
6088 return -ENOMEM;
6089 }
6090 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006091 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092 if (!memcmp(adapter->mc_addr_list.addr[i],
6093 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006094 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006095 adapter->mc_addr_list.addr[i],
6096 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006097
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006098 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006099 MAC_ADDRESS_STR,
6100 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006101 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6102 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006103 }
6104 }
Frank Liuf95e8132016-09-29 19:01:30 +08006105 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006106 /* Set rx filter */
6107 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306108 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006109 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006110 hdd_debug("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006111 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6112 }
6113
6114 return 0;
6115}
6116
6117/**
6118 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6119 * @command: Pointer to input string driver command
6120 * @adapter: Pointer to adapter
6121 * @action: Action to enable/disable filtering
6122 *
6123 * If action == false
6124 * Start filtering out data packets based on type
6125 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6126 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6127 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6128 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6129 *
6130 * if action == true
6131 * Stop filtering data packets based on type
6132 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6133 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6134 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6135 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6136 *
6137 * Current implementation only supports IPV4 address filtering by
6138 * selectively allowing IPV4 multicast data packest based on
6139 * address list received in .ndo_set_rx_mode
6140 *
6141 * Return: 0 for success, non-zero for failure
6142 */
6143static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6144 hdd_adapter_t *adapter,
6145 bool action)
6146{
6147 int ret = 0;
6148 uint8_t *value;
6149 uint8_t type;
6150
6151 value = command;
6152 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6153 if (!action)
6154 value = command + 16;
6155 else
6156 value = command + 13;
6157 ret = kstrtou8(value, 10, &type);
6158 if (ret < 0) {
6159 hdd_err("kstrtou8 failed invalid input value %d", type);
6160 return -EINVAL;
6161 }
6162
6163 switch (type) {
6164 case 2:
6165 /* Set rx filter for IPV4 multicast data packets */
6166 ret = hdd_set_rx_filter(adapter, action, 0x01);
6167 break;
6168 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006169 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006170 break;
6171 }
6172
6173 return ret;
6174}
6175
6176/**
6177 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6178 * @adapter: Pointer to network adapter
6179 * @hdd_ctx: Pointer to hdd context
6180 * @command: Pointer to input command
6181 * @command_len: Command length
6182 * @priv_data: Pointer to private data in command
6183 */
6184static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6185 hdd_context_t *hdd_ctx,
6186 uint8_t *command,
6187 uint8_t command_len,
6188 hdd_priv_data_t *priv_data)
6189{
6190 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6191}
6192
6193/**
6194 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6195 * @adapter: Pointer to network adapter
6196 * @hdd_ctx: Pointer to hdd context
6197 * @command: Pointer to input command
6198 * @command_len: Command length
6199 * @priv_data: Pointer to private data in command
6200 */
6201static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6202 hdd_context_t *hdd_ctx,
6203 uint8_t *command,
6204 uint8_t command_len,
6205 hdd_priv_data_t *priv_data)
6206{
6207 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6208}
6209
Archana Ramachandran393f3792015-11-13 17:13:21 -08006210/**
6211 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6212 * command
6213 * @value: Pointer to SETANTENNAMODE command
6214 * @mode: Pointer to antenna mode
6215 * @reason: Pointer to reason for set antenna mode
6216 *
6217 * This function parses the SETANTENNAMODE command passed in the format
6218 * SETANTENNAMODE<space>mode
6219 *
6220 * Return: 0 for success non-zero for failure
6221 */
6222static int hdd_parse_setantennamode_command(const uint8_t *value)
6223{
6224 const uint8_t *in_ptr = value;
6225 int tmp, v;
6226 char arg1[32];
6227
6228 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6229
6230 /* no argument after the command */
6231 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006232 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006233 return -EINVAL;
6234 }
6235
6236 /* no space after the command */
6237 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006238 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006239 return -EINVAL;
6240 }
6241
6242 /* remove empty spaces */
6243 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6244 in_ptr++;
6245
6246 /* no argument followed by spaces */
6247 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006248 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006249 return -EINVAL;
6250 }
6251
6252 /* get the argument i.e. antenna mode */
6253 v = sscanf(in_ptr, "%31s ", arg1);
6254 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006255 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006256 return -EINVAL;
6257 }
6258
6259 v = kstrtos32(arg1, 10, &tmp);
6260 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006261 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006262 return -EINVAL;
6263 }
6264
6265 return tmp;
6266}
6267
6268/**
6269 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6270 * mask is 2x2 mode
6271 * @hdd_ctx: Pointer to hdd contex
6272 *
6273 * Return: true if supported chain mask 2x2 else false
6274 */
6275static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6276{
6277 /*
6278 * Revisit and the update logic to determine the number
6279 * of TX/RX chains supported in the system when
6280 * antenna sharing per band chain mask support is
6281 * brought in
6282 */
6283 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6284}
6285
6286/**
6287 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6288 * chain mask is 1x1
6289 * @hdd_ctx: Pointer to hdd contex
6290 *
6291 * Return: true if supported chain mask 1x1 else false
6292 */
6293static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6294{
6295 /*
6296 * Revisit and update the logic to determine the number
6297 * of TX/RX chains supported in the system when
6298 * antenna sharing per band chain mask support is
6299 * brought in
6300 */
6301 return (!hdd_ctx->config->enable2x2) ? true : false;
6302}
6303
Nitesh Shahe50711f2017-04-26 16:30:45 +05306304QDF_STATUS hdd_update_smps_antenna_mode(hdd_context_t *hdd_ctx, int mode)
6305{
6306 QDF_STATUS status;
6307 uint8_t smps_mode;
6308 uint8_t smps_enable;
6309
6310 /* Update SME SMPS config */
6311 if (HDD_ANTENNA_MODE_1X1 == mode) {
6312 smps_enable = true;
6313 smps_mode = HDD_SMPS_MODE_STATIC;
6314 } else {
6315 smps_enable = false;
6316 smps_mode = HDD_SMPS_MODE_DISABLED;
6317 }
6318
6319 hdd_debug("Update SME SMPS enable: %d mode: %d",
6320 smps_enable, smps_mode);
6321 status = sme_update_mimo_power_save(
6322 hdd_ctx->hHal, smps_enable, smps_mode, false);
6323 if (QDF_STATUS_SUCCESS != status) {
6324 hdd_err("Update SMPS config failed enable: %d mode: %d"
6325 "status: %d",
6326 smps_enable, smps_mode, status);
6327 return QDF_STATUS_E_FAILURE;
6328 }
6329
6330 hdd_ctx->current_antenna_mode = mode;
6331 /*
6332 * Update the user requested nss in the mac context.
6333 * This will be used in tdls protocol engine to form tdls
6334 * Management frames.
6335 */
6336 sme_update_user_configured_nss(
6337 hdd_ctx->hHal,
6338 hdd_ctx->current_antenna_mode);
6339
6340 hdd_debug("Successfully switched to mode: %d x %d",
6341 hdd_ctx->current_antenna_mode,
6342 hdd_ctx->current_antenna_mode);
6343
6344 return QDF_STATUS_SUCCESS;
6345}
6346
Archana Ramachandran393f3792015-11-13 17:13:21 -08006347/**
6348 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6349 * handler
6350 * @adapter: Pointer to network adapter
6351 * @hdd_ctx: Pointer to hdd context
6352 * @command: Pointer to input command
6353 * @command_len: Command length
6354 * @priv_data: Pointer to private data in command
6355 */
6356static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6357 hdd_context_t *hdd_ctx,
6358 uint8_t *command,
6359 uint8_t command_len,
6360 hdd_priv_data_t *priv_data)
6361{
6362 struct sir_antenna_mode_param params;
6363 QDF_STATUS status;
6364 int ret = 0;
6365 int mode;
6366 uint8_t *value = command;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006367
6368 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6369 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6370 hdd_err("Operation invalid in non sta or concurrent mode");
6371 ret = -EPERM;
6372 goto exit;
6373 }
6374
6375 mode = hdd_parse_setantennamode_command(value);
6376 if (mode < 0) {
6377 hdd_err("Invalid SETANTENNA command");
6378 ret = mode;
6379 goto exit;
6380 }
6381
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006382 hdd_debug("Processing antenna mode switch to: %d", mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006383
6384 if (hdd_ctx->current_antenna_mode == mode) {
6385 hdd_err("System already in the requested mode");
6386 ret = 0;
6387 goto exit;
6388 }
6389
6390 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6391 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6392 hdd_err("System does not support 2x2 mode");
6393 ret = -EPERM;
6394 goto exit;
6395 }
6396
6397 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6398 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6399 hdd_err("System only supports 1x1 mode");
6400 ret = 0;
6401 goto exit;
6402 }
6403
6404 switch (mode) {
6405 case HDD_ANTENNA_MODE_1X1:
6406 params.num_rx_chains = 1;
6407 params.num_tx_chains = 1;
6408 break;
6409 case HDD_ANTENNA_MODE_2X2:
6410 params.num_rx_chains = 2;
6411 params.num_tx_chains = 2;
6412 break;
6413 default:
6414 hdd_err("unsupported antenna mode");
6415 ret = -EINVAL;
6416 goto exit;
6417 }
6418
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006419 /* Check TDLS status and update antenna mode */
6420 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006421 policy_mgr_is_sta_active_connection_exists(
6422 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006423 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6424 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006425 if (0 != ret)
6426 goto exit;
6427 }
6428
Archana Ramachandran393f3792015-11-13 17:13:21 -08006429 params.set_antenna_mode_resp =
6430 (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006431 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006432 params.num_rx_chains,
6433 params.num_tx_chains);
6434
6435
6436 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6437 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6438 if (QDF_STATUS_SUCCESS != status) {
6439 hdd_err("set antenna mode failed status : %d", status);
6440 ret = -EFAULT;
6441 goto exit;
6442 }
6443
6444 ret = wait_for_completion_timeout(
6445 &hdd_ctx->set_antenna_mode_cmpl,
6446 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6447 if (!ret) {
6448 ret = -EFAULT;
6449 hdd_err("send set antenna mode timed out");
6450 goto exit;
6451 }
6452
Nitesh Shahe50711f2017-04-26 16:30:45 +05306453 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006454 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006455 ret = -EFAULT;
6456 goto exit;
6457 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006458 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006459exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006460#ifdef FEATURE_WLAN_TDLS
6461 /* Reset tdls NSS flags */
6462 if (hdd_ctx->tdls_nss_switch_in_progress &&
6463 hdd_ctx->tdls_nss_teardown_complete) {
6464 hdd_ctx->tdls_nss_switch_in_progress = false;
6465 hdd_ctx->tdls_nss_teardown_complete = false;
6466 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006467 hdd_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
Kabilan Kannanff89f742016-08-15 18:14:10 -07006468 hdd_ctx->tdls_nss_switch_in_progress,
6469 hdd_ctx->tdls_nss_teardown_complete);
6470#endif
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006471 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006472 ret, hdd_ctx->current_antenna_mode);
6473 return ret;
6474
6475}
6476
6477/**
6478 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6479 * handler
6480 * @adapter: Pointer to hdd adapter
6481 * @hdd_ctx: Pointer to hdd context
6482 * @command: Pointer to input command
6483 * @command_len: length of the command
6484 * @priv_data: private data coming with the driver command
6485 *
6486 * Return: 0 for success non-zero for failure
6487 */
6488static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6489 hdd_context_t *hdd_ctx,
6490 uint8_t *command,
6491 uint8_t command_len,
6492 hdd_priv_data_t *priv_data)
6493{
6494 uint32_t antenna_mode = 0;
6495 char extra[32];
6496 uint8_t len = 0;
6497
6498 antenna_mode = hdd_ctx->current_antenna_mode;
6499 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6500 antenna_mode);
6501 len = QDF_MIN(priv_data->total_len, len + 1);
6502 if (copy_to_user(priv_data->buf, &extra, len)) {
6503 hdd_err("Failed to copy data to user buffer");
6504 return -EFAULT;
6505 }
6506
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006507 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006508
6509 return 0;
6510}
6511
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006512/*
6513 * dummy (no-op) hdd driver command handler
6514 */
6515static int drv_cmd_dummy(hdd_adapter_t *adapter,
6516 hdd_context_t *hdd_ctx,
6517 uint8_t *command,
6518 uint8_t command_len,
6519 hdd_priv_data_t *priv_data)
6520{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006521 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006522 adapter->dev->name, command);
6523 return 0;
6524}
6525
6526/*
6527 * handler for any unsupported wlan hdd driver command
6528 */
6529static int drv_cmd_invalid(hdd_adapter_t *adapter,
6530 hdd_context_t *hdd_ctx,
6531 uint8_t *command,
6532 uint8_t command_len,
6533 hdd_priv_data_t *priv_data)
6534{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306535 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006536 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6537 adapter->sessionId, 0));
6538
6539 hdd_warn("%s: Unsupported driver command \"%s\"",
6540 adapter->dev->name, command);
6541
6542 return -ENOTSUPP;
6543}
6544
6545/**
6546 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6547 * @adapter: HDD adapter
6548 * @hdd_ctx: HDD context
6549 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6550 * @command_len: command len
6551 * @priv_data: private data
6552 *
6553 * Return: status
6554 */
6555static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6556 hdd_context_t *hdd_ctx,
6557 uint8_t *command,
6558 uint8_t command_len,
6559 hdd_priv_data_t *priv_data)
6560{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306561 QDF_STATUS status;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006562 uint8_t fcc_constraint;
6563 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006564
6565 /*
6566 * this command would be called by user-space when it detects WLAN
6567 * ON after airplane mode is set. When APM is set, WLAN turns off.
6568 * But it can be turned back on. Otherwise; when APM is turned back
6569 * off, WLAN would turn back on. So at that point the command is
6570 * expected to come down. 0 means disable, 1 means enable. The
6571 * constraint is removed when parameter 1 is set or different
6572 * country code is set
6573 */
6574
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006575 err = kstrtou8(command + command_len + 1, 10, &fcc_constraint);
6576 if (err) {
6577 hdd_err("error %d parsing userspace fcc parameter", err);
6578 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006579 }
6580
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006581 status = ucfg_reg_set_fcc_constraint(hdd_ctx->hdd_pdev,
6582 fcc_constraint);
6583
6584 if (QDF_IS_STATUS_ERROR(status))
6585 hdd_err("Failed to %s tx power for channels 12/13",
6586 fcc_constraint ? "reduce" : "restore");
6587
6588 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006589}
6590
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306591/**
6592 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6593 * command
6594 * @value: Pointer to the command
6595 * @chan_number: Pointer to the channel number
6596 * @chan_bw: Pointer to the channel bandwidth
6597 *
6598 * Parses and provides the channel number and channel width from the input
6599 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6600 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6601 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6602 *
6603 * Return: 0 for success, non-zero for failure
6604 */
6605static int hdd_parse_set_channel_switch_command(uint8_t *value,
6606 uint32_t *chan_number,
6607 uint32_t *chan_bw)
6608{
6609 const uint8_t *in_ptr = value;
6610 int ret;
6611
6612 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6613
6614 /* no argument after the command */
6615 if (NULL == in_ptr) {
6616 hdd_err("No argument after the command");
6617 return -EINVAL;
6618 }
6619
6620 /* no space after the command */
6621 if (SPACE_ASCII_VALUE != *in_ptr) {
6622 hdd_err("No space after the command ");
6623 return -EINVAL;
6624 }
6625
6626 /* remove empty spaces and move the next argument */
6627 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6628 in_ptr++;
6629
6630 /* no argument followed by spaces */
6631 if ('\0' == *in_ptr) {
6632 hdd_err("No argument followed by spaces");
6633 return -EINVAL;
6634 }
6635
6636 /* get the two arguments: channel number and bandwidth */
6637 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6638 if (ret != 2) {
6639 hdd_err("Arguments retrieval from cmd string failed");
6640 return -EINVAL;
6641 }
6642
6643 return 0;
6644}
6645
6646/**
6647 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6648 * @adapter: HDD adapter
6649 * @hdd_ctx: HDD context
6650 * @command: Pointer to the input command CHANNEL_SWITCH
6651 * @command_len: Command len
6652 * @priv_data: Private data
6653 *
6654 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6655 * of SAP/P2P-GO
6656 *
6657 * Return: 0 for success, non-zero for failure
6658 */
6659static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
6660 hdd_context_t *hdd_ctx,
6661 uint8_t *command,
6662 uint8_t command_len,
6663 hdd_priv_data_t *priv_data)
6664{
6665 struct net_device *dev = adapter->dev;
6666 int status;
6667 uint32_t chan_number = 0, chan_bw = 0;
6668 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006669 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306670
Krunal Sonibe766b02016-03-10 13:00:44 -08006671 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6672 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306673 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6674 adapter->device_mode);
6675 return -EINVAL;
6676 }
6677
6678 status = hdd_parse_set_channel_switch_command(value,
6679 &chan_number, &chan_bw);
6680 if (status) {
6681 hdd_err("Invalid CHANNEL_SWITCH command");
6682 return status;
6683 }
6684
6685 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6686 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6687 return -EINVAL;
6688 }
6689
6690 if (chan_bw == 80)
6691 width = CH_WIDTH_80MHZ;
6692 else if (chan_bw == 40)
6693 width = CH_WIDTH_40MHZ;
6694 else
6695 width = CH_WIDTH_20MHZ;
6696
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006697 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306698
6699 status = hdd_softap_set_channel_change(dev, chan_number, width);
6700 if (status) {
6701 hdd_err("Set channel change fail");
6702 return status;
6703 }
6704
6705 return 0;
6706}
6707
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006708/*
6709 * The following table contains all supported WLAN HDD
6710 * IOCTL driver commands and the handler for each of them.
6711 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07006712static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006713 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
6714 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
6715 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
6716 {"SETBAND", drv_cmd_set_band},
6717 {"SETWMMPS", drv_cmd_set_wmmps},
6718 {"COUNTRY", drv_cmd_country},
6719 {"SETSUSPENDMODE", drv_cmd_dummy},
6720 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
6721 {"BTCOEXSCAN", drv_cmd_dummy},
6722 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006723 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
6724 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
6725 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
6726 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
6727 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
6728 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006729 {"SETROAMMODE", drv_cmd_set_roam_mode},
6730 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006731 {"SETROAMDELTA", drv_cmd_set_roam_delta},
6732 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006733 {"GETBAND", drv_cmd_get_band},
6734 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
6735 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
6736 {"GETCCXMODE", drv_cmd_get_ccx_mode},
6737 {"GETOKCMODE", drv_cmd_get_okc_mode},
6738 {"GETFASTROAM", drv_cmd_get_fast_roam},
6739 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
6740 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
6741 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
6742 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
6743 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
6744 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
6745 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
6746 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
6747 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
6748 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
6749 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
6750 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
6751 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
6752 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
6753 {"REASSOC", drv_cmd_reassoc},
6754 {"SETWESMODE", drv_cmd_set_wes_mode},
6755 {"GETWESMODE", drv_cmd_get_wes_mode},
6756 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
6757 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
6758 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
6759 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006760 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006761 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
6762 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006763 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006764 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006765 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
6766 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
6767 {"SCAN-ACTIVE", drv_cmd_scan_active},
6768 {"SCAN-PASSIVE", drv_cmd_scan_passive},
6769 {"GETDWELLTIME", drv_cmd_get_dwell_time},
6770 {"SETDWELLTIME", drv_cmd_set_dwell_time},
6771 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08006772 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
6773 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
6774 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
6775 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
6776 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
6777 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
6778 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006779#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006780 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
6781 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
6782 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006783 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
6784 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
6785 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006786#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006787 {"SETMCRATE", drv_cmd_set_mc_rate},
6788 {"MAXTXPOWER", drv_cmd_max_tx_power},
6789 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
6790 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
6791 {"GETLINKSTATUS", drv_cmd_get_link_status},
6792#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6793 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
6794 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
6795 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
6796#endif
6797#ifdef FEATURE_WLAN_TDLS
6798 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
6799 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
6800 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
6801 {"TDLSSCAN", drv_cmd_tdls_scan},
6802#endif
6803 {"RSSI", drv_cmd_get_rssi},
6804 {"LINKSPEED", drv_cmd_get_linkspeed},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006805 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
6806 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
6807 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306808 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08006809 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
6810 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006811};
6812
6813/**
6814 * hdd_drv_cmd_process() - chooses and runs the proper
6815 * handler based on the input command
6816 * @adapter: Pointer to the hdd adapter
6817 * @cmd: Pointer to the driver command
6818 * @priv_data: Pointer to the data associated with the command
6819 *
6820 * This function parses the input hdd driver command and runs
6821 * the proper handler
6822 *
6823 * Return: 0 for success non-zero for failure
6824 */
6825static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
6826 uint8_t *cmd,
6827 hdd_priv_data_t *priv_data)
6828{
6829 hdd_context_t *hdd_ctx;
6830 int i;
6831 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6832 uint8_t *cmd_i = NULL;
6833 hdd_drv_cmd_handler_t handler = NULL;
6834 int len = 0;
6835
6836 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006837 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006838 return -EINVAL;
6839 }
6840
6841 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
6842
6843 for (i = 0; i < cmd_num_total; i++) {
6844
6845 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6846 handler = hdd_drv_cmds[i].handler;
6847 len = strlen(cmd_i);
6848
6849 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006850 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006851 return -EINVAL;
6852 }
6853
6854 if (strncasecmp(cmd, cmd_i, len) == 0)
6855 return handler(adapter, hdd_ctx,
6856 cmd, len, priv_data);
6857 }
6858
6859 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6860}
6861
6862/**
6863 * hdd_driver_command() - top level wlan hdd driver command handler
6864 * @adapter: Pointer to the hdd adapter
6865 * @priv_data: Pointer to the raw command data
6866 *
6867 * This function is the top level wlan hdd driver command handler. It
6868 * handles the command with the help of hdd_drv_cmd_process()
6869 *
6870 * Return: 0 for success non-zero for failure
6871 */
6872static int hdd_driver_command(hdd_adapter_t *adapter,
6873 hdd_priv_data_t *priv_data)
6874{
6875 uint8_t *command = NULL;
6876 int ret = 0;
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306877 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006878
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306879 ENTER();
6880
Anurag Chouhan6d760662016-02-20 16:05:43 +05306881 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006882 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006883 return -EINVAL;
6884 }
6885
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306886 ret = wlan_hdd_validate_context(hdd_ctx);
6887 if (ret)
6888 return ret;
6889
6890 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
6891 hdd_err("Driver module is closed; command can not be processed");
6892 return -EINVAL;
6893 }
6894
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006895 /*
6896 * Note that valid pointers are provided by caller
6897 */
6898
6899 /* copy to local struct to avoid numerous changes to legacy code */
6900 if (priv_data->total_len <= 0 ||
6901 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006902 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006903 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006904 ret = -EINVAL;
6905 goto exit;
6906 }
6907
6908 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006909 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006910 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006911 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006912 ret = -ENOMEM;
6913 goto exit;
6914 }
6915
6916 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6917 ret = -EFAULT;
6918 goto exit;
6919 }
6920
6921 /* Make sure the command is NUL-terminated */
6922 command[priv_data->total_len] = '\0';
6923
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006924 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006925 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6926
6927exit:
6928 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006929 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306930 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006931 return ret;
6932}
6933
6934#ifdef CONFIG_COMPAT
6935static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6936{
6937 struct {
6938 compat_uptr_t buf;
6939 int used_len;
6940 int total_len;
6941 } compat_priv_data;
6942 hdd_priv_data_t priv_data;
6943 int ret = 0;
6944
6945 /*
6946 * Note that adapter and ifr have already been verified by caller,
6947 * and HDD context has also been validated
6948 */
6949 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
6950 sizeof(compat_priv_data))) {
6951 ret = -EFAULT;
6952 goto exit;
6953 }
6954 priv_data.buf = compat_ptr(compat_priv_data.buf);
6955 priv_data.used_len = compat_priv_data.used_len;
6956 priv_data.total_len = compat_priv_data.total_len;
6957 ret = hdd_driver_command(adapter, &priv_data);
6958exit:
6959 return ret;
6960}
6961#else /* CONFIG_COMPAT */
6962static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6963{
6964 /* will never be invoked */
6965 return 0;
6966}
6967#endif /* CONFIG_COMPAT */
6968
6969static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6970{
6971 hdd_priv_data_t priv_data;
6972 int ret = 0;
6973
6974 /*
6975 * Note that adapter and ifr have already been verified by caller,
6976 * and HDD context has also been validated
6977 */
6978 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
6979 ret = -EFAULT;
6980 else
6981 ret = hdd_driver_command(adapter, &priv_data);
6982
6983 return ret;
6984}
6985
6986/**
6987 * __hdd_ioctl() - ioctl handler for wlan network interfaces
6988 * @dev: device upon which the ioctl was received
6989 * @ifr: ioctl request information
6990 * @cmd: ioctl command
6991 *
6992 * This function does initial processing of wlan device ioctls.
6993 * Currently two flavors of ioctls are supported. The primary ioctl
6994 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
6995 * for Android "DRIVER" commands. The other ioctl that is
6996 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
6997 * for FTM on some platforms. This function simply verifies that the
6998 * driver is in a sane state, and that the ioctl is one of the
6999 * supported flavors, in which case flavor-specific handlers are
7000 * dispatched.
7001 *
7002 * Return: 0 on success, non-zero on error
7003 */
7004static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7005{
7006 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7007 hdd_context_t *hdd_ctx;
7008 int ret;
7009
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007010 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307011
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007012 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007013 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007014 ret = -ENODEV;
7015 goto exit;
7016 }
7017
7018 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007019 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007020 ret = -EINVAL;
7021 goto exit;
7022 }
7023#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307024 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007025 if (SIOCIOCTLTX99 == cmd) {
7026 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7027 goto exit;
7028 }
7029 }
7030#endif
7031
7032 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7033 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307034 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007035 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007036
7037 switch (cmd) {
7038 case (SIOCDEVPRIVATE + 1):
7039 if (is_compat_task())
7040 ret = hdd_driver_compat_ioctl(adapter, ifr);
7041 else
7042 ret = hdd_driver_ioctl(adapter, ifr);
7043 break;
7044 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007045 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007046 ret = -EINVAL;
7047 break;
7048 }
7049exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307050 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007051 return ret;
7052}
7053
7054/**
7055 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7056 * @dev: device upon which the ioctl was received
7057 * @ifr: ioctl request information
7058 * @cmd: ioctl command
7059 *
7060 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7061 * which is where the ioctls are really handled.
7062 *
7063 * Return: 0 on success, non-zero on error
7064 */
7065int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7066{
7067 int ret;
7068
7069 cds_ssr_protect(__func__);
7070 ret = __hdd_ioctl(dev, ifr, cmd);
7071 cds_ssr_unprotect(__func__);
7072 return ret;
7073}