blob: 81b3771a5af83102bd5eee37768539db0d5b1e99 [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
Ashish Kumar Dhanotiyabfe639f2017-06-12 18:34:34 +0530319 v = sscanf(inPtr, "%31s ", buf);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700320 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800321 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700322
323 v = kstrtos32(buf, 10, &tempInt);
324 if (v < 0)
325 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800326
327 switch (tempInt) {
328 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700329 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800330 return -EINVAL;
331 case 0:
332 case 6:
333 case 9:
334 case 12:
335 case 18:
336 case 24:
337 case 36:
338 case 48:
339 case 54:
340 *pTxFlags = eHAL_TX_RATE_LEGACY;
341 *pRate = tempInt * 10;
342 break;
343 case 65:
344 *pTxFlags = eHAL_TX_RATE_HT20;
345 *pRate = tempInt * 10;
346 break;
347 case 72:
348 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
349 *pRate = 722;
350 break;
351 }
352
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800353 hdd_debug("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800354
355 return 0;
356}
357
358/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700359 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
360 * @UserData: Adapter private data
361 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800362 *
363 * This is an asynchronous callback function from SME when the peer info
364 * is received
365 *
366 * Return: 0 for success non-zero for failure
367 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700368void
369hdd_get_ibss_peer_info_cb(void *pUserData,
370 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800371{
372 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800373 hdd_station_ctx_t *pStaCtx;
374 uint8_t i;
375
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800376 if ((NULL == adapter) ||
377 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800378 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800379 return;
380 }
381
382 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
383 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700384 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530385 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
386 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700387 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530388 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800389 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530390 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
391 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
392
393 for (i = 0; i < pPeerInfo->numPeers; i++)
394 pStaCtx->ibss_peer_info.peerInfoParams[i] =
395 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800396 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800397 hdd_debug("peerInfo %s: status %u, numPeers %u",
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530398 pPeerInfo ? "valid" : "null",
399 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
400 pPeerInfo ? pPeerInfo->numPeers : 0);
401 pStaCtx->ibss_peer_info.numPeers = 0;
402 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800403 }
404
405 complete(&adapter->ibss_peer_info_comp);
406}
407
408/**
409 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
410 * @adapter: Adapter context
411 *
412 * Request function to get IBSS peer info from lower layers
413 *
414 * Return: 0 for success non-zero for failure
415 */
416static
417QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
418{
419 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
420 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
421 unsigned long rc;
422
423 INIT_COMPLETION(adapter->ibss_peer_info_comp);
424
425 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700426 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800427 true, 0xFF);
428
429 if (QDF_STATUS_SUCCESS == retStatus) {
430 rc = wait_for_completion_timeout
431 (&adapter->ibss_peer_info_comp,
432 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
433
434 /* status will be 0 if timed out */
435 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700436 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800437 retStatus = QDF_STATUS_E_FAILURE;
438 return retStatus;
439 }
440 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700441 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800442 }
443
444 return retStatus;
445}
446
447/**
448 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
449 * @adapter: Adapter context
450 * @staIdx: Sta index for which the peer info is requested
451 *
452 * Request function to get IBSS peer info from lower layers
453 *
454 * Return: 0 for success non-zero for failure
455 */
456static QDF_STATUS
457hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
458{
459 unsigned long rc;
460 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
461 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
462
463 INIT_COMPLETION(adapter->ibss_peer_info_comp);
464
465 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700466 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800467 false, staIdx);
468
469 if (QDF_STATUS_SUCCESS == retStatus) {
470 rc = wait_for_completion_timeout(
471 &adapter->ibss_peer_info_comp,
472 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
473
474 /* status = 0 on timeout */
475 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700476 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800477 retStatus = QDF_STATUS_E_FAILURE;
478 return retStatus;
479 }
480 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700481 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800482 }
483
484 return retStatus;
485}
486
487/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700488static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800489hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
490{
491 uint8_t *inPtr = pValue;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700492
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800493 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
494
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700495 if (NULL == inPtr)
496 return QDF_STATUS_E_FAILURE;
497 else if (SPACE_ASCII_VALUE != *inPtr)
498 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800499
500 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
501 inPtr++;
502
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700503 if ('\0' == *inPtr)
504 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800505
506 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
507 inPtr[11] != ':' || inPtr[14] != ':') {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700508 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800509 }
510 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
511 (unsigned int *)&pPeerMacAddr->bytes[0],
512 (unsigned int *)&pPeerMacAddr->bytes[1],
513 (unsigned int *)&pPeerMacAddr->bytes[2],
514 (unsigned int *)&pPeerMacAddr->bytes[3],
515 (unsigned int *)&pPeerMacAddr->bytes[4],
516 (unsigned int *)&pPeerMacAddr->bytes[5]);
517
518 return QDF_STATUS_SUCCESS;
519}
520
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800521static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
522{
523 eCsrBand band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700524
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
526 switch (band) {
527 case eCSR_BAND_ALL:
528 *pBand = WLAN_HDD_UI_BAND_AUTO;
529 break;
530
531 case eCSR_BAND_24:
532 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
533 break;
534
535 case eCSR_BAND_5G:
536 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
537 break;
538
539 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700540 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800541 *pBand = -1;
542 break;
543 }
544}
545
546/**
547 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
548 * @data: input data
549 * @target_ap_bssid: pointer to bssid (output parameter)
550 * @channel: pointer to channel (output parameter)
551 *
552 * Return: 0 if parsing is successful; -EINVAL otherwise
553 */
554static int _hdd_parse_bssid_and_chan(const uint8_t **data,
555 uint8_t *bssid,
556 uint8_t *channel)
557{
558 const uint8_t *in_ptr;
559 int v = 0;
560 int temp_int;
561 uint8_t temp_buf[32];
562
563 /* 12 hexa decimal digits, 5 ':' and '\0' */
564 uint8_t mac_addr[18];
565
566 if (!data || !*data)
567 return -EINVAL;
568
569 in_ptr = *data;
570
571 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
572 /* no argument after the command */
573 if (NULL == in_ptr)
574 goto error;
575 /* no space after the command */
576 else if (SPACE_ASCII_VALUE != *in_ptr)
577 goto error;
578
579 /* remove empty spaces */
580 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
581 in_ptr++;
582
583 /* no argument followed by spaces */
584 if ('\0' == *in_ptr)
585 goto error;
586
587 v = sscanf(in_ptr, "%17s", mac_addr);
588 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700589 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
590 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800591 goto error;
592 }
593
594 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
595 hex_to_bin(mac_addr[1]);
596 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
597 hex_to_bin(mac_addr[4]);
598 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
599 hex_to_bin(mac_addr[7]);
600 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
601 hex_to_bin(mac_addr[10]);
602 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
603 hex_to_bin(mac_addr[13]);
604 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
605 hex_to_bin(mac_addr[16]);
606
607 /* point to the next argument */
608 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
609 /* no argument after the command */
610 if (NULL == in_ptr)
611 goto error;
612
613 /* remove empty spaces */
614 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
615 in_ptr++;
616
617 /* no argument followed by spaces */
618 if ('\0' == *in_ptr)
619 goto error;
620
621 /* get the next argument ie the channel number */
622 v = sscanf(in_ptr, "%31s ", temp_buf);
623 if (1 != v)
624 goto error;
625
626 v = kstrtos32(temp_buf, 10, &temp_int);
627 if ((v < 0) || (temp_int < 0) ||
628 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
629 return -EINVAL;
630
631 *channel = temp_int;
632 *data = in_ptr;
633 return 0;
634error:
635 *data = in_ptr;
636 return -EINVAL;
637}
638
639/**
640 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
641 * @pValue: Pointer to input data
642 * @pTargetApBssid: Pointer to target Ap bssid
643 * @pChannel: Pointer to the Target AP channel
644 * @pDwellTime: Pointer to the time to stay off-channel
645 * after transmitting action frame
646 * @pBuf: Pointer to data
647 * @pBufLen: Pointer to data length
648 *
649 * This function parses the send action frame data passed in the format
650 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
651 *
652 * Return: 0 for success non-zero for failure
653 */
654static int
655hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
656 uint8_t *pTargetApBssid,
657 uint8_t *pChannel, uint8_t *pDwellTime,
658 uint8_t **pBuf, uint8_t *pBufLen)
659{
660 const uint8_t *inPtr = pValue;
661 const uint8_t *dataEnd;
662 int tempInt;
663 int j = 0;
664 int i = 0;
665 int v = 0;
666 uint8_t tempBuf[32];
667 uint8_t tempByte = 0;
668
669 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
670 return -EINVAL;
671
672 /* point to the next argument */
673 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
674 /* no argument after the command */
675 if (NULL == inPtr)
676 return -EINVAL;
677 /* removing empty spaces */
678 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
679 inPtr++;
680
681 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700682 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800683 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800684
685 /* getting the next argument ie the dwell time */
686 v = sscanf(inPtr, "%31s ", tempBuf);
687 if (1 != v)
688 return -EINVAL;
689
690 v = kstrtos32(tempBuf, 10, &tempInt);
691 if (v < 0 || tempInt < 0)
692 return -EINVAL;
693
694 *pDwellTime = tempInt;
695
696 /* point to the next argument */
697 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
698 /* no argument after the command */
699 if (NULL == inPtr)
700 return -EINVAL;
701 /* removing empty spaces */
702 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
703 inPtr++;
704
705 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700706 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800707 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708
709 /* find the length of data */
710 dataEnd = inPtr;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700711 while (('\0' != *dataEnd))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800712 dataEnd++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700713
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800714 *pBufLen = dataEnd - inPtr;
715 if (*pBufLen <= 0)
716 return -EINVAL;
717
718 /*
719 * Allocate the number of bytes based on the number of input characters
720 * whether it is even or odd.
721 * if the number of input characters are even, then we need N/2 byte.
722 * if the number of input characters are odd, then we need do (N+1)/2
723 * to compensate rounding off.
724 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
725 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
726 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530727 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800728 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700729 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800730 return -ENOMEM;
731 }
732
733 /* the buffer received from the upper layer is character buffer,
734 * we need to prepare the buffer taking 2 characters in to a U8 hex
735 * decimal number for example 7f0000f0...form a buffer to contain 7f
736 * in 0th location, 00 in 1st and f0 in 3rd location
737 */
738 for (i = 0, j = 0; j < *pBufLen; j += 2) {
739 if (j + 1 == *pBufLen) {
740 tempByte = hex_to_bin(inPtr[j]);
741 } else {
742 tempByte =
743 (hex_to_bin(inPtr[j]) << 4) |
744 (hex_to_bin(inPtr[j + 1]));
745 }
746 (*pBuf)[i++] = tempByte;
747 }
748 *pBufLen = i;
749 return 0;
750}
751
752/**
753 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
754 * @pValue: Pointer to input data (its a NULL terminated string)
755 * @pTargetApBssid: Pointer to target Ap bssid
756 * @pChannel: Pointer to the Target AP channel
757 *
758 * This function parses the reasoc command data passed in the format
759 * REASSOC<space><bssid><space><channel>
760 *
761 * Return: 0 for success non-zero for failure
762 */
763static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
764 uint8_t *pTargetApBssid,
765 uint8_t *pChannel)
766{
767 const uint8_t *inPtr = pValue;
768
769 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
770 return -EINVAL;
771
772 return 0;
773}
774
Naveen Rawat05376ee2016-07-18 16:43:32 -0700775#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800776void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter,
777 const tSirMacAddr bssid, int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700778{
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800779 hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
780 tCsrRoamProfile *profile = &wext_state->roamProfile;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700781
Naveen Rawat4195c5e2017-05-22 17:07:45 -0700782 sme_fast_reassoc(WLAN_HDD_GET_HAL_CTX(adapter),
783 profile, bssid, channel, adapter->sessionId);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700784}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700785#endif
786
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787/**
788 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800789 * @adapter: Adapter upon which the command was received
790 * @bssid: BSSID with which to reassociate
791 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700792 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 *
794 * This function performs a userspace-directed reassoc operation
795 *
796 * Return: 0 for success non-zero for failure
797 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700798int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800799 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800800{
801 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700802 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800803 int ret = 0;
804
Naveen Rawat05376ee2016-07-18 16:43:32 -0700805 if (hdd_ctx == NULL) {
806 hdd_err("Invalid hdd ctx");
807 return -EINVAL;
808 }
809
Krunal Sonibe766b02016-03-10 13:00:44 -0800810 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800811 hdd_warn("Unsupported in mode %s(%d)",
812 hdd_device_mode_to_string(adapter->device_mode),
813 adapter->device_mode);
814 return -EINVAL;
815 }
816
817 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
818
819 /* if not associated, no need to proceed with reassoc */
820 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800821 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800822 ret = -EINVAL;
823 goto exit;
824 }
825
826 /*
827 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800828 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800829 */
830 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530831 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800832 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800833 channel = pHddStaCtx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834 }
835
836 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530837 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800838 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800839 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840 ret = -EINVAL;
841 goto exit;
842 }
843
844 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700845 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800846 hdd_wma_send_fastreassoc_cmd(adapter,
Naveen Rawat05376ee2016-07-18 16:43:32 -0700847 bssid, (int)channel);
848 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800849 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800850
851 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700852 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530853 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
855 &handoffInfo);
856 }
857exit:
858 return ret;
859}
860
861/**
862 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
863 * @adapter: Adapter upon which the command was received
864 * @command: ASCII text command that was received
865 *
866 * This function parses the v1 REASSOC command with the format
867 *
868 * REASSOC xx:xx:xx:xx:xx:xx CH
869 *
870 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
871 * BSSID and CH is the ASCII representation of the channel. For
872 * example
873 *
874 * REASSOC 00:0a:0b:11:22:33 48
875 *
876 * Return: 0 for success non-zero for failure
877 */
878static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
879{
880 uint8_t channel = 0;
881 tSirMacAddr bssid;
882 int ret;
883
884 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700885 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700886 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700887 else
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700888 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700889
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800890 return ret;
891}
892
893/**
894 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
895 * @adapter: Adapter upon which the command was received
896 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700897 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898 *
899 * This function parses the v2 REASSOC command with the format
900 *
901 * REASSOC <android_wifi_reassoc_params>
902 *
903 * Return: 0 for success non-zero for failure
904 */
905static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
906{
907 struct android_wifi_reassoc_params params;
908 tSirMacAddr bssid;
909 int ret;
910
911 /* The params are located after "REASSOC " */
912 memcpy(&params, command + 8, sizeof(params));
913
914 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700915 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916 ret = -EINVAL;
917 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700918 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800919 }
920 return ret;
921}
922
923/**
924 * hdd_parse_reassoc() - parse the REASSOC command
925 * @adapter: Adapter upon which the command was received
926 * @command: Command that was received
927 *
928 * There are two different versions of the REASSOC command. Version 1
929 * of the command contains a parameter list that is ASCII characters
930 * whereas version 2 contains a combination of ASCII and binary
931 * payload. Determine if a version 1 or a version 2 command is being
932 * parsed by examining the parameters, and then dispatch the parser
933 * that is appropriate for the command.
934 *
935 * Return: 0 for success non-zero for failure
936 */
937static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
938{
939 int ret;
940
941 /* both versions start with "REASSOC "
942 * v1 has a bssid and channel # as an ASCII string
943 * REASSOC xx:xx:xx:xx:xx:xx CH
944 * v2 has a C struct
945 * REASSOC <binary c struct>
946 *
947 * The first field in the v2 struct is also the bssid in ASCII.
948 * But in the case of a v2 message the BSSID is NUL-terminated.
949 * Hence we can peek at that offset to see if this is V1 or V2
950 * REASSOC xx:xx:xx:xx:xx:xx*
951 * 1111111111222222
952 * 01234567890123456789012345
953 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700954 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800955 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700956 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800957 ret = hdd_parse_reassoc_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800958
959 return ret;
960}
961
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962/**
963 * hdd_sendactionframe() - send a userspace-supplied action frame
964 * @adapter: Adapter upon which the command was received
965 * @bssid: BSSID target of the action frame
966 * @channel: Channel upon which to send the frame
967 * @dwell_time: Amount of time to dwell when the frame is sent
968 * @payload_len:Length of the payload
969 * @payload: Payload of the frame
970 *
971 * This function sends a userspace-supplied action frame
972 *
973 * Return: 0 for success non-zero for failure
974 */
975static int
976hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
977 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700978 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800979{
980 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700981 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800982 uint8_t *frame;
983 struct ieee80211_hdr_3addr *hdr;
984 u64 cookie;
985 hdd_station_ctx_t *pHddStaCtx;
986 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800987 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
988 (tpSirMacVendorSpecificFrameHdr) payload;
989#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
990 struct cfg80211_mgmt_tx_params params;
991#endif
992
Krunal Sonibe766b02016-03-10 13:00:44 -0800993 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994 hdd_warn("Unsupported in mode %s(%d)",
995 hdd_device_mode_to_string(adapter->device_mode),
996 adapter->device_mode);
997 return -EINVAL;
998 }
999
1000 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1001 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1002
1003 /* if not associated, no need to send action frame */
1004 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001005 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006 ret = -EINVAL;
1007 goto exit;
1008 }
1009
1010 /*
1011 * if the target bssid is different from currently associated AP,
1012 * then no need to send action frame
1013 */
1014 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301015 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001016 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001017 ret = -EINVAL;
1018 goto exit;
1019 }
1020
1021 chan.center_freq = sme_chn_to_freq(channel);
1022 /* Check if it is specific action frame */
1023 if (pVendorSpecific->category ==
1024 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1025 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001026
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301027 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 /*
1029 * if the channel number is different from operating
1030 * channel then no need to send action frame
1031 */
1032 if (channel != 0) {
1033 if (channel !=
1034 pHddStaCtx->conn_info.operationChannel) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001035 hdd_warn("channel(%d) is different from operating channel(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001036 channel,
1037 pHddStaCtx->conn_info.
1038 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 ret = -EINVAL;
1040 goto exit;
1041 }
1042 /*
1043 * If channel number is specified and same
1044 * as home channel, ensure that action frame
1045 * is sent immediately by cancelling
1046 * roaming scans. Otherwise large dwell times
1047 * may cause long delays in sending action
1048 * frames.
1049 */
1050 sme_abort_roam_scan(hdd_ctx->hHal,
1051 adapter->sessionId);
1052 } else {
1053 /*
1054 * 0 is accepted as current home channel,
1055 * delayed transmission of action frame is ok.
1056 */
1057 chan.center_freq =
1058 sme_chn_to_freq(pHddStaCtx->conn_info.
1059 operationChannel);
1060 }
1061 }
1062 }
1063 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001064 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 ret = -EINVAL;
1066 goto exit;
1067 }
1068
1069 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301070 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001071 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001072 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073 ret = -ENOMEM;
1074 goto exit;
1075 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076
1077 hdr = (struct ieee80211_hdr_3addr *)frame;
1078 hdr->frame_control =
1079 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301080 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1081 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301082 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301083 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1084 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001085
1086#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1087 params.chan = &chan;
1088 params.offchan = 0;
1089 params.wait = dwell_time;
1090 params.buf = frame;
1091 params.len = frame_len;
1092 params.no_cck = 1;
1093 params.dont_wait_for_ack = 1;
1094 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1095#else
1096 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001097 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001099
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001100 dwell_time, frame, frame_len, 1, 1, &cookie);
1101#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1102
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301103 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001104exit:
1105 return ret;
1106}
1107
1108/**
1109 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1110 * SENDACTIONFRAME command
1111 * @adapter: Adapter upon which the command was received
1112 * @command: ASCII text command that was received
1113 *
1114 * This function parses the v1 SENDACTIONFRAME command with the format
1115 *
1116 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1117 *
1118 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1119 * BSSID, CH is the ASCII representation of the channel, DW is the
1120 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1121 * payload. For example
1122 *
1123 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1124 *
1125 * Return: 0 for success non-zero for failure
1126 */
1127static int
1128hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1129{
1130 uint8_t channel = 0;
1131 uint8_t dwell_time = 0;
1132 uint8_t payload_len = 0;
1133 uint8_t *payload = NULL;
1134 tSirMacAddr bssid;
1135 int ret;
1136
1137 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1138 &dwell_time, &payload,
1139 &payload_len);
1140 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001141 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142 } else {
1143 ret = hdd_sendactionframe(adapter, bssid, channel,
1144 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301145 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001146 }
1147
1148 return ret;
1149}
1150
1151/**
1152 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1153 * SENDACTIONFRAME command
1154 * @adapter: Adapter upon which the command was received
1155 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001156 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001157 *
1158 * This function parses the v2 SENDACTIONFRAME command with the format
1159 *
1160 * SENDACTIONFRAME <android_wifi_af_params>
1161 *
1162 * Return: 0 for success non-zero for failure
1163 */
1164static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001165hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1166 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001167{
1168 struct android_wifi_af_params *params;
1169 tSirMacAddr bssid;
1170 int ret;
1171
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001172 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001173 total_len -= 16;
1174 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001175
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001176 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1177 (params->len > total_len)) {
1178 hdd_err("Invalid payload length: %d", params->len);
1179 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001180 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001181
1182 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1183 hdd_err("MAC address parsing failed");
1184 return -EINVAL;
1185 }
1186
1187 if (params->channel < 0 ||
1188 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1189 hdd_err("Invalid channel: %d", params->channel);
1190 return -EINVAL;
1191 }
1192
1193 if (params->dwell_time < 0) {
1194 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1195 return -EINVAL;
1196 }
1197
1198 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1199 params->dwell_time, params->len, params->data);
1200
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001201 return ret;
1202}
1203
1204/**
1205 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1206 * @adapter: Adapter upon which the command was received
1207 * @command: Command that was received
1208 *
1209 * There are two different versions of the SENDACTIONFRAME command.
1210 * Version 1 of the command contains a parameter list that is ASCII
1211 * characters whereas version 2 contains a combination of ASCII and
1212 * binary payload. Determine if a version 1 or a version 2 command is
1213 * being parsed by examining the parameters, and then dispatch the
1214 * parser that is appropriate for the version of the command.
1215 *
1216 * Return: 0 for success non-zero for failure
1217 */
1218static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001219hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1220 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001221{
1222 int ret;
1223
1224 /*
1225 * both versions start with "SENDACTIONFRAME "
1226 * v1 has a bssid and other parameters as an ASCII string
1227 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1228 * v2 has a C struct
1229 * SENDACTIONFRAME <binary c struct>
1230 *
1231 * The first field in the v2 struct is also the bssid in ASCII.
1232 * But in the case of a v2 message the BSSID is NUL-terminated.
1233 * Hence we can peek at that offset to see if this is V1 or V2
1234 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1235 * 111111111122222222223333
1236 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001237 * For both the commands, a valid command must have atleast
1238 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001239 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001240 if (total_len < 34) {
1241 hdd_err("Invalid command (total_len=%d)", total_len);
1242 return -EINVAL;
1243 }
1244
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001245 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001246 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001247 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001248 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249
1250 return ret;
1251}
1252
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253/**
1254 * hdd_parse_channellist() - HDD Parse channel list
1255 * @pValue: Pointer to input channel list
1256 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001257 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001258 * @pNumChannels: Pointer to number of roam scan channels
1259 *
1260 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001261 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1262 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001263 * if the Number of channels (N) does not match with the actual number
1264 * of channels passed then take the minimum of N and count of
1265 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1266 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1267 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1268 * removing duplicate channels from the list
1269 *
1270 * Return: 0 for success non-zero for failure
1271 */
1272static int
1273hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1274 uint8_t *pNumChannels)
1275{
1276 const uint8_t *inPtr = pValue;
1277 int tempInt;
1278 int j = 0;
1279 int v = 0;
1280 char buf[32];
1281
1282 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1283 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001284 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001285 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001286 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001287 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001288
1289 /* remove empty spaces */
1290 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1291 inPtr++;
1292
1293 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001294 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001295 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001296
1297 /* get the first argument ie the number of channels */
1298 v = sscanf(inPtr, "%31s ", buf);
1299 if (1 != v)
1300 return -EINVAL;
1301
1302 v = kstrtos32(buf, 10, &tempInt);
1303 if ((v < 0) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001304 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001306
1307 *pNumChannels = tempInt;
1308
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001309 hdd_debug("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001310
1311 for (j = 0; j < (*pNumChannels); j++) {
1312 /*
1313 * inPtr pointing to the beginning of first space after number
1314 * of channels
1315 */
1316 inPtr = strpbrk(inPtr, " ");
1317 /* no channel list after the number of channels argument */
1318 if (NULL == inPtr) {
1319 if (0 != j) {
1320 *pNumChannels = j;
1321 return 0;
1322 } else {
1323 return -EINVAL;
1324 }
1325 }
1326
1327 /* remove empty space */
1328 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1329 inPtr++;
1330
1331 /*
1332 * no channel list after the number of channels
1333 * argument and spaces
1334 */
1335 if ('\0' == *inPtr) {
1336 if (0 != j) {
1337 *pNumChannels = j;
1338 return 0;
1339 } else {
1340 return -EINVAL;
1341 }
1342 }
1343
1344 v = sscanf(inPtr, "%31s ", buf);
1345 if (1 != v)
1346 return -EINVAL;
1347
1348 v = kstrtos32(buf, 10, &tempInt);
1349 if ((v < 0) ||
1350 (tempInt <= 0) ||
1351 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1352 return -EINVAL;
1353 }
1354 pChannelList[j] = tempInt;
1355
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001356 hdd_debug("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001357 pChannelList[j]);
1358 }
1359
1360 return 0;
1361}
1362
1363/**
1364 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1365 * SETROAMSCANCHANNELS command
1366 * @adapter: Adapter upon which the command was received
1367 * @command: ASCII text command that was received
1368 *
1369 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1370 *
1371 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1372 *
1373 * Where "N" is the ASCII representation of the number of channels and
1374 * C1 thru Cn is the ASCII representation of the channels. For example
1375 *
1376 * SETROAMSCANCHANNELS 4 36 40 44 48
1377 *
1378 * Return: 0 for success non-zero for failure
1379 */
1380static int
1381hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1382 const char *command)
1383{
1384 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1385 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301386 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001387 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1388 int ret;
1389
1390 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1391 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001392 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001393 goto exit;
1394 }
1395
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301396 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001397 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1398 adapter->sessionId, num_chan));
1399
1400 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001401 hdd_err("number of channels (%d) supported exceeded max (%d)",
1402 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001403 ret = -EINVAL;
1404 goto exit;
1405 }
1406
1407 status =
1408 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1409 adapter->sessionId,
1410 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301411 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001412 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001413 ret = -EINVAL;
1414 goto exit;
1415 }
1416exit:
1417 return ret;
1418}
1419
1420/**
1421 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1422 * SETROAMSCANCHANNELS command
1423 * @adapter: Adapter upon which the command was received
1424 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001425 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426 *
1427 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1428 *
1429 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1430 *
1431 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1432 * what follows the space is an array of u08 parameters. For example
1433 *
1434 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1435 *
1436 * Return: 0 for success non-zero for failure
1437 */
1438static int
1439hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1440 const char *command)
1441{
1442 const uint8_t *value;
1443 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1444 uint8_t channel;
1445 uint8_t num_chan;
1446 int i;
1447 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301448 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449 int ret = 0;
1450
1451 /* array of values begins after "SETROAMSCANCHANNELS " */
1452 value = command + 20;
1453
1454 num_chan = *value++;
1455 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001456 hdd_err("number of channels (%d) supported exceeded max (%d)",
1457 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001458 ret = -EINVAL;
1459 goto exit;
1460 }
1461
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301462 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001463 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1464 adapter->sessionId, num_chan));
1465
1466 for (i = 0; i < num_chan; i++) {
1467 channel = *value++;
1468 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001469 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001470 i, channel);
1471 ret = -EINVAL;
1472 goto exit;
1473 }
1474 channel_list[i] = channel;
1475 }
1476 status =
1477 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1478 adapter->sessionId,
1479 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301480 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001481 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001482 ret = -EINVAL;
1483 goto exit;
1484 }
1485exit:
1486 return ret;
1487}
1488
1489/**
1490 * hdd_parse_set_roam_scan_channels() - parse the
1491 * SETROAMSCANCHANNELS command
1492 * @adapter: Adapter upon which the command was received
1493 * @command: Command that was received
1494 *
1495 * There are two different versions of the SETROAMSCANCHANNELS command.
1496 * Version 1 of the command contains a parameter list that is ASCII
1497 * characters whereas version 2 contains a binary payload. Determine
1498 * if a version 1 or a version 2 command is being parsed by examining
1499 * the parameters, and then dispatch the parser that is appropriate for
1500 * the command.
1501 *
1502 * Return: 0 for success non-zero for failure
1503 */
1504static int
1505hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1506{
1507 const char *cursor;
1508 char ch;
1509 bool v1;
1510 int ret;
1511
1512 /* start after "SETROAMSCANCHANNELS " */
1513 cursor = command + 20;
1514
1515 /* assume we have a version 1 command until proven otherwise */
1516 v1 = true;
1517
1518 /* v1 params will only contain ASCII digits and space */
1519 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001520 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001521 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001522 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001523
1524 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001525 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001526 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001527 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001528
1529 return ret;
1530}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001531
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001532#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001533/**
1534 * hdd_parse_plm_cmd() - HDD Parse Plm command
1535 * @pValue: Pointer to input data
1536 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1537 *
1538 * This function parses the plm command passed in the format
1539 * CCXPLMREQ<space><enable><space><dialog_token><space>
1540 * <meas_token><space><num_of_bursts><space><burst_int><space>
1541 * <measu duration><space><burst_len><space><desired_tx_pwr>
1542 * <space><multcast_addr><space><number_of_channels>
1543 * <space><channel_numbers>
1544 *
1545 * Return: 0 for success non-zero for failure
1546 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001547static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001548{
1549 uint8_t *cmdPtr = NULL;
1550 int count, content = 0, ret = 0;
1551 char buf[32];
1552
1553 /* move to argument list */
1554 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1555 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301556 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001557
1558 /* no space after the command */
1559 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301560 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001561
1562 /* remove empty spaces */
1563 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1564 cmdPtr++;
1565
1566 /* START/STOP PLM req */
1567 ret = sscanf(cmdPtr, "%31s ", buf);
1568 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301569 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001570
1571 ret = kstrtos32(buf, 10, &content);
1572 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301573 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574
1575 pPlmRequest->enable = content;
1576 cmdPtr = strpbrk(cmdPtr, " ");
1577
1578 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301579 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580
1581 /* remove empty spaces */
1582 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1583 cmdPtr++;
1584
1585 /* Dialog token of radio meas req containing meas reqIE */
1586 ret = sscanf(cmdPtr, "%31s ", buf);
1587 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301588 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001589
1590 ret = kstrtos32(buf, 10, &content);
1591 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301592 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001593
1594 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001595 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001596 cmdPtr = strpbrk(cmdPtr, " ");
1597
1598 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301599 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001600
1601 /* remove empty spaces */
1602 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1603 cmdPtr++;
1604
1605 /* measurement token of meas req IE */
1606 ret = sscanf(cmdPtr, "%31s ", buf);
1607 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301608 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001609
1610 ret = kstrtos32(buf, 10, &content);
1611 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301612 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613
1614 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001615 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001616
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001617 hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001618 if (pPlmRequest->enable) {
1619
1620 cmdPtr = strpbrk(cmdPtr, " ");
1621
1622 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301623 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001624
1625 /* remove empty spaces */
1626 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1627 cmdPtr++;
1628
1629 /* total number of bursts after which STA stops sending */
1630 ret = sscanf(cmdPtr, "%31s ", buf);
1631 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301632 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001633
1634 ret = kstrtos32(buf, 10, &content);
1635 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301636 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001637
1638 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301639 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001640
1641 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001642 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001643 cmdPtr = strpbrk(cmdPtr, " ");
1644
1645 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301646 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647
1648 /* remove empty spaces */
1649 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1650 cmdPtr++;
1651
1652 /* burst interval in seconds */
1653 ret = sscanf(cmdPtr, "%31s ", buf);
1654 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301655 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001656
1657 ret = kstrtos32(buf, 10, &content);
1658 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301659 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001660
1661 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301662 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001663
1664 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001665 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666 cmdPtr = strpbrk(cmdPtr, " ");
1667
1668 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301669 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670
1671 /* remove empty spaces */
1672 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1673 cmdPtr++;
1674
1675 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1676 ret = sscanf(cmdPtr, "%31s ", buf);
1677 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301678 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001679
1680 ret = kstrtos32(buf, 10, &content);
1681 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301682 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001683
1684 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301685 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686
1687 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001688 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 cmdPtr = strpbrk(cmdPtr, " ");
1690
1691 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301692 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693
1694 /* remove empty spaces */
1695 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1696 cmdPtr++;
1697
1698 /* burst length of PLM bursts */
1699 ret = sscanf(cmdPtr, "%31s ", buf);
1700 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301701 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
1703 ret = kstrtos32(buf, 10, &content);
1704 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301705 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001706
1707 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301708 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709
1710 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001711 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001712 cmdPtr = strpbrk(cmdPtr, " ");
1713
1714 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301715 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716
1717 /* remove empty spaces */
1718 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1719 cmdPtr++;
1720
1721 /* desired tx power for transmission of PLM bursts */
1722 ret = sscanf(cmdPtr, "%31s ", buf);
1723 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301724 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725
1726 ret = kstrtos32(buf, 10, &content);
1727 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301728 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729
1730 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301731 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732
1733 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001734 hdd_debug("desiredTxPwr %d",
1735 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736
Anurag Chouhan6d760662016-02-20 16:05:43 +05301737 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738 cmdPtr = strpbrk(cmdPtr, " ");
1739
1740 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301741 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742
1743 /* remove empty spaces */
1744 while ((SPACE_ASCII_VALUE == *cmdPtr)
1745 && ('\0' != *cmdPtr))
1746 cmdPtr++;
1747
1748 ret = sscanf(cmdPtr, "%31s ", buf);
1749 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301750 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001751
1752 ret = kstrtos32(buf, 16, &content);
1753 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301754 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001755
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001756 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757 }
1758
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001759 hdd_debug("MC addr " MAC_ADDRESS_STR,
1760 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001761
1762 cmdPtr = strpbrk(cmdPtr, " ");
1763
1764 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301765 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766
1767 /* remove empty spaces */
1768 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1769 cmdPtr++;
1770
1771 /* number of channels */
1772 ret = sscanf(cmdPtr, "%31s ", buf);
1773 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301774 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775
1776 ret = kstrtos32(buf, 10, &content);
1777 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301778 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779
1780 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301781 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001782
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001783 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001785 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786
1787 /* Channel numbers */
1788 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1789 cmdPtr = strpbrk(cmdPtr, " ");
1790
1791 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301792 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001793
1794 /* remove empty spaces */
1795 while ((SPACE_ASCII_VALUE == *cmdPtr)
1796 && ('\0' != *cmdPtr))
1797 cmdPtr++;
1798
1799 ret = sscanf(cmdPtr, "%31s ", buf);
1800 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301801 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802
1803 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001804 if (ret < 0 || content <= 0 ||
1805 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301806 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807
1808 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001809 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001810 }
1811 }
1812 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301813 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001814}
1815#endif
1816
1817#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1818static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1819{
1820 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1821 int rc;
1822
1823 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301824 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001826 hdd_ctx->ext_wow_should_suspend = is_success;
1827 complete(&hdd_ctx->ready_to_extwow);
1828}
1829
1830static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1831 tpSirExtWoWParams arg_params)
1832{
1833 tSirExtWoWParams params;
Jeff Johnson17d62672017-03-27 08:00:11 -07001834 QDF_STATUS qdf_ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1836 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1837 int rc;
1838
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301839 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001840
1841 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1842
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301843 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844 &wlan_hdd_ready_to_extwow,
1845 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301846 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001847 hdd_err("sme_configure_ext_wow returned failure %d",
1848 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001849 return -EPERM;
1850 }
1851
1852 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1853 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1854 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001855 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001856 return -EPERM;
1857 }
1858
Jeff Johnson17d62672017-03-27 08:00:11 -07001859 if (!hdd_ctx->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001860 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001861 return -EPERM;
1862 }
1863
Jeff Johnson17d62672017-03-27 08:00:11 -07001864 if (hdd_ctx->config->extWowGotoSuspend) {
1865 hdd_info("Received ready to ExtWoW. Going to suspend");
1866
1867 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1868 if (rc < 0) {
1869 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1870 rc);
1871 return rc;
1872 }
1873 rc = wlan_hdd_bus_suspend();
1874 if (rc) {
1875 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1876 rc);
1877 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1878 return rc;
1879 }
1880 }
1881
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001882 return 0;
1883}
1884
1885static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1886 int value)
1887{
1888 tSirExtWoWParams params;
1889 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1890 int rc;
1891
1892 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301893 if (rc)
1894 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895
1896 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1897 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001898 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001899 return -EINVAL;
1900 }
1901
1902 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1903 hdd_ctx->is_extwow_app_type1_param_set)
1904 params.type = value;
1905 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1906 hdd_ctx->is_extwow_app_type2_param_set)
1907 params.type = value;
1908 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1909 hdd_ctx->is_extwow_app_type1_param_set &&
1910 hdd_ctx->is_extwow_app_type2_param_set)
1911 params.type = value;
1912 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001913 hdd_err("Set app params before enable it value %d",
1914 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915 return -EINVAL;
1916 }
1917
1918 params.vdev_id = vdev_id;
1919 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1920 (hdd_ctx->config->extWowApp2WakeupPinNumber
1921 << 8);
1922
1923 return hdd_enable_ext_wow(adapter, &params);
1924}
1925
1926static int hdd_set_app_type1_params(tHalHandle hHal,
1927 tpSirAppType1Params arg_params)
1928{
1929 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301930 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001931
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301932 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301934 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1935 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001936 hdd_err("sme_configure_app_type1_params returned failure %d",
1937 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001938 return -EPERM;
1939 }
1940
1941 return 0;
1942}
1943
1944static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
1945 char *arg, int len)
1946{
1947 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1948 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1949 char id[20], password[20];
1950 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001951 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001952
1953 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301954 if (rc)
1955 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001956
1957 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001958 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001959 return -EINVAL;
1960 }
1961
1962 memset(&params, 0, sizeof(tSirAppType1Params));
1963 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05301964 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965
1966 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301967 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001968 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301969 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001971 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001972 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001973 params.identification_id, params.id_length,
1974 params.password, params.pass_length);
1975
1976 return hdd_set_app_type1_params(hHal, &params);
1977}
1978
1979static int hdd_set_app_type2_params(tHalHandle hHal,
1980 tpSirAppType2Params arg_params)
1981{
1982 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301983 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301985 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301987 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
1988 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001989 hdd_err("sme_configure_app_type2_params returned failure %d",
1990 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 return -EPERM;
1992 }
1993
1994 return 0;
1995}
1996
1997static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
1998 char *arg, int len)
1999{
2000 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2001 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2002 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302003 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004 tSirAppType2Params params;
2005 int ret;
2006
2007 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302008 if (ret)
2009 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002010
2011 memset(&params, 0, sizeof(tSirAppType2Params));
2012
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302013 ret = sscanf(arg, "%17s %16s %x %x %x %u %u %hu %hu %u %u %u %u %u %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002014 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2015 (unsigned int *)&params.ip_device_ip,
2016 (unsigned int *)&params.ip_server_ip,
2017 (unsigned int *)&params.tcp_seq,
2018 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302019 (uint16_t *)&params.tcp_src_port,
2020 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021 (unsigned int *)&params.keepalive_init,
2022 (unsigned int *)&params.keepalive_min,
2023 (unsigned int *)&params.keepalive_max,
2024 (unsigned int *)&params.keepalive_inc,
2025 (unsigned int *)&params.tcp_tx_timeout_val,
2026 (unsigned int *)&params.tcp_rx_timeout_val);
2027
2028 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002029 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002030 return -EINVAL;
2031 }
2032
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002033 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
2034 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2035 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002036 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037 return -EINVAL;
2038 }
2039
2040 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2041 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002042 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043 return -EINVAL;
2044 }
2045
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302046 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302047 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048
2049 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302050 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051
2052 params.vdev_id = adapter->sessionId;
2053 params.tcp_src_port = (params.tcp_src_port != 0) ?
2054 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2055 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2056 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2057 params.keepalive_init = (params.keepalive_init != 0) ?
2058 params.keepalive_init : hdd_ctx->config->
2059 extWowApp2KAInitPingInterval;
2060 params.keepalive_min =
2061 (params.keepalive_min != 0) ?
2062 params.keepalive_min :
2063 hdd_ctx->config->extWowApp2KAMinPingInterval;
2064 params.keepalive_max =
2065 (params.keepalive_max != 0) ?
2066 params.keepalive_max :
2067 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2068 params.keepalive_inc =
2069 (params.keepalive_inc != 0) ?
2070 params.keepalive_inc :
2071 hdd_ctx->config->extWowApp2KAIncPingInterval;
2072 params.tcp_tx_timeout_val =
2073 (params.tcp_tx_timeout_val != 0) ?
2074 params.tcp_tx_timeout_val :
2075 hdd_ctx->config->extWowApp2TcpTxTimeout;
2076 params.tcp_rx_timeout_val =
2077 (params.tcp_rx_timeout_val != 0) ?
2078 params.tcp_rx_timeout_val :
2079 hdd_ctx->config->extWowApp2TcpRxTimeout;
2080
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002081 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002082 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2084 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2085 params.keepalive_init, params.keepalive_min,
2086 params.keepalive_max, params.keepalive_inc,
2087 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2088
2089 return hdd_set_app_type2_params(hHal, &params);
2090}
2091#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2092
2093/**
2094 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2095 * @pValue: Pointer to MAXTXPOWER command
2096 * @pDbm: Pointer to tx power
2097 *
2098 * This function parses the MAXTXPOWER command passed in the format
2099 * MAXTXPOWER<space>X(Tx power in dbm)
2100 *
2101 * For example input commands:
2102 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2103 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2104 *
2105 * Return: 0 for success non-zero for failure
2106 */
2107static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2108{
2109 uint8_t *inPtr = pValue;
2110 int tempInt;
2111 int v = 0;
2112 *pTxPower = 0;
2113
2114 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2115 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002116 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002117 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002118 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002119 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002120
2121 /* remove empty spaces */
2122 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2123 inPtr++;
2124
2125 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002126 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002127 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002128
2129 v = kstrtos32(inPtr, 10, &tempInt);
2130
2131 /* Range checking for passed parameter */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002132 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002133 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002134
2135 *pTxPower = tempInt;
2136
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002137 hdd_debug("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002138
2139 return 0;
2140} /* End of hdd_parse_setmaxtxpower_command */
2141
2142static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2143 char *extra, uint8_t n, uint8_t *len)
2144{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002146 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002147 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002148 }
2149
2150 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2151 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2152 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002153 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002154 }
2155 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002156 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2157 (int)pCfg->nActiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002158 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002159 }
2160 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2162 (int)pCfg->nPassiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002163 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002164 }
2165 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2167 (int)pCfg->nPassiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002168 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002169 }
2170 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002171 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2172 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002173 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002174 }
2175
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002176 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002177}
2178
2179static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2180{
2181 tHalHandle hHal;
2182 struct hdd_config *pCfg;
2183 uint8_t *value = command;
2184 tSmeConfigParams smeConfig;
2185 int val = 0, temp = 0;
2186
2187 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2188 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2189 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002190 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002191 return -EINVAL;
2192 }
2193
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302194 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002195 sme_get_config_param(hHal, &smeConfig);
2196
2197 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2198 value = value + 24;
2199 temp = kstrtou32(value, 10, &val);
2200 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2201 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002202 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002203 return -EFAULT;
2204 }
2205 pCfg->nActiveMaxChnTime = val;
2206 smeConfig.csrConfig.nActiveMaxChnTime = val;
2207 sme_update_config(hHal, &smeConfig);
2208 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2209 value = value + 24;
2210 temp = kstrtou32(value, 10, &val);
2211 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2212 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002213 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002214 return -EFAULT;
2215 }
2216 pCfg->nActiveMinChnTime = val;
2217 smeConfig.csrConfig.nActiveMinChnTime = val;
2218 sme_update_config(hHal, &smeConfig);
2219 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2220 value = value + 25;
2221 temp = kstrtou32(value, 10, &val);
2222 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2223 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002224 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002225 return -EFAULT;
2226 }
2227 pCfg->nPassiveMaxChnTime = val;
2228 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2229 sme_update_config(hHal, &smeConfig);
2230 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2231 value = value + 25;
2232 temp = kstrtou32(value, 10, &val);
2233 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2234 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002235 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002236 return -EFAULT;
2237 }
2238 pCfg->nPassiveMinChnTime = val;
2239 smeConfig.csrConfig.nPassiveMinChnTime = val;
2240 sme_update_config(hHal, &smeConfig);
2241 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2242 value = value + 13;
2243 temp = kstrtou32(value, 10, &val);
2244 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2245 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002246 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002247 return -EFAULT;
2248 }
2249 pCfg->nActiveMaxChnTime = val;
2250 smeConfig.csrConfig.nActiveMaxChnTime = val;
2251 sme_update_config(hHal, &smeConfig);
2252 } else {
2253 return -EINVAL;
2254 }
2255
2256 return 0;
2257}
2258
Jeff Johnson253c0c22017-01-23 16:59:38 -08002259struct link_status_priv {
2260 uint8_t link_status;
2261};
2262
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002263static void hdd_get_link_status_cb(uint8_t status, void *context)
2264{
Jeff Johnson253c0c22017-01-23 16:59:38 -08002265 struct hdd_request *request;
2266 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002267
Jeff Johnson253c0c22017-01-23 16:59:38 -08002268 request = hdd_request_get(context);
2269 if (!request) {
2270 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002271 return;
2272 }
2273
Jeff Johnson253c0c22017-01-23 16:59:38 -08002274 priv = hdd_request_priv(request);
2275 priv->link_status = status;
2276 hdd_request_complete(request);
2277 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002278}
2279
2280/**
2281 * wlan_hdd_get_link_status() - get link status
2282 * @pAdapter: pointer to the adapter
2283 *
2284 * This function sends a request to query the link status and waits
2285 * on a timer to invoke the callback. if the callback is invoked then
2286 * latest link status shall be returned or otherwise cached value
2287 * will be returned.
2288 *
2289 * Return: On success, link status shall be returned.
2290 * On error or not associated, link status 0 will be returned.
2291 */
2292static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2293{
2294
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002295 hdd_station_ctx_t *pHddStaCtx =
2296 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302297 QDF_STATUS hstatus;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002298 int ret;
2299 void *cookie;
2300 struct hdd_request *request;
2301 struct link_status_priv *priv;
2302 static const struct hdd_request_params params = {
2303 .priv_size = sizeof(*priv),
2304 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2305 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002306
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05302307 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002308 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2309 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002310 return 0;
2311 }
2312
Krunal Sonibe766b02016-03-10 13:00:44 -08002313 if ((QDF_STA_MODE != adapter->device_mode) &&
2314 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002315 hdd_warn("Unsupported in mode %s(%d)",
2316 hdd_device_mode_to_string(adapter->device_mode),
2317 adapter->device_mode);
2318 return 0;
2319 }
2320
2321 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2322 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2323 /* If not associated, then expected link status return
2324 * value is 0
2325 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002326 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002327 return 0;
2328 }
2329
Jeff Johnson253c0c22017-01-23 16:59:38 -08002330 request = hdd_request_alloc(&params);
2331 if (!request) {
2332 hdd_err("Request allocation failure");
2333 return 0;
2334 }
2335 cookie = hdd_request_cookie(request);
2336
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002337 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2338 hdd_get_link_status_cb,
Jeff Johnson253c0c22017-01-23 16:59:38 -08002339 cookie, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302340 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002341 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002342 /* return a cached value */
2343 } else {
2344 /* request is sent -- wait for the response */
Jeff Johnson253c0c22017-01-23 16:59:38 -08002345 ret = hdd_request_wait_for_response(request);
2346 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002347 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002348 /* return a cached value */
2349 } else {
2350 /* update the adapter with the fresh results */
2351 priv = hdd_request_priv(request);
2352 adapter->linkStatus = priv->link_status;
2353 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002354 }
2355
Jeff Johnson253c0c22017-01-23 16:59:38 -08002356 /*
2357 * either we never sent a request, we sent a request and
2358 * received a response or we sent a request and timed out.
2359 * regardless we are done with the request.
2360 */
2361 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002362
2363 /* either callback updated adapter stats or it has cached data */
2364 return adapter->linkStatus;
2365}
2366
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002367static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2368{
2369 int payload_len;
2370 struct sk_buff *skb;
2371 struct nlmsghdr *nlh;
2372 uint8_t *data;
2373
2374 payload_len = ETH_ALEN;
2375
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002376 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002377 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002378 return;
2379 }
2380
2381 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2382 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002383 hdd_err("nlmsg_new() failed for msg size[%d]",
2384 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002385 return;
2386 }
2387
2388 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2389
2390 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002391 hdd_err("nlmsg_put() failed for msg size[%d]",
2392 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002393
2394 kfree_skb(skb);
2395 return;
2396 }
2397
2398 data = nlmsg_data(nlh);
2399 memcpy(data, MacAddr, ETH_ALEN);
2400
2401 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002402 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2403 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002404 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002405}
2406
2407
2408/**
2409 * hdd_ParseuserParams - return a pointer to the next argument
2410 * @pValue: Input argument string
2411 * @ppArg: Output pointer to the next argument
2412 *
2413 * This function parses argument stream and finds the pointer
2414 * to the next argument
2415 *
2416 * Return: 0 if the next argument found; -EINVAL otherwise
2417 */
2418static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2419{
2420 uint8_t *pVal;
2421
2422 pVal = strnchr(pValue, strlen(pValue), ' ');
2423
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002424 if (NULL == pVal) /* no argument remains */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002425 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002426 else if (SPACE_ASCII_VALUE != *pVal)/* no space after the current arg */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002427 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002428
2429 pVal++;
2430
2431 /* remove empty spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002432 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002433 pVal++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002434
2435 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002436 if ('\0' == *pVal)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002437 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002438
2439 *ppArg = pVal;
2440
2441 return 0;
2442}
2443
2444/**
2445 * hdd_parse_ibsstx_fail_event_params - Parse params
2446 * for SETIBSSTXFAILEVENT
2447 * @pValue: Input ibss tx fail event argument
2448 * @tx_fail_count: (Output parameter) Tx fail counter
2449 * @pid: (Output parameter) PID
2450 *
2451 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2452 */
2453static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2454 uint8_t *tx_fail_count,
2455 uint16_t *pid)
2456{
2457 uint8_t *param = NULL;
2458 int ret;
2459
2460 ret = hdd_parse_user_params(pValue, &param);
2461
2462 if (0 == ret && NULL != param) {
2463 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2464 ret = -EINVAL;
2465 goto done;
2466 }
2467 } else {
2468 goto done;
2469 }
2470
2471 if (0 == *tx_fail_count) {
2472 *pid = 0;
2473 goto done;
2474 }
2475
2476 pValue = param;
2477 pValue++;
2478
2479 ret = hdd_parse_user_params(pValue, &param);
2480
2481 if (0 == ret) {
2482 if (1 != sscanf(param, "%hu", pid)) {
2483 ret = -EINVAL;
2484 goto done;
2485 }
2486 } else {
2487 goto done;
2488 }
2489
2490done:
2491 return ret;
2492}
2493
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002494#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002495/**
2496 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2497 * @pValue: Pointer to data
2498 * @pEseBcnReq: Output pointer to store parsed ie information
2499 *
2500 * This function parses the ese beacon request passed in the format
2501 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2502 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2503 * <space>Scan Mode N<space>Meas Duration N
2504 *
2505 * If the Number of bcn req fields (N) does not match with the
2506 * actual number of fields passed then take N.
2507 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2508 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2509 * This function does not take care of removing duplicate channels from the
2510 * list
2511 *
2512 * Return: 0 for success non-zero for failure
2513 */
2514static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2515 tCsrEseBeaconReq *pEseBcnReq)
2516{
2517 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002518 uint8_t input = 0;
2519 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002520 int j = 0, i = 0, v = 0;
2521 char buf[32];
2522
2523 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002524 if (NULL == inPtr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002525 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002526 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002527 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002528
2529 /* remove empty spaces */
2530 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2531 inPtr++;
2532
2533 /* no argument followed by spaces */
2534 if ('\0' == *inPtr)
2535 return -EINVAL;
2536
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002537 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002538 v = sscanf(inPtr, "%31s ", buf);
2539 if (1 != v)
2540 return -EINVAL;
2541
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002542 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002543 if (v < 0)
2544 return -EINVAL;
2545
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002546 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2547 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002548
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002549 hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002550
2551 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2552 for (i = 0; i < 4; i++) {
2553 /*
2554 * inPtr pointing to the beginning of 1st space
2555 * after number of ie fields
2556 */
2557 inPtr = strpbrk(inPtr, " ");
2558 /* no ie data after the number of ie fields argument */
2559 if (NULL == inPtr)
2560 return -EINVAL;
2561
2562 /* remove empty space */
2563 while ((SPACE_ASCII_VALUE == *inPtr)
2564 && ('\0' != *inPtr))
2565 inPtr++;
2566
2567 /*
2568 * no ie data after the number of ie fields
2569 * argument and spaces
2570 */
2571 if ('\0' == *inPtr)
2572 return -EINVAL;
2573
2574 v = sscanf(inPtr, "%31s ", buf);
2575 if (1 != v)
2576 return -EINVAL;
2577
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002578 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002579 if (v < 0)
2580 return -EINVAL;
2581
2582 switch (i) {
2583 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002584 if (!tempInt) {
2585 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002586 tempInt);
2587 return -EINVAL;
2588 }
2589 pEseBcnReq->bcnReq[j].measurementToken =
2590 tempInt;
2591 break;
2592
2593 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002594 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002595 (tempInt >
2596 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002597 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002598 tempInt);
2599 return -EINVAL;
2600 }
2601 pEseBcnReq->bcnReq[j].channel = tempInt;
2602 break;
2603
2604 case 2: /* Scan mode */
2605 if ((tempInt < eSIR_PASSIVE_SCAN)
2606 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002607 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002608 tempInt);
2609 return -EINVAL;
2610 }
2611 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2612 break;
2613
2614 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002615 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002616 && (pEseBcnReq->bcnReq[j].scanMode !=
2617 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002618 (pEseBcnReq->bcnReq[j].scanMode ==
2619 eSIR_BEACON_TABLE)) {
2620 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002621 tempInt);
2622 return -EINVAL;
2623 }
2624 pEseBcnReq->bcnReq[j].measurementDuration =
2625 tempInt;
2626 break;
2627 }
2628 }
2629 }
2630
2631 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002632 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002633 j,
2634 pEseBcnReq->bcnReq[j].measurementToken,
2635 pEseBcnReq->bcnReq[j].channel,
2636 pEseBcnReq->bcnReq[j].scanMode,
2637 pEseBcnReq->bcnReq[j].measurementDuration);
2638 }
2639
2640 return 0;
2641}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002642
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002643/**
2644 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2645 * @pValue: Pointer to input data
2646 * @pCckmIe: Pointer to output cckm Ie
2647 * @pCckmIeLen: Pointer to output cckm ie length
2648 *
2649 * This function parses the SETCCKM IE command
2650 * SETCCKMIE<space><ie data>
2651 *
2652 * Return: 0 for success non-zero for failure
2653 */
2654static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2655 uint8_t *pCckmIeLen)
2656{
2657 uint8_t *inPtr = pValue;
2658 uint8_t *dataEnd;
2659 int j = 0;
2660 int i = 0;
2661 uint8_t tempByte = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002662
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002663 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2664 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002665 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002666 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002667 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002668 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002669
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002670 /* remove empty spaces */
2671 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2672 inPtr++;
2673 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002674 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002675 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002676
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002677 /* find the length of data */
2678 dataEnd = inPtr;
2679 while (('\0' != *dataEnd)) {
2680 dataEnd++;
2681 ++(*pCckmIeLen);
2682 }
2683 if (*pCckmIeLen <= 0)
2684 return -EINVAL;
2685 /*
2686 * Allocate the number of bytes based on the number of input characters
2687 * whether it is even or odd.
2688 * if the number of input characters are even, then we need N / 2 byte.
2689 * if the number of input characters are odd, then we need do
2690 * (N + 1) / 2 to compensate rounding off.
2691 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2692 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2693 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302694 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002695 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002696 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002697 return -ENOMEM;
2698 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002699 /*
2700 * the buffer received from the upper layer is character buffer,
2701 * we need to prepare the buffer taking 2 characters in to a U8 hex
2702 * decimal number for example 7f0000f0...form a buffer to contain
2703 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2704 */
2705 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2706 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2707 (hex_to_bin(inPtr[j + 1]));
2708 (*pCckmIe)[i++] = tempByte;
2709 }
2710 *pCckmIeLen = i;
2711 return 0;
2712}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002713#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002714
2715int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2716{
2717 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302718 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002719 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2720 struct hdd_config *pConfig = NULL;
2721
2722 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002723 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002724 return -EINVAL;
2725 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002726 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2727 (QDF_SAP_MODE != pAdapter->device_mode) &&
2728 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002729 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2730 hdd_device_mode_to_string(pAdapter->device_mode),
2731 pAdapter->device_mode);
2732 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002733 return -EINVAL;
2734 }
2735 pConfig = pHddCtx->config;
2736 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2737 rateUpdate.dev_mode = pAdapter->device_mode;
2738 rateUpdate.mcastDataRate24GHz = targetRate;
2739 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2740 rateUpdate.mcastDataRate5GHz = targetRate;
2741 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302742 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002743 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002744 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2745 hdd_device_mode_to_string(pAdapter->device_mode),
2746 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002747 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302748 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002749 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002750 return -EFAULT;
2751 }
2752 return 0;
2753}
2754
2755static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2756 hdd_context_t *hdd_ctx,
2757 uint8_t *command,
2758 uint8_t command_len,
2759 hdd_priv_data_t *priv_data)
2760{
2761 int ret = 0;
2762
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302763 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002764 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2765 adapter->sessionId,
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002766 (unsigned int)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002767 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2768 + 3) << 16 | *(hdd_ctx->
2769 p2pDeviceAddress.bytes + 4) << 8 |
2770 *(hdd_ctx->p2pDeviceAddress.bytes +
2771 5))));
2772
2773 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2774 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002775 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002776 ret = -EFAULT;
2777 }
2778
2779 return ret;
2780}
2781
2782/**
2783 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2784 * @adapter: Adapter on which the command was received
2785 * @hdd_ctx: HDD global context
2786 * @command: Entire driver command received from userspace
2787 * @command_len: Length of @command
2788 * @priv_data: Pointer to ioctl private data structure
2789 *
2790 * This is a trivial command hander function which simply forwards the
2791 * command to the actual command processor within the P2P module.
2792 *
2793 * Return: 0 on success, non-zero on failure
2794 */
2795static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2796 hdd_context_t *hdd_ctx,
2797 uint8_t *command,
2798 uint8_t command_len,
2799 hdd_priv_data_t *priv_data)
2800{
2801 return hdd_set_p2p_noa(adapter->dev, command);
2802}
2803
2804/**
2805 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2806 * @adapter: Adapter on which the command was received
2807 * @hdd_ctx: HDD global context
2808 * @command: Entire driver command received from userspace
2809 * @command_len: Length of @command
2810 * @priv_data: Pointer to ioctl private data structure
2811 *
2812 * This is a trivial command hander function which simply forwards the
2813 * command to the actual command processor within the P2P module.
2814 *
2815 * Return: 0 on success, non-zero on failure
2816 */
2817static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2818 hdd_context_t *hdd_ctx,
2819 uint8_t *command,
2820 uint8_t command_len,
2821 hdd_priv_data_t *priv_data)
2822{
2823 return hdd_set_p2p_opps(adapter->dev, command);
2824}
2825
2826static int drv_cmd_set_band(hdd_adapter_t *adapter,
2827 hdd_context_t *hdd_ctx,
2828 uint8_t *command,
2829 uint8_t command_len,
2830 hdd_priv_data_t *priv_data)
2831{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002832 int err;
2833 uint8_t band;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002834
2835 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002836 * Parse the band value passed from userspace. The first 8 bytes
2837 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002838 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002839 err = kstrtou8(command + command_len + 1, 10, &band);
2840 if (err) {
2841 hdd_err("error %d parsing userspace band parameter", err);
2842 return err;
2843 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002844
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002845 return hdd_reg_set_band(adapter->dev, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002846}
2847
2848static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2849 hdd_context_t *hdd_ctx,
2850 uint8_t *command,
2851 uint8_t command_len,
2852 hdd_priv_data_t *priv_data)
2853{
2854 return hdd_wmmps_helper(adapter, command);
2855}
2856
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002857static inline int drv_cmd_country(hdd_adapter_t *adapter,
2858 hdd_context_t *hdd_ctx,
2859 uint8_t *command,
2860 uint8_t command_len,
2861 hdd_priv_data_t *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002862{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002863 return hdd_reg_set_country(hdd_ctx, command + command_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002864}
2865
2866static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
2867 hdd_context_t *hdd_ctx,
2868 uint8_t *command,
2869 uint8_t command_len,
2870 hdd_priv_data_t *priv_data)
2871{
2872 int ret = 0;
2873 uint8_t *value = command;
2874 int8_t rssi = 0;
2875 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302876 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002877
2878 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2879 value = value + command_len + 1;
2880
2881 /* Convert the value from ascii to integer */
2882 ret = kstrtos8(value, 10, &rssi);
2883 if (ret < 0) {
2884 /*
2885 * If the input value is greater than max value of datatype,
2886 * then also kstrtou8 fails
2887 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002888 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2889 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2890 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002891 ret = -EINVAL;
2892 goto exit;
2893 }
2894
2895 lookUpThreshold = abs(rssi);
2896
2897 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
2898 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002899 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002900 lookUpThreshold,
2901 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2902 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
2903 ret = -EINVAL;
2904 goto exit;
2905 }
2906
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302907 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002908 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
2909 adapter->sessionId, lookUpThreshold));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002910 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002911 lookUpThreshold);
2912
2913 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
2914 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
2915 adapter->sessionId,
2916 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302917 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002918 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002919 ret = -EPERM;
2920 goto exit;
2921 }
2922
2923exit:
2924 return ret;
2925}
2926
2927static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
2928 hdd_context_t *hdd_ctx,
2929 uint8_t *command,
2930 uint8_t command_len,
2931 hdd_priv_data_t *priv_data)
2932{
2933 int ret = 0;
2934 uint8_t lookUpThreshold =
2935 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
2936 int rssi = (-1) * lookUpThreshold;
2937 char extra[32];
2938 uint8_t len = 0;
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_GETROAMTRIGGER_IOCTL,
2942 adapter->sessionId, lookUpThreshold));
2943
2944 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05302945 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002946 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002947 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002948 ret = -EFAULT;
2949 }
2950
2951 return ret;
2952}
2953
2954static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
2955 hdd_context_t *hdd_ctx,
2956 uint8_t *command,
2957 uint8_t command_len,
2958 hdd_priv_data_t *priv_data)
2959{
2960 int ret = 0;
2961 uint8_t *value = command;
2962 uint8_t roamScanPeriod = 0;
2963 uint16_t neighborEmptyScanRefreshPeriod =
2964 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
2965
2966 /* input refresh period is in terms of seconds */
2967
2968 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
2969 value = value + command_len + 1;
2970
2971 /* Convert the value from ascii to integer */
2972 ret = kstrtou8(value, 10, &roamScanPeriod);
2973 if (ret < 0) {
2974 /*
2975 * If the input value is greater than max value of datatype,
2976 * then also kstrtou8 fails
2977 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002978 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2979 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
2980 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002981 ret = -EINVAL;
2982 goto exit;
2983 }
2984
2985 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
2986 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002987 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
2988 roamScanPeriod,
2989 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
2990 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002991 ret = -EINVAL;
2992 goto exit;
2993 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302994 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002995 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
2996 adapter->sessionId, roamScanPeriod));
2997 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
2998
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002999 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003000 roamScanPeriod);
3001
3002 hdd_ctx->config->nEmptyScanRefreshPeriod =
3003 neighborEmptyScanRefreshPeriod;
3004 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3005 adapter->sessionId,
3006 neighborEmptyScanRefreshPeriod);
3007
3008exit:
3009 return ret;
3010}
3011
3012static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3013 hdd_context_t *hdd_ctx,
3014 uint8_t *command,
3015 uint8_t command_len,
3016 hdd_priv_data_t *priv_data)
3017{
3018 int ret = 0;
3019 uint16_t nEmptyScanRefreshPeriod =
3020 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3021 char extra[32];
3022 uint8_t len = 0;
3023
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303024 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003025 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3026 adapter->sessionId,
3027 nEmptyScanRefreshPeriod));
3028 len = scnprintf(extra, sizeof(extra), "%s %d",
3029 "GETROAMSCANPERIOD",
3030 (nEmptyScanRefreshPeriod / 1000));
3031 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303032 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003033 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003034 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003035 ret = -EFAULT;
3036 }
3037
3038 return ret;
3039}
3040
3041static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3042 hdd_context_t *hdd_ctx,
3043 uint8_t *command,
3044 uint8_t command_len,
3045 hdd_priv_data_t *priv_data)
3046{
3047 int ret = 0;
3048 uint8_t *value = command;
3049 uint8_t roamScanRefreshPeriod = 0;
3050 uint16_t neighborScanRefreshPeriod =
3051 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3052
3053 /* input refresh period is in terms of seconds */
3054 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3055 value = value + command_len + 1;
3056
3057 /* Convert the value from ascii to integer */
3058 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3059 if (ret < 0) {
3060 /*
3061 * If the input value is greater than max value of datatype,
3062 * then also kstrtou8 fails
3063 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003064 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3065 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3066 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003067 ret = -EINVAL;
3068 goto exit;
3069 }
3070
3071 if ((roamScanRefreshPeriod <
3072 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3073 || (roamScanRefreshPeriod >
3074 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003075 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3076 roamScanRefreshPeriod,
3077 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3078 / 1000),
3079 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3080 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003081 ret = -EINVAL;
3082 goto exit;
3083 }
3084 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3085
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003086 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003087 roamScanRefreshPeriod);
3088
3089 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3090 neighborScanRefreshPeriod;
3091 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3092 adapter->sessionId,
3093 neighborScanRefreshPeriod);
3094
3095exit:
3096 return ret;
3097}
3098
3099static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3100 hdd_context_t *hdd_ctx,
3101 uint8_t *command,
3102 uint8_t command_len,
3103 hdd_priv_data_t *priv_data)
3104{
3105 int ret = 0;
3106 uint16_t value =
3107 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3108 char extra[32];
3109 uint8_t len = 0;
3110
3111 len = scnprintf(extra, sizeof(extra), "%s %d",
3112 "GETROAMSCANREFRESHPERIOD",
3113 (value / 1000));
3114 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303115 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003116 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003117 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003118 ret = -EFAULT;
3119 }
3120
3121 return ret;
3122}
3123
3124static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3125 hdd_context_t *hdd_ctx,
3126 uint8_t *command,
3127 uint8_t command_len,
3128 hdd_priv_data_t *priv_data)
3129{
3130 int ret = 0;
3131 uint8_t *value = command;
3132 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3133
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003134 if (!adapter->fast_roaming_allowed) {
3135 hdd_err("Roaming is always disabled on this interface");
3136 goto exit;
3137 }
3138
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003139 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3140 value = value + SIZE_OF_SETROAMMODE + 1;
3141
3142 /* Convert the value from ascii to integer */
3143 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3144 if (ret < 0) {
3145 /*
3146 * If the input value is greater than max value of datatype,
3147 * then also kstrtou8 fails
3148 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003149 hdd_err("kstrtou8 failed range [%d - %d]",
3150 CFG_LFR_FEATURE_ENABLED_MIN,
3151 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003152 ret = -EINVAL;
3153 goto exit;
3154 }
3155 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3156 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003157 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3158 roamMode,
3159 CFG_LFR_FEATURE_ENABLED_MIN,
3160 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003161 ret = -EINVAL;
3162 goto exit;
3163 }
3164
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003165 hdd_debug("Received Command to Set Roam Mode = %d",
3166 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003167 /*
3168 * Note that
3169 * SETROAMMODE 0 is to enable LFR while
3170 * SETROAMMODE 1 is to disable LFR, but
3171 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3172 * enable/disable. So, we have to invert the value
3173 * to call sme_update_is_fast_roam_ini_feature_enabled.
3174 */
3175 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3176 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3177 else
3178 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3179
3180 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3181 if (roamMode) {
3182 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3183 sme_update_roam_scan_offload_enabled(
3184 (tHalHandle)(hdd_ctx->hHal),
3185 hdd_ctx->config->isRoamOffloadScanEnabled);
3186 sme_update_is_fast_roam_ini_feature_enabled(
3187 hdd_ctx->hHal,
3188 adapter->sessionId,
3189 roamMode);
3190 } else {
3191 sme_update_is_fast_roam_ini_feature_enabled(
3192 hdd_ctx->hHal,
3193 adapter->sessionId,
3194 roamMode);
3195 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3196 sme_update_roam_scan_offload_enabled(
3197 (tHalHandle)(hdd_ctx->hHal),
3198 hdd_ctx->config->isRoamOffloadScanEnabled);
3199 }
3200
3201
3202exit:
3203 return ret;
3204}
3205
3206static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3207 hdd_context_t *hdd_ctx,
3208 uint8_t *command,
3209 uint8_t command_len,
3210 hdd_priv_data_t *priv_data)
3211{
3212 int ret = 0;
3213 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3214 char extra[32];
3215 uint8_t len = 0;
3216
3217 /*
3218 * roamMode value shall be inverted because the sementics is different.
3219 */
3220 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3221 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3222 else
3223 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3224
3225 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303226 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003227 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003228 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003229 ret = -EFAULT;
3230 }
3231
3232 return ret;
3233}
3234
3235static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3236 hdd_context_t *hdd_ctx,
3237 uint8_t *command,
3238 uint8_t command_len,
3239 hdd_priv_data_t *priv_data)
3240{
3241 int ret = 0;
3242 uint8_t *value = command;
3243 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3244
3245 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3246 value = value + command_len + 1;
3247
3248 /* Convert the value from ascii to integer */
3249 ret = kstrtou8(value, 10, &roamRssiDiff);
3250 if (ret < 0) {
3251 /*
3252 * If the input value is greater than max value of datatype,
3253 * then also kstrtou8 fails
3254 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003255 hdd_err("kstrtou8 failed range [%d - %d]",
3256 CFG_ROAM_RSSI_DIFF_MIN,
3257 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003258 ret = -EINVAL;
3259 goto exit;
3260 }
3261
3262 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3263 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003264 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3265 roamRssiDiff,
3266 CFG_ROAM_RSSI_DIFF_MIN,
3267 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003268 ret = -EINVAL;
3269 goto exit;
3270 }
3271
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003272 hdd_debug("Received Command to Set roam rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003273 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003274
3275 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3276 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3277 adapter->sessionId,
3278 roamRssiDiff);
3279
3280exit:
3281 return ret;
3282}
3283
3284static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3285 hdd_context_t *hdd_ctx,
3286 uint8_t *command,
3287 uint8_t command_len,
3288 hdd_priv_data_t *priv_data)
3289{
3290 int ret = 0;
3291 uint8_t roamRssiDiff =
3292 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3293 char extra[32];
3294 uint8_t len = 0;
3295
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303296 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003297 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3298 adapter->sessionId, roamRssiDiff));
3299
3300 len = scnprintf(extra, sizeof(extra), "%s %d",
3301 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303302 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003303
3304 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003305 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003306 ret = -EFAULT;
3307 }
3308
3309 return ret;
3310}
3311
3312static int drv_cmd_get_band(hdd_adapter_t *adapter,
3313 hdd_context_t *hdd_ctx,
3314 uint8_t *command,
3315 uint8_t command_len,
3316 hdd_priv_data_t *priv_data)
3317{
3318 int ret = 0;
3319 int band = -1;
3320 char extra[32];
3321 uint8_t len = 0;
3322
3323 hdd_get_band_helper(hdd_ctx, &band);
3324
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303325 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003326 TRACE_CODE_HDD_GETBAND_IOCTL,
3327 adapter->sessionId, band));
3328
3329 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303330 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003331
3332 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003333 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003334 ret = -EFAULT;
3335 }
3336
3337 return ret;
3338}
3339
3340static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3341 hdd_context_t *hdd_ctx,
3342 uint8_t *command,
3343 uint8_t command_len,
3344 hdd_priv_data_t *priv_data)
3345{
3346 return hdd_parse_set_roam_scan_channels(adapter, command);
3347}
3348
3349static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3350 hdd_context_t *hdd_ctx,
3351 uint8_t *command,
3352 uint8_t command_len,
3353 hdd_priv_data_t *priv_data)
3354{
3355 int ret = 0;
3356 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3357 uint8_t numChannels = 0;
3358 uint8_t j = 0;
3359 char extra[128] = { 0 };
3360 int len;
3361
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303362 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003363 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3364 ChannelList,
3365 &numChannels,
3366 adapter->sessionId)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003367 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003368 ret = -EFAULT;
3369 goto exit;
3370 }
3371
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303372 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003373 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3374 adapter->sessionId, numChannels));
3375 /*
3376 * output channel list is of the format
3377 * [Number of roam scan channels][Channel1][Channel2]...
3378 * copy the number of channels in the 0th index
3379 */
3380 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3381 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303382 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003383 len += scnprintf(extra + len, sizeof(extra) - len,
3384 " %d", ChannelList[j]);
3385
Anurag Chouhan6d760662016-02-20 16:05:43 +05303386 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003387 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003388 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003389 ret = -EFAULT;
3390 goto exit;
3391 }
3392
3393exit:
3394 return ret;
3395}
3396
3397static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3398 hdd_context_t *hdd_ctx,
3399 uint8_t *command,
3400 uint8_t command_len,
3401 hdd_priv_data_t *priv_data)
3402{
3403 int ret = 0;
3404 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3405 char extra[32];
3406 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003407 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003408
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003409 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003411 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003412 * then this operation is not permitted (return FAILURE)
3413 */
3414 if (eseMode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003415 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003416 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003417 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418 ret = -EPERM;
3419 goto exit;
3420 }
3421
3422 len = scnprintf(extra, sizeof(extra), "%s %d",
3423 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303424 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003425 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003426 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003427 ret = -EFAULT;
3428 goto exit;
3429 }
3430
3431exit:
3432 return ret;
3433}
3434
3435static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3436 hdd_context_t *hdd_ctx,
3437 uint8_t *command,
3438 uint8_t command_len,
3439 hdd_priv_data_t *priv_data)
3440{
3441 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003442 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003443 char extra[32];
3444 uint8_t len = 0;
3445
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003446 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003447 /*
3448 * Check if the features OKC/ESE/11R are supported simultaneously,
3449 * then this operation is not permitted (return FAILURE)
3450 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003451 if (pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3453 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003454 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003455 ret = -EPERM;
3456 goto exit;
3457 }
3458
3459 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003460 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303461 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003462
3463 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003464 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003465 ret = -EFAULT;
3466 goto exit;
3467 }
3468
3469exit:
3470 return ret;
3471}
3472
3473static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3474 hdd_context_t *hdd_ctx,
3475 uint8_t *command,
3476 uint8_t command_len,
3477 hdd_priv_data_t *priv_data)
3478{
3479 int ret = 0;
3480 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3481 char extra[32];
3482 uint8_t len = 0;
3483
3484 len = scnprintf(extra, sizeof(extra), "%s %d",
3485 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303486 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003487
3488 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003489 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003490 ret = -EFAULT;
3491 }
3492
3493 return ret;
3494}
3495
3496static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3497 hdd_context_t *hdd_ctx,
3498 uint8_t *command,
3499 uint8_t command_len,
3500 hdd_priv_data_t *priv_data)
3501{
3502 int ret = 0;
3503 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3504 char extra[32];
3505 uint8_t len = 0;
3506
3507 len = scnprintf(extra, sizeof(extra), "%s %d",
3508 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303509 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003510
3511 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003512 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003513 ret = -EFAULT;
3514 }
3515
3516 return ret;
3517}
3518
3519static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3520 hdd_context_t *hdd_ctx,
3521 uint8_t *command,
3522 uint8_t command_len,
3523 hdd_priv_data_t *priv_data)
3524{
3525 int ret = 0;
3526 uint8_t *value = command;
3527 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3528
3529 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3530 value = value + command_len + 1;
3531
3532 /* Convert the value from ascii to integer */
3533 ret = kstrtou8(value, 10, &minTime);
3534 if (ret < 0) {
3535 /*
3536 * If the input value is greater than max value of datatype,
3537 * then also kstrtou8 fails
3538 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003539 hdd_err("kstrtou8 failed range [%d - %d]",
3540 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3541 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003542 ret = -EINVAL;
3543 goto exit;
3544 }
3545
3546 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3547 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003548 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3549 minTime,
3550 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3551 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003552 ret = -EINVAL;
3553 goto exit;
3554 }
3555
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303556 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003557 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3558 adapter->sessionId, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003559 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003560 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003561
3562 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3563 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3564 minTime,
3565 adapter->sessionId);
3566
3567exit:
3568 return ret;
3569}
3570
3571static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3572 hdd_context_t *hdd_ctx,
3573 uint8_t *command,
3574 uint8_t command_len,
3575 hdd_priv_data_t *priv_data)
3576{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003577 return hdd_parse_sendactionframe(adapter, command,
3578 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003579}
3580
3581static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3582 hdd_context_t *hdd_ctx,
3583 uint8_t *command,
3584 uint8_t command_len,
3585 hdd_priv_data_t *priv_data)
3586{
3587 int ret = 0;
3588 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3589 adapter->sessionId);
3590 char extra[32];
3591 uint8_t len = 0;
3592
3593 /* value is interms of msec */
3594 len = scnprintf(extra, sizeof(extra), "%s %d",
3595 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303596 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003597
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303598 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003599 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3600 adapter->sessionId, val));
3601
3602 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003603 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003604 ret = -EFAULT;
3605 }
3606
3607 return ret;
3608}
3609
3610static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3611 hdd_context_t *hdd_ctx,
3612 uint8_t *command,
3613 uint8_t command_len,
3614 hdd_priv_data_t *priv_data)
3615{
3616 int ret = 0;
3617 uint8_t *value = command;
3618 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3619
3620 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3621 value = value + command_len + 1;
3622
3623 /* Convert the value from ascii to integer */
3624 ret = kstrtou16(value, 10, &maxTime);
3625 if (ret < 0) {
3626 /*
3627 * If the input value is greater than max value of datatype,
3628 * then also kstrtou8 fails
3629 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003630 hdd_err("kstrtou16 failed range [%d - %d]",
3631 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3632 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003633 ret = -EINVAL;
3634 goto exit;
3635 }
3636
3637 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3638 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003639 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3640 maxTime,
3641 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3642 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003643 ret = -EINVAL;
3644 goto exit;
3645 }
3646
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003647 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003648 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003649
3650 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3651 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3652 adapter->sessionId,
3653 maxTime);
3654
3655exit:
3656 return ret;
3657}
3658
3659static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3660 hdd_context_t *hdd_ctx,
3661 uint8_t *command,
3662 uint8_t command_len,
3663 hdd_priv_data_t *priv_data)
3664{
3665 int ret = 0;
3666 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3667 adapter->sessionId);
3668 char extra[32];
3669 uint8_t len = 0;
3670
3671 /* value is interms of msec */
3672 len = scnprintf(extra, sizeof(extra), "%s %d",
3673 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303674 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003675
3676 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003677 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003678 ret = -EFAULT;
3679 }
3680
3681 return ret;
3682}
3683
3684static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3685 hdd_context_t *hdd_ctx,
3686 uint8_t *command,
3687 uint8_t command_len,
3688 hdd_priv_data_t *priv_data)
3689{
3690 int ret = 0;
3691 uint8_t *value = command;
3692 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3693
3694 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3695 value = value + command_len + 1;
3696
3697 /* Convert the value from ascii to integer */
3698 ret = kstrtou16(value, 10, &val);
3699 if (ret < 0) {
3700 /*
3701 * If the input value is greater than max value of datatype,
3702 * then also kstrtou8 fails
3703 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003704 hdd_err("kstrtou16 failed range [%d - %d]",
3705 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3706 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707 ret = -EINVAL;
3708 goto exit;
3709 }
3710
3711 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3712 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003713 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3714 val,
3715 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3716 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003717 ret = -EINVAL;
3718 goto exit;
3719 }
3720
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003721 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003722 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003723
3724 hdd_ctx->config->nNeighborScanPeriod = val;
3725 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3726 adapter->sessionId, val);
3727
3728exit:
3729 return ret;
3730}
3731
3732static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3733 hdd_context_t *hdd_ctx,
3734 uint8_t *command,
3735 uint8_t command_len,
3736 hdd_priv_data_t *priv_data)
3737{
3738 int ret = 0;
3739 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3740 adapter->
3741 sessionId);
3742 char extra[32];
3743 uint8_t len = 0;
3744
3745 /* value is interms of msec */
3746 len = scnprintf(extra, sizeof(extra), "%s %d",
3747 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303748 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003749
3750 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003751 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003752 ret = -EFAULT;
3753 }
3754
3755 return ret;
3756}
3757
3758static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3759 hdd_context_t *hdd_ctx,
3760 uint8_t *command,
3761 uint8_t command_len,
3762 hdd_priv_data_t *priv_data)
3763{
3764 int ret = 0;
3765 uint8_t *value = command;
3766 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3767
3768 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3769 value = value + command_len + 1;
3770
3771 /* Convert the value from ascii to integer */
3772 ret = kstrtou8(value, 10, &val);
3773 if (ret < 0) {
3774 /*
3775 * If the input value is greater than max value of datatype,
3776 * then also kstrtou8 fails
3777 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003778 hdd_err("kstrtou8 failed range [%d - %d]",
3779 CFG_ROAM_INTRA_BAND_MIN,
3780 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003781 ret = -EINVAL;
3782 goto exit;
3783 }
3784
3785 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3786 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003787 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3788 val,
3789 CFG_ROAM_INTRA_BAND_MIN,
3790 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791 ret = -EINVAL;
3792 goto exit;
3793 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003794 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003795 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003796
3797 hdd_ctx->config->nRoamIntraBand = val;
3798 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3799
3800exit:
3801 return ret;
3802}
3803
3804static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3805 hdd_context_t *hdd_ctx,
3806 uint8_t *command,
3807 uint8_t command_len,
3808 hdd_priv_data_t *priv_data)
3809{
3810 int ret = 0;
3811 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3812 char extra[32];
3813 uint8_t len = 0;
3814
3815 /* value is interms of msec */
3816 len = scnprintf(extra, sizeof(extra), "%s %d",
3817 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303818 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003819 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003820 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003821 ret = -EFAULT;
3822 }
3823
3824 return ret;
3825}
3826
3827static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3828 hdd_context_t *hdd_ctx,
3829 uint8_t *command,
3830 uint8_t command_len,
3831 hdd_priv_data_t *priv_data)
3832{
3833 int ret = 0;
3834 uint8_t *value = command;
3835 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3836
3837 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3838 value = value + command_len + 1;
3839
3840 /* Convert the value from ascii to integer */
3841 ret = kstrtou8(value, 10, &nProbes);
3842 if (ret < 0) {
3843 /*
3844 * If the input value is greater than max value of datatype,
3845 * then also kstrtou8 fails
3846 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003847 hdd_err("kstrtou8 failed range [%d - %d]",
3848 CFG_ROAM_SCAN_N_PROBES_MIN,
3849 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003850 ret = -EINVAL;
3851 goto exit;
3852 }
3853
3854 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3855 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003856 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3857 nProbes,
3858 CFG_ROAM_SCAN_N_PROBES_MIN,
3859 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003860 ret = -EINVAL;
3861 goto exit;
3862 }
3863
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003864 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003865 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003866
3867 hdd_ctx->config->nProbes = nProbes;
3868 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3869 adapter->sessionId, nProbes);
3870
3871exit:
3872 return ret;
3873}
3874
3875static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3876 hdd_context_t *hdd_ctx,
3877 uint8_t *command,
3878 uint8_t command_len,
3879 hdd_priv_data_t *priv_data)
3880{
3881 int ret = 0;
3882 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3883 char extra[32];
3884 uint8_t len = 0;
3885
3886 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303887 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003888 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003889 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003890 ret = -EFAULT;
3891 }
3892
3893 return ret;
3894}
3895
3896static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
3897 hdd_context_t *hdd_ctx,
3898 uint8_t *command,
3899 uint8_t command_len,
3900 hdd_priv_data_t *priv_data)
3901{
3902 int ret = 0;
3903 uint8_t *value = command;
3904 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3905
3906 /* input value is in units of msec */
3907
3908 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3909 value = value + command_len + 1;
3910
3911 /* Convert the value from ascii to integer */
3912 ret = kstrtou16(value, 10, &homeAwayTime);
3913 if (ret < 0) {
3914 /*
3915 * If the input value is greater than max value of datatype,
3916 * then also kstrtou8 fails
3917 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003918 hdd_err("kstrtou8 failed range [%d - %d]",
3919 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3920 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003921 ret = -EINVAL;
3922 goto exit;
3923 }
3924
3925 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
3926 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003927 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003928 homeAwayTime,
3929 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3930 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
3931 ret = -EINVAL;
3932 goto exit;
3933 }
3934
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003935 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003936 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003937
3938 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
3939 homeAwayTime) {
3940 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
3941 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
3942 adapter->sessionId,
3943 homeAwayTime,
3944 true);
3945 }
3946
3947exit:
3948 return ret;
3949}
3950
3951static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
3952 hdd_context_t *hdd_ctx,
3953 uint8_t *command,
3954 uint8_t command_len,
3955 hdd_priv_data_t *priv_data)
3956{
3957 int ret = 0;
3958 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
3959 char extra[32];
3960 uint8_t len = 0;
3961
3962 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303963 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003964
3965 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003966 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967 ret = -EFAULT;
3968 }
3969
3970 return ret;
3971}
3972
3973static int drv_cmd_reassoc(hdd_adapter_t *adapter,
3974 hdd_context_t *hdd_ctx,
3975 uint8_t *command,
3976 uint8_t command_len,
3977 hdd_priv_data_t *priv_data)
3978{
3979 return hdd_parse_reassoc(adapter, command);
3980}
3981
3982static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
3983 hdd_context_t *hdd_ctx,
3984 uint8_t *command,
3985 uint8_t command_len,
3986 hdd_priv_data_t *priv_data)
3987{
3988 int ret = 0;
3989 uint8_t *value = command;
3990 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
3991
3992 /* Move pointer to ahead of SETWESMODE<delimiter> */
3993 value = value + command_len + 1;
3994
3995 /* Convert the value from ascii to integer */
3996 ret = kstrtou8(value, 10, &wesMode);
3997 if (ret < 0) {
3998 /*
3999 * If the input value is greater than max value of datatype,
4000 * then also kstrtou8 fails
4001 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004002 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004003 CFG_ENABLE_WES_MODE_NAME_MIN,
4004 CFG_ENABLE_WES_MODE_NAME_MAX);
4005 ret = -EINVAL;
4006 goto exit;
4007 }
4008
4009 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4010 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004011 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012 wesMode,
4013 CFG_ENABLE_WES_MODE_NAME_MIN,
4014 CFG_ENABLE_WES_MODE_NAME_MAX);
4015 ret = -EINVAL;
4016 goto exit;
4017 }
4018
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004019 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004020 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004021
4022 hdd_ctx->config->isWESModeEnabled = wesMode;
4023 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4024
4025exit:
4026 return ret;
4027}
4028
4029static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4030 hdd_context_t *hdd_ctx,
4031 uint8_t *command,
4032 uint8_t command_len,
4033 hdd_priv_data_t *priv_data)
4034{
4035 int ret = 0;
4036 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4037 char extra[32];
4038 uint8_t len = 0;
4039
4040 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304041 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004042 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004043 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004044 ret = -EFAULT;
4045 }
4046
4047 return ret;
4048}
4049
4050static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4051 hdd_context_t *hdd_ctx,
4052 uint8_t *command,
4053 uint8_t command_len,
4054 hdd_priv_data_t *priv_data)
4055{
4056 int ret = 0;
4057 uint8_t *value = command;
4058 uint8_t nOpportunisticThresholdDiff =
4059 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4060
4061 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4062 value = value + command_len + 1;
4063
4064 /* Convert the value from ascii to integer */
4065 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4066 if (ret < 0) {
4067 /*
4068 * If the input value is greater than max value of datatype,
4069 * then also kstrtou8 fails
4070 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004071 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004072 ret = -EINVAL;
4073 goto exit;
4074 }
4075
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004076 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004077 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004078
4079 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4080 adapter->sessionId,
4081 nOpportunisticThresholdDiff);
4082
4083exit:
4084 return ret;
4085}
4086
4087static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4088 hdd_context_t *hdd_ctx,
4089 uint8_t *command,
4090 uint8_t command_len,
4091 hdd_priv_data_t *priv_data)
4092{
4093 int ret = 0;
4094 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4095 hdd_ctx->hHal);
4096 char extra[32];
4097 uint8_t len = 0;
4098
4099 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304100 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004101 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004102 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004103 ret = -EFAULT;
4104 }
4105
4106 return ret;
4107}
4108
4109static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4110 hdd_context_t *hdd_ctx,
4111 uint8_t *command,
4112 uint8_t command_len,
4113 hdd_priv_data_t *priv_data)
4114{
4115 int ret = 0;
4116 uint8_t *value = command;
4117 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4118
4119 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4120 value = value + command_len + 1;
4121
4122 /* Convert the value from ascii to integer */
4123 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4124 if (ret < 0) {
4125 /*
4126 * If the input value is greater than max value of datatype,
4127 * then also kstrtou8 fails
4128 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004129 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004130 ret = -EINVAL;
4131 goto exit;
4132 }
4133
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004134 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004135 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004136
4137 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4138 adapter->sessionId,
4139 nRoamRescanRssiDiff);
4140
4141exit:
4142 return ret;
4143}
4144
4145static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4146 hdd_context_t *hdd_ctx,
4147 uint8_t *command,
4148 uint8_t command_len,
4149 hdd_priv_data_t *priv_data)
4150{
4151 int ret = 0;
4152 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4153 char extra[32];
4154 uint8_t len = 0;
4155
4156 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304157 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004158 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004159 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004160 ret = -EFAULT;
4161 }
4162
4163 return ret;
4164}
4165
4166static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4167 hdd_context_t *hdd_ctx,
4168 uint8_t *command,
4169 uint8_t command_len,
4170 hdd_priv_data_t *priv_data)
4171{
4172 int ret = 0;
4173 uint8_t *value = command;
4174 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4175
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004176 if (!adapter->fast_roaming_allowed) {
4177 hdd_err("Roaming is always disabled on this interface");
4178 goto exit;
4179 }
4180
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004181 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4182 value = value + command_len + 1;
4183
4184 /* Convert the value from ascii to integer */
4185 ret = kstrtou8(value, 10, &lfrMode);
4186 if (ret < 0) {
4187 /*
4188 * If the input value is greater than max value of datatype,
4189 * then also kstrtou8 fails
4190 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004191 hdd_err("kstrtou8 failed range [%d - %d]",
4192 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004193 CFG_LFR_FEATURE_ENABLED_MAX);
4194 ret = -EINVAL;
4195 goto exit;
4196 }
4197
4198 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4199 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004200 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004201 lfrMode,
4202 CFG_LFR_FEATURE_ENABLED_MIN,
4203 CFG_LFR_FEATURE_ENABLED_MAX);
4204 ret = -EINVAL;
4205 goto exit;
4206 }
4207
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004208 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004209 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004210
4211 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4212 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4213 adapter->
4214 sessionId,
4215 lfrMode);
4216
4217exit:
4218 return ret;
4219}
4220
4221static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4222 hdd_context_t *hdd_ctx,
4223 uint8_t *command,
4224 uint8_t command_len,
4225 hdd_priv_data_t *priv_data)
4226{
4227 int ret = 0;
4228 uint8_t *value = command;
4229 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4230
4231 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4232 value = value + command_len + 1;
4233
4234 /* Convert the value from ascii to integer */
4235 ret = kstrtou8(value, 10, &ft);
4236 if (ret < 0) {
4237 /*
4238 * If the input value is greater than max value of datatype,
4239 * then also kstrtou8 fails
4240 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004241 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004242 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4243 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4244 ret = -EINVAL;
4245 goto exit;
4246 }
4247
4248 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4249 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004250 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251 ft,
4252 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4253 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4254 ret = -EINVAL;
4255 goto exit;
4256 }
4257
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004258 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004259
4260 hdd_ctx->config->isFastTransitionEnabled = ft;
4261 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4262
4263exit:
4264 return ret;
4265}
4266
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004267static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4268 hdd_context_t *hdd_ctx,
4269 uint8_t *command,
4270 uint8_t command_len,
4271 hdd_priv_data_t *priv_data)
4272{
4273 int ret = 0;
4274 uint8_t *value = command;
4275 uint8_t channel = 0;
4276 tSirMacAddr targetApBssid;
4277 uint32_t roamId = 0;
4278 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004279 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 hdd_station_ctx_t *pHddStaCtx;
4281
Krunal Sonibe766b02016-03-10 13:00:44 -08004282 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004283 hdd_warn("Unsupported in mode %s(%d)",
4284 hdd_device_mode_to_string(adapter->device_mode),
4285 adapter->device_mode);
4286 return -EINVAL;
4287 }
4288
4289 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4290
4291 /* if not associated, no need to proceed with reassoc */
4292 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004293 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004294 ret = -EINVAL;
4295 goto exit;
4296 }
4297
4298 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4299 &channel);
4300 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004301 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004302 goto exit;
4303 }
4304
4305 /*
4306 * if the target bssid is same as currently associated AP,
4307 * issue reassoc to same AP
4308 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004309 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004310 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304311 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004312 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304313 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004314 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304315 targetApBssid,
4316 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304317 } else {
4318 sme_get_modify_profile_fields(hdd_ctx->hHal,
4319 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004320 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304321 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4322 NULL, modProfileFields, &roamId, 1);
4323 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004324 return 0;
4325 }
4326
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304327 /* Check channel number is a valid channel number */
Selvaraj, Sridhar64b0a9c2017-05-11 16:50:15 +05304328 if (channel && (QDF_STATUS_SUCCESS !=
4329 wlan_hdd_validate_operation_channel(adapter, channel))) {
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304330 hdd_err("Invalid Channel [%d]", channel);
4331 return -EINVAL;
4332 }
4333
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004334 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004335 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 targetApBssid, (int)channel);
4337 goto exit;
4338 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004339 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 handoffInfo.channel = channel;
4341 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004342 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004343 sizeof(tSirMacAddr));
4344 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4345 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004346exit:
4347 return ret;
4348}
4349
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004350static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4351 hdd_context_t *hdd_ctx,
4352 uint8_t *command,
4353 uint8_t command_len,
4354 hdd_priv_data_t *priv_data)
4355{
4356 int ret = 0;
4357 uint8_t *value = command;
4358 uint8_t roamScanControl = 0;
4359
4360 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4361 value = value + command_len + 1;
4362
4363 /* Convert the value from ascii to integer */
4364 ret = kstrtou8(value, 10, &roamScanControl);
4365 if (ret < 0) {
4366 /*
4367 * If the input value is greater than max value of datatype,
4368 * then also kstrtou8 fails
4369 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004370 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004371 ret = -EINVAL;
4372 goto exit;
4373 }
4374
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004375 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004376 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004377
4378 if (0 != roamScanControl) {
4379 ret = 0; /* return success but ignore param value "true" */
4380 goto exit;
4381 }
4382
4383 sme_set_roam_scan_control(hdd_ctx->hHal,
4384 adapter->sessionId,
4385 roamScanControl);
4386
4387exit:
4388 return ret;
4389}
4390
4391static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4392 hdd_context_t *hdd_ctx,
4393 uint8_t *command,
4394 uint8_t command_len,
4395 hdd_priv_data_t *priv_data)
4396{
4397 int ret = 0;
4398 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004399 uint32_t okc_mode;
4400 struct pmkid_mode_bits pmkid_modes;
4401
4402 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004403
4404 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004405 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004406 * then this operation is not permitted (return FAILURE)
4407 */
4408 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004409 pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004410 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004411 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004412 ret = -EPERM;
4413 goto exit;
4414 }
4415
4416 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4417 value = value + command_len + 1;
4418
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004419 /* get the current configured value */
4420 okc_mode = hdd_ctx->config->pmkid_modes & CFG_PMKID_MODES_OKC;
4421
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004422 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004423 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004424 if (ret < 0) {
4425 /*
4426 * If the input value is greater than max value of datatype,
4427 * then also kstrtou8 fails
4428 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004429 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430 ret = -EINVAL;
4431 goto exit;
4432 }
4433
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004434 if ((okc_mode < 0) ||
4435 (okc_mode > 1)) {
4436 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4437 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004438 ret = -EINVAL;
4439 goto exit;
4440 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004441 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004442 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004444 if (okc_mode)
4445 hdd_ctx->config->pmkid_modes |= CFG_PMKID_MODES_OKC;
4446 else
4447 hdd_ctx->config->pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004448
4449exit:
4450 return ret;
4451}
4452
4453static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4454 hdd_context_t *hdd_ctx,
4455 uint8_t *command,
4456 uint8_t command_len,
4457 hdd_priv_data_t *priv_data)
4458{
4459 int ret = 0;
4460 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4461 char extra[32];
4462 uint8_t len = 0;
4463
4464 len = scnprintf(extra, sizeof(extra), "%s %d",
4465 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304466 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004467 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004468 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004469 ret = -EFAULT;
4470 }
4471
4472 return ret;
4473}
4474
4475static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4476 hdd_context_t *hdd_ctx,
4477 uint8_t *command,
4478 uint8_t command_len,
4479 hdd_priv_data_t *priv_data)
4480{
4481 int ret = 0;
4482 char *bcMode;
4483
4484 bcMode = command + 11;
4485 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004486 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004487 hdd_ctx->btCoexModeSet = true;
4488 ret = wlan_hdd_scan_abort(adapter);
4489 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004490 hdd_err("Failed to abort existing scan status: %d",
4491 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004492 }
4493 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004494 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004495 hdd_ctx->btCoexModeSet = false;
4496 }
4497
4498 return ret;
4499}
4500
4501static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4502 hdd_context_t *hdd_ctx,
4503 uint8_t *command,
4504 uint8_t command_len,
4505 hdd_priv_data_t *priv_data)
4506{
4507 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4508 return 0;
4509}
4510
4511static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4512 hdd_context_t *hdd_ctx,
4513 uint8_t *command,
4514 uint8_t command_len,
4515 hdd_priv_data_t *priv_data)
4516{
4517 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4518 return 0;
4519}
4520
4521static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4522 hdd_context_t *hdd_ctx,
4523 uint8_t *command,
4524 uint8_t command_len,
4525 hdd_priv_data_t *priv_data)
4526{
4527 int ret = 0;
4528 struct hdd_config *pCfg =
4529 (WLAN_HDD_GET_CTX(adapter))->config;
4530 char extra[32];
4531 uint8_t len = 0;
4532
4533 memset(extra, 0, sizeof(extra));
4534 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304535 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004536 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004537 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004538 ret = -EFAULT;
4539 goto exit;
4540 }
4541 ret = len;
4542exit:
4543 return ret;
4544}
4545
4546static int drv_cmd_set_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 return hdd_set_dwell_time(adapter, command);
4553}
4554
4555static int drv_cmd_miracast(hdd_adapter_t *adapter,
4556 hdd_context_t *hdd_ctx,
4557 uint8_t *command,
4558 uint8_t command_len,
4559 hdd_priv_data_t *priv_data)
4560{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304561 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004562 int ret = 0;
4563 tHalHandle hHal;
4564 uint8_t filterType = 0;
4565 hdd_context_t *pHddCtx = NULL;
4566 uint8_t *value;
4567
4568 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304569 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004570 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004571
4572 hHal = pHddCtx->hHal;
4573 value = command + 9;
4574
4575 /* Convert the value from ascii to integer */
4576 ret = kstrtou8(value, 10, &filterType);
4577 if (ret < 0) {
4578 /*
4579 * If the input value is greater than max value of datatype,
4580 * then also kstrtou8 fails
4581 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004582 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004583 ret = -EINVAL;
4584 goto exit;
4585 }
4586 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4587 || (filterType >
4588 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004589 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004590 ret = -EINVAL;
4591 goto exit;
4592 }
4593 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4594 pHddCtx->miracast_value = filterType;
4595
4596 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304597 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004598 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004599 return -EBUSY;
4600 }
4601
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004602 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4603 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004604
4605exit:
4606 return ret;
4607}
4608
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004609/* Function header is left blank intentionally */
4610static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4611 int32_t *oui_length, int32_t limit)
4612{
4613 uint8_t len;
4614 uint8_t data;
4615
4616 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4617 command++;
4618 limit--;
4619 }
4620
4621 len = 2;
4622
4623 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4624 (limit > 1)) {
4625 sscanf(command, "%02x", (unsigned int *)&data);
4626 ie[len++] = data;
4627 command += 2;
4628 limit -= 2;
4629 }
4630
4631 *oui_length = len - 2;
4632
4633 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4634 command++;
4635 limit--;
4636 }
4637
4638 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4639 (limit > 1)) {
4640 sscanf(command, "%02x", (unsigned int *)&data);
4641 ie[len++] = data;
4642 command += 2;
4643 limit -= 2;
4644 }
4645
4646 ie[0] = IE_EID_VENDOR;
4647 ie[1] = len - 2;
4648
4649 return len;
4650}
4651
4652/**
4653 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4654 * @adapter: Pointer to adapter
4655 * @hdd_ctx: Pointer to HDD context
4656 * @command: Pointer to command string
4657 * @command_len : Command length
4658 * @priv_data : Pointer to priv data
4659 *
4660 * Return:
4661 * int status code
4662 */
4663static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4664 hdd_context_t *hdd_ctx,
4665 uint8_t *command,
4666 uint8_t command_len,
4667 hdd_priv_data_t *priv_data)
4668{
4669 int i = 0;
4670 int status;
4671 int ret = 0;
4672 uint8_t *ibss_ie;
4673 int32_t oui_length = 0;
4674 uint32_t ibss_ie_length;
4675 uint8_t *value = command;
4676 tSirModifyIE ibssModifyIE;
4677 tCsrRoamProfile *pRoamProfile;
4678 hdd_wext_state_t *pWextState;
4679
4680
Krunal Sonibe766b02016-03-10 13:00:44 -08004681 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004682 hdd_debug("Device_mode %s(%d) not IBSS",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004683 hdd_device_mode_to_string(adapter->device_mode),
4684 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004685 return ret;
4686 }
4687
4688 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4689
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004690 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004691
4692
4693 /* validate argument of command */
4694 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004695 hdd_err("No arguments in command length %zu",
4696 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004697 ret = -EFAULT;
4698 goto exit;
4699 }
4700
4701 /* moving to arguments of commands */
4702 value = value + command_len;
4703 command_len = strlen(value);
4704
4705 /* oui_data can't be less than 3 bytes */
4706 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004707 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4708 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004709 ret = -EFAULT;
4710 goto exit;
4711 }
4712
4713 ibss_ie = qdf_mem_malloc(command_len);
4714 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004715 hdd_err("Could not allocate memory for command length %d",
4716 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004717 ret = -ENOMEM;
4718 goto exit;
4719 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004720
4721 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4722 &oui_length,
4723 command_len);
4724 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004725 hdd_err("Could not parse command %s return length %d",
4726 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004727 ret = -EFAULT;
4728 qdf_mem_free(ibss_ie);
4729 goto exit;
4730 }
4731
4732 pRoamProfile = &pWextState->roamProfile;
4733
4734 qdf_copy_macaddr(&ibssModifyIE.bssid,
4735 pRoamProfile->BSSIDs.bssid);
4736
4737 ibssModifyIE.smeSessionId = adapter->sessionId;
4738 ibssModifyIE.notify = true;
4739 ibssModifyIE.ieID = IE_EID_VENDOR;
4740 ibssModifyIE.ieIDLen = ibss_ie_length;
4741 ibssModifyIE.ieBufferlength = ibss_ie_length;
4742 ibssModifyIE.pIEBuffer = ibss_ie;
4743 ibssModifyIE.oui_length = oui_length;
4744
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004745 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4746 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004747 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004748 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004749
4750 /* Probe Bcn modification */
4751 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4752 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4753
4754 /* Populating probe resp frame */
4755 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4756 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4757
4758 qdf_mem_free(ibss_ie);
4759
4760 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4761 adapter->sessionId);
4762 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004763 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004764 status);
4765 ret = -EINVAL;
4766 goto exit;
4767 }
4768
4769exit:
4770 return ret;
4771}
4772
4773static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4774 hdd_context_t *hdd_ctx,
4775 uint8_t *command,
4776 uint8_t command_len,
4777 hdd_priv_data_t *priv_data)
4778{
4779 int ret = 0;
4780 uint8_t *value = command;
4781 uint8_t ucRmcEnable = 0;
4782 int status;
4783
Krunal Sonibe766b02016-03-10 13:00:44 -08004784 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4785 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004786 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4787 hdd_device_mode_to_string(adapter->device_mode),
4788 adapter->device_mode);
4789 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004790 ret = -EINVAL;
4791 goto exit;
4792 }
4793
4794 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4795 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004796 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004797 ret = -EINVAL;
4798 goto exit;
4799 }
4800
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004801 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004802
4803 if (true == ucRmcEnable) {
4804 status = sme_enable_rmc((tHalHandle)
4805 (hdd_ctx->hHal),
4806 adapter->sessionId);
4807 } else if (false == ucRmcEnable) {
4808 status = sme_disable_rmc((tHalHandle)
4809 (hdd_ctx->hHal),
4810 adapter->sessionId);
4811 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004812 hdd_err("Invalid SETRMCENABLE command %d",
4813 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004814 ret = -EINVAL;
4815 goto exit;
4816 }
4817
4818 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004819 hdd_err("SETRMC %d failed status %d",
4820 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004821 ret = -EINVAL;
4822 goto exit;
4823 }
4824
4825exit:
4826 return ret;
4827}
4828
4829static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4830 hdd_context_t *hdd_ctx,
4831 uint8_t *command,
4832 uint8_t command_len,
4833 hdd_priv_data_t *priv_data)
4834{
4835 int ret = 0;
4836 uint8_t *value = command;
4837 uint32_t uActionPeriod = 0;
4838 int status;
4839
Krunal Sonibe766b02016-03-10 13:00:44 -08004840 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4841 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004842 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004843 hdd_device_mode_to_string(adapter->device_mode),
4844 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004845 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004846 ret = -EINVAL;
4847 goto exit;
4848 }
4849
4850 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4851 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004852 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004853 ret = -EINVAL;
4854 goto exit;
4855 }
4856
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004857 hdd_debug("uActionPeriod %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004858 uActionPeriod);
4859
4860 if (sme_cfg_set_int(hdd_ctx->hHal,
4861 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4862 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004863 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4864 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004865 ret = -EINVAL;
4866 goto exit;
4867 }
4868
4869 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4870 adapter->sessionId);
4871 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004872 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004873 status);
4874 ret = -EINVAL;
4875 goto exit;
4876 }
4877
4878exit:
4879 return ret;
4880}
4881
4882static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
4883 hdd_context_t *hdd_ctx,
4884 uint8_t *command,
4885 uint8_t command_len,
4886 hdd_priv_data_t *priv_data)
4887{
4888 int ret = 0;
4889 int status = QDF_STATUS_SUCCESS;
4890 hdd_station_ctx_t *pHddStaCtx = NULL;
4891 char *extra = NULL;
4892 int idx = 0;
4893 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004894 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004895 uint32_t numOfBytestoPrint = 0;
4896
Krunal Sonibe766b02016-03-10 13:00:44 -08004897 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004898 hdd_warn("Unsupported in mode %s(%d)",
4899 hdd_device_mode_to_string(adapter->device_mode),
4900 adapter->device_mode);
4901 return -EINVAL;
4902 }
4903
4904 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004905 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004906
4907 /* Handle the command */
4908 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
4909 if (QDF_STATUS_SUCCESS == status) {
4910 /*
4911 * The variable extra needed to be allocated on the heap since
4912 * amount of memory required to copy the data for 32 devices
4913 * exceeds the size of 1024 bytes of default stack size. On
4914 * 64 bit devices, the default max stack size of 2048 bytes
4915 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004916 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004917
4918 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004919 hdd_err("memory allocation failed");
4920 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004921 goto exit;
4922 }
4923
4924 /* Copy number of stations */
4925 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004926 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004927 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004928 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
4929 idx++) {
4930 int8_t rssi;
4931 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004932
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004933 qdf_mem_copy(mac_addr,
4934 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4935 mac_addr, sizeof(mac_addr));
4936
4937 tx_rate =
4938 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4939 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05304940 /*
4941 * Only lower 3 bytes are rate info. Mask of the MSByte
4942 */
4943 tx_rate &= 0x00FFFFFF;
4944
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004945 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4946 rssi;
4947
4948 length += scnprintf((extra + length),
4949 WLAN_MAX_BUF_SIZE - length,
4950 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
4951 mac_addr[0], mac_addr[1], mac_addr[2],
4952 mac_addr[3], mac_addr[4], mac_addr[5],
4953 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004954 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004955 * cdf_trace_msg has limitation of 512 bytes for the
4956 * print buffer. Hence printing the data in two chunks.
4957 * The first chunk will have the data for 16 devices
4958 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004959 */
4960 if (idx < NUM_OF_STA_DATA_TO_PRINT)
4961 numOfBytestoPrint = length;
4962 }
4963
4964 /*
4965 * Copy the data back into buffer, if the data to copy is
4966 * more than 512 bytes than we will split the data and do
4967 * it in two shots
4968 */
4969 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004970 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004971 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05304972 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004973 }
4974
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07004975 /* This overwrites the last space, which we already copied */
4976 extra[numOfBytestoPrint - 1] = '\0';
4977 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004978
4979 if (length > numOfBytestoPrint) {
4980 if (copy_to_user
4981 (priv_data->buf + numOfBytestoPrint,
4982 extra + numOfBytestoPrint,
4983 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004984 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004985 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05304986 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004987 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07004988 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004989 }
4990
4991 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004992 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004993 } else {
4994 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004995 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
4996 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004997 ret = -EINVAL;
4998 goto exit;
4999 }
5000 ret = 0;
5001
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305002mem_free:
5003 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005004exit:
5005 return ret;
5006}
5007
5008/* Peer Info <Peer Addr> command */
5009static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5010 hdd_context_t *hdd_ctx,
5011 uint8_t *command,
5012 uint8_t command_len,
5013 hdd_priv_data_t *priv_data)
5014{
5015 int ret = 0;
5016 uint8_t *value = command;
5017 QDF_STATUS status;
5018 hdd_station_ctx_t *pHddStaCtx = NULL;
5019 char extra[128] = { 0 };
5020 uint32_t length = 0;
5021 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005022 struct qdf_mac_addr peerMacAddr;
5023
Krunal Sonibe766b02016-03-10 13:00:44 -08005024 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005025 hdd_warn("Unsupported in mode %s(%d)",
5026 hdd_device_mode_to_string(adapter->device_mode),
5027 adapter->device_mode);
5028 return -EINVAL;
5029 }
5030
5031 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5032
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005033 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005034
5035 /* if there are no peers, no need to continue with the command */
5036 if (eConnectionState_IbssConnected !=
5037 pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005038 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005039 ret = -EINVAL;
5040 goto exit;
5041 }
5042
5043 /* Parse the incoming command buffer */
5044 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5045 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005046 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005047 ret = -EINVAL;
5048 goto exit;
5049 }
5050
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005051 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005052 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005053
Naveen Rawatc45d1622016-07-05 12:20:09 -07005054 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005055 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005056 ret = -EINVAL;
5057 goto exit;
5058 }
5059
5060 /* Handle the command */
5061 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5062 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005063 uint32_t txRate =
5064 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305065 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5066 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005067
5068 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005069 (int)txRate,
5070 (int)pHddStaCtx->ibss_peer_info.
5071 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005072
5073 /* Copy the data back into buffer */
5074 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005075 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005076 ret = -EFAULT;
5077 goto exit;
5078 }
5079 } else {
5080 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005081 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5082 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005083 ret = -EINVAL;
5084 goto exit;
5085 }
5086
5087 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005088 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005089 ret = 0;
5090
5091exit:
5092 return ret;
5093}
5094
5095static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5096 hdd_context_t *hdd_ctx,
5097 uint8_t *command,
5098 uint8_t command_len,
5099 hdd_priv_data_t *priv_data)
5100{
5101 int ret = 0;
5102 uint8_t *value = command;
5103 uint32_t uRate = 0;
5104 tTxrateinfoflags txFlags = 0;
5105 tSirRateUpdateInd rateUpdateParams = {0};
5106 int status;
5107 struct hdd_config *pConfig = hdd_ctx->config;
5108
Krunal Sonibe766b02016-03-10 13:00:44 -08005109 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5110 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005111 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5112 hdd_device_mode_to_string(adapter->device_mode),
5113 adapter->device_mode);
5114 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005115 ret = -EINVAL;
5116 goto exit;
5117 }
5118
5119 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5120 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005121 hdd_err("Invalid SETRMCTXRATE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005122 ret = -EINVAL;
5123 goto exit;
5124 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005125 hdd_debug("uRate %d", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005126 /* -1 implies ignore this param */
5127 rateUpdateParams.ucastDataRate = -1;
5128
5129 /*
5130 * Fill the user specifieed RMC rate param
5131 * and the derived tx flags.
5132 */
5133 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5134 rateUpdateParams.reliableMcastDataRate = uRate;
5135 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5136 rateUpdateParams.dev_mode = adapter->device_mode;
5137 rateUpdateParams.bcastDataRate = -1;
5138 memcpy(rateUpdateParams.bssid.bytes,
5139 adapter->macAddressCurrent.bytes,
5140 sizeof(rateUpdateParams.bssid));
5141 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5142 &rateUpdateParams);
5143
5144exit:
5145 return ret;
5146}
5147
5148static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5149 hdd_context_t *hdd_ctx,
5150 uint8_t *command,
5151 uint8_t command_len,
5152 hdd_priv_data_t *priv_data)
5153{
5154 int ret = 0;
5155 char *value;
5156 uint8_t tx_fail_count = 0;
5157 uint16_t pid = 0;
5158
5159 value = command;
5160
5161 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5162
5163 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005164 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005165 goto exit;
5166 }
5167
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005168 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005169
5170 if (0 == tx_fail_count) {
5171 /* Disable TX Fail Indication */
5172 if (QDF_STATUS_SUCCESS ==
5173 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5174 tx_fail_count,
5175 NULL)) {
5176 cesium_pid = 0;
5177 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005178 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005179 ret = -EINVAL;
5180 }
5181 } else {
5182 if (QDF_STATUS_SUCCESS ==
5183 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5184 tx_fail_count,
5185 (void *)hdd_tx_fail_ind_callback)) {
5186 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005187 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005188 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005189 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005190 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005191 ret = -EINVAL;
5192 }
5193 }
5194
5195exit:
5196 return ret;
5197}
5198
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005199#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005200static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5201 hdd_context_t *hdd_ctx,
5202 uint8_t *command,
5203 uint8_t command_len,
5204 hdd_priv_data_t *priv_data)
5205{
5206 int ret = 0;
5207 uint8_t *value = command;
5208 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5209 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305210 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005211
5212 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5213 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005214 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005215 goto exit;
5216 }
5217 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005218 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005219 numChannels,
5220 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5221 ret = -EINVAL;
5222 goto exit;
5223 }
5224 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5225 adapter->sessionId,
5226 ChannelList,
5227 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305228 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005229 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005230 ret = -EINVAL;
5231 goto exit;
5232 }
5233
5234exit:
5235 return ret;
5236}
5237
5238static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5239 hdd_context_t *hdd_ctx,
5240 uint8_t *command,
5241 uint8_t command_len,
5242 hdd_priv_data_t *priv_data)
5243{
5244 int ret = 0;
5245 uint8_t *value = command;
5246 char extra[128] = { 0 };
5247 int len = 0;
5248 uint8_t tid = 0;
5249 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005250 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005251
Krunal Sonibe766b02016-03-10 13:00:44 -08005252 if ((QDF_STA_MODE != adapter->device_mode) &&
5253 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005254 hdd_warn("Unsupported in mode %s(%d)",
5255 hdd_device_mode_to_string(adapter->device_mode),
5256 adapter->device_mode);
5257 return -EINVAL;
5258 }
5259
5260 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5261
5262 /* if not associated, return error */
5263 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005264 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005265 ret = -EINVAL;
5266 goto exit;
5267 }
5268
5269 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5270 value = value + command_len + 1;
5271
5272 /* Convert the value from ascii to integer */
5273 ret = kstrtou8(value, 10, &tid);
5274 if (ret < 0) {
5275 /*
5276 * If the input value is greater than max value of datatype,
5277 * then also kstrtou8 fails
5278 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005279 hdd_err("kstrtou8 failed range [%d - %d]",
5280 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005281 TID_MAX_VALUE);
5282 ret = -EINVAL;
5283 goto exit;
5284 }
5285 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005286 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005287 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5288 ret = -EINVAL;
5289 goto exit;
5290 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005291 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005292 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005293 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5294 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005295 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005296 goto exit;
5297 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005298 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005299 "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 -08005300 tsm_metrics.UplinkPktQueueDly,
5301 tsm_metrics.UplinkPktQueueDlyHist[0],
5302 tsm_metrics.UplinkPktQueueDlyHist[1],
5303 tsm_metrics.UplinkPktQueueDlyHist[2],
5304 tsm_metrics.UplinkPktQueueDlyHist[3],
5305 tsm_metrics.UplinkPktTxDly,
5306 tsm_metrics.UplinkPktLoss,
5307 tsm_metrics.UplinkPktCount,
5308 tsm_metrics.RoamingCount,
5309 tsm_metrics.RoamingDly);
5310 /*
5311 * Output TSM stats is of the format
5312 * GETTSMSTATS [PktQueueDly]
5313 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5314 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5315 */
5316 len = scnprintf(extra,
5317 sizeof(extra),
5318 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5319 command,
5320 tsm_metrics.UplinkPktQueueDly,
5321 tsm_metrics.UplinkPktQueueDlyHist[0],
5322 tsm_metrics.UplinkPktQueueDlyHist[1],
5323 tsm_metrics.UplinkPktQueueDlyHist[2],
5324 tsm_metrics.UplinkPktQueueDlyHist[3],
5325 tsm_metrics.UplinkPktTxDly,
5326 tsm_metrics.UplinkPktLoss,
5327 tsm_metrics.UplinkPktCount,
5328 tsm_metrics.RoamingCount,
5329 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305330 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005331 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005332 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005333 ret = -EFAULT;
5334 goto exit;
5335 }
5336
5337exit:
5338 return ret;
5339}
5340
5341static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5342 hdd_context_t *hdd_ctx,
5343 uint8_t *command,
5344 uint8_t command_len,
5345 hdd_priv_data_t *priv_data)
5346{
5347 int ret;
5348 uint8_t *value = command;
5349 uint8_t *cckmIe = NULL;
5350 uint8_t cckmIeLen = 0;
5351
5352 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5353 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005354 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005355 goto exit;
5356 }
5357
5358 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005359 hdd_err("CCKM Ie input length is more than max[%d]",
5360 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005361 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305362 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005363 cckmIe = NULL;
5364 }
5365 ret = -EINVAL;
5366 goto exit;
5367 }
5368
5369 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5370 cckmIe, cckmIeLen);
5371 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305372 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005373 cckmIe = NULL;
5374 }
5375
5376exit:
5377 return ret;
5378}
5379
5380static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5381 hdd_context_t *hdd_ctx,
5382 uint8_t *command,
5383 uint8_t command_len,
5384 hdd_priv_data_t *priv_data)
5385{
5386 int ret;
5387 uint8_t *value = command;
5388 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305389 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005390
Krunal Sonibe766b02016-03-10 13:00:44 -08005391 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005392 hdd_warn("Unsupported in mode %s(%d)",
5393 hdd_device_mode_to_string(adapter->device_mode),
5394 adapter->device_mode);
5395 return -EINVAL;
5396 }
5397
5398 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5399 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005400 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005401 goto exit;
5402 }
5403
5404 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005405 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005406 hdd_indicate_ese_bcn_report_no_results(adapter,
5407 eseBcnReq.bcnReq[0].measurementToken,
5408 0x02, /* BIT(1) set for measurement done */
5409 0); /* no BSS */
5410 goto exit;
5411 }
5412
5413 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5414 adapter->sessionId,
5415 &eseBcnReq);
5416
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305417 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005418 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005419 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005420 ret = -EBUSY;
5421 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305422 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005423 hdd_err("sme_set_ese_beacon_request failed (%d)",
5424 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005425 ret = -EINVAL;
5426 goto exit;
5427 }
5428
5429exit:
5430 return ret;
5431}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005432
5433/**
5434 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5435 * @adapter: Pointer to the HDD adapter
5436 * @hdd_ctx: Pointer to the HDD context
5437 * @command: Driver command string
5438 * @command_len: Driver command string length
5439 * @priv_data: Private data coming with the driver command. Unused here
5440 *
5441 * This function handles driver command that sets the ESE PLM request
5442 *
5443 * Return: 0 on success; negative errno otherwise
5444 */
5445static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5446 hdd_context_t *hdd_ctx,
5447 uint8_t *command,
5448 uint8_t command_len,
5449 hdd_priv_data_t *priv_data)
5450{
5451 int ret = 0;
5452 uint8_t *value = command;
5453 QDF_STATUS status = QDF_STATUS_SUCCESS;
5454 tpSirPlmReq pPlmRequest = NULL;
5455
5456 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5457 if (NULL == pPlmRequest) {
5458 ret = -ENOMEM;
5459 goto exit;
5460 }
5461
5462 status = hdd_parse_plm_cmd(value, pPlmRequest);
5463 if (QDF_STATUS_SUCCESS != status) {
5464 qdf_mem_free(pPlmRequest);
5465 pPlmRequest = NULL;
5466 ret = -EINVAL;
5467 goto exit;
5468 }
5469 pPlmRequest->sessionId = adapter->sessionId;
5470
5471 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5472 if (QDF_STATUS_SUCCESS != status) {
5473 qdf_mem_free(pPlmRequest);
5474 pPlmRequest = NULL;
5475 ret = -EINVAL;
5476 goto exit;
5477 }
5478
5479exit:
5480 return ret;
5481}
5482
5483/**
5484 * drv_cmd_set_ccx_mode() - Set ESE mode
5485 * @adapter: Pointer to the HDD adapter
5486 * @hdd_ctx: Pointer to the HDD context
5487 * @command: Driver command string
5488 * @command_len: Driver command string length
5489 * @priv_data: Private data coming with the driver command. Unused here
5490 *
5491 * This function handles driver command that sets ESE mode
5492 *
5493 * Return: 0 on success; negative errno otherwise
5494 */
5495static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5496 hdd_context_t *hdd_ctx,
5497 uint8_t *command,
5498 uint8_t command_len,
5499 hdd_priv_data_t *priv_data)
5500{
5501 int ret = 0;
5502 uint8_t *value = command;
5503 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005504 struct pmkid_mode_bits pmkid_modes;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005505
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005506 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005507 /*
5508 * Check if the features OKC/ESE/11R are supported simultaneously,
5509 * then this operation is not permitted (return FAILURE)
5510 */
5511 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005512 pmkid_modes.fw_okc &&
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005513 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5514 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5515 ret = -EPERM;
5516 goto exit;
5517 }
5518
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005519 if (!adapter->fast_roaming_allowed) {
5520 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5521 ret = -EPERM;
5522 goto exit;
5523 }
5524
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005525 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5526 value = value + command_len + 1;
5527
5528 /* Convert the value from ascii to integer */
5529 ret = kstrtou8(value, 10, &eseMode);
5530 if (ret < 0) {
5531 /*
5532 * If the input value is greater than max value of datatype,
5533 * then also kstrtou8 fails
5534 */
5535 hdd_err("kstrtou8 failed range [%d - %d]",
5536 CFG_ESE_FEATURE_ENABLED_MIN,
5537 CFG_ESE_FEATURE_ENABLED_MAX);
5538 ret = -EINVAL;
5539 goto exit;
5540 }
5541
5542 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5543 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5544 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5545 eseMode,
5546 CFG_ESE_FEATURE_ENABLED_MIN,
5547 CFG_ESE_FEATURE_ENABLED_MAX);
5548 ret = -EINVAL;
5549 goto exit;
5550 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005551 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005552
5553 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5554 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5555 adapter->sessionId,
5556 eseMode);
5557
5558exit:
5559 return ret;
5560}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005561#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005562
5563static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5564 hdd_context_t *hdd_ctx,
5565 uint8_t *command,
5566 uint8_t command_len,
5567 hdd_priv_data_t *priv_data)
5568{
5569 int ret = 0;
5570 uint8_t *value = command;
5571 int targetRate;
5572
5573 /* input value is in units of hundred kbps */
5574
5575 /* Move pointer to ahead of SETMCRATE<delimiter> */
5576 value = value + command_len + 1;
5577
5578 /* Convert the value from ascii to integer, decimal base */
5579 ret = kstrtouint(value, 10, &targetRate);
5580
5581 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5582 return ret;
5583}
5584
5585static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5586 hdd_context_t *hdd_ctx,
5587 uint8_t *command,
5588 uint8_t command_len,
5589 hdd_priv_data_t *priv_data)
5590{
5591 int ret = 0;
5592 int status;
5593 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305594 QDF_STATUS qdf_status;
5595 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005596 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305597 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5598 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005599 hdd_adapter_list_node_t *pAdapterNode = NULL;
5600 hdd_adapter_list_node_t *pNext = NULL;
5601
5602 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5603 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005604 hdd_err("Invalid MAXTXPOWER command");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005605 ret = -EINVAL;
5606 goto exit;
5607 }
5608
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305609 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005610 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305611 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005612 adapter = pAdapterNode->pAdapter;
5613 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305614 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005615 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305616 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005617 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005618
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005619 hdd_debug("Device mode %d max tx power %d selfMac: "
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005620 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005621 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005622 MAC_ADDR_ARRAY(selfMac.bytes),
5623 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005624
Srinivas Girigowda97215232015-09-24 12:26:28 -07005625 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5626 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305627 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005628 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005629 ret = -EINVAL;
5630 goto exit;
5631 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005632 hdd_debug("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305633 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005634 &pNext);
5635 pAdapterNode = pNext;
5636 }
5637
5638exit:
5639 return ret;
5640}
5641
5642static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5643 hdd_context_t *hdd_ctx,
5644 uint8_t *command,
5645 uint8_t command_len,
5646 hdd_priv_data_t *priv_data)
5647{
5648 int ret = 0;
5649 uint8_t *value = command;
5650 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5651
5652 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5653 value = value + command_len + 1;
5654
5655 /* Convert the value from ascii to integer */
5656 ret = kstrtou8(value, 10, &dfsScanMode);
5657 if (ret < 0) {
5658 /*
5659 * If the input value is greater than max value of datatype,
5660 * then also kstrtou8 fails
5661 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005662 hdd_err("kstrtou8 failed range [%d - %d]",
5663 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005664 CFG_ROAMING_DFS_CHANNEL_MAX);
5665 ret = -EINVAL;
5666 goto exit;
5667 }
5668
5669 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5670 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005671 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005672 dfsScanMode,
5673 CFG_ROAMING_DFS_CHANNEL_MIN,
5674 CFG_ROAMING_DFS_CHANNEL_MAX);
5675 ret = -EINVAL;
5676 goto exit;
5677 }
5678
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005679 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005680 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005681
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005682 /* When DFS scanning is disabled, the DFS channels need to be
5683 * removed from the operation of device.
5684 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005685 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5686 dfsScanMode != CFG_ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005687 if (ret < 0) {
5688 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005689 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005690 goto exit;
5691 }
5692
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005693 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5694 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5695 dfsScanMode);
5696
5697exit:
5698 return ret;
5699}
5700
5701static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5702 hdd_context_t *hdd_ctx,
5703 uint8_t *command,
5704 uint8_t command_len,
5705 hdd_priv_data_t *priv_data)
5706{
5707 int ret = 0;
5708 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5709 char extra[32];
5710 uint8_t len = 0;
5711
5712 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305713 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005714 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005715 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005716 ret = -EFAULT;
5717 }
5718
5719 return ret;
5720}
5721
5722static int drv_cmd_get_link_status(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 int value = wlan_hdd_get_link_status(adapter);
5730 char extra[32];
5731 uint8_t len;
5732
5733 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
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
5743#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5744static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5745 hdd_context_t *hdd_ctx,
5746 uint8_t *command,
5747 uint8_t command_len,
5748 hdd_priv_data_t *priv_data)
5749{
5750 uint8_t *value = command;
5751 int set_value;
5752
5753 /* Move pointer to ahead of ENABLEEXTWOW */
5754 value = value + command_len;
5755
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305756 if (!(sscanf(value, "%d", &set_value))) {
5757 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5758 ("No input identified"));
5759 return -EINVAL;
5760 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005761
5762 return hdd_enable_ext_wow_parser(adapter,
5763 adapter->sessionId,
5764 set_value);
5765}
5766
5767static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5768 hdd_context_t *hdd_ctx,
5769 uint8_t *command,
5770 uint8_t command_len,
5771 hdd_priv_data_t *priv_data)
5772{
5773 int ret;
5774 uint8_t *value = command;
5775
5776 /* Move pointer to ahead of SETAPP1PARAMS */
5777 value = value + command_len;
5778
5779 ret = hdd_set_app_type1_parser(adapter,
5780 value, strlen(value));
5781 if (ret >= 0)
5782 hdd_ctx->is_extwow_app_type1_param_set = true;
5783
5784 return ret;
5785}
5786
5787static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5788 hdd_context_t *hdd_ctx,
5789 uint8_t *command,
5790 uint8_t command_len,
5791 hdd_priv_data_t *priv_data)
5792{
5793 int ret;
5794 uint8_t *value = command;
5795
5796 /* Move pointer to ahead of SETAPP2PARAMS */
5797 value = value + command_len;
5798
5799 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5800 if (ret >= 0)
5801 hdd_ctx->is_extwow_app_type2_param_set = true;
5802
5803 return ret;
5804}
5805#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5806
5807#ifdef FEATURE_WLAN_TDLS
5808/**
5809 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5810 * @adapter: Pointer to the HDD adapter
5811 * @hdd_ctx: Pointer to the HDD context
5812 * @command: Driver command string
5813 * @command_len: Driver command string length
5814 * @priv_data: Private data coming with the driver command. Unused here
5815 *
5816 * This function handles driver command that sets the secondary tdls off channel
5817 * offset
5818 *
5819 * Return: 0 on success; negative errno otherwise
5820 */
5821static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5822 hdd_context_t *hdd_ctx,
5823 uint8_t *command,
5824 uint8_t command_len,
5825 hdd_priv_data_t *priv_data)
5826{
5827 int ret;
5828 uint8_t *value = command;
5829 int set_value;
5830
5831 /* Move pointer to point the string */
5832 value += command_len;
5833
5834 ret = sscanf(value, "%d", &set_value);
5835 if (ret != 1)
5836 return -EINVAL;
5837
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005838 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005839
5840 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5841
5842 return ret;
5843}
5844
5845/**
5846 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5847 * @adapter: Pointer to the HDD adapter
5848 * @hdd_ctx: Pointer to the HDD context
5849 * @command: Driver command string
5850 * @command_len: Driver command string length
5851 * @priv_data: Private data coming with the driver command. Unused here
5852 *
5853 * This function handles driver command that sets tdls off channel mode
5854 *
5855 * Return: 0 on success; negative errno otherwise
5856 */
5857static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5858 hdd_context_t *hdd_ctx,
5859 uint8_t *command,
5860 uint8_t command_len,
5861 hdd_priv_data_t *priv_data)
5862{
5863 int ret;
5864 uint8_t *value = command;
5865 int set_value;
5866
5867 /* Move pointer to point the string */
5868 value += command_len;
5869
5870 ret = sscanf(value, "%d", &set_value);
5871 if (ret != 1)
5872 return -EINVAL;
5873
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005874 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005875
5876 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5877
5878 return ret;
5879}
5880
5881/**
5882 * drv_cmd_tdls_off_channel() - set tdls off channel number
5883 * @adapter: Pointer to the HDD adapter
5884 * @hdd_ctx: Pointer to the HDD context
5885 * @command: Driver command string
5886 * @command_len: Driver command string length
5887 * @priv_data: Private data coming with the driver command. Unused here
5888 *
5889 * This function handles driver command that sets tdls off channel number
5890 *
5891 * Return: 0 on success; negative errno otherwise
5892 */
5893static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5894 hdd_context_t *hdd_ctx,
5895 uint8_t *command,
5896 uint8_t command_len,
5897 hdd_priv_data_t *priv_data)
5898{
5899 int ret;
5900 uint8_t *value = command;
5901 int set_value;
5902
5903 /* Move pointer to point the string */
5904 value += command_len;
5905
5906 ret = sscanf(value, "%d", &set_value);
5907 if (ret != 1)
5908 return -EINVAL;
5909
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -07005910 if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, set_value)) {
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005911 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5912 set_value);
5913 return -EINVAL;
5914 }
5915
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005916 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005917
5918 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5919
5920 return ret;
5921}
5922
5923/**
5924 * drv_cmd_tdls_scan() - set tdls scan type
5925 * @adapter: Pointer to the HDD adapter
5926 * @hdd_ctx: Pointer to the HDD context
5927 * @command: Driver command string
5928 * @command_len: Driver command string length
5929 * @priv_data: Private data coming with the driver command. Unused here
5930 *
5931 * This function handles driver command that sets tdls scan type
5932 *
5933 * Return: 0 on success; negative errno otherwise
5934 */
5935static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
5936 hdd_context_t *hdd_ctx,
5937 uint8_t *command,
5938 uint8_t command_len,
5939 hdd_priv_data_t *priv_data)
5940{
5941 int ret;
5942 uint8_t *value = command;
5943 int set_value;
5944
5945 /* Move pointer to point the string */
5946 value += command_len;
5947
5948 ret = sscanf(value, "%d", &set_value);
5949 if (ret != 1)
5950 return -EINVAL;
5951
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005952 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005953
5954 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
5955
5956 return ret;
5957}
5958#endif
5959
5960static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
5961 hdd_context_t *hdd_ctx,
5962 uint8_t *command,
5963 uint8_t command_len,
5964 hdd_priv_data_t *priv_data)
5965{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005966 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005967 int8_t rssi = 0;
5968 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005969
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005970 uint8_t len = 0;
5971
5972 wlan_hdd_get_rssi(adapter, &rssi);
5973
5974 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305975 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005976
5977 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005978 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005979 ret = -EFAULT;
5980 }
5981
5982 return ret;
5983}
5984
5985static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
5986 hdd_context_t *hdd_ctx,
5987 uint8_t *command,
5988 uint8_t command_len,
5989 hdd_priv_data_t *priv_data)
5990{
5991 int ret;
5992 uint32_t link_speed = 0;
5993 char extra[32];
5994 uint8_t len = 0;
5995
5996 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
5997 if (0 != ret)
5998 return ret;
5999
6000 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306001 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006002 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006003 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006004 ret = -EFAULT;
6005 }
6006
6007 return ret;
6008}
6009
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006010/**
6011 * hdd_set_rx_filter() - set RX filter
6012 * @adapter: Pointer to adapter
6013 * @action: Filter action
6014 * @pattern: Address pattern
6015 *
6016 * Address pattern is most significant byte of address for example
6017 * 0x01 for IPV4 multicast address
6018 * 0x33 for IPV6 multicast address
6019 * 0xFF for broadcast address
6020 *
6021 * Return: 0 for success, non-zero for failure
6022 */
6023static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6024 uint8_t pattern)
6025{
6026 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006027 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006028 tHalHandle handle;
6029 tSirRcvFltMcAddrList *filter;
6030 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6031
6032 ret = wlan_hdd_validate_context(hdd_ctx);
6033 if (0 != ret)
6034 return ret;
6035
6036 handle = hdd_ctx->hHal;
6037
6038 if (NULL == handle) {
6039 hdd_err("HAL Handle is NULL");
6040 return -EINVAL;
6041 }
6042
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306043 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006044 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306045 return -EINVAL;
6046 }
6047
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006048 /*
6049 * If action is false it means start dropping packets
6050 * Set addr_filter_pattern which will be used when sending
6051 * MC/BC address list to target
6052 */
6053 if (!action)
6054 adapter->addr_filter_pattern = pattern;
6055 else
6056 adapter->addr_filter_pattern = 0;
6057
Krunal Sonibe766b02016-03-10 13:00:44 -08006058 if (((adapter->device_mode == QDF_STA_MODE) ||
6059 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006060 adapter->mc_addr_list.mc_cnt &&
6061 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6062
6063
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306064 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006065 if (NULL == filter) {
6066 hdd_err("Could not allocate Memory");
6067 return -ENOMEM;
6068 }
6069 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006070 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006071 if (!memcmp(adapter->mc_addr_list.addr[i],
6072 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006073 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006074 adapter->mc_addr_list.addr[i],
6075 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006076
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006077 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006078 MAC_ADDRESS_STR,
6079 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006080 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6081 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006082 }
6083 }
Frank Liuf95e8132016-09-29 19:01:30 +08006084 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006085 /* Set rx filter */
6086 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306087 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006088 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006089 hdd_debug("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006090 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6091 }
6092
6093 return 0;
6094}
6095
6096/**
6097 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6098 * @command: Pointer to input string driver command
6099 * @adapter: Pointer to adapter
6100 * @action: Action to enable/disable filtering
6101 *
6102 * If action == false
6103 * Start filtering out data packets based on type
6104 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6105 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6106 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6107 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6108 *
6109 * if action == true
6110 * Stop filtering data packets based on type
6111 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6112 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6113 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6114 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6115 *
6116 * Current implementation only supports IPV4 address filtering by
6117 * selectively allowing IPV4 multicast data packest based on
6118 * address list received in .ndo_set_rx_mode
6119 *
6120 * Return: 0 for success, non-zero for failure
6121 */
6122static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6123 hdd_adapter_t *adapter,
6124 bool action)
6125{
6126 int ret = 0;
6127 uint8_t *value;
6128 uint8_t type;
6129
6130 value = command;
6131 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6132 if (!action)
6133 value = command + 16;
6134 else
6135 value = command + 13;
6136 ret = kstrtou8(value, 10, &type);
6137 if (ret < 0) {
6138 hdd_err("kstrtou8 failed invalid input value %d", type);
6139 return -EINVAL;
6140 }
6141
6142 switch (type) {
6143 case 2:
6144 /* Set rx filter for IPV4 multicast data packets */
6145 ret = hdd_set_rx_filter(adapter, action, 0x01);
6146 break;
6147 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006148 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006149 break;
6150 }
6151
6152 return ret;
6153}
6154
6155/**
6156 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6157 * @adapter: Pointer to network adapter
6158 * @hdd_ctx: Pointer to hdd context
6159 * @command: Pointer to input command
6160 * @command_len: Command length
6161 * @priv_data: Pointer to private data in command
6162 */
6163static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6164 hdd_context_t *hdd_ctx,
6165 uint8_t *command,
6166 uint8_t command_len,
6167 hdd_priv_data_t *priv_data)
6168{
6169 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6170}
6171
6172/**
6173 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6174 * @adapter: Pointer to network adapter
6175 * @hdd_ctx: Pointer to hdd context
6176 * @command: Pointer to input command
6177 * @command_len: Command length
6178 * @priv_data: Pointer to private data in command
6179 */
6180static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6181 hdd_context_t *hdd_ctx,
6182 uint8_t *command,
6183 uint8_t command_len,
6184 hdd_priv_data_t *priv_data)
6185{
6186 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6187}
6188
Archana Ramachandran393f3792015-11-13 17:13:21 -08006189/**
6190 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6191 * command
6192 * @value: Pointer to SETANTENNAMODE command
6193 * @mode: Pointer to antenna mode
6194 * @reason: Pointer to reason for set antenna mode
6195 *
6196 * This function parses the SETANTENNAMODE command passed in the format
6197 * SETANTENNAMODE<space>mode
6198 *
6199 * Return: 0 for success non-zero for failure
6200 */
6201static int hdd_parse_setantennamode_command(const uint8_t *value)
6202{
6203 const uint8_t *in_ptr = value;
6204 int tmp, v;
6205 char arg1[32];
6206
6207 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6208
6209 /* no argument after the command */
6210 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006211 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006212 return -EINVAL;
6213 }
6214
6215 /* no space after the command */
6216 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006217 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006218 return -EINVAL;
6219 }
6220
6221 /* remove empty spaces */
6222 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6223 in_ptr++;
6224
6225 /* no argument followed by spaces */
6226 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006227 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006228 return -EINVAL;
6229 }
6230
6231 /* get the argument i.e. antenna mode */
6232 v = sscanf(in_ptr, "%31s ", arg1);
6233 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006234 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006235 return -EINVAL;
6236 }
6237
6238 v = kstrtos32(arg1, 10, &tmp);
6239 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006240 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006241 return -EINVAL;
6242 }
6243
6244 return tmp;
6245}
6246
6247/**
6248 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6249 * mask is 2x2 mode
6250 * @hdd_ctx: Pointer to hdd contex
6251 *
6252 * Return: true if supported chain mask 2x2 else false
6253 */
6254static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6255{
6256 /*
6257 * Revisit and the update logic to determine the number
6258 * of TX/RX chains supported in the system when
6259 * antenna sharing per band chain mask support is
6260 * brought in
6261 */
6262 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6263}
6264
6265/**
6266 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6267 * chain mask is 1x1
6268 * @hdd_ctx: Pointer to hdd contex
6269 *
6270 * Return: true if supported chain mask 1x1 else false
6271 */
6272static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6273{
6274 /*
6275 * Revisit and update the logic to determine the number
6276 * of TX/RX chains supported in the system when
6277 * antenna sharing per band chain mask support is
6278 * brought in
6279 */
6280 return (!hdd_ctx->config->enable2x2) ? true : false;
6281}
6282
Nitesh Shahe50711f2017-04-26 16:30:45 +05306283QDF_STATUS hdd_update_smps_antenna_mode(hdd_context_t *hdd_ctx, int mode)
6284{
6285 QDF_STATUS status;
6286 uint8_t smps_mode;
6287 uint8_t smps_enable;
6288
6289 /* Update SME SMPS config */
6290 if (HDD_ANTENNA_MODE_1X1 == mode) {
6291 smps_enable = true;
6292 smps_mode = HDD_SMPS_MODE_STATIC;
6293 } else {
6294 smps_enable = false;
6295 smps_mode = HDD_SMPS_MODE_DISABLED;
6296 }
6297
6298 hdd_debug("Update SME SMPS enable: %d mode: %d",
6299 smps_enable, smps_mode);
6300 status = sme_update_mimo_power_save(
6301 hdd_ctx->hHal, smps_enable, smps_mode, false);
6302 if (QDF_STATUS_SUCCESS != status) {
6303 hdd_err("Update SMPS config failed enable: %d mode: %d"
6304 "status: %d",
6305 smps_enable, smps_mode, status);
6306 return QDF_STATUS_E_FAILURE;
6307 }
6308
6309 hdd_ctx->current_antenna_mode = mode;
6310 /*
6311 * Update the user requested nss in the mac context.
6312 * This will be used in tdls protocol engine to form tdls
6313 * Management frames.
6314 */
6315 sme_update_user_configured_nss(
6316 hdd_ctx->hHal,
6317 hdd_ctx->current_antenna_mode);
6318
6319 hdd_debug("Successfully switched to mode: %d x %d",
6320 hdd_ctx->current_antenna_mode,
6321 hdd_ctx->current_antenna_mode);
6322
6323 return QDF_STATUS_SUCCESS;
6324}
6325
Archana Ramachandran393f3792015-11-13 17:13:21 -08006326/**
6327 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6328 * handler
6329 * @adapter: Pointer to network adapter
6330 * @hdd_ctx: Pointer to hdd context
6331 * @command: Pointer to input command
6332 * @command_len: Command length
6333 * @priv_data: Pointer to private data in command
6334 */
6335static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6336 hdd_context_t *hdd_ctx,
6337 uint8_t *command,
6338 uint8_t command_len,
6339 hdd_priv_data_t *priv_data)
6340{
6341 struct sir_antenna_mode_param params;
6342 QDF_STATUS status;
6343 int ret = 0;
6344 int mode;
6345 uint8_t *value = command;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006346
6347 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6348 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6349 hdd_err("Operation invalid in non sta or concurrent mode");
6350 ret = -EPERM;
6351 goto exit;
6352 }
6353
6354 mode = hdd_parse_setantennamode_command(value);
6355 if (mode < 0) {
6356 hdd_err("Invalid SETANTENNA command");
6357 ret = mode;
6358 goto exit;
6359 }
6360
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006361 hdd_debug("Processing antenna mode switch to: %d", mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006362
6363 if (hdd_ctx->current_antenna_mode == mode) {
6364 hdd_err("System already in the requested mode");
6365 ret = 0;
6366 goto exit;
6367 }
6368
6369 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6370 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6371 hdd_err("System does not support 2x2 mode");
6372 ret = -EPERM;
6373 goto exit;
6374 }
6375
6376 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6377 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6378 hdd_err("System only supports 1x1 mode");
6379 ret = 0;
6380 goto exit;
6381 }
6382
6383 switch (mode) {
6384 case HDD_ANTENNA_MODE_1X1:
6385 params.num_rx_chains = 1;
6386 params.num_tx_chains = 1;
6387 break;
6388 case HDD_ANTENNA_MODE_2X2:
6389 params.num_rx_chains = 2;
6390 params.num_tx_chains = 2;
6391 break;
6392 default:
6393 hdd_err("unsupported antenna mode");
6394 ret = -EINVAL;
6395 goto exit;
6396 }
6397
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006398 /* Check TDLS status and update antenna mode */
6399 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006400 policy_mgr_is_sta_active_connection_exists(
6401 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006402 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6403 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006404 if (0 != ret)
6405 goto exit;
6406 }
6407
Archana Ramachandran393f3792015-11-13 17:13:21 -08006408 params.set_antenna_mode_resp =
6409 (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006410 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006411 params.num_rx_chains,
6412 params.num_tx_chains);
6413
6414
6415 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6416 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6417 if (QDF_STATUS_SUCCESS != status) {
6418 hdd_err("set antenna mode failed status : %d", status);
6419 ret = -EFAULT;
6420 goto exit;
6421 }
6422
6423 ret = wait_for_completion_timeout(
6424 &hdd_ctx->set_antenna_mode_cmpl,
6425 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6426 if (!ret) {
6427 ret = -EFAULT;
6428 hdd_err("send set antenna mode timed out");
6429 goto exit;
6430 }
6431
Nitesh Shahe50711f2017-04-26 16:30:45 +05306432 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006433 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006434 ret = -EFAULT;
6435 goto exit;
6436 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006437 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006438exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006439#ifdef FEATURE_WLAN_TDLS
6440 /* Reset tdls NSS flags */
6441 if (hdd_ctx->tdls_nss_switch_in_progress &&
6442 hdd_ctx->tdls_nss_teardown_complete) {
6443 hdd_ctx->tdls_nss_switch_in_progress = false;
6444 hdd_ctx->tdls_nss_teardown_complete = false;
6445 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006446 hdd_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
Kabilan Kannanff89f742016-08-15 18:14:10 -07006447 hdd_ctx->tdls_nss_switch_in_progress,
6448 hdd_ctx->tdls_nss_teardown_complete);
6449#endif
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006450 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006451 ret, hdd_ctx->current_antenna_mode);
6452 return ret;
6453
6454}
6455
6456/**
6457 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6458 * handler
6459 * @adapter: Pointer to hdd adapter
6460 * @hdd_ctx: Pointer to hdd context
6461 * @command: Pointer to input command
6462 * @command_len: length of the command
6463 * @priv_data: private data coming with the driver command
6464 *
6465 * Return: 0 for success non-zero for failure
6466 */
6467static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6468 hdd_context_t *hdd_ctx,
6469 uint8_t *command,
6470 uint8_t command_len,
6471 hdd_priv_data_t *priv_data)
6472{
6473 uint32_t antenna_mode = 0;
6474 char extra[32];
6475 uint8_t len = 0;
6476
6477 antenna_mode = hdd_ctx->current_antenna_mode;
6478 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6479 antenna_mode);
6480 len = QDF_MIN(priv_data->total_len, len + 1);
6481 if (copy_to_user(priv_data->buf, &extra, len)) {
6482 hdd_err("Failed to copy data to user buffer");
6483 return -EFAULT;
6484 }
6485
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006486 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006487
6488 return 0;
6489}
6490
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006491/*
6492 * dummy (no-op) hdd driver command handler
6493 */
6494static int drv_cmd_dummy(hdd_adapter_t *adapter,
6495 hdd_context_t *hdd_ctx,
6496 uint8_t *command,
6497 uint8_t command_len,
6498 hdd_priv_data_t *priv_data)
6499{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006500 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006501 adapter->dev->name, command);
6502 return 0;
6503}
6504
6505/*
6506 * handler for any unsupported wlan hdd driver command
6507 */
6508static int drv_cmd_invalid(hdd_adapter_t *adapter,
6509 hdd_context_t *hdd_ctx,
6510 uint8_t *command,
6511 uint8_t command_len,
6512 hdd_priv_data_t *priv_data)
6513{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306514 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006515 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6516 adapter->sessionId, 0));
6517
6518 hdd_warn("%s: Unsupported driver command \"%s\"",
6519 adapter->dev->name, command);
6520
6521 return -ENOTSUPP;
6522}
6523
6524/**
6525 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6526 * @adapter: HDD adapter
6527 * @hdd_ctx: HDD context
6528 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6529 * @command_len: command len
6530 * @priv_data: private data
6531 *
6532 * Return: status
6533 */
6534static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6535 hdd_context_t *hdd_ctx,
6536 uint8_t *command,
6537 uint8_t command_len,
6538 hdd_priv_data_t *priv_data)
6539{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306540 QDF_STATUS status;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006541 uint8_t fcc_constraint;
6542 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006543
6544 /*
6545 * this command would be called by user-space when it detects WLAN
6546 * ON after airplane mode is set. When APM is set, WLAN turns off.
6547 * But it can be turned back on. Otherwise; when APM is turned back
6548 * off, WLAN would turn back on. So at that point the command is
6549 * expected to come down. 0 means disable, 1 means enable. The
6550 * constraint is removed when parameter 1 is set or different
6551 * country code is set
6552 */
6553
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006554 err = kstrtou8(command + command_len + 1, 10, &fcc_constraint);
6555 if (err) {
6556 hdd_err("error %d parsing userspace fcc parameter", err);
6557 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006558 }
6559
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006560 status = ucfg_reg_set_fcc_constraint(hdd_ctx->hdd_pdev,
6561 fcc_constraint);
6562
6563 if (QDF_IS_STATUS_ERROR(status))
6564 hdd_err("Failed to %s tx power for channels 12/13",
6565 fcc_constraint ? "reduce" : "restore");
6566
6567 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006568}
6569
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306570/**
6571 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6572 * command
6573 * @value: Pointer to the command
6574 * @chan_number: Pointer to the channel number
6575 * @chan_bw: Pointer to the channel bandwidth
6576 *
6577 * Parses and provides the channel number and channel width from the input
6578 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6579 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6580 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6581 *
6582 * Return: 0 for success, non-zero for failure
6583 */
6584static int hdd_parse_set_channel_switch_command(uint8_t *value,
6585 uint32_t *chan_number,
6586 uint32_t *chan_bw)
6587{
6588 const uint8_t *in_ptr = value;
6589 int ret;
6590
6591 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6592
6593 /* no argument after the command */
6594 if (NULL == in_ptr) {
6595 hdd_err("No argument after the command");
6596 return -EINVAL;
6597 }
6598
6599 /* no space after the command */
6600 if (SPACE_ASCII_VALUE != *in_ptr) {
6601 hdd_err("No space after the command ");
6602 return -EINVAL;
6603 }
6604
6605 /* remove empty spaces and move the next argument */
6606 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6607 in_ptr++;
6608
6609 /* no argument followed by spaces */
6610 if ('\0' == *in_ptr) {
6611 hdd_err("No argument followed by spaces");
6612 return -EINVAL;
6613 }
6614
6615 /* get the two arguments: channel number and bandwidth */
6616 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6617 if (ret != 2) {
6618 hdd_err("Arguments retrieval from cmd string failed");
6619 return -EINVAL;
6620 }
6621
6622 return 0;
6623}
6624
6625/**
6626 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6627 * @adapter: HDD adapter
6628 * @hdd_ctx: HDD context
6629 * @command: Pointer to the input command CHANNEL_SWITCH
6630 * @command_len: Command len
6631 * @priv_data: Private data
6632 *
6633 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6634 * of SAP/P2P-GO
6635 *
6636 * Return: 0 for success, non-zero for failure
6637 */
6638static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
6639 hdd_context_t *hdd_ctx,
6640 uint8_t *command,
6641 uint8_t command_len,
6642 hdd_priv_data_t *priv_data)
6643{
6644 struct net_device *dev = adapter->dev;
6645 int status;
6646 uint32_t chan_number = 0, chan_bw = 0;
6647 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006648 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306649
Krunal Sonibe766b02016-03-10 13:00:44 -08006650 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6651 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306652 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6653 adapter->device_mode);
6654 return -EINVAL;
6655 }
6656
6657 status = hdd_parse_set_channel_switch_command(value,
6658 &chan_number, &chan_bw);
6659 if (status) {
6660 hdd_err("Invalid CHANNEL_SWITCH command");
6661 return status;
6662 }
6663
6664 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6665 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6666 return -EINVAL;
6667 }
6668
6669 if (chan_bw == 80)
6670 width = CH_WIDTH_80MHZ;
6671 else if (chan_bw == 40)
6672 width = CH_WIDTH_40MHZ;
6673 else
6674 width = CH_WIDTH_20MHZ;
6675
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006676 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306677
6678 status = hdd_softap_set_channel_change(dev, chan_number, width);
6679 if (status) {
6680 hdd_err("Set channel change fail");
6681 return status;
6682 }
6683
6684 return 0;
6685}
6686
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006687/*
6688 * The following table contains all supported WLAN HDD
6689 * IOCTL driver commands and the handler for each of them.
6690 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07006691static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006692 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
6693 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
6694 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
6695 {"SETBAND", drv_cmd_set_band},
6696 {"SETWMMPS", drv_cmd_set_wmmps},
6697 {"COUNTRY", drv_cmd_country},
6698 {"SETSUSPENDMODE", drv_cmd_dummy},
6699 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
6700 {"BTCOEXSCAN", drv_cmd_dummy},
6701 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006702 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
6703 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
6704 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
6705 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
6706 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
6707 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006708 {"SETROAMMODE", drv_cmd_set_roam_mode},
6709 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006710 {"SETROAMDELTA", drv_cmd_set_roam_delta},
6711 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006712 {"GETBAND", drv_cmd_get_band},
6713 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
6714 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
6715 {"GETCCXMODE", drv_cmd_get_ccx_mode},
6716 {"GETOKCMODE", drv_cmd_get_okc_mode},
6717 {"GETFASTROAM", drv_cmd_get_fast_roam},
6718 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
6719 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
6720 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
6721 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
6722 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
6723 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
6724 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
6725 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
6726 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
6727 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
6728 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
6729 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
6730 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
6731 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
6732 {"REASSOC", drv_cmd_reassoc},
6733 {"SETWESMODE", drv_cmd_set_wes_mode},
6734 {"GETWESMODE", drv_cmd_get_wes_mode},
6735 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
6736 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
6737 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
6738 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006739 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006740 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
6741 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006742 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006743 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006744 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
6745 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
6746 {"SCAN-ACTIVE", drv_cmd_scan_active},
6747 {"SCAN-PASSIVE", drv_cmd_scan_passive},
6748 {"GETDWELLTIME", drv_cmd_get_dwell_time},
6749 {"SETDWELLTIME", drv_cmd_set_dwell_time},
6750 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08006751 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
6752 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
6753 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
6754 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
6755 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
6756 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
6757 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006758#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006759 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
6760 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
6761 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006762 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
6763 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
6764 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006765#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006766 {"SETMCRATE", drv_cmd_set_mc_rate},
6767 {"MAXTXPOWER", drv_cmd_max_tx_power},
6768 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
6769 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
6770 {"GETLINKSTATUS", drv_cmd_get_link_status},
6771#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6772 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
6773 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
6774 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
6775#endif
6776#ifdef FEATURE_WLAN_TDLS
6777 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
6778 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
6779 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
6780 {"TDLSSCAN", drv_cmd_tdls_scan},
6781#endif
6782 {"RSSI", drv_cmd_get_rssi},
6783 {"LINKSPEED", drv_cmd_get_linkspeed},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006784 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
6785 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
6786 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306787 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08006788 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
6789 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Hanumanth Reddy Pothula0161e1d2017-02-14 17:36:13 +05306790 {"STOP", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006791};
6792
6793/**
6794 * hdd_drv_cmd_process() - chooses and runs the proper
6795 * handler based on the input command
6796 * @adapter: Pointer to the hdd adapter
6797 * @cmd: Pointer to the driver command
6798 * @priv_data: Pointer to the data associated with the command
6799 *
6800 * This function parses the input hdd driver command and runs
6801 * the proper handler
6802 *
6803 * Return: 0 for success non-zero for failure
6804 */
6805static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
6806 uint8_t *cmd,
6807 hdd_priv_data_t *priv_data)
6808{
6809 hdd_context_t *hdd_ctx;
6810 int i;
6811 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6812 uint8_t *cmd_i = NULL;
6813 hdd_drv_cmd_handler_t handler = NULL;
6814 int len = 0;
6815
6816 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006817 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006818 return -EINVAL;
6819 }
6820
6821 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
6822
6823 for (i = 0; i < cmd_num_total; i++) {
6824
6825 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6826 handler = hdd_drv_cmds[i].handler;
6827 len = strlen(cmd_i);
6828
6829 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006830 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006831 return -EINVAL;
6832 }
6833
6834 if (strncasecmp(cmd, cmd_i, len) == 0)
6835 return handler(adapter, hdd_ctx,
6836 cmd, len, priv_data);
6837 }
6838
6839 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6840}
6841
6842/**
6843 * hdd_driver_command() - top level wlan hdd driver command handler
6844 * @adapter: Pointer to the hdd adapter
6845 * @priv_data: Pointer to the raw command data
6846 *
6847 * This function is the top level wlan hdd driver command handler. It
6848 * handles the command with the help of hdd_drv_cmd_process()
6849 *
6850 * Return: 0 for success non-zero for failure
6851 */
6852static int hdd_driver_command(hdd_adapter_t *adapter,
6853 hdd_priv_data_t *priv_data)
6854{
6855 uint8_t *command = NULL;
6856 int ret = 0;
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306857 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006858
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306859 ENTER();
6860
Anurag Chouhan6d760662016-02-20 16:05:43 +05306861 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006862 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006863 return -EINVAL;
6864 }
6865
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306866 ret = wlan_hdd_validate_context(hdd_ctx);
6867 if (ret)
6868 return ret;
6869
6870 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
6871 hdd_err("Driver module is closed; command can not be processed");
6872 return -EINVAL;
6873 }
6874
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006875 /*
6876 * Note that valid pointers are provided by caller
6877 */
6878
6879 /* copy to local struct to avoid numerous changes to legacy code */
6880 if (priv_data->total_len <= 0 ||
6881 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006882 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006883 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006884 ret = -EINVAL;
6885 goto exit;
6886 }
6887
6888 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006889 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006890 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006891 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006892 ret = -ENOMEM;
6893 goto exit;
6894 }
6895
6896 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6897 ret = -EFAULT;
6898 goto exit;
6899 }
6900
6901 /* Make sure the command is NUL-terminated */
6902 command[priv_data->total_len] = '\0';
6903
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006904 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006905 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6906
6907exit:
6908 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006909 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306910 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006911 return ret;
6912}
6913
6914#ifdef CONFIG_COMPAT
6915static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6916{
6917 struct {
6918 compat_uptr_t buf;
6919 int used_len;
6920 int total_len;
6921 } compat_priv_data;
6922 hdd_priv_data_t priv_data;
6923 int ret = 0;
6924
6925 /*
6926 * Note that adapter and ifr have already been verified by caller,
6927 * and HDD context has also been validated
6928 */
6929 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
6930 sizeof(compat_priv_data))) {
6931 ret = -EFAULT;
6932 goto exit;
6933 }
6934 priv_data.buf = compat_ptr(compat_priv_data.buf);
6935 priv_data.used_len = compat_priv_data.used_len;
6936 priv_data.total_len = compat_priv_data.total_len;
6937 ret = hdd_driver_command(adapter, &priv_data);
6938exit:
6939 return ret;
6940}
6941#else /* CONFIG_COMPAT */
6942static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6943{
6944 /* will never be invoked */
6945 return 0;
6946}
6947#endif /* CONFIG_COMPAT */
6948
6949static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6950{
6951 hdd_priv_data_t priv_data;
6952 int ret = 0;
6953
6954 /*
6955 * Note that adapter and ifr have already been verified by caller,
6956 * and HDD context has also been validated
6957 */
6958 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
6959 ret = -EFAULT;
6960 else
6961 ret = hdd_driver_command(adapter, &priv_data);
6962
6963 return ret;
6964}
6965
6966/**
6967 * __hdd_ioctl() - ioctl handler for wlan network interfaces
6968 * @dev: device upon which the ioctl was received
6969 * @ifr: ioctl request information
6970 * @cmd: ioctl command
6971 *
6972 * This function does initial processing of wlan device ioctls.
6973 * Currently two flavors of ioctls are supported. The primary ioctl
6974 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
6975 * for Android "DRIVER" commands. The other ioctl that is
6976 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
6977 * for FTM on some platforms. This function simply verifies that the
6978 * driver is in a sane state, and that the ioctl is one of the
6979 * supported flavors, in which case flavor-specific handlers are
6980 * dispatched.
6981 *
6982 * Return: 0 on success, non-zero on error
6983 */
6984static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
6985{
6986 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
6987 hdd_context_t *hdd_ctx;
6988 int ret;
6989
Jeff Johnson3c3994a2016-02-11 08:12:30 -08006990 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306991
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006992 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006993 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006994 ret = -ENODEV;
6995 goto exit;
6996 }
6997
6998 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006999 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007000 ret = -EINVAL;
7001 goto exit;
7002 }
7003#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307004 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007005 if (SIOCIOCTLTX99 == cmd) {
7006 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7007 goto exit;
7008 }
7009 }
7010#endif
7011
7012 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7013 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307014 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007015 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007016
7017 switch (cmd) {
7018 case (SIOCDEVPRIVATE + 1):
7019 if (is_compat_task())
7020 ret = hdd_driver_compat_ioctl(adapter, ifr);
7021 else
7022 ret = hdd_driver_ioctl(adapter, ifr);
7023 break;
7024 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007025 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007026 ret = -EINVAL;
7027 break;
7028 }
7029exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307030 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007031 return ret;
7032}
7033
7034/**
7035 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7036 * @dev: device upon which the ioctl was received
7037 * @ifr: ioctl request information
7038 * @cmd: ioctl command
7039 *
7040 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7041 * which is where the ioctls are really handled.
7042 *
7043 * Return: 0 on success, non-zero on error
7044 */
7045int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7046{
7047 int ret;
7048
7049 cds_ssr_protect(__func__);
7050 ret = __hdd_ioctl(dev, ifr, cmd);
7051 cds_ssr_unprotect(__func__);
7052 return ret;
7053}