blob: 1935edc3d06b6f4689f71d6a8b72cb1ac3e665fa [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Rajeev Kumarea95edd2017-01-11 20:49:36 -08002 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/* Include Files */
29
30#include <wlan_hdd_includes.h>
31#include <wlan_hdd_wowl.h>
32#include "wlan_hdd_trace.h"
33#include "wlan_hdd_ioctl.h"
34#include "wlan_hdd_power.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070035#include "wlan_hdd_regulatory.h"
Jeff Johnson253c0c22017-01-23 16:59:38 -080036#include "wlan_hdd_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080037#include "wlan_hdd_driver_ops.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080038#include "wlan_policy_mgr_api.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053039#include "wlan_hdd_hostapd.h"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080040#include "scheduler_api.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070041#include "wlan_reg_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080042#include "wlan_hdd_p2p.h"
43#include <linux/ctype.h>
44#include "wma.h"
45#include "wlan_hdd_napi.h"
46
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080047#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080048#include <sme_api.h>
49#include <sir_api.h>
50#endif
51#include "hif.h"
52
53#if defined(LINUX_QCMBR)
54#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
55#endif
56
57/*
58 * Size of Driver command strings from upper layer
59 */
60#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
61#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
62
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080063/*
64 * Ibss prop IE from command will be of size:
65 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
66 * OUI_DATA should be at least 3 bytes long
67 */
68#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080070#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071#define TID_MIN_VALUE 0
72#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080073#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080074
75/*
76 * Maximum buffer size used for returning the data back to user space
77 */
78#define WLAN_MAX_BUF_SIZE 1024
79#define WLAN_PRIV_DATA_MAX_LEN 8192
80
81/*
82 * Driver miracast parameters 0-Disabled
83 * 1-Source, 2-Sink
84 */
85#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
86#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
87
88/*
89 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
90 * we will split the printing.
91 */
92#define NUM_OF_STA_DATA_TO_PRINT 16
93
94/*
95 * Android DRIVER command structures
96 */
97struct android_wifi_reassoc_params {
98 unsigned char bssid[18];
99 int channel;
100};
101
102#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
103struct android_wifi_af_params {
104 unsigned char bssid[18];
105 int channel;
106 int dwell_time;
107 int len;
108 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
109};
110
111/*
112 * Define HDD driver command handling entry, each contains a command
113 * string and the handler.
114 */
115typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
116 hdd_context_t *hdd_ctx,
117 uint8_t *cmd,
118 uint8_t cmd_name_len,
119 hdd_priv_data_t *priv_data);
120
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700121struct hdd_drv_cmd {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800122 const char *cmd;
123 hdd_drv_cmd_handler_t handler;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700124};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800125
126#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
127#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
128#define WLAN_HDD_MAX_TCP_PORT 65535
129#endif
130
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800131static uint16_t cesium_pid;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800132
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800133#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800134struct tsm_priv {
135 tAniTrafStrmMetrics tsm_metrics;
136};
137
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800138static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
139 const uint32_t staId, void *context)
140{
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800141 struct hdd_request *request;
142 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800144 request = hdd_request_get(context);
145 if (!request) {
146 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800147 return;
148 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800149 priv = hdd_request_priv(request);
150 priv->tsm_metrics = tsm_metrics;
151 hdd_request_complete(request);
152 hdd_request_put(request);
153 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800154
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800155}
156
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800157static int hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800158 const uint8_t tid,
159 tAniTrafStrmMetrics *tsm_metrics)
160{
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800161 hdd_context_t *hdd_ctx;
162 hdd_station_ctx_t *hdd_sta_ctx;
163 QDF_STATUS status;
164 int ret;
165 void *cookie;
166 struct hdd_request *request;
167 struct tsm_priv *priv;
168 static const struct hdd_request_params params = {
169 .priv_size = sizeof(*priv),
170 .timeout_ms = WLAN_WAIT_TIME_STATS,
171 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800172
173 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700174 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800175 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176 }
177
178 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
179 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
180
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800181 request = hdd_request_alloc(&params);
182 if (!request) {
183 hdd_err("Request allocation failure");
184 return -ENOMEM;
185 }
186 cookie = hdd_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800187
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800188 status = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
189 hdd_sta_ctx->conn_info.staId[0],
190 hdd_sta_ctx->conn_info.bssId,
191 cookie, hdd_ctx->pcds_context, tid);
192 if (QDF_STATUS_SUCCESS != status) {
193 hdd_err("Unable to retrieve tsm statistics");
194 ret = qdf_status_to_os_return(status);
195 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800196 }
197
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800198 ret = hdd_request_wait_for_response(request);
199 if (ret) {
200 hdd_err("SME timed out while retrieving tsm statistics");
201 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800203
204 priv = hdd_request_priv(request);
205 *tsm_metrics = priv->tsm_metrics;
206
207 cleanup:
208 hdd_request_put(request);
209
210 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800212#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800213
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800214/* Function header is left blank intentionally */
215static int hdd_parse_setrmcenable_command(uint8_t *pValue,
216 uint8_t *pRmcEnable)
217{
218 uint8_t *inPtr = pValue;
219 int tempInt;
220 int v = 0;
221 char buf[32];
222 *pRmcEnable = 0;
223
224 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
225
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700226 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800227 return 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700228 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800229 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800230
231 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
232 inPtr++;
233
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700234 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800235 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800236
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700237 v = sscanf(inPtr, "%32s ", buf);
238 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800239 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700240
241 v = kstrtos32(buf, 10, &tempInt);
242 if (v < 0)
243 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800244
245 *pRmcEnable = tempInt;
246
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800247 hdd_debug("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800248
249 return 0;
250}
251
252/* Function header is left blank intentionally */
253static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
254 uint32_t *pActionPeriod)
255{
256 uint8_t *inPtr = pValue;
257 int tempInt;
258 int v = 0;
259 char buf[32];
260 *pActionPeriod = 0;
261
262 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
263
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700264 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800265 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700266 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800267 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800268
269 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
270 inPtr++;
271
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700272 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800273 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800274
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700275 v = sscanf(inPtr, "%32s ", buf);
276 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800277 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700278
279 v = kstrtos32(buf, 10, &tempInt);
280 if (v < 0)
281 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800282
283 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700284 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800285 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800286
287 *pActionPeriod = tempInt;
288
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800289 hdd_debug("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800290
291 return 0;
292}
293
294/* Function header is left blank intentionally */
295static int hdd_parse_setrmcrate_command(uint8_t *pValue,
296 uint32_t *pRate,
297 tTxrateinfoflags *pTxFlags)
298{
299 uint8_t *inPtr = pValue;
300 int tempInt;
301 int v = 0;
302 char buf[32];
303 *pRate = 0;
304 *pTxFlags = 0;
305
306 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
307
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700308 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800309 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700310 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800311 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800312
313 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
314 inPtr++;
315
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700316 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800317 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800318
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700319 v = sscanf(inPtr, "%32s ", buf);
320 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800321 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700322
323 v = kstrtos32(buf, 10, &tempInt);
324 if (v < 0)
325 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800326
327 switch (tempInt) {
328 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700329 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800330 return -EINVAL;
331 case 0:
332 case 6:
333 case 9:
334 case 12:
335 case 18:
336 case 24:
337 case 36:
338 case 48:
339 case 54:
340 *pTxFlags = eHAL_TX_RATE_LEGACY;
341 *pRate = tempInt * 10;
342 break;
343 case 65:
344 *pTxFlags = eHAL_TX_RATE_HT20;
345 *pRate = tempInt * 10;
346 break;
347 case 72:
348 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
349 *pRate = 722;
350 break;
351 }
352
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800353 hdd_debug("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800354
355 return 0;
356}
357
358/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700359 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
360 * @UserData: Adapter private data
361 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800362 *
363 * This is an asynchronous callback function from SME when the peer info
364 * is received
365 *
366 * Return: 0 for success non-zero for failure
367 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700368void
369hdd_get_ibss_peer_info_cb(void *pUserData,
370 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800371{
372 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800373 hdd_station_ctx_t *pStaCtx;
374 uint8_t i;
375
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800376 if ((NULL == adapter) ||
377 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800378 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800379 return;
380 }
381
382 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
383 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700384 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530385 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
386 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700387 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530388 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800389 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530390 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
391 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
392
393 for (i = 0; i < pPeerInfo->numPeers; i++)
394 pStaCtx->ibss_peer_info.peerInfoParams[i] =
395 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800396 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800397 hdd_debug("peerInfo %s: status %u, numPeers %u",
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530398 pPeerInfo ? "valid" : "null",
399 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
400 pPeerInfo ? pPeerInfo->numPeers : 0);
401 pStaCtx->ibss_peer_info.numPeers = 0;
402 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800403 }
404
405 complete(&adapter->ibss_peer_info_comp);
406}
407
408/**
409 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
410 * @adapter: Adapter context
411 *
412 * Request function to get IBSS peer info from lower layers
413 *
414 * Return: 0 for success non-zero for failure
415 */
416static
417QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
418{
419 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
420 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
421 unsigned long rc;
422
423 INIT_COMPLETION(adapter->ibss_peer_info_comp);
424
425 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700426 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800427 true, 0xFF);
428
429 if (QDF_STATUS_SUCCESS == retStatus) {
430 rc = wait_for_completion_timeout
431 (&adapter->ibss_peer_info_comp,
432 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
433
434 /* status will be 0 if timed out */
435 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700436 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800437 retStatus = QDF_STATUS_E_FAILURE;
438 return retStatus;
439 }
440 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700441 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800442 }
443
444 return retStatus;
445}
446
447/**
448 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
449 * @adapter: Adapter context
450 * @staIdx: Sta index for which the peer info is requested
451 *
452 * Request function to get IBSS peer info from lower layers
453 *
454 * Return: 0 for success non-zero for failure
455 */
456static QDF_STATUS
457hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
458{
459 unsigned long rc;
460 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
461 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
462
463 INIT_COMPLETION(adapter->ibss_peer_info_comp);
464
465 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700466 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800467 false, staIdx);
468
469 if (QDF_STATUS_SUCCESS == retStatus) {
470 rc = wait_for_completion_timeout(
471 &adapter->ibss_peer_info_comp,
472 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
473
474 /* status = 0 on timeout */
475 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700476 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800477 retStatus = QDF_STATUS_E_FAILURE;
478 return retStatus;
479 }
480 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700481 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800482 }
483
484 return retStatus;
485}
486
487/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700488static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800489hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
490{
491 uint8_t *inPtr = pValue;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700492
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800493 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
494
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700495 if (NULL == inPtr)
496 return QDF_STATUS_E_FAILURE;
497 else if (SPACE_ASCII_VALUE != *inPtr)
498 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800499
500 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
501 inPtr++;
502
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700503 if ('\0' == *inPtr)
504 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800505
506 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
507 inPtr[11] != ':' || inPtr[14] != ':') {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700508 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800509 }
510 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
511 (unsigned int *)&pPeerMacAddr->bytes[0],
512 (unsigned int *)&pPeerMacAddr->bytes[1],
513 (unsigned int *)&pPeerMacAddr->bytes[2],
514 (unsigned int *)&pPeerMacAddr->bytes[3],
515 (unsigned int *)&pPeerMacAddr->bytes[4],
516 (unsigned int *)&pPeerMacAddr->bytes[5]);
517
518 return QDF_STATUS_SUCCESS;
519}
520
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800521static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
522{
523 eCsrBand band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700524
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
526 switch (band) {
527 case eCSR_BAND_ALL:
528 *pBand = WLAN_HDD_UI_BAND_AUTO;
529 break;
530
531 case eCSR_BAND_24:
532 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
533 break;
534
535 case eCSR_BAND_5G:
536 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
537 break;
538
539 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700540 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800541 *pBand = -1;
542 break;
543 }
544}
545
546/**
547 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
548 * @data: input data
549 * @target_ap_bssid: pointer to bssid (output parameter)
550 * @channel: pointer to channel (output parameter)
551 *
552 * Return: 0 if parsing is successful; -EINVAL otherwise
553 */
554static int _hdd_parse_bssid_and_chan(const uint8_t **data,
555 uint8_t *bssid,
556 uint8_t *channel)
557{
558 const uint8_t *in_ptr;
559 int v = 0;
560 int temp_int;
561 uint8_t temp_buf[32];
562
563 /* 12 hexa decimal digits, 5 ':' and '\0' */
564 uint8_t mac_addr[18];
565
566 if (!data || !*data)
567 return -EINVAL;
568
569 in_ptr = *data;
570
571 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
572 /* no argument after the command */
573 if (NULL == in_ptr)
574 goto error;
575 /* no space after the command */
576 else if (SPACE_ASCII_VALUE != *in_ptr)
577 goto error;
578
579 /* remove empty spaces */
580 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
581 in_ptr++;
582
583 /* no argument followed by spaces */
584 if ('\0' == *in_ptr)
585 goto error;
586
587 v = sscanf(in_ptr, "%17s", mac_addr);
588 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700589 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
590 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800591 goto error;
592 }
593
594 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
595 hex_to_bin(mac_addr[1]);
596 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
597 hex_to_bin(mac_addr[4]);
598 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
599 hex_to_bin(mac_addr[7]);
600 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
601 hex_to_bin(mac_addr[10]);
602 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
603 hex_to_bin(mac_addr[13]);
604 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
605 hex_to_bin(mac_addr[16]);
606
607 /* point to the next argument */
608 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
609 /* no argument after the command */
610 if (NULL == in_ptr)
611 goto error;
612
613 /* remove empty spaces */
614 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
615 in_ptr++;
616
617 /* no argument followed by spaces */
618 if ('\0' == *in_ptr)
619 goto error;
620
621 /* get the next argument ie the channel number */
622 v = sscanf(in_ptr, "%31s ", temp_buf);
623 if (1 != v)
624 goto error;
625
626 v = kstrtos32(temp_buf, 10, &temp_int);
627 if ((v < 0) || (temp_int < 0) ||
628 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
629 return -EINVAL;
630
631 *channel = temp_int;
632 *data = in_ptr;
633 return 0;
634error:
635 *data = in_ptr;
636 return -EINVAL;
637}
638
639/**
640 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
641 * @pValue: Pointer to input data
642 * @pTargetApBssid: Pointer to target Ap bssid
643 * @pChannel: Pointer to the Target AP channel
644 * @pDwellTime: Pointer to the time to stay off-channel
645 * after transmitting action frame
646 * @pBuf: Pointer to data
647 * @pBufLen: Pointer to data length
648 *
649 * This function parses the send action frame data passed in the format
650 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
651 *
652 * Return: 0 for success non-zero for failure
653 */
654static int
655hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
656 uint8_t *pTargetApBssid,
657 uint8_t *pChannel, uint8_t *pDwellTime,
658 uint8_t **pBuf, uint8_t *pBufLen)
659{
660 const uint8_t *inPtr = pValue;
661 const uint8_t *dataEnd;
662 int tempInt;
663 int j = 0;
664 int i = 0;
665 int v = 0;
666 uint8_t tempBuf[32];
667 uint8_t tempByte = 0;
668
669 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
670 return -EINVAL;
671
672 /* point to the next argument */
673 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
674 /* no argument after the command */
675 if (NULL == inPtr)
676 return -EINVAL;
677 /* removing empty spaces */
678 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
679 inPtr++;
680
681 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700682 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800683 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800684
685 /* getting the next argument ie the dwell time */
686 v = sscanf(inPtr, "%31s ", tempBuf);
687 if (1 != v)
688 return -EINVAL;
689
690 v = kstrtos32(tempBuf, 10, &tempInt);
691 if (v < 0 || tempInt < 0)
692 return -EINVAL;
693
694 *pDwellTime = tempInt;
695
696 /* point to the next argument */
697 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
698 /* no argument after the command */
699 if (NULL == inPtr)
700 return -EINVAL;
701 /* removing empty spaces */
702 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
703 inPtr++;
704
705 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700706 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800707 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708
709 /* find the length of data */
710 dataEnd = inPtr;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700711 while (('\0' != *dataEnd))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800712 dataEnd++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700713
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800714 *pBufLen = dataEnd - inPtr;
715 if (*pBufLen <= 0)
716 return -EINVAL;
717
718 /*
719 * Allocate the number of bytes based on the number of input characters
720 * whether it is even or odd.
721 * if the number of input characters are even, then we need N/2 byte.
722 * if the number of input characters are odd, then we need do (N+1)/2
723 * to compensate rounding off.
724 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
725 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
726 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530727 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800728 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700729 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800730 return -ENOMEM;
731 }
732
733 /* the buffer received from the upper layer is character buffer,
734 * we need to prepare the buffer taking 2 characters in to a U8 hex
735 * decimal number for example 7f0000f0...form a buffer to contain 7f
736 * in 0th location, 00 in 1st and f0 in 3rd location
737 */
738 for (i = 0, j = 0; j < *pBufLen; j += 2) {
739 if (j + 1 == *pBufLen) {
740 tempByte = hex_to_bin(inPtr[j]);
741 } else {
742 tempByte =
743 (hex_to_bin(inPtr[j]) << 4) |
744 (hex_to_bin(inPtr[j + 1]));
745 }
746 (*pBuf)[i++] = tempByte;
747 }
748 *pBufLen = i;
749 return 0;
750}
751
752/**
753 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
754 * @pValue: Pointer to input data (its a NULL terminated string)
755 * @pTargetApBssid: Pointer to target Ap bssid
756 * @pChannel: Pointer to the Target AP channel
757 *
758 * This function parses the reasoc command data passed in the format
759 * REASSOC<space><bssid><space><channel>
760 *
761 * Return: 0 for success non-zero for failure
762 */
763static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
764 uint8_t *pTargetApBssid,
765 uint8_t *pChannel)
766{
767 const uint8_t *inPtr = pValue;
768
769 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
770 return -EINVAL;
771
772 return 0;
773}
774
Naveen Rawat05376ee2016-07-18 16:43:32 -0700775#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800776void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter,
777 const tSirMacAddr bssid, int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700778{
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800779 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
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002307 if (cds_is_driver_recovering()) {
2308 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;
3407
3408 /*
3409 * Check if the features OKC/ESE/11R are supported simultaneously,
3410 * then this operation is not permitted (return FAILURE)
3411 */
3412 if (eseMode &&
3413 hdd_is_okc_mode_enabled(hdd_ctx) &&
3414 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003415 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003416 ret = -EPERM;
3417 goto exit;
3418 }
3419
3420 len = scnprintf(extra, sizeof(extra), "%s %d",
3421 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303422 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003424 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003425 ret = -EFAULT;
3426 goto exit;
3427 }
3428
3429exit:
3430 return ret;
3431}
3432
3433static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3434 hdd_context_t *hdd_ctx,
3435 uint8_t *command,
3436 uint8_t command_len,
3437 hdd_priv_data_t *priv_data)
3438{
3439 int ret = 0;
3440 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3441 char extra[32];
3442 uint8_t len = 0;
3443
3444 /*
3445 * Check if the features OKC/ESE/11R are supported simultaneously,
3446 * then this operation is not permitted (return FAILURE)
3447 */
3448 if (okcMode &&
3449 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3450 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003451 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452 ret = -EPERM;
3453 goto exit;
3454 }
3455
3456 len = scnprintf(extra, sizeof(extra), "%s %d",
3457 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303458 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003459
3460 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003461 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003462 ret = -EFAULT;
3463 goto exit;
3464 }
3465
3466exit:
3467 return ret;
3468}
3469
3470static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3471 hdd_context_t *hdd_ctx,
3472 uint8_t *command,
3473 uint8_t command_len,
3474 hdd_priv_data_t *priv_data)
3475{
3476 int ret = 0;
3477 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3478 char extra[32];
3479 uint8_t len = 0;
3480
3481 len = scnprintf(extra, sizeof(extra), "%s %d",
3482 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303483 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003484
3485 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003486 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003487 ret = -EFAULT;
3488 }
3489
3490 return ret;
3491}
3492
3493static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3494 hdd_context_t *hdd_ctx,
3495 uint8_t *command,
3496 uint8_t command_len,
3497 hdd_priv_data_t *priv_data)
3498{
3499 int ret = 0;
3500 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3501 char extra[32];
3502 uint8_t len = 0;
3503
3504 len = scnprintf(extra, sizeof(extra), "%s %d",
3505 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303506 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003507
3508 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003509 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003510 ret = -EFAULT;
3511 }
3512
3513 return ret;
3514}
3515
3516static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3517 hdd_context_t *hdd_ctx,
3518 uint8_t *command,
3519 uint8_t command_len,
3520 hdd_priv_data_t *priv_data)
3521{
3522 int ret = 0;
3523 uint8_t *value = command;
3524 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3525
3526 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3527 value = value + command_len + 1;
3528
3529 /* Convert the value from ascii to integer */
3530 ret = kstrtou8(value, 10, &minTime);
3531 if (ret < 0) {
3532 /*
3533 * If the input value is greater than max value of datatype,
3534 * then also kstrtou8 fails
3535 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003536 hdd_err("kstrtou8 failed range [%d - %d]",
3537 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3538 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003539 ret = -EINVAL;
3540 goto exit;
3541 }
3542
3543 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3544 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003545 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3546 minTime,
3547 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3548 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003549 ret = -EINVAL;
3550 goto exit;
3551 }
3552
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303553 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003554 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3555 adapter->sessionId, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003556 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003557 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003558
3559 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3560 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3561 minTime,
3562 adapter->sessionId);
3563
3564exit:
3565 return ret;
3566}
3567
3568static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3569 hdd_context_t *hdd_ctx,
3570 uint8_t *command,
3571 uint8_t command_len,
3572 hdd_priv_data_t *priv_data)
3573{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003574 return hdd_parse_sendactionframe(adapter, command,
3575 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003576}
3577
3578static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3579 hdd_context_t *hdd_ctx,
3580 uint8_t *command,
3581 uint8_t command_len,
3582 hdd_priv_data_t *priv_data)
3583{
3584 int ret = 0;
3585 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3586 adapter->sessionId);
3587 char extra[32];
3588 uint8_t len = 0;
3589
3590 /* value is interms of msec */
3591 len = scnprintf(extra, sizeof(extra), "%s %d",
3592 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303593 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003594
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303595 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003596 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3597 adapter->sessionId, val));
3598
3599 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003600 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003601 ret = -EFAULT;
3602 }
3603
3604 return ret;
3605}
3606
3607static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3608 hdd_context_t *hdd_ctx,
3609 uint8_t *command,
3610 uint8_t command_len,
3611 hdd_priv_data_t *priv_data)
3612{
3613 int ret = 0;
3614 uint8_t *value = command;
3615 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3616
3617 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3618 value = value + command_len + 1;
3619
3620 /* Convert the value from ascii to integer */
3621 ret = kstrtou16(value, 10, &maxTime);
3622 if (ret < 0) {
3623 /*
3624 * If the input value is greater than max value of datatype,
3625 * then also kstrtou8 fails
3626 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003627 hdd_err("kstrtou16 failed range [%d - %d]",
3628 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3629 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003630 ret = -EINVAL;
3631 goto exit;
3632 }
3633
3634 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3635 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003636 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3637 maxTime,
3638 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3639 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003640 ret = -EINVAL;
3641 goto exit;
3642 }
3643
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003644 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003645 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003646
3647 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3648 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3649 adapter->sessionId,
3650 maxTime);
3651
3652exit:
3653 return ret;
3654}
3655
3656static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3657 hdd_context_t *hdd_ctx,
3658 uint8_t *command,
3659 uint8_t command_len,
3660 hdd_priv_data_t *priv_data)
3661{
3662 int ret = 0;
3663 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3664 adapter->sessionId);
3665 char extra[32];
3666 uint8_t len = 0;
3667
3668 /* value is interms of msec */
3669 len = scnprintf(extra, sizeof(extra), "%s %d",
3670 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303671 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003672
3673 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003674 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003675 ret = -EFAULT;
3676 }
3677
3678 return ret;
3679}
3680
3681static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3682 hdd_context_t *hdd_ctx,
3683 uint8_t *command,
3684 uint8_t command_len,
3685 hdd_priv_data_t *priv_data)
3686{
3687 int ret = 0;
3688 uint8_t *value = command;
3689 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3690
3691 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3692 value = value + command_len + 1;
3693
3694 /* Convert the value from ascii to integer */
3695 ret = kstrtou16(value, 10, &val);
3696 if (ret < 0) {
3697 /*
3698 * If the input value is greater than max value of datatype,
3699 * then also kstrtou8 fails
3700 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003701 hdd_err("kstrtou16 failed range [%d - %d]",
3702 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3703 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003704 ret = -EINVAL;
3705 goto exit;
3706 }
3707
3708 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3709 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003710 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3711 val,
3712 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3713 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003714 ret = -EINVAL;
3715 goto exit;
3716 }
3717
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003718 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003719 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003720
3721 hdd_ctx->config->nNeighborScanPeriod = val;
3722 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3723 adapter->sessionId, val);
3724
3725exit:
3726 return ret;
3727}
3728
3729static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3730 hdd_context_t *hdd_ctx,
3731 uint8_t *command,
3732 uint8_t command_len,
3733 hdd_priv_data_t *priv_data)
3734{
3735 int ret = 0;
3736 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3737 adapter->
3738 sessionId);
3739 char extra[32];
3740 uint8_t len = 0;
3741
3742 /* value is interms of msec */
3743 len = scnprintf(extra, sizeof(extra), "%s %d",
3744 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303745 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003746
3747 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003748 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003749 ret = -EFAULT;
3750 }
3751
3752 return ret;
3753}
3754
3755static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3756 hdd_context_t *hdd_ctx,
3757 uint8_t *command,
3758 uint8_t command_len,
3759 hdd_priv_data_t *priv_data)
3760{
3761 int ret = 0;
3762 uint8_t *value = command;
3763 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3764
3765 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3766 value = value + command_len + 1;
3767
3768 /* Convert the value from ascii to integer */
3769 ret = kstrtou8(value, 10, &val);
3770 if (ret < 0) {
3771 /*
3772 * If the input value is greater than max value of datatype,
3773 * then also kstrtou8 fails
3774 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003775 hdd_err("kstrtou8 failed range [%d - %d]",
3776 CFG_ROAM_INTRA_BAND_MIN,
3777 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003778 ret = -EINVAL;
3779 goto exit;
3780 }
3781
3782 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3783 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003784 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3785 val,
3786 CFG_ROAM_INTRA_BAND_MIN,
3787 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003788 ret = -EINVAL;
3789 goto exit;
3790 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003791 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003792 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003793
3794 hdd_ctx->config->nRoamIntraBand = val;
3795 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3796
3797exit:
3798 return ret;
3799}
3800
3801static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3802 hdd_context_t *hdd_ctx,
3803 uint8_t *command,
3804 uint8_t command_len,
3805 hdd_priv_data_t *priv_data)
3806{
3807 int ret = 0;
3808 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3809 char extra[32];
3810 uint8_t len = 0;
3811
3812 /* value is interms of msec */
3813 len = scnprintf(extra, sizeof(extra), "%s %d",
3814 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303815 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003816 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003817 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003818 ret = -EFAULT;
3819 }
3820
3821 return ret;
3822}
3823
3824static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3825 hdd_context_t *hdd_ctx,
3826 uint8_t *command,
3827 uint8_t command_len,
3828 hdd_priv_data_t *priv_data)
3829{
3830 int ret = 0;
3831 uint8_t *value = command;
3832 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3833
3834 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3835 value = value + command_len + 1;
3836
3837 /* Convert the value from ascii to integer */
3838 ret = kstrtou8(value, 10, &nProbes);
3839 if (ret < 0) {
3840 /*
3841 * If the input value is greater than max value of datatype,
3842 * then also kstrtou8 fails
3843 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003844 hdd_err("kstrtou8 failed range [%d - %d]",
3845 CFG_ROAM_SCAN_N_PROBES_MIN,
3846 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003847 ret = -EINVAL;
3848 goto exit;
3849 }
3850
3851 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3852 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003853 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3854 nProbes,
3855 CFG_ROAM_SCAN_N_PROBES_MIN,
3856 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003857 ret = -EINVAL;
3858 goto exit;
3859 }
3860
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003861 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003862 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003863
3864 hdd_ctx->config->nProbes = nProbes;
3865 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3866 adapter->sessionId, nProbes);
3867
3868exit:
3869 return ret;
3870}
3871
3872static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3873 hdd_context_t *hdd_ctx,
3874 uint8_t *command,
3875 uint8_t command_len,
3876 hdd_priv_data_t *priv_data)
3877{
3878 int ret = 0;
3879 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3880 char extra[32];
3881 uint8_t len = 0;
3882
3883 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303884 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003885 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003886 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003887 ret = -EFAULT;
3888 }
3889
3890 return ret;
3891}
3892
3893static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
3894 hdd_context_t *hdd_ctx,
3895 uint8_t *command,
3896 uint8_t command_len,
3897 hdd_priv_data_t *priv_data)
3898{
3899 int ret = 0;
3900 uint8_t *value = command;
3901 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3902
3903 /* input value is in units of msec */
3904
3905 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3906 value = value + command_len + 1;
3907
3908 /* Convert the value from ascii to integer */
3909 ret = kstrtou16(value, 10, &homeAwayTime);
3910 if (ret < 0) {
3911 /*
3912 * If the input value is greater than max value of datatype,
3913 * then also kstrtou8 fails
3914 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003915 hdd_err("kstrtou8 failed range [%d - %d]",
3916 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3917 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918 ret = -EINVAL;
3919 goto exit;
3920 }
3921
3922 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
3923 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003924 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003925 homeAwayTime,
3926 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3927 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
3928 ret = -EINVAL;
3929 goto exit;
3930 }
3931
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003932 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003933 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003934
3935 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
3936 homeAwayTime) {
3937 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
3938 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
3939 adapter->sessionId,
3940 homeAwayTime,
3941 true);
3942 }
3943
3944exit:
3945 return ret;
3946}
3947
3948static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
3949 hdd_context_t *hdd_ctx,
3950 uint8_t *command,
3951 uint8_t command_len,
3952 hdd_priv_data_t *priv_data)
3953{
3954 int ret = 0;
3955 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
3956 char extra[32];
3957 uint8_t len = 0;
3958
3959 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303960 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003961
3962 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003963 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003964 ret = -EFAULT;
3965 }
3966
3967 return ret;
3968}
3969
3970static int drv_cmd_reassoc(hdd_adapter_t *adapter,
3971 hdd_context_t *hdd_ctx,
3972 uint8_t *command,
3973 uint8_t command_len,
3974 hdd_priv_data_t *priv_data)
3975{
3976 return hdd_parse_reassoc(adapter, command);
3977}
3978
3979static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
3980 hdd_context_t *hdd_ctx,
3981 uint8_t *command,
3982 uint8_t command_len,
3983 hdd_priv_data_t *priv_data)
3984{
3985 int ret = 0;
3986 uint8_t *value = command;
3987 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
3988
3989 /* Move pointer to ahead of SETWESMODE<delimiter> */
3990 value = value + command_len + 1;
3991
3992 /* Convert the value from ascii to integer */
3993 ret = kstrtou8(value, 10, &wesMode);
3994 if (ret < 0) {
3995 /*
3996 * If the input value is greater than max value of datatype,
3997 * then also kstrtou8 fails
3998 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003999 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004000 CFG_ENABLE_WES_MODE_NAME_MIN,
4001 CFG_ENABLE_WES_MODE_NAME_MAX);
4002 ret = -EINVAL;
4003 goto exit;
4004 }
4005
4006 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4007 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004008 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004009 wesMode,
4010 CFG_ENABLE_WES_MODE_NAME_MIN,
4011 CFG_ENABLE_WES_MODE_NAME_MAX);
4012 ret = -EINVAL;
4013 goto exit;
4014 }
4015
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004016 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004017 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004018
4019 hdd_ctx->config->isWESModeEnabled = wesMode;
4020 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4021
4022exit:
4023 return ret;
4024}
4025
4026static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4027 hdd_context_t *hdd_ctx,
4028 uint8_t *command,
4029 uint8_t command_len,
4030 hdd_priv_data_t *priv_data)
4031{
4032 int ret = 0;
4033 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4034 char extra[32];
4035 uint8_t len = 0;
4036
4037 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304038 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004039 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004040 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004041 ret = -EFAULT;
4042 }
4043
4044 return ret;
4045}
4046
4047static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4048 hdd_context_t *hdd_ctx,
4049 uint8_t *command,
4050 uint8_t command_len,
4051 hdd_priv_data_t *priv_data)
4052{
4053 int ret = 0;
4054 uint8_t *value = command;
4055 uint8_t nOpportunisticThresholdDiff =
4056 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4057
4058 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4059 value = value + command_len + 1;
4060
4061 /* Convert the value from ascii to integer */
4062 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4063 if (ret < 0) {
4064 /*
4065 * If the input value is greater than max value of datatype,
4066 * then also kstrtou8 fails
4067 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004068 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004069 ret = -EINVAL;
4070 goto exit;
4071 }
4072
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004073 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004074 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004075
4076 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4077 adapter->sessionId,
4078 nOpportunisticThresholdDiff);
4079
4080exit:
4081 return ret;
4082}
4083
4084static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4085 hdd_context_t *hdd_ctx,
4086 uint8_t *command,
4087 uint8_t command_len,
4088 hdd_priv_data_t *priv_data)
4089{
4090 int ret = 0;
4091 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4092 hdd_ctx->hHal);
4093 char extra[32];
4094 uint8_t len = 0;
4095
4096 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304097 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004098 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004099 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004100 ret = -EFAULT;
4101 }
4102
4103 return ret;
4104}
4105
4106static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4107 hdd_context_t *hdd_ctx,
4108 uint8_t *command,
4109 uint8_t command_len,
4110 hdd_priv_data_t *priv_data)
4111{
4112 int ret = 0;
4113 uint8_t *value = command;
4114 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4115
4116 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4117 value = value + command_len + 1;
4118
4119 /* Convert the value from ascii to integer */
4120 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4121 if (ret < 0) {
4122 /*
4123 * If the input value is greater than max value of datatype,
4124 * then also kstrtou8 fails
4125 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004126 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004127 ret = -EINVAL;
4128 goto exit;
4129 }
4130
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004131 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004132 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004133
4134 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4135 adapter->sessionId,
4136 nRoamRescanRssiDiff);
4137
4138exit:
4139 return ret;
4140}
4141
4142static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4143 hdd_context_t *hdd_ctx,
4144 uint8_t *command,
4145 uint8_t command_len,
4146 hdd_priv_data_t *priv_data)
4147{
4148 int ret = 0;
4149 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4150 char extra[32];
4151 uint8_t len = 0;
4152
4153 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304154 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004155 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004156 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004157 ret = -EFAULT;
4158 }
4159
4160 return ret;
4161}
4162
4163static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4164 hdd_context_t *hdd_ctx,
4165 uint8_t *command,
4166 uint8_t command_len,
4167 hdd_priv_data_t *priv_data)
4168{
4169 int ret = 0;
4170 uint8_t *value = command;
4171 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4172
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004173 if (!adapter->fast_roaming_allowed) {
4174 hdd_err("Roaming is always disabled on this interface");
4175 goto exit;
4176 }
4177
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004178 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4179 value = value + command_len + 1;
4180
4181 /* Convert the value from ascii to integer */
4182 ret = kstrtou8(value, 10, &lfrMode);
4183 if (ret < 0) {
4184 /*
4185 * If the input value is greater than max value of datatype,
4186 * then also kstrtou8 fails
4187 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004188 hdd_err("kstrtou8 failed range [%d - %d]",
4189 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190 CFG_LFR_FEATURE_ENABLED_MAX);
4191 ret = -EINVAL;
4192 goto exit;
4193 }
4194
4195 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4196 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004197 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004198 lfrMode,
4199 CFG_LFR_FEATURE_ENABLED_MIN,
4200 CFG_LFR_FEATURE_ENABLED_MAX);
4201 ret = -EINVAL;
4202 goto exit;
4203 }
4204
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004205 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004206 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004207
4208 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4209 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4210 adapter->
4211 sessionId,
4212 lfrMode);
4213
4214exit:
4215 return ret;
4216}
4217
4218static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4219 hdd_context_t *hdd_ctx,
4220 uint8_t *command,
4221 uint8_t command_len,
4222 hdd_priv_data_t *priv_data)
4223{
4224 int ret = 0;
4225 uint8_t *value = command;
4226 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4227
4228 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4229 value = value + command_len + 1;
4230
4231 /* Convert the value from ascii to integer */
4232 ret = kstrtou8(value, 10, &ft);
4233 if (ret < 0) {
4234 /*
4235 * If the input value is greater than max value of datatype,
4236 * then also kstrtou8 fails
4237 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004238 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004239 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4240 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4241 ret = -EINVAL;
4242 goto exit;
4243 }
4244
4245 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4246 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004247 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004248 ft,
4249 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4250 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4251 ret = -EINVAL;
4252 goto exit;
4253 }
4254
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004255 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004256
4257 hdd_ctx->config->isFastTransitionEnabled = ft;
4258 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4259
4260exit:
4261 return ret;
4262}
4263
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004264static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4265 hdd_context_t *hdd_ctx,
4266 uint8_t *command,
4267 uint8_t command_len,
4268 hdd_priv_data_t *priv_data)
4269{
4270 int ret = 0;
4271 uint8_t *value = command;
4272 uint8_t channel = 0;
4273 tSirMacAddr targetApBssid;
4274 uint32_t roamId = 0;
4275 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004276 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004277 hdd_station_ctx_t *pHddStaCtx;
4278
Krunal Sonibe766b02016-03-10 13:00:44 -08004279 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 hdd_warn("Unsupported in mode %s(%d)",
4281 hdd_device_mode_to_string(adapter->device_mode),
4282 adapter->device_mode);
4283 return -EINVAL;
4284 }
4285
4286 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4287
4288 /* if not associated, no need to proceed with reassoc */
4289 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004290 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004291 ret = -EINVAL;
4292 goto exit;
4293 }
4294
4295 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4296 &channel);
4297 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004298 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004299 goto exit;
4300 }
4301
4302 /*
4303 * if the target bssid is same as currently associated AP,
4304 * issue reassoc to same AP
4305 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004306 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004307 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304308 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004309 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304310 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004311 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304312 targetApBssid,
4313 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304314 } else {
4315 sme_get_modify_profile_fields(hdd_ctx->hHal,
4316 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004317 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304318 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4319 NULL, modProfileFields, &roamId, 1);
4320 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004321 return 0;
4322 }
4323
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304324 /* Check channel number is a valid channel number */
4325 if (QDF_STATUS_SUCCESS !=
4326 wlan_hdd_validate_operation_channel(adapter, channel)) {
4327 hdd_err("Invalid Channel [%d]", channel);
4328 return -EINVAL;
4329 }
4330
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004331 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004332 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004333 targetApBssid, (int)channel);
4334 goto exit;
4335 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004337 handoffInfo.channel = channel;
4338 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004339 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 sizeof(tSirMacAddr));
4341 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4342 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004343exit:
4344 return ret;
4345}
4346
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004347static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4348 hdd_context_t *hdd_ctx,
4349 uint8_t *command,
4350 uint8_t command_len,
4351 hdd_priv_data_t *priv_data)
4352{
4353 int ret = 0;
4354 uint8_t *value = command;
4355 uint8_t roamScanControl = 0;
4356
4357 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4358 value = value + command_len + 1;
4359
4360 /* Convert the value from ascii to integer */
4361 ret = kstrtou8(value, 10, &roamScanControl);
4362 if (ret < 0) {
4363 /*
4364 * If the input value is greater than max value of datatype,
4365 * then also kstrtou8 fails
4366 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004367 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004368 ret = -EINVAL;
4369 goto exit;
4370 }
4371
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004372 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004373 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004374
4375 if (0 != roamScanControl) {
4376 ret = 0; /* return success but ignore param value "true" */
4377 goto exit;
4378 }
4379
4380 sme_set_roam_scan_control(hdd_ctx->hHal,
4381 adapter->sessionId,
4382 roamScanControl);
4383
4384exit:
4385 return ret;
4386}
4387
4388static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4389 hdd_context_t *hdd_ctx,
4390 uint8_t *command,
4391 uint8_t command_len,
4392 hdd_priv_data_t *priv_data)
4393{
4394 int ret = 0;
4395 uint8_t *value = command;
4396 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4397
4398 /*
4399 * Check if the features OKC/ESE/11R are supported simultaneously,
4400 * then this operation is not permitted (return FAILURE)
4401 */
4402 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4403 hdd_is_okc_mode_enabled(hdd_ctx) &&
4404 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004405 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004406 ret = -EPERM;
4407 goto exit;
4408 }
4409
4410 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4411 value = value + command_len + 1;
4412
4413 /* Convert the value from ascii to integer */
4414 ret = kstrtou8(value, 10, &okcMode);
4415 if (ret < 0) {
4416 /*
4417 * If the input value is greater than max value of datatype,
4418 * then also kstrtou8 fails
4419 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004420 hdd_err("kstrtou8 failed range [%d - %d]",
4421 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004422 CFG_OKC_FEATURE_ENABLED_MAX);
4423 ret = -EINVAL;
4424 goto exit;
4425 }
4426
4427 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4428 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004429 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430 okcMode,
4431 CFG_OKC_FEATURE_ENABLED_MIN,
4432 CFG_OKC_FEATURE_ENABLED_MAX);
4433 ret = -EINVAL;
4434 goto exit;
4435 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004436 hdd_debug("Received Command to change okc mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004437 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004438
4439 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4440
4441exit:
4442 return ret;
4443}
4444
4445static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4446 hdd_context_t *hdd_ctx,
4447 uint8_t *command,
4448 uint8_t command_len,
4449 hdd_priv_data_t *priv_data)
4450{
4451 int ret = 0;
4452 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4453 char extra[32];
4454 uint8_t len = 0;
4455
4456 len = scnprintf(extra, sizeof(extra), "%s %d",
4457 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304458 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004459 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004460 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004461 ret = -EFAULT;
4462 }
4463
4464 return ret;
4465}
4466
4467static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4468 hdd_context_t *hdd_ctx,
4469 uint8_t *command,
4470 uint8_t command_len,
4471 hdd_priv_data_t *priv_data)
4472{
4473 int ret = 0;
4474 char *bcMode;
4475
4476 bcMode = command + 11;
4477 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004478 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004479 hdd_ctx->btCoexModeSet = true;
4480 ret = wlan_hdd_scan_abort(adapter);
4481 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004482 hdd_err("Failed to abort existing scan status: %d",
4483 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484 }
4485 } else if ('2' == *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 = false;
4488 }
4489
4490 return ret;
4491}
4492
4493static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4494 hdd_context_t *hdd_ctx,
4495 uint8_t *command,
4496 uint8_t command_len,
4497 hdd_priv_data_t *priv_data)
4498{
4499 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4500 return 0;
4501}
4502
4503static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4504 hdd_context_t *hdd_ctx,
4505 uint8_t *command,
4506 uint8_t command_len,
4507 hdd_priv_data_t *priv_data)
4508{
4509 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4510 return 0;
4511}
4512
4513static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4514 hdd_context_t *hdd_ctx,
4515 uint8_t *command,
4516 uint8_t command_len,
4517 hdd_priv_data_t *priv_data)
4518{
4519 int ret = 0;
4520 struct hdd_config *pCfg =
4521 (WLAN_HDD_GET_CTX(adapter))->config;
4522 char extra[32];
4523 uint8_t len = 0;
4524
4525 memset(extra, 0, sizeof(extra));
4526 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304527 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004528 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004529 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004530 ret = -EFAULT;
4531 goto exit;
4532 }
4533 ret = len;
4534exit:
4535 return ret;
4536}
4537
4538static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4539 hdd_context_t *hdd_ctx,
4540 uint8_t *command,
4541 uint8_t command_len,
4542 hdd_priv_data_t *priv_data)
4543{
4544 return hdd_set_dwell_time(adapter, command);
4545}
4546
4547static int drv_cmd_miracast(hdd_adapter_t *adapter,
4548 hdd_context_t *hdd_ctx,
4549 uint8_t *command,
4550 uint8_t command_len,
4551 hdd_priv_data_t *priv_data)
4552{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304553 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004554 int ret = 0;
4555 tHalHandle hHal;
4556 uint8_t filterType = 0;
4557 hdd_context_t *pHddCtx = NULL;
4558 uint8_t *value;
4559
4560 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304561 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004562 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563
4564 hHal = pHddCtx->hHal;
4565 value = command + 9;
4566
4567 /* Convert the value from ascii to integer */
4568 ret = kstrtou8(value, 10, &filterType);
4569 if (ret < 0) {
4570 /*
4571 * If the input value is greater than max value of datatype,
4572 * then also kstrtou8 fails
4573 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004574 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004575 ret = -EINVAL;
4576 goto exit;
4577 }
4578 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4579 || (filterType >
4580 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004581 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004582 ret = -EINVAL;
4583 goto exit;
4584 }
4585 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4586 pHddCtx->miracast_value = filterType;
4587
4588 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304589 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004590 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004591 return -EBUSY;
4592 }
4593
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004594 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4595 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004596
4597exit:
4598 return ret;
4599}
4600
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004601/* Function header is left blank intentionally */
4602static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4603 int32_t *oui_length, int32_t limit)
4604{
4605 uint8_t len;
4606 uint8_t data;
4607
4608 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4609 command++;
4610 limit--;
4611 }
4612
4613 len = 2;
4614
4615 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4616 (limit > 1)) {
4617 sscanf(command, "%02x", (unsigned int *)&data);
4618 ie[len++] = data;
4619 command += 2;
4620 limit -= 2;
4621 }
4622
4623 *oui_length = len - 2;
4624
4625 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4626 command++;
4627 limit--;
4628 }
4629
4630 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4631 (limit > 1)) {
4632 sscanf(command, "%02x", (unsigned int *)&data);
4633 ie[len++] = data;
4634 command += 2;
4635 limit -= 2;
4636 }
4637
4638 ie[0] = IE_EID_VENDOR;
4639 ie[1] = len - 2;
4640
4641 return len;
4642}
4643
4644/**
4645 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4646 * @adapter: Pointer to adapter
4647 * @hdd_ctx: Pointer to HDD context
4648 * @command: Pointer to command string
4649 * @command_len : Command length
4650 * @priv_data : Pointer to priv data
4651 *
4652 * Return:
4653 * int status code
4654 */
4655static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4656 hdd_context_t *hdd_ctx,
4657 uint8_t *command,
4658 uint8_t command_len,
4659 hdd_priv_data_t *priv_data)
4660{
4661 int i = 0;
4662 int status;
4663 int ret = 0;
4664 uint8_t *ibss_ie;
4665 int32_t oui_length = 0;
4666 uint32_t ibss_ie_length;
4667 uint8_t *value = command;
4668 tSirModifyIE ibssModifyIE;
4669 tCsrRoamProfile *pRoamProfile;
4670 hdd_wext_state_t *pWextState;
4671
4672
Krunal Sonibe766b02016-03-10 13:00:44 -08004673 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004674 hdd_debug("Device_mode %s(%d) not IBSS",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004675 hdd_device_mode_to_string(adapter->device_mode),
4676 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004677 return ret;
4678 }
4679
4680 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4681
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004682 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004683
4684
4685 /* validate argument of command */
4686 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004687 hdd_err("No arguments in command length %zu",
4688 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004689 ret = -EFAULT;
4690 goto exit;
4691 }
4692
4693 /* moving to arguments of commands */
4694 value = value + command_len;
4695 command_len = strlen(value);
4696
4697 /* oui_data can't be less than 3 bytes */
4698 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004699 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4700 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004701 ret = -EFAULT;
4702 goto exit;
4703 }
4704
4705 ibss_ie = qdf_mem_malloc(command_len);
4706 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004707 hdd_err("Could not allocate memory for command length %d",
4708 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004709 ret = -ENOMEM;
4710 goto exit;
4711 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004712
4713 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4714 &oui_length,
4715 command_len);
4716 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004717 hdd_err("Could not parse command %s return length %d",
4718 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004719 ret = -EFAULT;
4720 qdf_mem_free(ibss_ie);
4721 goto exit;
4722 }
4723
4724 pRoamProfile = &pWextState->roamProfile;
4725
4726 qdf_copy_macaddr(&ibssModifyIE.bssid,
4727 pRoamProfile->BSSIDs.bssid);
4728
4729 ibssModifyIE.smeSessionId = adapter->sessionId;
4730 ibssModifyIE.notify = true;
4731 ibssModifyIE.ieID = IE_EID_VENDOR;
4732 ibssModifyIE.ieIDLen = ibss_ie_length;
4733 ibssModifyIE.ieBufferlength = ibss_ie_length;
4734 ibssModifyIE.pIEBuffer = ibss_ie;
4735 ibssModifyIE.oui_length = oui_length;
4736
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004737 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4738 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004739 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004740 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004741
4742 /* Probe Bcn modification */
4743 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4744 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4745
4746 /* Populating probe resp frame */
4747 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4748 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4749
4750 qdf_mem_free(ibss_ie);
4751
4752 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4753 adapter->sessionId);
4754 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004755 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004756 status);
4757 ret = -EINVAL;
4758 goto exit;
4759 }
4760
4761exit:
4762 return ret;
4763}
4764
4765static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4766 hdd_context_t *hdd_ctx,
4767 uint8_t *command,
4768 uint8_t command_len,
4769 hdd_priv_data_t *priv_data)
4770{
4771 int ret = 0;
4772 uint8_t *value = command;
4773 uint8_t ucRmcEnable = 0;
4774 int status;
4775
Krunal Sonibe766b02016-03-10 13:00:44 -08004776 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4777 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004778 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4779 hdd_device_mode_to_string(adapter->device_mode),
4780 adapter->device_mode);
4781 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004782 ret = -EINVAL;
4783 goto exit;
4784 }
4785
4786 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4787 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004788 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004789 ret = -EINVAL;
4790 goto exit;
4791 }
4792
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004793 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004794
4795 if (true == ucRmcEnable) {
4796 status = sme_enable_rmc((tHalHandle)
4797 (hdd_ctx->hHal),
4798 adapter->sessionId);
4799 } else if (false == ucRmcEnable) {
4800 status = sme_disable_rmc((tHalHandle)
4801 (hdd_ctx->hHal),
4802 adapter->sessionId);
4803 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004804 hdd_err("Invalid SETRMCENABLE command %d",
4805 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004806 ret = -EINVAL;
4807 goto exit;
4808 }
4809
4810 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004811 hdd_err("SETRMC %d failed status %d",
4812 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004813 ret = -EINVAL;
4814 goto exit;
4815 }
4816
4817exit:
4818 return ret;
4819}
4820
4821static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4822 hdd_context_t *hdd_ctx,
4823 uint8_t *command,
4824 uint8_t command_len,
4825 hdd_priv_data_t *priv_data)
4826{
4827 int ret = 0;
4828 uint8_t *value = command;
4829 uint32_t uActionPeriod = 0;
4830 int status;
4831
Krunal Sonibe766b02016-03-10 13:00:44 -08004832 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4833 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004834 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004835 hdd_device_mode_to_string(adapter->device_mode),
4836 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004837 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004838 ret = -EINVAL;
4839 goto exit;
4840 }
4841
4842 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4843 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004844 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004845 ret = -EINVAL;
4846 goto exit;
4847 }
4848
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004849 hdd_debug("uActionPeriod %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004850 uActionPeriod);
4851
4852 if (sme_cfg_set_int(hdd_ctx->hHal,
4853 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4854 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004855 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4856 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004857 ret = -EINVAL;
4858 goto exit;
4859 }
4860
4861 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4862 adapter->sessionId);
4863 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004864 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004865 status);
4866 ret = -EINVAL;
4867 goto exit;
4868 }
4869
4870exit:
4871 return ret;
4872}
4873
4874static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
4875 hdd_context_t *hdd_ctx,
4876 uint8_t *command,
4877 uint8_t command_len,
4878 hdd_priv_data_t *priv_data)
4879{
4880 int ret = 0;
4881 int status = QDF_STATUS_SUCCESS;
4882 hdd_station_ctx_t *pHddStaCtx = NULL;
4883 char *extra = NULL;
4884 int idx = 0;
4885 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004886 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004887 uint32_t numOfBytestoPrint = 0;
4888
Krunal Sonibe766b02016-03-10 13:00:44 -08004889 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004890 hdd_warn("Unsupported in mode %s(%d)",
4891 hdd_device_mode_to_string(adapter->device_mode),
4892 adapter->device_mode);
4893 return -EINVAL;
4894 }
4895
4896 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004897 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004898
4899 /* Handle the command */
4900 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
4901 if (QDF_STATUS_SUCCESS == status) {
4902 /*
4903 * The variable extra needed to be allocated on the heap since
4904 * amount of memory required to copy the data for 32 devices
4905 * exceeds the size of 1024 bytes of default stack size. On
4906 * 64 bit devices, the default max stack size of 2048 bytes
4907 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004908 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004909
4910 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004911 hdd_err("memory allocation failed");
4912 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004913 goto exit;
4914 }
4915
4916 /* Copy number of stations */
4917 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004918 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004919 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004920 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
4921 idx++) {
4922 int8_t rssi;
4923 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004924
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004925 qdf_mem_copy(mac_addr,
4926 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4927 mac_addr, sizeof(mac_addr));
4928
4929 tx_rate =
4930 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4931 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05304932 /*
4933 * Only lower 3 bytes are rate info. Mask of the MSByte
4934 */
4935 tx_rate &= 0x00FFFFFF;
4936
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004937 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4938 rssi;
4939
4940 length += scnprintf((extra + length),
4941 WLAN_MAX_BUF_SIZE - length,
4942 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
4943 mac_addr[0], mac_addr[1], mac_addr[2],
4944 mac_addr[3], mac_addr[4], mac_addr[5],
4945 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004946 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004947 * cdf_trace_msg has limitation of 512 bytes for the
4948 * print buffer. Hence printing the data in two chunks.
4949 * The first chunk will have the data for 16 devices
4950 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004951 */
4952 if (idx < NUM_OF_STA_DATA_TO_PRINT)
4953 numOfBytestoPrint = length;
4954 }
4955
4956 /*
4957 * Copy the data back into buffer, if the data to copy is
4958 * more than 512 bytes than we will split the data and do
4959 * it in two shots
4960 */
4961 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004962 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004963 ret = -EFAULT;
4964 goto exit;
4965 }
4966
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07004967 /* This overwrites the last space, which we already copied */
4968 extra[numOfBytestoPrint - 1] = '\0';
4969 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004970
4971 if (length > numOfBytestoPrint) {
4972 if (copy_to_user
4973 (priv_data->buf + numOfBytestoPrint,
4974 extra + numOfBytestoPrint,
4975 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004976 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004977 ret = -EFAULT;
4978 goto exit;
4979 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07004980 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004981 }
4982
4983 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004984 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004985 } else {
4986 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004987 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
4988 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004989 ret = -EINVAL;
4990 goto exit;
4991 }
4992 ret = 0;
4993
4994exit:
4995 return ret;
4996}
4997
4998/* Peer Info <Peer Addr> command */
4999static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5000 hdd_context_t *hdd_ctx,
5001 uint8_t *command,
5002 uint8_t command_len,
5003 hdd_priv_data_t *priv_data)
5004{
5005 int ret = 0;
5006 uint8_t *value = command;
5007 QDF_STATUS status;
5008 hdd_station_ctx_t *pHddStaCtx = NULL;
5009 char extra[128] = { 0 };
5010 uint32_t length = 0;
5011 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005012 struct qdf_mac_addr peerMacAddr;
5013
Krunal Sonibe766b02016-03-10 13:00:44 -08005014 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005015 hdd_warn("Unsupported in mode %s(%d)",
5016 hdd_device_mode_to_string(adapter->device_mode),
5017 adapter->device_mode);
5018 return -EINVAL;
5019 }
5020
5021 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5022
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005023 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005024
5025 /* if there are no peers, no need to continue with the command */
5026 if (eConnectionState_IbssConnected !=
5027 pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005028 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005029 ret = -EINVAL;
5030 goto exit;
5031 }
5032
5033 /* Parse the incoming command buffer */
5034 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5035 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005036 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005037 ret = -EINVAL;
5038 goto exit;
5039 }
5040
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005041 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005042 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005043
Naveen Rawatc45d1622016-07-05 12:20:09 -07005044 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005045 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005046 ret = -EINVAL;
5047 goto exit;
5048 }
5049
5050 /* Handle the command */
5051 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5052 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005053 uint32_t txRate =
5054 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305055 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5056 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005057
5058 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005059 (int)txRate,
5060 (int)pHddStaCtx->ibss_peer_info.
5061 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005062
5063 /* Copy the data back into buffer */
5064 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005065 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005066 ret = -EFAULT;
5067 goto exit;
5068 }
5069 } else {
5070 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005071 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5072 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005073 ret = -EINVAL;
5074 goto exit;
5075 }
5076
5077 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005078 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005079 ret = 0;
5080
5081exit:
5082 return ret;
5083}
5084
5085static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5086 hdd_context_t *hdd_ctx,
5087 uint8_t *command,
5088 uint8_t command_len,
5089 hdd_priv_data_t *priv_data)
5090{
5091 int ret = 0;
5092 uint8_t *value = command;
5093 uint32_t uRate = 0;
5094 tTxrateinfoflags txFlags = 0;
5095 tSirRateUpdateInd rateUpdateParams = {0};
5096 int status;
5097 struct hdd_config *pConfig = hdd_ctx->config;
5098
Krunal Sonibe766b02016-03-10 13:00:44 -08005099 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5100 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005101 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5102 hdd_device_mode_to_string(adapter->device_mode),
5103 adapter->device_mode);
5104 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005105 ret = -EINVAL;
5106 goto exit;
5107 }
5108
5109 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5110 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005111 hdd_err("Invalid SETRMCTXRATE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005112 ret = -EINVAL;
5113 goto exit;
5114 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005115 hdd_debug("uRate %d", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005116 /* -1 implies ignore this param */
5117 rateUpdateParams.ucastDataRate = -1;
5118
5119 /*
5120 * Fill the user specifieed RMC rate param
5121 * and the derived tx flags.
5122 */
5123 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5124 rateUpdateParams.reliableMcastDataRate = uRate;
5125 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5126 rateUpdateParams.dev_mode = adapter->device_mode;
5127 rateUpdateParams.bcastDataRate = -1;
5128 memcpy(rateUpdateParams.bssid.bytes,
5129 adapter->macAddressCurrent.bytes,
5130 sizeof(rateUpdateParams.bssid));
5131 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5132 &rateUpdateParams);
5133
5134exit:
5135 return ret;
5136}
5137
5138static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5139 hdd_context_t *hdd_ctx,
5140 uint8_t *command,
5141 uint8_t command_len,
5142 hdd_priv_data_t *priv_data)
5143{
5144 int ret = 0;
5145 char *value;
5146 uint8_t tx_fail_count = 0;
5147 uint16_t pid = 0;
5148
5149 value = command;
5150
5151 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5152
5153 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005154 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005155 goto exit;
5156 }
5157
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005158 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005159
5160 if (0 == tx_fail_count) {
5161 /* Disable TX Fail Indication */
5162 if (QDF_STATUS_SUCCESS ==
5163 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5164 tx_fail_count,
5165 NULL)) {
5166 cesium_pid = 0;
5167 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005168 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005169 ret = -EINVAL;
5170 }
5171 } else {
5172 if (QDF_STATUS_SUCCESS ==
5173 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5174 tx_fail_count,
5175 (void *)hdd_tx_fail_ind_callback)) {
5176 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005177 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005178 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005179 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005180 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005181 ret = -EINVAL;
5182 }
5183 }
5184
5185exit:
5186 return ret;
5187}
5188
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005189#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005190static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5191 hdd_context_t *hdd_ctx,
5192 uint8_t *command,
5193 uint8_t command_len,
5194 hdd_priv_data_t *priv_data)
5195{
5196 int ret = 0;
5197 uint8_t *value = command;
5198 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5199 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305200 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005201
5202 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5203 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005204 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005205 goto exit;
5206 }
5207 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005208 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005209 numChannels,
5210 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5211 ret = -EINVAL;
5212 goto exit;
5213 }
5214 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5215 adapter->sessionId,
5216 ChannelList,
5217 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305218 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005219 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005220 ret = -EINVAL;
5221 goto exit;
5222 }
5223
5224exit:
5225 return ret;
5226}
5227
5228static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5229 hdd_context_t *hdd_ctx,
5230 uint8_t *command,
5231 uint8_t command_len,
5232 hdd_priv_data_t *priv_data)
5233{
5234 int ret = 0;
5235 uint8_t *value = command;
5236 char extra[128] = { 0 };
5237 int len = 0;
5238 uint8_t tid = 0;
5239 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005240 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005241
Krunal Sonibe766b02016-03-10 13:00:44 -08005242 if ((QDF_STA_MODE != adapter->device_mode) &&
5243 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005244 hdd_warn("Unsupported in mode %s(%d)",
5245 hdd_device_mode_to_string(adapter->device_mode),
5246 adapter->device_mode);
5247 return -EINVAL;
5248 }
5249
5250 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5251
5252 /* if not associated, return error */
5253 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005254 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005255 ret = -EINVAL;
5256 goto exit;
5257 }
5258
5259 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5260 value = value + command_len + 1;
5261
5262 /* Convert the value from ascii to integer */
5263 ret = kstrtou8(value, 10, &tid);
5264 if (ret < 0) {
5265 /*
5266 * If the input value is greater than max value of datatype,
5267 * then also kstrtou8 fails
5268 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005269 hdd_err("kstrtou8 failed range [%d - %d]",
5270 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005271 TID_MAX_VALUE);
5272 ret = -EINVAL;
5273 goto exit;
5274 }
5275 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005276 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005277 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5278 ret = -EINVAL;
5279 goto exit;
5280 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005281 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005282 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005283 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5284 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005285 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005286 goto exit;
5287 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005288 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005289 "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 -08005290 tsm_metrics.UplinkPktQueueDly,
5291 tsm_metrics.UplinkPktQueueDlyHist[0],
5292 tsm_metrics.UplinkPktQueueDlyHist[1],
5293 tsm_metrics.UplinkPktQueueDlyHist[2],
5294 tsm_metrics.UplinkPktQueueDlyHist[3],
5295 tsm_metrics.UplinkPktTxDly,
5296 tsm_metrics.UplinkPktLoss,
5297 tsm_metrics.UplinkPktCount,
5298 tsm_metrics.RoamingCount,
5299 tsm_metrics.RoamingDly);
5300 /*
5301 * Output TSM stats is of the format
5302 * GETTSMSTATS [PktQueueDly]
5303 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5304 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5305 */
5306 len = scnprintf(extra,
5307 sizeof(extra),
5308 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5309 command,
5310 tsm_metrics.UplinkPktQueueDly,
5311 tsm_metrics.UplinkPktQueueDlyHist[0],
5312 tsm_metrics.UplinkPktQueueDlyHist[1],
5313 tsm_metrics.UplinkPktQueueDlyHist[2],
5314 tsm_metrics.UplinkPktQueueDlyHist[3],
5315 tsm_metrics.UplinkPktTxDly,
5316 tsm_metrics.UplinkPktLoss,
5317 tsm_metrics.UplinkPktCount,
5318 tsm_metrics.RoamingCount,
5319 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305320 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005321 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005322 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005323 ret = -EFAULT;
5324 goto exit;
5325 }
5326
5327exit:
5328 return ret;
5329}
5330
5331static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5332 hdd_context_t *hdd_ctx,
5333 uint8_t *command,
5334 uint8_t command_len,
5335 hdd_priv_data_t *priv_data)
5336{
5337 int ret;
5338 uint8_t *value = command;
5339 uint8_t *cckmIe = NULL;
5340 uint8_t cckmIeLen = 0;
5341
5342 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5343 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005344 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005345 goto exit;
5346 }
5347
5348 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005349 hdd_err("CCKM Ie input length is more than max[%d]",
5350 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005351 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305352 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005353 cckmIe = NULL;
5354 }
5355 ret = -EINVAL;
5356 goto exit;
5357 }
5358
5359 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5360 cckmIe, cckmIeLen);
5361 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
5366exit:
5367 return ret;
5368}
5369
5370static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5371 hdd_context_t *hdd_ctx,
5372 uint8_t *command,
5373 uint8_t command_len,
5374 hdd_priv_data_t *priv_data)
5375{
5376 int ret;
5377 uint8_t *value = command;
5378 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305379 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005380
Krunal Sonibe766b02016-03-10 13:00:44 -08005381 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005382 hdd_warn("Unsupported in mode %s(%d)",
5383 hdd_device_mode_to_string(adapter->device_mode),
5384 adapter->device_mode);
5385 return -EINVAL;
5386 }
5387
5388 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5389 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005390 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005391 goto exit;
5392 }
5393
5394 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005395 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005396 hdd_indicate_ese_bcn_report_no_results(adapter,
5397 eseBcnReq.bcnReq[0].measurementToken,
5398 0x02, /* BIT(1) set for measurement done */
5399 0); /* no BSS */
5400 goto exit;
5401 }
5402
5403 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5404 adapter->sessionId,
5405 &eseBcnReq);
5406
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305407 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005408 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005409 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005410 ret = -EBUSY;
5411 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305412 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005413 hdd_err("sme_set_ese_beacon_request failed (%d)",
5414 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005415 ret = -EINVAL;
5416 goto exit;
5417 }
5418
5419exit:
5420 return ret;
5421}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005422
5423/**
5424 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5425 * @adapter: Pointer to the HDD adapter
5426 * @hdd_ctx: Pointer to the HDD context
5427 * @command: Driver command string
5428 * @command_len: Driver command string length
5429 * @priv_data: Private data coming with the driver command. Unused here
5430 *
5431 * This function handles driver command that sets the ESE PLM request
5432 *
5433 * Return: 0 on success; negative errno otherwise
5434 */
5435static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5436 hdd_context_t *hdd_ctx,
5437 uint8_t *command,
5438 uint8_t command_len,
5439 hdd_priv_data_t *priv_data)
5440{
5441 int ret = 0;
5442 uint8_t *value = command;
5443 QDF_STATUS status = QDF_STATUS_SUCCESS;
5444 tpSirPlmReq pPlmRequest = NULL;
5445
5446 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5447 if (NULL == pPlmRequest) {
5448 ret = -ENOMEM;
5449 goto exit;
5450 }
5451
5452 status = hdd_parse_plm_cmd(value, pPlmRequest);
5453 if (QDF_STATUS_SUCCESS != status) {
5454 qdf_mem_free(pPlmRequest);
5455 pPlmRequest = NULL;
5456 ret = -EINVAL;
5457 goto exit;
5458 }
5459 pPlmRequest->sessionId = adapter->sessionId;
5460
5461 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5462 if (QDF_STATUS_SUCCESS != status) {
5463 qdf_mem_free(pPlmRequest);
5464 pPlmRequest = NULL;
5465 ret = -EINVAL;
5466 goto exit;
5467 }
5468
5469exit:
5470 return ret;
5471}
5472
5473/**
5474 * drv_cmd_set_ccx_mode() - Set ESE mode
5475 * @adapter: Pointer to the HDD adapter
5476 * @hdd_ctx: Pointer to the HDD context
5477 * @command: Driver command string
5478 * @command_len: Driver command string length
5479 * @priv_data: Private data coming with the driver command. Unused here
5480 *
5481 * This function handles driver command that sets ESE mode
5482 *
5483 * Return: 0 on success; negative errno otherwise
5484 */
5485static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5486 hdd_context_t *hdd_ctx,
5487 uint8_t *command,
5488 uint8_t command_len,
5489 hdd_priv_data_t *priv_data)
5490{
5491 int ret = 0;
5492 uint8_t *value = command;
5493 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5494
5495 /*
5496 * Check if the features OKC/ESE/11R are supported simultaneously,
5497 * then this operation is not permitted (return FAILURE)
5498 */
5499 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5500 hdd_is_okc_mode_enabled(hdd_ctx) &&
5501 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5502 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5503 ret = -EPERM;
5504 goto exit;
5505 }
5506
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005507 if (!adapter->fast_roaming_allowed) {
5508 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5509 ret = -EPERM;
5510 goto exit;
5511 }
5512
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005513 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5514 value = value + command_len + 1;
5515
5516 /* Convert the value from ascii to integer */
5517 ret = kstrtou8(value, 10, &eseMode);
5518 if (ret < 0) {
5519 /*
5520 * If the input value is greater than max value of datatype,
5521 * then also kstrtou8 fails
5522 */
5523 hdd_err("kstrtou8 failed range [%d - %d]",
5524 CFG_ESE_FEATURE_ENABLED_MIN,
5525 CFG_ESE_FEATURE_ENABLED_MAX);
5526 ret = -EINVAL;
5527 goto exit;
5528 }
5529
5530 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5531 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5532 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5533 eseMode,
5534 CFG_ESE_FEATURE_ENABLED_MIN,
5535 CFG_ESE_FEATURE_ENABLED_MAX);
5536 ret = -EINVAL;
5537 goto exit;
5538 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005539 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005540
5541 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5542 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5543 adapter->sessionId,
5544 eseMode);
5545
5546exit:
5547 return ret;
5548}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005549#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005550
5551static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5552 hdd_context_t *hdd_ctx,
5553 uint8_t *command,
5554 uint8_t command_len,
5555 hdd_priv_data_t *priv_data)
5556{
5557 int ret = 0;
5558 uint8_t *value = command;
5559 int targetRate;
5560
5561 /* input value is in units of hundred kbps */
5562
5563 /* Move pointer to ahead of SETMCRATE<delimiter> */
5564 value = value + command_len + 1;
5565
5566 /* Convert the value from ascii to integer, decimal base */
5567 ret = kstrtouint(value, 10, &targetRate);
5568
5569 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5570 return ret;
5571}
5572
5573static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5574 hdd_context_t *hdd_ctx,
5575 uint8_t *command,
5576 uint8_t command_len,
5577 hdd_priv_data_t *priv_data)
5578{
5579 int ret = 0;
5580 int status;
5581 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305582 QDF_STATUS qdf_status;
5583 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005584 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305585 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5586 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005587 hdd_adapter_list_node_t *pAdapterNode = NULL;
5588 hdd_adapter_list_node_t *pNext = NULL;
5589
5590 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5591 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005592 hdd_err("Invalid MAXTXPOWER command");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005593 ret = -EINVAL;
5594 goto exit;
5595 }
5596
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305597 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005598 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305599 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005600 adapter = pAdapterNode->pAdapter;
5601 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305602 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005603 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305604 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005605 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005606
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005607 hdd_debug("Device mode %d max tx power %d selfMac: "
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005608 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005609 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005610 MAC_ADDR_ARRAY(selfMac.bytes),
5611 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005612
Srinivas Girigowda97215232015-09-24 12:26:28 -07005613 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5614 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305615 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005616 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005617 ret = -EINVAL;
5618 goto exit;
5619 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005620 hdd_debug("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305621 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005622 &pNext);
5623 pAdapterNode = pNext;
5624 }
5625
5626exit:
5627 return ret;
5628}
5629
5630static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5631 hdd_context_t *hdd_ctx,
5632 uint8_t *command,
5633 uint8_t command_len,
5634 hdd_priv_data_t *priv_data)
5635{
5636 int ret = 0;
5637 uint8_t *value = command;
5638 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5639
5640 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5641 value = value + command_len + 1;
5642
5643 /* Convert the value from ascii to integer */
5644 ret = kstrtou8(value, 10, &dfsScanMode);
5645 if (ret < 0) {
5646 /*
5647 * If the input value is greater than max value of datatype,
5648 * then also kstrtou8 fails
5649 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005650 hdd_err("kstrtou8 failed range [%d - %d]",
5651 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005652 CFG_ROAMING_DFS_CHANNEL_MAX);
5653 ret = -EINVAL;
5654 goto exit;
5655 }
5656
5657 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5658 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005659 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005660 dfsScanMode,
5661 CFG_ROAMING_DFS_CHANNEL_MIN,
5662 CFG_ROAMING_DFS_CHANNEL_MAX);
5663 ret = -EINVAL;
5664 goto exit;
5665 }
5666
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005667 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005668 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005669
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005670 /* When DFS scanning is disabled, the DFS channels need to be
5671 * removed from the operation of device.
5672 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005673 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5674 dfsScanMode != CFG_ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005675 if (ret < 0) {
5676 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005677 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005678 goto exit;
5679 }
5680
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005681 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5682 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5683 dfsScanMode);
5684
5685exit:
5686 return ret;
5687}
5688
5689static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5690 hdd_context_t *hdd_ctx,
5691 uint8_t *command,
5692 uint8_t command_len,
5693 hdd_priv_data_t *priv_data)
5694{
5695 int ret = 0;
5696 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5697 char extra[32];
5698 uint8_t len = 0;
5699
5700 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305701 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005702 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005703 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005704 ret = -EFAULT;
5705 }
5706
5707 return ret;
5708}
5709
5710static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5711 hdd_context_t *hdd_ctx,
5712 uint8_t *command,
5713 uint8_t command_len,
5714 hdd_priv_data_t *priv_data)
5715{
5716 int ret = 0;
5717 int value = wlan_hdd_get_link_status(adapter);
5718 char extra[32];
5719 uint8_t len;
5720
5721 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305722 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005723 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005724 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005725 ret = -EFAULT;
5726 }
5727
5728 return ret;
5729}
5730
5731#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5732static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5733 hdd_context_t *hdd_ctx,
5734 uint8_t *command,
5735 uint8_t command_len,
5736 hdd_priv_data_t *priv_data)
5737{
5738 uint8_t *value = command;
5739 int set_value;
5740
5741 /* Move pointer to ahead of ENABLEEXTWOW */
5742 value = value + command_len;
5743
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305744 if (!(sscanf(value, "%d", &set_value))) {
5745 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5746 ("No input identified"));
5747 return -EINVAL;
5748 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005749
5750 return hdd_enable_ext_wow_parser(adapter,
5751 adapter->sessionId,
5752 set_value);
5753}
5754
5755static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5756 hdd_context_t *hdd_ctx,
5757 uint8_t *command,
5758 uint8_t command_len,
5759 hdd_priv_data_t *priv_data)
5760{
5761 int ret;
5762 uint8_t *value = command;
5763
5764 /* Move pointer to ahead of SETAPP1PARAMS */
5765 value = value + command_len;
5766
5767 ret = hdd_set_app_type1_parser(adapter,
5768 value, strlen(value));
5769 if (ret >= 0)
5770 hdd_ctx->is_extwow_app_type1_param_set = true;
5771
5772 return ret;
5773}
5774
5775static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5776 hdd_context_t *hdd_ctx,
5777 uint8_t *command,
5778 uint8_t command_len,
5779 hdd_priv_data_t *priv_data)
5780{
5781 int ret;
5782 uint8_t *value = command;
5783
5784 /* Move pointer to ahead of SETAPP2PARAMS */
5785 value = value + command_len;
5786
5787 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5788 if (ret >= 0)
5789 hdd_ctx->is_extwow_app_type2_param_set = true;
5790
5791 return ret;
5792}
5793#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5794
5795#ifdef FEATURE_WLAN_TDLS
5796/**
5797 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5798 * @adapter: Pointer to the HDD adapter
5799 * @hdd_ctx: Pointer to the HDD context
5800 * @command: Driver command string
5801 * @command_len: Driver command string length
5802 * @priv_data: Private data coming with the driver command. Unused here
5803 *
5804 * This function handles driver command that sets the secondary tdls off channel
5805 * offset
5806 *
5807 * Return: 0 on success; negative errno otherwise
5808 */
5809static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5810 hdd_context_t *hdd_ctx,
5811 uint8_t *command,
5812 uint8_t command_len,
5813 hdd_priv_data_t *priv_data)
5814{
5815 int ret;
5816 uint8_t *value = command;
5817 int set_value;
5818
5819 /* Move pointer to point the string */
5820 value += command_len;
5821
5822 ret = sscanf(value, "%d", &set_value);
5823 if (ret != 1)
5824 return -EINVAL;
5825
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005826 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005827
5828 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5829
5830 return ret;
5831}
5832
5833/**
5834 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5835 * @adapter: Pointer to the HDD adapter
5836 * @hdd_ctx: Pointer to the HDD context
5837 * @command: Driver command string
5838 * @command_len: Driver command string length
5839 * @priv_data: Private data coming with the driver command. Unused here
5840 *
5841 * This function handles driver command that sets tdls off channel mode
5842 *
5843 * Return: 0 on success; negative errno otherwise
5844 */
5845static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5846 hdd_context_t *hdd_ctx,
5847 uint8_t *command,
5848 uint8_t command_len,
5849 hdd_priv_data_t *priv_data)
5850{
5851 int ret;
5852 uint8_t *value = command;
5853 int set_value;
5854
5855 /* Move pointer to point the string */
5856 value += command_len;
5857
5858 ret = sscanf(value, "%d", &set_value);
5859 if (ret != 1)
5860 return -EINVAL;
5861
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005862 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005863
5864 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5865
5866 return ret;
5867}
5868
5869/**
5870 * drv_cmd_tdls_off_channel() - set tdls off channel number
5871 * @adapter: Pointer to the HDD adapter
5872 * @hdd_ctx: Pointer to the HDD context
5873 * @command: Driver command string
5874 * @command_len: Driver command string length
5875 * @priv_data: Private data coming with the driver command. Unused here
5876 *
5877 * This function handles driver command that sets tdls off channel number
5878 *
5879 * Return: 0 on success; negative errno otherwise
5880 */
5881static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5882 hdd_context_t *hdd_ctx,
5883 uint8_t *command,
5884 uint8_t command_len,
5885 hdd_priv_data_t *priv_data)
5886{
5887 int ret;
5888 uint8_t *value = command;
5889 int set_value;
5890
5891 /* Move pointer to point the string */
5892 value += command_len;
5893
5894 ret = sscanf(value, "%d", &set_value);
5895 if (ret != 1)
5896 return -EINVAL;
5897
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -07005898 if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, set_value)) {
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005899 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5900 set_value);
5901 return -EINVAL;
5902 }
5903
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005904 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005905
5906 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5907
5908 return ret;
5909}
5910
5911/**
5912 * drv_cmd_tdls_scan() - set tdls scan type
5913 * @adapter: Pointer to the HDD adapter
5914 * @hdd_ctx: Pointer to the HDD context
5915 * @command: Driver command string
5916 * @command_len: Driver command string length
5917 * @priv_data: Private data coming with the driver command. Unused here
5918 *
5919 * This function handles driver command that sets tdls scan type
5920 *
5921 * Return: 0 on success; negative errno otherwise
5922 */
5923static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
5924 hdd_context_t *hdd_ctx,
5925 uint8_t *command,
5926 uint8_t command_len,
5927 hdd_priv_data_t *priv_data)
5928{
5929 int ret;
5930 uint8_t *value = command;
5931 int set_value;
5932
5933 /* Move pointer to point the string */
5934 value += command_len;
5935
5936 ret = sscanf(value, "%d", &set_value);
5937 if (ret != 1)
5938 return -EINVAL;
5939
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005940 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005941
5942 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
5943
5944 return ret;
5945}
5946#endif
5947
5948static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
5949 hdd_context_t *hdd_ctx,
5950 uint8_t *command,
5951 uint8_t command_len,
5952 hdd_priv_data_t *priv_data)
5953{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005954 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005955 int8_t rssi = 0;
5956 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005957
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005958 uint8_t len = 0;
5959
5960 wlan_hdd_get_rssi(adapter, &rssi);
5961
5962 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305963 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005964
5965 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005966 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005967 ret = -EFAULT;
5968 }
5969
5970 return ret;
5971}
5972
5973static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
5974 hdd_context_t *hdd_ctx,
5975 uint8_t *command,
5976 uint8_t command_len,
5977 hdd_priv_data_t *priv_data)
5978{
5979 int ret;
5980 uint32_t link_speed = 0;
5981 char extra[32];
5982 uint8_t len = 0;
5983
5984 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
5985 if (0 != ret)
5986 return ret;
5987
5988 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305989 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005990 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005991 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005992 ret = -EFAULT;
5993 }
5994
5995 return ret;
5996}
5997
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005998/**
5999 * hdd_set_rx_filter() - set RX filter
6000 * @adapter: Pointer to adapter
6001 * @action: Filter action
6002 * @pattern: Address pattern
6003 *
6004 * Address pattern is most significant byte of address for example
6005 * 0x01 for IPV4 multicast address
6006 * 0x33 for IPV6 multicast address
6007 * 0xFF for broadcast address
6008 *
6009 * Return: 0 for success, non-zero for failure
6010 */
6011static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6012 uint8_t pattern)
6013{
6014 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006015 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006016 tHalHandle handle;
6017 tSirRcvFltMcAddrList *filter;
6018 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6019
6020 ret = wlan_hdd_validate_context(hdd_ctx);
6021 if (0 != ret)
6022 return ret;
6023
6024 handle = hdd_ctx->hHal;
6025
6026 if (NULL == handle) {
6027 hdd_err("HAL Handle is NULL");
6028 return -EINVAL;
6029 }
6030
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306031 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006032 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306033 return -EINVAL;
6034 }
6035
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006036 /*
6037 * If action is false it means start dropping packets
6038 * Set addr_filter_pattern which will be used when sending
6039 * MC/BC address list to target
6040 */
6041 if (!action)
6042 adapter->addr_filter_pattern = pattern;
6043 else
6044 adapter->addr_filter_pattern = 0;
6045
Krunal Sonibe766b02016-03-10 13:00:44 -08006046 if (((adapter->device_mode == QDF_STA_MODE) ||
6047 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006048 adapter->mc_addr_list.mc_cnt &&
6049 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6050
6051
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306052 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006053 if (NULL == filter) {
6054 hdd_err("Could not allocate Memory");
6055 return -ENOMEM;
6056 }
6057 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006058 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006059 if (!memcmp(adapter->mc_addr_list.addr[i],
6060 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006061 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006062 adapter->mc_addr_list.addr[i],
6063 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006064
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006065 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006066 MAC_ADDRESS_STR,
6067 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006068 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6069 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006070 }
6071 }
Frank Liuf95e8132016-09-29 19:01:30 +08006072 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006073 /* Set rx filter */
6074 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306075 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006076 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006077 hdd_debug("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006078 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6079 }
6080
6081 return 0;
6082}
6083
6084/**
6085 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6086 * @command: Pointer to input string driver command
6087 * @adapter: Pointer to adapter
6088 * @action: Action to enable/disable filtering
6089 *
6090 * If action == false
6091 * Start filtering out data packets based on type
6092 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6093 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6094 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6095 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6096 *
6097 * if action == true
6098 * Stop filtering data packets based on type
6099 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6100 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6101 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6102 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6103 *
6104 * Current implementation only supports IPV4 address filtering by
6105 * selectively allowing IPV4 multicast data packest based on
6106 * address list received in .ndo_set_rx_mode
6107 *
6108 * Return: 0 for success, non-zero for failure
6109 */
6110static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6111 hdd_adapter_t *adapter,
6112 bool action)
6113{
6114 int ret = 0;
6115 uint8_t *value;
6116 uint8_t type;
6117
6118 value = command;
6119 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6120 if (!action)
6121 value = command + 16;
6122 else
6123 value = command + 13;
6124 ret = kstrtou8(value, 10, &type);
6125 if (ret < 0) {
6126 hdd_err("kstrtou8 failed invalid input value %d", type);
6127 return -EINVAL;
6128 }
6129
6130 switch (type) {
6131 case 2:
6132 /* Set rx filter for IPV4 multicast data packets */
6133 ret = hdd_set_rx_filter(adapter, action, 0x01);
6134 break;
6135 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006136 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006137 break;
6138 }
6139
6140 return ret;
6141}
6142
6143/**
6144 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6145 * @adapter: Pointer to network adapter
6146 * @hdd_ctx: Pointer to hdd context
6147 * @command: Pointer to input command
6148 * @command_len: Command length
6149 * @priv_data: Pointer to private data in command
6150 */
6151static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6152 hdd_context_t *hdd_ctx,
6153 uint8_t *command,
6154 uint8_t command_len,
6155 hdd_priv_data_t *priv_data)
6156{
6157 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6158}
6159
6160/**
6161 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6162 * @adapter: Pointer to network adapter
6163 * @hdd_ctx: Pointer to hdd context
6164 * @command: Pointer to input command
6165 * @command_len: Command length
6166 * @priv_data: Pointer to private data in command
6167 */
6168static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6169 hdd_context_t *hdd_ctx,
6170 uint8_t *command,
6171 uint8_t command_len,
6172 hdd_priv_data_t *priv_data)
6173{
6174 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6175}
6176
Archana Ramachandran393f3792015-11-13 17:13:21 -08006177/**
6178 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6179 * command
6180 * @value: Pointer to SETANTENNAMODE command
6181 * @mode: Pointer to antenna mode
6182 * @reason: Pointer to reason for set antenna mode
6183 *
6184 * This function parses the SETANTENNAMODE command passed in the format
6185 * SETANTENNAMODE<space>mode
6186 *
6187 * Return: 0 for success non-zero for failure
6188 */
6189static int hdd_parse_setantennamode_command(const uint8_t *value)
6190{
6191 const uint8_t *in_ptr = value;
6192 int tmp, v;
6193 char arg1[32];
6194
6195 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6196
6197 /* no argument after the command */
6198 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006199 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006200 return -EINVAL;
6201 }
6202
6203 /* no space after the command */
6204 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006205 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006206 return -EINVAL;
6207 }
6208
6209 /* remove empty spaces */
6210 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6211 in_ptr++;
6212
6213 /* no argument followed by spaces */
6214 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006215 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006216 return -EINVAL;
6217 }
6218
6219 /* get the argument i.e. antenna mode */
6220 v = sscanf(in_ptr, "%31s ", arg1);
6221 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006222 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006223 return -EINVAL;
6224 }
6225
6226 v = kstrtos32(arg1, 10, &tmp);
6227 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006228 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006229 return -EINVAL;
6230 }
6231
6232 return tmp;
6233}
6234
6235/**
6236 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6237 * mask is 2x2 mode
6238 * @hdd_ctx: Pointer to hdd contex
6239 *
6240 * Return: true if supported chain mask 2x2 else false
6241 */
6242static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6243{
6244 /*
6245 * Revisit and the update logic to determine the number
6246 * of TX/RX chains supported in the system when
6247 * antenna sharing per band chain mask support is
6248 * brought in
6249 */
6250 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6251}
6252
6253/**
6254 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6255 * chain mask is 1x1
6256 * @hdd_ctx: Pointer to hdd contex
6257 *
6258 * Return: true if supported chain mask 1x1 else false
6259 */
6260static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6261{
6262 /*
6263 * Revisit and update the logic to determine the number
6264 * of TX/RX chains supported in the system when
6265 * antenna sharing per band chain mask support is
6266 * brought in
6267 */
6268 return (!hdd_ctx->config->enable2x2) ? true : false;
6269}
6270
Nitesh Shahe50711f2017-04-26 16:30:45 +05306271QDF_STATUS hdd_update_smps_antenna_mode(hdd_context_t *hdd_ctx, int mode)
6272{
6273 QDF_STATUS status;
6274 uint8_t smps_mode;
6275 uint8_t smps_enable;
6276
6277 /* Update SME SMPS config */
6278 if (HDD_ANTENNA_MODE_1X1 == mode) {
6279 smps_enable = true;
6280 smps_mode = HDD_SMPS_MODE_STATIC;
6281 } else {
6282 smps_enable = false;
6283 smps_mode = HDD_SMPS_MODE_DISABLED;
6284 }
6285
6286 hdd_debug("Update SME SMPS enable: %d mode: %d",
6287 smps_enable, smps_mode);
6288 status = sme_update_mimo_power_save(
6289 hdd_ctx->hHal, smps_enable, smps_mode, false);
6290 if (QDF_STATUS_SUCCESS != status) {
6291 hdd_err("Update SMPS config failed enable: %d mode: %d"
6292 "status: %d",
6293 smps_enable, smps_mode, status);
6294 return QDF_STATUS_E_FAILURE;
6295 }
6296
6297 hdd_ctx->current_antenna_mode = mode;
6298 /*
6299 * Update the user requested nss in the mac context.
6300 * This will be used in tdls protocol engine to form tdls
6301 * Management frames.
6302 */
6303 sme_update_user_configured_nss(
6304 hdd_ctx->hHal,
6305 hdd_ctx->current_antenna_mode);
6306
6307 hdd_debug("Successfully switched to mode: %d x %d",
6308 hdd_ctx->current_antenna_mode,
6309 hdd_ctx->current_antenna_mode);
6310
6311 return QDF_STATUS_SUCCESS;
6312}
6313
Archana Ramachandran393f3792015-11-13 17:13:21 -08006314/**
6315 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6316 * handler
6317 * @adapter: Pointer to network adapter
6318 * @hdd_ctx: Pointer to hdd context
6319 * @command: Pointer to input command
6320 * @command_len: Command length
6321 * @priv_data: Pointer to private data in command
6322 */
6323static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6324 hdd_context_t *hdd_ctx,
6325 uint8_t *command,
6326 uint8_t command_len,
6327 hdd_priv_data_t *priv_data)
6328{
6329 struct sir_antenna_mode_param params;
6330 QDF_STATUS status;
6331 int ret = 0;
6332 int mode;
6333 uint8_t *value = command;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006334
6335 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6336 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6337 hdd_err("Operation invalid in non sta or concurrent mode");
6338 ret = -EPERM;
6339 goto exit;
6340 }
6341
6342 mode = hdd_parse_setantennamode_command(value);
6343 if (mode < 0) {
6344 hdd_err("Invalid SETANTENNA command");
6345 ret = mode;
6346 goto exit;
6347 }
6348
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006349 hdd_debug("Processing antenna mode switch to: %d", mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006350
6351 if (hdd_ctx->current_antenna_mode == mode) {
6352 hdd_err("System already in the requested mode");
6353 ret = 0;
6354 goto exit;
6355 }
6356
6357 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6358 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6359 hdd_err("System does not support 2x2 mode");
6360 ret = -EPERM;
6361 goto exit;
6362 }
6363
6364 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6365 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6366 hdd_err("System only supports 1x1 mode");
6367 ret = 0;
6368 goto exit;
6369 }
6370
6371 switch (mode) {
6372 case HDD_ANTENNA_MODE_1X1:
6373 params.num_rx_chains = 1;
6374 params.num_tx_chains = 1;
6375 break;
6376 case HDD_ANTENNA_MODE_2X2:
6377 params.num_rx_chains = 2;
6378 params.num_tx_chains = 2;
6379 break;
6380 default:
6381 hdd_err("unsupported antenna mode");
6382 ret = -EINVAL;
6383 goto exit;
6384 }
6385
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006386 /* Check TDLS status and update antenna mode */
6387 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006388 policy_mgr_is_sta_active_connection_exists(
6389 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006390 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6391 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006392 if (0 != ret)
6393 goto exit;
6394 }
6395
Archana Ramachandran393f3792015-11-13 17:13:21 -08006396 params.set_antenna_mode_resp =
6397 (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006398 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006399 params.num_rx_chains,
6400 params.num_tx_chains);
6401
6402
6403 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6404 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6405 if (QDF_STATUS_SUCCESS != status) {
6406 hdd_err("set antenna mode failed status : %d", status);
6407 ret = -EFAULT;
6408 goto exit;
6409 }
6410
6411 ret = wait_for_completion_timeout(
6412 &hdd_ctx->set_antenna_mode_cmpl,
6413 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6414 if (!ret) {
6415 ret = -EFAULT;
6416 hdd_err("send set antenna mode timed out");
6417 goto exit;
6418 }
6419
Nitesh Shahe50711f2017-04-26 16:30:45 +05306420 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006421 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006422 ret = -EFAULT;
6423 goto exit;
6424 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006425 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006426exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006427#ifdef FEATURE_WLAN_TDLS
6428 /* Reset tdls NSS flags */
6429 if (hdd_ctx->tdls_nss_switch_in_progress &&
6430 hdd_ctx->tdls_nss_teardown_complete) {
6431 hdd_ctx->tdls_nss_switch_in_progress = false;
6432 hdd_ctx->tdls_nss_teardown_complete = false;
6433 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006434 hdd_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
Kabilan Kannanff89f742016-08-15 18:14:10 -07006435 hdd_ctx->tdls_nss_switch_in_progress,
6436 hdd_ctx->tdls_nss_teardown_complete);
6437#endif
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006438 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006439 ret, hdd_ctx->current_antenna_mode);
6440 return ret;
6441
6442}
6443
6444/**
6445 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6446 * handler
6447 * @adapter: Pointer to hdd adapter
6448 * @hdd_ctx: Pointer to hdd context
6449 * @command: Pointer to input command
6450 * @command_len: length of the command
6451 * @priv_data: private data coming with the driver command
6452 *
6453 * Return: 0 for success non-zero for failure
6454 */
6455static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6456 hdd_context_t *hdd_ctx,
6457 uint8_t *command,
6458 uint8_t command_len,
6459 hdd_priv_data_t *priv_data)
6460{
6461 uint32_t antenna_mode = 0;
6462 char extra[32];
6463 uint8_t len = 0;
6464
6465 antenna_mode = hdd_ctx->current_antenna_mode;
6466 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6467 antenna_mode);
6468 len = QDF_MIN(priv_data->total_len, len + 1);
6469 if (copy_to_user(priv_data->buf, &extra, len)) {
6470 hdd_err("Failed to copy data to user buffer");
6471 return -EFAULT;
6472 }
6473
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006474 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006475
6476 return 0;
6477}
6478
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006479/*
6480 * dummy (no-op) hdd driver command handler
6481 */
6482static int drv_cmd_dummy(hdd_adapter_t *adapter,
6483 hdd_context_t *hdd_ctx,
6484 uint8_t *command,
6485 uint8_t command_len,
6486 hdd_priv_data_t *priv_data)
6487{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006488 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006489 adapter->dev->name, command);
6490 return 0;
6491}
6492
6493/*
6494 * handler for any unsupported wlan hdd driver command
6495 */
6496static int drv_cmd_invalid(hdd_adapter_t *adapter,
6497 hdd_context_t *hdd_ctx,
6498 uint8_t *command,
6499 uint8_t command_len,
6500 hdd_priv_data_t *priv_data)
6501{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306502 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006503 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6504 adapter->sessionId, 0));
6505
6506 hdd_warn("%s: Unsupported driver command \"%s\"",
6507 adapter->dev->name, command);
6508
6509 return -ENOTSUPP;
6510}
6511
6512/**
6513 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6514 * @adapter: HDD adapter
6515 * @hdd_ctx: HDD context
6516 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6517 * @command_len: command len
6518 * @priv_data: private data
6519 *
6520 * Return: status
6521 */
6522static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6523 hdd_context_t *hdd_ctx,
6524 uint8_t *command,
6525 uint8_t command_len,
6526 hdd_priv_data_t *priv_data)
6527{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306528 QDF_STATUS status;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006529 uint8_t fcc_constraint;
6530 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006531
6532 /*
6533 * this command would be called by user-space when it detects WLAN
6534 * ON after airplane mode is set. When APM is set, WLAN turns off.
6535 * But it can be turned back on. Otherwise; when APM is turned back
6536 * off, WLAN would turn back on. So at that point the command is
6537 * expected to come down. 0 means disable, 1 means enable. The
6538 * constraint is removed when parameter 1 is set or different
6539 * country code is set
6540 */
6541
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006542 err = kstrtou8(command + command_len + 1, 10, &fcc_constraint);
6543 if (err) {
6544 hdd_err("error %d parsing userspace fcc parameter", err);
6545 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006546 }
6547
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006548 status = ucfg_reg_set_fcc_constraint(hdd_ctx->hdd_pdev,
6549 fcc_constraint);
6550
6551 if (QDF_IS_STATUS_ERROR(status))
6552 hdd_err("Failed to %s tx power for channels 12/13",
6553 fcc_constraint ? "reduce" : "restore");
6554
6555 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006556}
6557
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306558/**
6559 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6560 * command
6561 * @value: Pointer to the command
6562 * @chan_number: Pointer to the channel number
6563 * @chan_bw: Pointer to the channel bandwidth
6564 *
6565 * Parses and provides the channel number and channel width from the input
6566 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6567 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6568 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6569 *
6570 * Return: 0 for success, non-zero for failure
6571 */
6572static int hdd_parse_set_channel_switch_command(uint8_t *value,
6573 uint32_t *chan_number,
6574 uint32_t *chan_bw)
6575{
6576 const uint8_t *in_ptr = value;
6577 int ret;
6578
6579 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6580
6581 /* no argument after the command */
6582 if (NULL == in_ptr) {
6583 hdd_err("No argument after the command");
6584 return -EINVAL;
6585 }
6586
6587 /* no space after the command */
6588 if (SPACE_ASCII_VALUE != *in_ptr) {
6589 hdd_err("No space after the command ");
6590 return -EINVAL;
6591 }
6592
6593 /* remove empty spaces and move the next argument */
6594 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6595 in_ptr++;
6596
6597 /* no argument followed by spaces */
6598 if ('\0' == *in_ptr) {
6599 hdd_err("No argument followed by spaces");
6600 return -EINVAL;
6601 }
6602
6603 /* get the two arguments: channel number and bandwidth */
6604 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6605 if (ret != 2) {
6606 hdd_err("Arguments retrieval from cmd string failed");
6607 return -EINVAL;
6608 }
6609
6610 return 0;
6611}
6612
6613/**
6614 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6615 * @adapter: HDD adapter
6616 * @hdd_ctx: HDD context
6617 * @command: Pointer to the input command CHANNEL_SWITCH
6618 * @command_len: Command len
6619 * @priv_data: Private data
6620 *
6621 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6622 * of SAP/P2P-GO
6623 *
6624 * Return: 0 for success, non-zero for failure
6625 */
6626static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
6627 hdd_context_t *hdd_ctx,
6628 uint8_t *command,
6629 uint8_t command_len,
6630 hdd_priv_data_t *priv_data)
6631{
6632 struct net_device *dev = adapter->dev;
6633 int status;
6634 uint32_t chan_number = 0, chan_bw = 0;
6635 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006636 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306637
Krunal Sonibe766b02016-03-10 13:00:44 -08006638 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6639 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306640 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6641 adapter->device_mode);
6642 return -EINVAL;
6643 }
6644
6645 status = hdd_parse_set_channel_switch_command(value,
6646 &chan_number, &chan_bw);
6647 if (status) {
6648 hdd_err("Invalid CHANNEL_SWITCH command");
6649 return status;
6650 }
6651
6652 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6653 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6654 return -EINVAL;
6655 }
6656
6657 if (chan_bw == 80)
6658 width = CH_WIDTH_80MHZ;
6659 else if (chan_bw == 40)
6660 width = CH_WIDTH_40MHZ;
6661 else
6662 width = CH_WIDTH_20MHZ;
6663
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006664 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306665
6666 status = hdd_softap_set_channel_change(dev, chan_number, width);
6667 if (status) {
6668 hdd_err("Set channel change fail");
6669 return status;
6670 }
6671
6672 return 0;
6673}
6674
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006675/*
6676 * The following table contains all supported WLAN HDD
6677 * IOCTL driver commands and the handler for each of them.
6678 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07006679static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006680 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
6681 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
6682 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
6683 {"SETBAND", drv_cmd_set_band},
6684 {"SETWMMPS", drv_cmd_set_wmmps},
6685 {"COUNTRY", drv_cmd_country},
6686 {"SETSUSPENDMODE", drv_cmd_dummy},
6687 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
6688 {"BTCOEXSCAN", drv_cmd_dummy},
6689 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006690 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
6691 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
6692 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
6693 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
6694 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
6695 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006696 {"SETROAMMODE", drv_cmd_set_roam_mode},
6697 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006698 {"SETROAMDELTA", drv_cmd_set_roam_delta},
6699 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006700 {"GETBAND", drv_cmd_get_band},
6701 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
6702 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
6703 {"GETCCXMODE", drv_cmd_get_ccx_mode},
6704 {"GETOKCMODE", drv_cmd_get_okc_mode},
6705 {"GETFASTROAM", drv_cmd_get_fast_roam},
6706 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
6707 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
6708 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
6709 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
6710 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
6711 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
6712 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
6713 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
6714 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
6715 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
6716 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
6717 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
6718 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
6719 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
6720 {"REASSOC", drv_cmd_reassoc},
6721 {"SETWESMODE", drv_cmd_set_wes_mode},
6722 {"GETWESMODE", drv_cmd_get_wes_mode},
6723 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
6724 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
6725 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
6726 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006727 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006728 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
6729 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006730 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006731 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006732 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
6733 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
6734 {"SCAN-ACTIVE", drv_cmd_scan_active},
6735 {"SCAN-PASSIVE", drv_cmd_scan_passive},
6736 {"GETDWELLTIME", drv_cmd_get_dwell_time},
6737 {"SETDWELLTIME", drv_cmd_set_dwell_time},
6738 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08006739 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
6740 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
6741 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
6742 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
6743 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
6744 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
6745 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006746#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006747 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
6748 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
6749 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006750 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
6751 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
6752 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006753#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006754 {"SETMCRATE", drv_cmd_set_mc_rate},
6755 {"MAXTXPOWER", drv_cmd_max_tx_power},
6756 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
6757 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
6758 {"GETLINKSTATUS", drv_cmd_get_link_status},
6759#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6760 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
6761 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
6762 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
6763#endif
6764#ifdef FEATURE_WLAN_TDLS
6765 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
6766 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
6767 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
6768 {"TDLSSCAN", drv_cmd_tdls_scan},
6769#endif
6770 {"RSSI", drv_cmd_get_rssi},
6771 {"LINKSPEED", drv_cmd_get_linkspeed},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006772 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
6773 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
6774 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306775 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08006776 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
6777 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006778};
6779
6780/**
6781 * hdd_drv_cmd_process() - chooses and runs the proper
6782 * handler based on the input command
6783 * @adapter: Pointer to the hdd adapter
6784 * @cmd: Pointer to the driver command
6785 * @priv_data: Pointer to the data associated with the command
6786 *
6787 * This function parses the input hdd driver command and runs
6788 * the proper handler
6789 *
6790 * Return: 0 for success non-zero for failure
6791 */
6792static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
6793 uint8_t *cmd,
6794 hdd_priv_data_t *priv_data)
6795{
6796 hdd_context_t *hdd_ctx;
6797 int i;
6798 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6799 uint8_t *cmd_i = NULL;
6800 hdd_drv_cmd_handler_t handler = NULL;
6801 int len = 0;
6802
6803 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006804 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006805 return -EINVAL;
6806 }
6807
6808 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
6809
6810 for (i = 0; i < cmd_num_total; i++) {
6811
6812 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6813 handler = hdd_drv_cmds[i].handler;
6814 len = strlen(cmd_i);
6815
6816 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006817 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006818 return -EINVAL;
6819 }
6820
6821 if (strncasecmp(cmd, cmd_i, len) == 0)
6822 return handler(adapter, hdd_ctx,
6823 cmd, len, priv_data);
6824 }
6825
6826 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6827}
6828
6829/**
6830 * hdd_driver_command() - top level wlan hdd driver command handler
6831 * @adapter: Pointer to the hdd adapter
6832 * @priv_data: Pointer to the raw command data
6833 *
6834 * This function is the top level wlan hdd driver command handler. It
6835 * handles the command with the help of hdd_drv_cmd_process()
6836 *
6837 * Return: 0 for success non-zero for failure
6838 */
6839static int hdd_driver_command(hdd_adapter_t *adapter,
6840 hdd_priv_data_t *priv_data)
6841{
6842 uint8_t *command = NULL;
6843 int ret = 0;
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306844 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006845
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306846 ENTER();
6847
Anurag Chouhan6d760662016-02-20 16:05:43 +05306848 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006849 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006850 return -EINVAL;
6851 }
6852
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306853 ret = wlan_hdd_validate_context(hdd_ctx);
6854 if (ret)
6855 return ret;
6856
6857 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
6858 hdd_err("Driver module is closed; command can not be processed");
6859 return -EINVAL;
6860 }
6861
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006862 /*
6863 * Note that valid pointers are provided by caller
6864 */
6865
6866 /* copy to local struct to avoid numerous changes to legacy code */
6867 if (priv_data->total_len <= 0 ||
6868 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006869 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006870 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006871 ret = -EINVAL;
6872 goto exit;
6873 }
6874
6875 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006876 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006877 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006878 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006879 ret = -ENOMEM;
6880 goto exit;
6881 }
6882
6883 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6884 ret = -EFAULT;
6885 goto exit;
6886 }
6887
6888 /* Make sure the command is NUL-terminated */
6889 command[priv_data->total_len] = '\0';
6890
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006891 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006892 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6893
6894exit:
6895 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006896 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306897 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006898 return ret;
6899}
6900
6901#ifdef CONFIG_COMPAT
6902static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6903{
6904 struct {
6905 compat_uptr_t buf;
6906 int used_len;
6907 int total_len;
6908 } compat_priv_data;
6909 hdd_priv_data_t priv_data;
6910 int ret = 0;
6911
6912 /*
6913 * Note that adapter and ifr have already been verified by caller,
6914 * and HDD context has also been validated
6915 */
6916 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
6917 sizeof(compat_priv_data))) {
6918 ret = -EFAULT;
6919 goto exit;
6920 }
6921 priv_data.buf = compat_ptr(compat_priv_data.buf);
6922 priv_data.used_len = compat_priv_data.used_len;
6923 priv_data.total_len = compat_priv_data.total_len;
6924 ret = hdd_driver_command(adapter, &priv_data);
6925exit:
6926 return ret;
6927}
6928#else /* CONFIG_COMPAT */
6929static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6930{
6931 /* will never be invoked */
6932 return 0;
6933}
6934#endif /* CONFIG_COMPAT */
6935
6936static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6937{
6938 hdd_priv_data_t priv_data;
6939 int ret = 0;
6940
6941 /*
6942 * Note that adapter and ifr have already been verified by caller,
6943 * and HDD context has also been validated
6944 */
6945 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
6946 ret = -EFAULT;
6947 else
6948 ret = hdd_driver_command(adapter, &priv_data);
6949
6950 return ret;
6951}
6952
6953/**
6954 * __hdd_ioctl() - ioctl handler for wlan network interfaces
6955 * @dev: device upon which the ioctl was received
6956 * @ifr: ioctl request information
6957 * @cmd: ioctl command
6958 *
6959 * This function does initial processing of wlan device ioctls.
6960 * Currently two flavors of ioctls are supported. The primary ioctl
6961 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
6962 * for Android "DRIVER" commands. The other ioctl that is
6963 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
6964 * for FTM on some platforms. This function simply verifies that the
6965 * driver is in a sane state, and that the ioctl is one of the
6966 * supported flavors, in which case flavor-specific handlers are
6967 * dispatched.
6968 *
6969 * Return: 0 on success, non-zero on error
6970 */
6971static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
6972{
6973 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
6974 hdd_context_t *hdd_ctx;
6975 int ret;
6976
Jeff Johnson3c3994a2016-02-11 08:12:30 -08006977 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306978
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006979 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006980 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006981 ret = -ENODEV;
6982 goto exit;
6983 }
6984
6985 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006986 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006987 ret = -EINVAL;
6988 goto exit;
6989 }
6990#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05306991 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006992 if (SIOCIOCTLTX99 == cmd) {
6993 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
6994 goto exit;
6995 }
6996 }
6997#endif
6998
6999 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7000 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307001 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007002 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007003
7004 switch (cmd) {
7005 case (SIOCDEVPRIVATE + 1):
7006 if (is_compat_task())
7007 ret = hdd_driver_compat_ioctl(adapter, ifr);
7008 else
7009 ret = hdd_driver_ioctl(adapter, ifr);
7010 break;
7011 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007012 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007013 ret = -EINVAL;
7014 break;
7015 }
7016exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307017 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007018 return ret;
7019}
7020
7021/**
7022 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7023 * @dev: device upon which the ioctl was received
7024 * @ifr: ioctl request information
7025 * @cmd: ioctl command
7026 *
7027 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7028 * which is where the ioctls are really handled.
7029 *
7030 * Return: 0 on success, non-zero on error
7031 */
7032int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7033{
7034 int ret;
7035
7036 cds_ssr_protect(__func__);
7037 ret = __hdd_ioctl(dev, ifr, cmd);
7038 cds_ssr_unprotect(__func__);
7039 return ret;
7040}