blob: f79fe9763778340f785c70c93ee76489505f76a4 [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,
Jeff Johnson621cf972017-08-28 11:58:44 -0700116 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800117 uint8_t *cmd,
118 uint8_t cmd_name_len,
Jeff Johnson353cd292017-08-17 06:47:26 -0700119 struct hdd_priv_data *priv_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800120
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530121/**
122 * struct hdd_drv_cmd - Structure to store ioctl command handling info
123 * @cmd: Name of the command
124 * @handler: Command handler to be invoked
125 * @args: Set to true if command expects input parameters
126 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700127struct hdd_drv_cmd {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800128 const char *cmd;
129 hdd_drv_cmd_handler_t handler;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530130 bool args;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700131};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800132
133#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
134#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
135#define WLAN_HDD_MAX_TCP_PORT 65535
136#endif
137
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800138static uint16_t cesium_pid;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800139
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530140/**
141 * drv_cmd_validate() - Validates for space in hdd driver command
142 * @command: pointer to input data (its a NULL terminated string)
143 * @len: length of command name
144 *
145 * This function checks for space after command name and if no space
146 * is found returns error.
147 *
148 * Return: 0 for success non-zero for failure
149 */
150static int drv_cmd_validate(uint8_t *command, int len)
151{
152 if (command[len] != ' ')
153 return -EINVAL;
154
155 return 0;
156}
157
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800158#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800159struct tsm_priv {
160 tAniTrafStrmMetrics tsm_metrics;
161};
162
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800163static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
164 const uint32_t staId, void *context)
165{
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800166 struct hdd_request *request;
167 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800168
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800169 request = hdd_request_get(context);
170 if (!request) {
171 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800172 return;
173 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800174 priv = hdd_request_priv(request);
175 priv->tsm_metrics = tsm_metrics;
176 hdd_request_complete(request);
177 hdd_request_put(request);
178 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800179
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800180}
181
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800182static int hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800183 const uint8_t tid,
184 tAniTrafStrmMetrics *tsm_metrics)
185{
Jeff Johnson621cf972017-08-28 11:58:44 -0700186 struct hdd_context *hdd_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800187 hdd_station_ctx_t *hdd_sta_ctx;
188 QDF_STATUS status;
189 int ret;
190 void *cookie;
191 struct hdd_request *request;
192 struct tsm_priv *priv;
193 static const struct hdd_request_params params = {
194 .priv_size = sizeof(*priv),
195 .timeout_ms = WLAN_WAIT_TIME_STATS,
196 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800197
198 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700199 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800200 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800201 }
202
203 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
204 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
205
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800206 request = hdd_request_alloc(&params);
207 if (!request) {
208 hdd_err("Request allocation failure");
209 return -ENOMEM;
210 }
211 cookie = hdd_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800212
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800213 status = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
214 hdd_sta_ctx->conn_info.staId[0],
215 hdd_sta_ctx->conn_info.bssId,
216 cookie, hdd_ctx->pcds_context, tid);
217 if (QDF_STATUS_SUCCESS != status) {
218 hdd_err("Unable to retrieve tsm statistics");
219 ret = qdf_status_to_os_return(status);
220 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800221 }
222
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800223 ret = hdd_request_wait_for_response(request);
224 if (ret) {
225 hdd_err("SME timed out while retrieving tsm statistics");
226 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800227 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800228
229 priv = hdd_request_priv(request);
230 *tsm_metrics = priv->tsm_metrics;
231
232 cleanup:
233 hdd_request_put(request);
234
235 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800236}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800237#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800238
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800239/* Function header is left blank intentionally */
240static int hdd_parse_setrmcenable_command(uint8_t *pValue,
241 uint8_t *pRmcEnable)
242{
243 uint8_t *inPtr = pValue;
244 int tempInt;
245 int v = 0;
246 char buf[32];
247 *pRmcEnable = 0;
248
249 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
250
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700251 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800252 return 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700253 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800254 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800255
256 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
257 inPtr++;
258
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700259 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800260 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800261
Ashish Kumar Dhanotiya9cd0d7c2017-08-02 17:08:05 +0530262 v = sscanf(inPtr, "%31s ", buf);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700263 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800264 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700265
266 v = kstrtos32(buf, 10, &tempInt);
267 if (v < 0)
268 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800269
270 *pRmcEnable = tempInt;
271
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800272 hdd_debug("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800273
274 return 0;
275}
276
277/* Function header is left blank intentionally */
278static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
279 uint32_t *pActionPeriod)
280{
281 uint8_t *inPtr = pValue;
282 int tempInt;
283 int v = 0;
284 char buf[32];
285 *pActionPeriod = 0;
286
287 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
288
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700289 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800290 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700291 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800292 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800293
294 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
295 inPtr++;
296
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700297 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800298 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800299
Ashish Kumar Dhanotiya9cd0d7c2017-08-02 17:08:05 +0530300 v = sscanf(inPtr, "%31s ", buf);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700301 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800302 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700303
304 v = kstrtos32(buf, 10, &tempInt);
305 if (v < 0)
306 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800307
308 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700309 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800310 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800311
312 *pActionPeriod = tempInt;
313
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800314 hdd_debug("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800315
316 return 0;
317}
318
319/* Function header is left blank intentionally */
320static int hdd_parse_setrmcrate_command(uint8_t *pValue,
321 uint32_t *pRate,
322 tTxrateinfoflags *pTxFlags)
323{
324 uint8_t *inPtr = pValue;
325 int tempInt;
326 int v = 0;
327 char buf[32];
328 *pRate = 0;
329 *pTxFlags = 0;
330
331 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
332
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700333 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800334 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700335 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800336 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800337
338 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
339 inPtr++;
340
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700341 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800342 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800343
Ashish Kumar Dhanotiyabfe639f2017-06-12 18:34:34 +0530344 v = sscanf(inPtr, "%31s ", buf);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700345 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800346 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700347
348 v = kstrtos32(buf, 10, &tempInt);
349 if (v < 0)
350 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800351
352 switch (tempInt) {
353 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700354 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800355 return -EINVAL;
356 case 0:
357 case 6:
358 case 9:
359 case 12:
360 case 18:
361 case 24:
362 case 36:
363 case 48:
364 case 54:
365 *pTxFlags = eHAL_TX_RATE_LEGACY;
366 *pRate = tempInt * 10;
367 break;
368 case 65:
369 *pTxFlags = eHAL_TX_RATE_HT20;
370 *pRate = tempInt * 10;
371 break;
372 case 72:
373 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
374 *pRate = 722;
375 break;
376 }
377
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800378 hdd_debug("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800379
380 return 0;
381}
382
383/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700384 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
385 * @UserData: Adapter private data
386 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800387 *
388 * This is an asynchronous callback function from SME when the peer info
389 * is received
390 *
391 * Return: 0 for success non-zero for failure
392 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700393void
394hdd_get_ibss_peer_info_cb(void *pUserData,
395 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800396{
397 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800398 hdd_station_ctx_t *pStaCtx;
399 uint8_t i;
400
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800401 if ((NULL == adapter) ||
402 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800403 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800404 return;
405 }
406
407 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
408 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700409 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530410 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
411 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700412 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530413 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800414 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530415 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
416 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
417
418 for (i = 0; i < pPeerInfo->numPeers; i++)
419 pStaCtx->ibss_peer_info.peerInfoParams[i] =
420 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800421 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800422 hdd_debug("peerInfo %s: status %u, numPeers %u",
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530423 pPeerInfo ? "valid" : "null",
424 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
425 pPeerInfo ? pPeerInfo->numPeers : 0);
426 pStaCtx->ibss_peer_info.numPeers = 0;
427 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800428 }
429
430 complete(&adapter->ibss_peer_info_comp);
431}
432
433/**
434 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
435 * @adapter: Adapter context
436 *
437 * Request function to get IBSS peer info from lower layers
438 *
439 * Return: 0 for success non-zero for failure
440 */
441static
442QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
443{
444 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
445 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
446 unsigned long rc;
447
448 INIT_COMPLETION(adapter->ibss_peer_info_comp);
449
450 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700451 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800452 true, 0xFF);
453
454 if (QDF_STATUS_SUCCESS == retStatus) {
455 rc = wait_for_completion_timeout
456 (&adapter->ibss_peer_info_comp,
457 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
458
459 /* status will be 0 if timed out */
460 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700461 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800462 retStatus = QDF_STATUS_E_FAILURE;
463 return retStatus;
464 }
465 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700466 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800467 }
468
469 return retStatus;
470}
471
472/**
473 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
474 * @adapter: Adapter context
475 * @staIdx: Sta index for which the peer info is requested
476 *
477 * Request function to get IBSS peer info from lower layers
478 *
479 * Return: 0 for success non-zero for failure
480 */
481static QDF_STATUS
482hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
483{
484 unsigned long rc;
485 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
486 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
487
488 INIT_COMPLETION(adapter->ibss_peer_info_comp);
489
490 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700491 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800492 false, staIdx);
493
494 if (QDF_STATUS_SUCCESS == retStatus) {
495 rc = wait_for_completion_timeout(
496 &adapter->ibss_peer_info_comp,
497 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
498
499 /* status = 0 on timeout */
500 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700501 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800502 retStatus = QDF_STATUS_E_FAILURE;
503 return retStatus;
504 }
505 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700506 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800507 }
508
509 return retStatus;
510}
511
512/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700513static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800514hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
515{
516 uint8_t *inPtr = pValue;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700517
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800518 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
519
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700520 if (NULL == inPtr)
521 return QDF_STATUS_E_FAILURE;
522 else if (SPACE_ASCII_VALUE != *inPtr)
523 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800524
525 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
526 inPtr++;
527
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700528 if ('\0' == *inPtr)
529 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800530
531 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
532 inPtr[11] != ':' || inPtr[14] != ':') {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700533 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800534 }
535 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
536 (unsigned int *)&pPeerMacAddr->bytes[0],
537 (unsigned int *)&pPeerMacAddr->bytes[1],
538 (unsigned int *)&pPeerMacAddr->bytes[2],
539 (unsigned int *)&pPeerMacAddr->bytes[3],
540 (unsigned int *)&pPeerMacAddr->bytes[4],
541 (unsigned int *)&pPeerMacAddr->bytes[5]);
542
543 return QDF_STATUS_SUCCESS;
544}
545
Jeff Johnson621cf972017-08-28 11:58:44 -0700546static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *pBand)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800547{
548 eCsrBand band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700549
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
551 switch (band) {
552 case eCSR_BAND_ALL:
553 *pBand = WLAN_HDD_UI_BAND_AUTO;
554 break;
555
556 case eCSR_BAND_24:
557 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
558 break;
559
560 case eCSR_BAND_5G:
561 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
562 break;
563
564 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700565 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800566 *pBand = -1;
567 break;
568 }
569}
570
571/**
572 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
573 * @data: input data
574 * @target_ap_bssid: pointer to bssid (output parameter)
575 * @channel: pointer to channel (output parameter)
576 *
577 * Return: 0 if parsing is successful; -EINVAL otherwise
578 */
579static int _hdd_parse_bssid_and_chan(const uint8_t **data,
580 uint8_t *bssid,
581 uint8_t *channel)
582{
583 const uint8_t *in_ptr;
584 int v = 0;
585 int temp_int;
586 uint8_t temp_buf[32];
587
588 /* 12 hexa decimal digits, 5 ':' and '\0' */
589 uint8_t mac_addr[18];
590
591 if (!data || !*data)
592 return -EINVAL;
593
594 in_ptr = *data;
595
596 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
597 /* no argument after the command */
598 if (NULL == in_ptr)
599 goto error;
600 /* no space after the command */
601 else if (SPACE_ASCII_VALUE != *in_ptr)
602 goto error;
603
604 /* remove empty spaces */
605 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
606 in_ptr++;
607
608 /* no argument followed by spaces */
609 if ('\0' == *in_ptr)
610 goto error;
611
612 v = sscanf(in_ptr, "%17s", mac_addr);
613 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700614 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
615 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800616 goto error;
617 }
618
619 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
620 hex_to_bin(mac_addr[1]);
621 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
622 hex_to_bin(mac_addr[4]);
623 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
624 hex_to_bin(mac_addr[7]);
625 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
626 hex_to_bin(mac_addr[10]);
627 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
628 hex_to_bin(mac_addr[13]);
629 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
630 hex_to_bin(mac_addr[16]);
631
632 /* point to the next argument */
633 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
634 /* no argument after the command */
635 if (NULL == in_ptr)
636 goto error;
637
638 /* remove empty spaces */
639 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
640 in_ptr++;
641
642 /* no argument followed by spaces */
643 if ('\0' == *in_ptr)
644 goto error;
645
646 /* get the next argument ie the channel number */
647 v = sscanf(in_ptr, "%31s ", temp_buf);
648 if (1 != v)
649 goto error;
650
651 v = kstrtos32(temp_buf, 10, &temp_int);
652 if ((v < 0) || (temp_int < 0) ||
653 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
654 return -EINVAL;
655
656 *channel = temp_int;
657 *data = in_ptr;
658 return 0;
659error:
660 *data = in_ptr;
661 return -EINVAL;
662}
663
664/**
665 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
666 * @pValue: Pointer to input data
667 * @pTargetApBssid: Pointer to target Ap bssid
668 * @pChannel: Pointer to the Target AP channel
669 * @pDwellTime: Pointer to the time to stay off-channel
670 * after transmitting action frame
671 * @pBuf: Pointer to data
672 * @pBufLen: Pointer to data length
673 *
674 * This function parses the send action frame data passed in the format
675 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
676 *
677 * Return: 0 for success non-zero for failure
678 */
679static int
680hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
681 uint8_t *pTargetApBssid,
682 uint8_t *pChannel, uint8_t *pDwellTime,
683 uint8_t **pBuf, uint8_t *pBufLen)
684{
685 const uint8_t *inPtr = pValue;
686 const uint8_t *dataEnd;
687 int tempInt;
688 int j = 0;
689 int i = 0;
690 int v = 0;
691 uint8_t tempBuf[32];
692 uint8_t tempByte = 0;
693
694 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
695 return -EINVAL;
696
697 /* point to the next argument */
698 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
699 /* no argument after the command */
700 if (NULL == inPtr)
701 return -EINVAL;
702 /* removing empty spaces */
703 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
704 inPtr++;
705
706 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700707 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800709
710 /* getting the next argument ie the dwell time */
711 v = sscanf(inPtr, "%31s ", tempBuf);
712 if (1 != v)
713 return -EINVAL;
714
715 v = kstrtos32(tempBuf, 10, &tempInt);
716 if (v < 0 || tempInt < 0)
717 return -EINVAL;
718
719 *pDwellTime = tempInt;
720
721 /* point to the next argument */
722 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
723 /* no argument after the command */
724 if (NULL == inPtr)
725 return -EINVAL;
726 /* removing empty spaces */
727 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
728 inPtr++;
729
730 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700731 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800733
734 /* find the length of data */
735 dataEnd = inPtr;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700736 while (('\0' != *dataEnd))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800737 dataEnd++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700738
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800739 *pBufLen = dataEnd - inPtr;
740 if (*pBufLen <= 0)
741 return -EINVAL;
742
743 /*
744 * Allocate the number of bytes based on the number of input characters
745 * whether it is even or odd.
746 * if the number of input characters are even, then we need N/2 byte.
747 * if the number of input characters are odd, then we need do (N+1)/2
748 * to compensate rounding off.
749 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
750 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
751 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530752 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800753 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700754 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800755 return -ENOMEM;
756 }
757
758 /* the buffer received from the upper layer is character buffer,
759 * we need to prepare the buffer taking 2 characters in to a U8 hex
760 * decimal number for example 7f0000f0...form a buffer to contain 7f
761 * in 0th location, 00 in 1st and f0 in 3rd location
762 */
763 for (i = 0, j = 0; j < *pBufLen; j += 2) {
764 if (j + 1 == *pBufLen) {
765 tempByte = hex_to_bin(inPtr[j]);
766 } else {
767 tempByte =
768 (hex_to_bin(inPtr[j]) << 4) |
769 (hex_to_bin(inPtr[j + 1]));
770 }
771 (*pBuf)[i++] = tempByte;
772 }
773 *pBufLen = i;
774 return 0;
775}
776
777/**
778 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
779 * @pValue: Pointer to input data (its a NULL terminated string)
780 * @pTargetApBssid: Pointer to target Ap bssid
781 * @pChannel: Pointer to the Target AP channel
782 *
783 * This function parses the reasoc command data passed in the format
784 * REASSOC<space><bssid><space><channel>
785 *
786 * Return: 0 for success non-zero for failure
787 */
788static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
789 uint8_t *pTargetApBssid,
790 uint8_t *pChannel)
791{
792 const uint8_t *inPtr = pValue;
793
794 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
795 return -EINVAL;
796
797 return 0;
798}
799
Naveen Rawat05376ee2016-07-18 16:43:32 -0700800#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800801void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter,
802 const tSirMacAddr bssid, int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700803{
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800804 hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
805 tCsrRoamProfile *profile = &wext_state->roamProfile;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700806
Naveen Rawat4195c5e2017-05-22 17:07:45 -0700807 sme_fast_reassoc(WLAN_HDD_GET_HAL_CTX(adapter),
808 profile, bssid, channel, adapter->sessionId);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700809}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700810#endif
811
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800812/**
813 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800814 * @adapter: Adapter upon which the command was received
815 * @bssid: BSSID with which to reassociate
816 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700817 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800818 *
819 * This function performs a userspace-directed reassoc operation
820 *
821 * Return: 0 for success non-zero for failure
822 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700823int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800824 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800825{
826 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnson621cf972017-08-28 11:58:44 -0700827 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800828 int ret = 0;
829
Naveen Rawat05376ee2016-07-18 16:43:32 -0700830 if (hdd_ctx == NULL) {
831 hdd_err("Invalid hdd ctx");
832 return -EINVAL;
833 }
834
Krunal Sonibe766b02016-03-10 13:00:44 -0800835 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800836 hdd_warn("Unsupported in mode %s(%d)",
837 hdd_device_mode_to_string(adapter->device_mode),
838 adapter->device_mode);
839 return -EINVAL;
840 }
841
842 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
843
844 /* if not associated, no need to proceed with reassoc */
845 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800846 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847 ret = -EINVAL;
848 goto exit;
849 }
850
851 /*
852 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800853 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 */
855 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530856 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800857 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800858 channel = pHddStaCtx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859 }
860
861 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530862 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800863 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800864 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800865 ret = -EINVAL;
866 goto exit;
867 }
868
869 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700870 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800871 hdd_wma_send_fastreassoc_cmd(adapter,
Naveen Rawat05376ee2016-07-18 16:43:32 -0700872 bssid, (int)channel);
873 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800874 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875
876 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700877 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530878 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800879 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
880 &handoffInfo);
881 }
882exit:
883 return ret;
884}
885
886/**
887 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
888 * @adapter: Adapter upon which the command was received
889 * @command: ASCII text command that was received
890 *
891 * This function parses the v1 REASSOC command with the format
892 *
893 * REASSOC xx:xx:xx:xx:xx:xx CH
894 *
895 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
896 * BSSID and CH is the ASCII representation of the channel. For
897 * example
898 *
899 * REASSOC 00:0a:0b:11:22:33 48
900 *
901 * Return: 0 for success non-zero for failure
902 */
903static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
904{
905 uint8_t channel = 0;
906 tSirMacAddr bssid;
907 int ret;
908
909 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700910 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700911 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700912 else
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700913 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700914
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800915 return ret;
916}
917
918/**
919 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
920 * @adapter: Adapter upon which the command was received
921 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700922 * followed by binary data
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530923 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924 *
925 * This function parses the v2 REASSOC command with the format
926 *
927 * REASSOC <android_wifi_reassoc_params>
928 *
929 * Return: 0 for success non-zero for failure
930 */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530931static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command,
932 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933{
934 struct android_wifi_reassoc_params params;
935 tSirMacAddr bssid;
936 int ret;
937
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530938 if (total_len < sizeof(params) + 8) {
939 hdd_err("Invalid command length");
940 return -EINVAL;
941 }
942
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800943 /* The params are located after "REASSOC " */
944 memcpy(&params, command + 8, sizeof(params));
945
946 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700947 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800948 ret = -EINVAL;
949 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700950 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951 }
952 return ret;
953}
954
955/**
956 * hdd_parse_reassoc() - parse the REASSOC command
957 * @adapter: Adapter upon which the command was received
958 * @command: Command that was received
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530959 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800960 *
961 * There are two different versions of the REASSOC command. Version 1
962 * of the command contains a parameter list that is ASCII characters
963 * whereas version 2 contains a combination of ASCII and binary
964 * payload. Determine if a version 1 or a version 2 command is being
965 * parsed by examining the parameters, and then dispatch the parser
966 * that is appropriate for the command.
967 *
968 * Return: 0 for success non-zero for failure
969 */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530970static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command,
971 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800972{
973 int ret;
974
975 /* both versions start with "REASSOC "
976 * v1 has a bssid and channel # as an ASCII string
977 * REASSOC xx:xx:xx:xx:xx:xx CH
978 * v2 has a C struct
979 * REASSOC <binary c struct>
980 *
981 * The first field in the v2 struct is also the bssid in ASCII.
982 * But in the case of a v2 message the BSSID is NUL-terminated.
983 * Hence we can peek at that offset to see if this is V1 or V2
984 * REASSOC xx:xx:xx:xx:xx:xx*
985 * 1111111111222222
986 * 01234567890123456789012345
987 */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530988
989 if (total_len < 26) {
990 hdd_err("Invalid command, total_len = %d", total_len);
991 return -EINVAL;
992 }
993
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700994 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800995 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700996 else
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530997 ret = hdd_parse_reassoc_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800998
999 return ret;
1000}
1001
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001002/**
1003 * hdd_sendactionframe() - send a userspace-supplied action frame
1004 * @adapter: Adapter upon which the command was received
1005 * @bssid: BSSID target of the action frame
1006 * @channel: Channel upon which to send the frame
1007 * @dwell_time: Amount of time to dwell when the frame is sent
1008 * @payload_len:Length of the payload
1009 * @payload: Payload of the frame
1010 *
1011 * This function sends a userspace-supplied action frame
1012 *
1013 * Return: 0 for success non-zero for failure
1014 */
1015static int
1016hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1017 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001018 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019{
1020 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001021 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001022 uint8_t *frame;
1023 struct ieee80211_hdr_3addr *hdr;
1024 u64 cookie;
1025 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnson621cf972017-08-28 11:58:44 -07001026 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1028 (tpSirMacVendorSpecificFrameHdr) payload;
1029#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1030 struct cfg80211_mgmt_tx_params params;
1031#endif
1032
Krunal Sonibe766b02016-03-10 13:00:44 -08001033 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034 hdd_warn("Unsupported in mode %s(%d)",
1035 hdd_device_mode_to_string(adapter->device_mode),
1036 adapter->device_mode);
1037 return -EINVAL;
1038 }
1039
1040 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1041 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1042
1043 /* if not associated, no need to send action frame */
1044 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001045 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046 ret = -EINVAL;
1047 goto exit;
1048 }
1049
1050 /*
1051 * if the target bssid is different from currently associated AP,
1052 * then no need to send action frame
1053 */
1054 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301055 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001056 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057 ret = -EINVAL;
1058 goto exit;
1059 }
1060
1061 chan.center_freq = sme_chn_to_freq(channel);
1062 /* Check if it is specific action frame */
1063 if (pVendorSpecific->category ==
1064 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1065 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001066
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301067 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001068 /*
1069 * if the channel number is different from operating
1070 * channel then no need to send action frame
1071 */
1072 if (channel != 0) {
1073 if (channel !=
1074 pHddStaCtx->conn_info.operationChannel) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001075 hdd_warn("channel(%d) is different from operating channel(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001076 channel,
1077 pHddStaCtx->conn_info.
1078 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001079 ret = -EINVAL;
1080 goto exit;
1081 }
1082 /*
1083 * If channel number is specified and same
1084 * as home channel, ensure that action frame
1085 * is sent immediately by cancelling
1086 * roaming scans. Otherwise large dwell times
1087 * may cause long delays in sending action
1088 * frames.
1089 */
1090 sme_abort_roam_scan(hdd_ctx->hHal,
1091 adapter->sessionId);
1092 } else {
1093 /*
1094 * 0 is accepted as current home channel,
1095 * delayed transmission of action frame is ok.
1096 */
1097 chan.center_freq =
1098 sme_chn_to_freq(pHddStaCtx->conn_info.
1099 operationChannel);
1100 }
1101 }
1102 }
1103 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001104 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105 ret = -EINVAL;
1106 goto exit;
1107 }
1108
1109 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301110 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001111 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001112 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001113 ret = -ENOMEM;
1114 goto exit;
1115 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001116
1117 hdr = (struct ieee80211_hdr_3addr *)frame;
1118 hdr->frame_control =
1119 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301120 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1121 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301122 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301123 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1124 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001125
1126#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1127 params.chan = &chan;
1128 params.offchan = 0;
1129 params.wait = dwell_time;
1130 params.buf = frame;
1131 params.len = frame_len;
1132 params.no_cck = 1;
1133 params.dont_wait_for_ack = 1;
1134 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1135#else
1136 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001137 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001138 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001139
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140 dwell_time, frame, frame_len, 1, 1, &cookie);
1141#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1142
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301143 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001144exit:
1145 return ret;
1146}
1147
1148/**
1149 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1150 * SENDACTIONFRAME command
1151 * @adapter: Adapter upon which the command was received
1152 * @command: ASCII text command that was received
1153 *
1154 * This function parses the v1 SENDACTIONFRAME command with the format
1155 *
1156 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1157 *
1158 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1159 * BSSID, CH is the ASCII representation of the channel, DW is the
1160 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1161 * payload. For example
1162 *
1163 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1164 *
1165 * Return: 0 for success non-zero for failure
1166 */
1167static int
1168hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1169{
1170 uint8_t channel = 0;
1171 uint8_t dwell_time = 0;
1172 uint8_t payload_len = 0;
1173 uint8_t *payload = NULL;
1174 tSirMacAddr bssid;
1175 int ret;
1176
1177 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1178 &dwell_time, &payload,
1179 &payload_len);
1180 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001181 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001182 } else {
1183 ret = hdd_sendactionframe(adapter, bssid, channel,
1184 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301185 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001186 }
1187
1188 return ret;
1189}
1190
1191/**
1192 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1193 * SENDACTIONFRAME command
1194 * @adapter: Adapter upon which the command was received
1195 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001196 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001197 *
1198 * This function parses the v2 SENDACTIONFRAME command with the format
1199 *
1200 * SENDACTIONFRAME <android_wifi_af_params>
1201 *
1202 * Return: 0 for success non-zero for failure
1203 */
1204static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001205hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1206 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001207{
1208 struct android_wifi_af_params *params;
1209 tSirMacAddr bssid;
1210 int ret;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301211 int len_wo_payload = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001212
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001213 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001214 total_len -= 16;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301215 len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE;
1216 if (total_len <= len_wo_payload) {
1217 hdd_err("Invalid command len");
1218 return -EINVAL;
1219 }
1220
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001221 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001222
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001223 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301224 (params->len > (total_len - len_wo_payload))) {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001225 hdd_err("Invalid payload length: %d", params->len);
1226 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001227 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001228
1229 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1230 hdd_err("MAC address parsing failed");
1231 return -EINVAL;
1232 }
1233
1234 if (params->channel < 0 ||
1235 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1236 hdd_err("Invalid channel: %d", params->channel);
1237 return -EINVAL;
1238 }
1239
1240 if (params->dwell_time < 0) {
1241 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1242 return -EINVAL;
1243 }
1244
1245 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1246 params->dwell_time, params->len, params->data);
1247
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001248 return ret;
1249}
1250
1251/**
1252 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1253 * @adapter: Adapter upon which the command was received
1254 * @command: Command that was received
1255 *
1256 * There are two different versions of the SENDACTIONFRAME command.
1257 * Version 1 of the command contains a parameter list that is ASCII
1258 * characters whereas version 2 contains a combination of ASCII and
1259 * binary payload. Determine if a version 1 or a version 2 command is
1260 * being parsed by examining the parameters, and then dispatch the
1261 * parser that is appropriate for the version of the command.
1262 *
1263 * Return: 0 for success non-zero for failure
1264 */
1265static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001266hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1267 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001268{
1269 int ret;
1270
1271 /*
1272 * both versions start with "SENDACTIONFRAME "
1273 * v1 has a bssid and other parameters as an ASCII string
1274 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1275 * v2 has a C struct
1276 * SENDACTIONFRAME <binary c struct>
1277 *
1278 * The first field in the v2 struct is also the bssid in ASCII.
1279 * But in the case of a v2 message the BSSID is NUL-terminated.
1280 * Hence we can peek at that offset to see if this is V1 or V2
1281 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1282 * 111111111122222222223333
1283 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001284 * For both the commands, a valid command must have atleast
1285 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001286 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001287 if (total_len < 34) {
1288 hdd_err("Invalid command (total_len=%d)", total_len);
1289 return -EINVAL;
1290 }
1291
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001292 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001293 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001294 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001295 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001296
1297 return ret;
1298}
1299
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001300/**
1301 * hdd_parse_channellist() - HDD Parse channel list
1302 * @pValue: Pointer to input channel list
1303 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001304 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305 * @pNumChannels: Pointer to number of roam scan channels
1306 *
1307 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001308 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1309 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001310 * if the Number of channels (N) does not match with the actual number
1311 * of channels passed then take the minimum of N and count of
1312 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1313 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1314 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1315 * removing duplicate channels from the list
1316 *
1317 * Return: 0 for success non-zero for failure
1318 */
1319static int
1320hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1321 uint8_t *pNumChannels)
1322{
1323 const uint8_t *inPtr = pValue;
1324 int tempInt;
1325 int j = 0;
1326 int v = 0;
1327 char buf[32];
1328
1329 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1330 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001331 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001332 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001333 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001334 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001335
1336 /* remove empty spaces */
1337 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1338 inPtr++;
1339
1340 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001341 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001342 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001343
1344 /* get the first argument ie the number of channels */
1345 v = sscanf(inPtr, "%31s ", buf);
1346 if (1 != v)
1347 return -EINVAL;
1348
1349 v = kstrtos32(buf, 10, &tempInt);
1350 if ((v < 0) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001351 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001352 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001353
1354 *pNumChannels = tempInt;
1355
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001356 hdd_debug("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001357
1358 for (j = 0; j < (*pNumChannels); j++) {
1359 /*
1360 * inPtr pointing to the beginning of first space after number
1361 * of channels
1362 */
1363 inPtr = strpbrk(inPtr, " ");
1364 /* no channel list after the number of channels argument */
1365 if (NULL == inPtr) {
1366 if (0 != j) {
1367 *pNumChannels = j;
1368 return 0;
1369 } else {
1370 return -EINVAL;
1371 }
1372 }
1373
1374 /* remove empty space */
1375 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1376 inPtr++;
1377
1378 /*
1379 * no channel list after the number of channels
1380 * argument and spaces
1381 */
1382 if ('\0' == *inPtr) {
1383 if (0 != j) {
1384 *pNumChannels = j;
1385 return 0;
1386 } else {
1387 return -EINVAL;
1388 }
1389 }
1390
1391 v = sscanf(inPtr, "%31s ", buf);
1392 if (1 != v)
1393 return -EINVAL;
1394
1395 v = kstrtos32(buf, 10, &tempInt);
1396 if ((v < 0) ||
1397 (tempInt <= 0) ||
1398 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1399 return -EINVAL;
1400 }
1401 pChannelList[j] = tempInt;
1402
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001403 hdd_debug("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001404 pChannelList[j]);
1405 }
1406
1407 return 0;
1408}
1409
1410/**
1411 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1412 * SETROAMSCANCHANNELS command
1413 * @adapter: Adapter upon which the command was received
1414 * @command: ASCII text command that was received
1415 *
1416 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1417 *
1418 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1419 *
1420 * Where "N" is the ASCII representation of the number of channels and
1421 * C1 thru Cn is the ASCII representation of the channels. For example
1422 *
1423 * SETROAMSCANCHANNELS 4 36 40 44 48
1424 *
1425 * Return: 0 for success non-zero for failure
1426 */
1427static int
1428hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1429 const char *command)
1430{
1431 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1432 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301433 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001434 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001435 int ret;
1436
1437 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1438 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001439 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001440 goto exit;
1441 }
1442
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301443 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001444 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1445 adapter->sessionId, num_chan));
1446
1447 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001448 hdd_err("number of channels (%d) supported exceeded max (%d)",
1449 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001450 ret = -EINVAL;
1451 goto exit;
1452 }
1453
1454 status =
1455 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1456 adapter->sessionId,
1457 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301458 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001459 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001460 ret = -EINVAL;
1461 goto exit;
1462 }
1463exit:
1464 return ret;
1465}
1466
1467/**
1468 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1469 * SETROAMSCANCHANNELS command
1470 * @adapter: Adapter upon which the command was received
1471 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001472 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001473 *
1474 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1475 *
1476 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1477 *
1478 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1479 * what follows the space is an array of u08 parameters. For example
1480 *
1481 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1482 *
1483 * Return: 0 for success non-zero for failure
1484 */
1485static int
1486hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1487 const char *command)
1488{
1489 const uint8_t *value;
1490 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1491 uint8_t channel;
1492 uint8_t num_chan;
1493 int i;
Jeff Johnson621cf972017-08-28 11:58:44 -07001494 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301495 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496 int ret = 0;
1497
1498 /* array of values begins after "SETROAMSCANCHANNELS " */
1499 value = command + 20;
1500
1501 num_chan = *value++;
1502 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001503 hdd_err("number of channels (%d) supported exceeded max (%d)",
1504 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001505 ret = -EINVAL;
1506 goto exit;
1507 }
1508
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301509 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001510 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1511 adapter->sessionId, num_chan));
1512
1513 for (i = 0; i < num_chan; i++) {
1514 channel = *value++;
1515 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001516 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001517 i, channel);
1518 ret = -EINVAL;
1519 goto exit;
1520 }
1521 channel_list[i] = channel;
1522 }
1523 status =
1524 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1525 adapter->sessionId,
1526 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301527 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001528 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001529 ret = -EINVAL;
1530 goto exit;
1531 }
1532exit:
1533 return ret;
1534}
1535
1536/**
1537 * hdd_parse_set_roam_scan_channels() - parse the
1538 * SETROAMSCANCHANNELS command
1539 * @adapter: Adapter upon which the command was received
1540 * @command: Command that was received
1541 *
1542 * There are two different versions of the SETROAMSCANCHANNELS command.
1543 * Version 1 of the command contains a parameter list that is ASCII
1544 * characters whereas version 2 contains a binary payload. Determine
1545 * if a version 1 or a version 2 command is being parsed by examining
1546 * the parameters, and then dispatch the parser that is appropriate for
1547 * the command.
1548 *
1549 * Return: 0 for success non-zero for failure
1550 */
1551static int
1552hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1553{
1554 const char *cursor;
1555 char ch;
1556 bool v1;
1557 int ret;
1558
1559 /* start after "SETROAMSCANCHANNELS " */
1560 cursor = command + 20;
1561
1562 /* assume we have a version 1 command until proven otherwise */
1563 v1 = true;
1564
1565 /* v1 params will only contain ASCII digits and space */
1566 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001567 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001568 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001569 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001570
1571 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001573 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001575
1576 return ret;
1577}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001578
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001579#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580/**
1581 * hdd_parse_plm_cmd() - HDD Parse Plm command
1582 * @pValue: Pointer to input data
1583 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1584 *
1585 * This function parses the plm command passed in the format
1586 * CCXPLMREQ<space><enable><space><dialog_token><space>
1587 * <meas_token><space><num_of_bursts><space><burst_int><space>
1588 * <measu duration><space><burst_len><space><desired_tx_pwr>
1589 * <space><multcast_addr><space><number_of_channels>
1590 * <space><channel_numbers>
1591 *
1592 * Return: 0 for success non-zero for failure
1593 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001594static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001595{
1596 uint8_t *cmdPtr = NULL;
1597 int count, content = 0, ret = 0;
1598 char buf[32];
1599
1600 /* move to argument list */
1601 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1602 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301603 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001604
1605 /* no space after the command */
1606 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301607 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608
1609 /* remove empty spaces */
1610 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1611 cmdPtr++;
1612
1613 /* START/STOP PLM req */
1614 ret = sscanf(cmdPtr, "%31s ", buf);
1615 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301616 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001617
1618 ret = kstrtos32(buf, 10, &content);
1619 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301620 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001621
1622 pPlmRequest->enable = content;
1623 cmdPtr = strpbrk(cmdPtr, " ");
1624
1625 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301626 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001627
1628 /* remove empty spaces */
1629 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1630 cmdPtr++;
1631
1632 /* Dialog token of radio meas req containing meas reqIE */
1633 ret = sscanf(cmdPtr, "%31s ", buf);
1634 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301635 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001636
1637 ret = kstrtos32(buf, 10, &content);
1638 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301639 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001640
1641 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001642 hdd_debug("diag token %d", pPlmRequest->diag_token);
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 /* measurement token of meas req IE */
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 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001662 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001663
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001664 hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001665 if (pPlmRequest->enable) {
1666
1667 cmdPtr = strpbrk(cmdPtr, " ");
1668
1669 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301670 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001671
1672 /* remove empty spaces */
1673 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1674 cmdPtr++;
1675
1676 /* total number of bursts after which STA stops sending */
1677 ret = sscanf(cmdPtr, "%31s ", buf);
1678 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301679 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001680
1681 ret = kstrtos32(buf, 10, &content);
1682 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301683 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001684
1685 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301686 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001687
1688 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001689 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001690 cmdPtr = strpbrk(cmdPtr, " ");
1691
1692 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301693 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694
1695 /* remove empty spaces */
1696 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1697 cmdPtr++;
1698
1699 /* burst interval in seconds */
1700 ret = sscanf(cmdPtr, "%31s ", buf);
1701 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301702 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001703
1704 ret = kstrtos32(buf, 10, &content);
1705 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301706 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001707
1708 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301709 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001710
1711 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001712 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001713 cmdPtr = strpbrk(cmdPtr, " ");
1714
1715 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301716 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001717
1718 /* remove empty spaces */
1719 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1720 cmdPtr++;
1721
1722 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1723 ret = sscanf(cmdPtr, "%31s ", buf);
1724 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301725 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001726
1727 ret = kstrtos32(buf, 10, &content);
1728 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301729 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730
1731 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301732 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733
1734 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001735 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736 cmdPtr = strpbrk(cmdPtr, " ");
1737
1738 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301739 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740
1741 /* remove empty spaces */
1742 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1743 cmdPtr++;
1744
1745 /* burst length of PLM bursts */
1746 ret = sscanf(cmdPtr, "%31s ", buf);
1747 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301748 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749
1750 ret = kstrtos32(buf, 10, &content);
1751 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301752 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753
1754 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301755 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001756
1757 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001758 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001759 cmdPtr = strpbrk(cmdPtr, " ");
1760
1761 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301762 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763
1764 /* remove empty spaces */
1765 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1766 cmdPtr++;
1767
1768 /* desired tx power for transmission of PLM bursts */
1769 ret = sscanf(cmdPtr, "%31s ", buf);
1770 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301771 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001772
1773 ret = kstrtos32(buf, 10, &content);
1774 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301775 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001776
1777 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301778 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779
1780 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001781 hdd_debug("desiredTxPwr %d",
1782 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783
Anurag Chouhan6d760662016-02-20 16:05:43 +05301784 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001785 cmdPtr = strpbrk(cmdPtr, " ");
1786
1787 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301788 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789
1790 /* remove empty spaces */
1791 while ((SPACE_ASCII_VALUE == *cmdPtr)
1792 && ('\0' != *cmdPtr))
1793 cmdPtr++;
1794
1795 ret = sscanf(cmdPtr, "%31s ", buf);
1796 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301797 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798
1799 ret = kstrtos32(buf, 16, &content);
1800 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301801 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001803 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001804 }
1805
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001806 hdd_debug("MC addr " MAC_ADDRESS_STR,
1807 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808
1809 cmdPtr = strpbrk(cmdPtr, " ");
1810
1811 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301812 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001813
1814 /* remove empty spaces */
1815 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1816 cmdPtr++;
1817
1818 /* number of channels */
1819 ret = sscanf(cmdPtr, "%31s ", buf);
1820 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301821 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001822
1823 ret = kstrtos32(buf, 10, &content);
1824 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301825 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001826
1827 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301828 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001829
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001830 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001831 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001832 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001833
1834 /* Channel numbers */
1835 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1836 cmdPtr = strpbrk(cmdPtr, " ");
1837
1838 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301839 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001840
1841 /* remove empty spaces */
1842 while ((SPACE_ASCII_VALUE == *cmdPtr)
1843 && ('\0' != *cmdPtr))
1844 cmdPtr++;
1845
1846 ret = sscanf(cmdPtr, "%31s ", buf);
1847 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301848 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001849
1850 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001851 if (ret < 0 || content <= 0 ||
1852 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301853 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854
1855 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001856 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857 }
1858 }
1859 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301860 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001861}
1862#endif
1863
1864#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1865static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1866{
Jeff Johnson621cf972017-08-28 11:58:44 -07001867 struct hdd_context *hdd_ctx = (struct hdd_context *) callbackContext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001868 int rc;
1869
1870 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301871 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001872 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001873 hdd_ctx->ext_wow_should_suspend = is_success;
1874 complete(&hdd_ctx->ready_to_extwow);
1875}
1876
1877static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1878 tpSirExtWoWParams arg_params)
1879{
1880 tSirExtWoWParams params;
Jeff Johnson17d62672017-03-27 08:00:11 -07001881 QDF_STATUS qdf_ret_status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001882 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001883 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1884 int rc;
1885
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301886 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887
1888 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1889
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301890 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891 &wlan_hdd_ready_to_extwow,
1892 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301893 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001894 hdd_err("sme_configure_ext_wow returned failure %d",
1895 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001896 return -EPERM;
1897 }
1898
1899 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1900 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1901 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001902 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903 return -EPERM;
1904 }
1905
Jeff Johnson17d62672017-03-27 08:00:11 -07001906 if (!hdd_ctx->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001907 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908 return -EPERM;
1909 }
1910
Jeff Johnson17d62672017-03-27 08:00:11 -07001911 if (hdd_ctx->config->extWowGotoSuspend) {
1912 hdd_info("Received ready to ExtWoW. Going to suspend");
1913
1914 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1915 if (rc < 0) {
1916 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1917 rc);
1918 return rc;
1919 }
1920 rc = wlan_hdd_bus_suspend();
1921 if (rc) {
1922 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1923 rc);
1924 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1925 return rc;
1926 }
1927 }
1928
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001929 return 0;
1930}
1931
1932static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1933 int value)
1934{
1935 tSirExtWoWParams params;
Jeff Johnson621cf972017-08-28 11:58:44 -07001936 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937 int rc;
1938
1939 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301940 if (rc)
1941 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001942
1943 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1944 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001945 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946 return -EINVAL;
1947 }
1948
1949 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1950 hdd_ctx->is_extwow_app_type1_param_set)
1951 params.type = value;
1952 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1953 hdd_ctx->is_extwow_app_type2_param_set)
1954 params.type = value;
1955 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1956 hdd_ctx->is_extwow_app_type1_param_set &&
1957 hdd_ctx->is_extwow_app_type2_param_set)
1958 params.type = value;
1959 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001960 hdd_err("Set app params before enable it value %d",
1961 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962 return -EINVAL;
1963 }
1964
1965 params.vdev_id = vdev_id;
1966 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1967 (hdd_ctx->config->extWowApp2WakeupPinNumber
1968 << 8);
1969
1970 return hdd_enable_ext_wow(adapter, &params);
1971}
1972
1973static int hdd_set_app_type1_params(tHalHandle hHal,
1974 tpSirAppType1Params arg_params)
1975{
1976 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301977 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001978
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301979 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001980
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301981 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1982 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001983 hdd_err("sme_configure_app_type1_params returned failure %d",
1984 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985 return -EPERM;
1986 }
1987
1988 return 0;
1989}
1990
1991static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
1992 char *arg, int len)
1993{
Jeff Johnson621cf972017-08-28 11:58:44 -07001994 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001995 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1996 char id[20], password[20];
1997 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001998 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999
2000 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302001 if (rc)
2002 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003
2004 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002005 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 return -EINVAL;
2007 }
2008
2009 memset(&params, 0, sizeof(tSirAppType1Params));
2010 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302011 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012
2013 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302014 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302016 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002018 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002019 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020 params.identification_id, params.id_length,
2021 params.password, params.pass_length);
2022
2023 return hdd_set_app_type1_params(hHal, &params);
2024}
2025
2026static int hdd_set_app_type2_params(tHalHandle hHal,
2027 tpSirAppType2Params arg_params)
2028{
2029 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302030 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302032 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002033
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302034 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2035 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002036 hdd_err("sme_configure_app_type2_params returned failure %d",
2037 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038 return -EPERM;
2039 }
2040
2041 return 0;
2042}
2043
2044static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2045 char *arg, int len)
2046{
Jeff Johnson621cf972017-08-28 11:58:44 -07002047 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2049 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302050 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051 tSirAppType2Params params;
2052 int ret;
2053
2054 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302055 if (ret)
2056 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002057
2058 memset(&params, 0, sizeof(tSirAppType2Params));
2059
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302060 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 -08002061 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2062 (unsigned int *)&params.ip_device_ip,
2063 (unsigned int *)&params.ip_server_ip,
2064 (unsigned int *)&params.tcp_seq,
2065 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302066 (uint16_t *)&params.tcp_src_port,
2067 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068 (unsigned int *)&params.keepalive_init,
2069 (unsigned int *)&params.keepalive_min,
2070 (unsigned int *)&params.keepalive_max,
2071 (unsigned int *)&params.keepalive_inc,
2072 (unsigned int *)&params.tcp_tx_timeout_val,
2073 (unsigned int *)&params.tcp_rx_timeout_val);
2074
2075 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002076 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002077 return -EINVAL;
2078 }
2079
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002080 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
2081 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2082 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002083 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084 return -EINVAL;
2085 }
2086
2087 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2088 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002089 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002090 return -EINVAL;
2091 }
2092
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302093 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302094 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002095
2096 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302097 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002098
2099 params.vdev_id = adapter->sessionId;
2100 params.tcp_src_port = (params.tcp_src_port != 0) ?
2101 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2102 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2103 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2104 params.keepalive_init = (params.keepalive_init != 0) ?
2105 params.keepalive_init : hdd_ctx->config->
2106 extWowApp2KAInitPingInterval;
2107 params.keepalive_min =
2108 (params.keepalive_min != 0) ?
2109 params.keepalive_min :
2110 hdd_ctx->config->extWowApp2KAMinPingInterval;
2111 params.keepalive_max =
2112 (params.keepalive_max != 0) ?
2113 params.keepalive_max :
2114 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2115 params.keepalive_inc =
2116 (params.keepalive_inc != 0) ?
2117 params.keepalive_inc :
2118 hdd_ctx->config->extWowApp2KAIncPingInterval;
2119 params.tcp_tx_timeout_val =
2120 (params.tcp_tx_timeout_val != 0) ?
2121 params.tcp_tx_timeout_val :
2122 hdd_ctx->config->extWowApp2TcpTxTimeout;
2123 params.tcp_rx_timeout_val =
2124 (params.tcp_rx_timeout_val != 0) ?
2125 params.tcp_rx_timeout_val :
2126 hdd_ctx->config->extWowApp2TcpRxTimeout;
2127
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002128 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002129 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002130 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2131 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2132 params.keepalive_init, params.keepalive_min,
2133 params.keepalive_max, params.keepalive_inc,
2134 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2135
2136 return hdd_set_app_type2_params(hHal, &params);
2137}
2138#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2139
2140/**
2141 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2142 * @pValue: Pointer to MAXTXPOWER command
2143 * @pDbm: Pointer to tx power
2144 *
2145 * This function parses the MAXTXPOWER command passed in the format
2146 * MAXTXPOWER<space>X(Tx power in dbm)
2147 *
2148 * For example input commands:
2149 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2150 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2151 *
2152 * Return: 0 for success non-zero for failure
2153 */
2154static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2155{
2156 uint8_t *inPtr = pValue;
2157 int tempInt;
2158 int v = 0;
2159 *pTxPower = 0;
2160
2161 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2162 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002163 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002164 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002165 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002167
2168 /* remove empty spaces */
2169 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2170 inPtr++;
2171
2172 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002173 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002174 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002175
2176 v = kstrtos32(inPtr, 10, &tempInt);
2177
2178 /* Range checking for passed parameter */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002179 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002180 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002181
2182 *pTxPower = tempInt;
2183
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002184 hdd_debug("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002185
2186 return 0;
2187} /* End of hdd_parse_setmaxtxpower_command */
2188
2189static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2190 char *extra, uint8_t n, uint8_t *len)
2191{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002192 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002193 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002194 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002195 }
2196
2197 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2198 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2199 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002200 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002201 }
2202 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002203 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2204 (int)pCfg->nActiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002205 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002206 }
2207 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002208 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2209 (int)pCfg->nPassiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002210 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002211 }
2212 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002213 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2214 (int)pCfg->nPassiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002215 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002216 }
2217 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002218 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2219 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002220 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002221 }
2222
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002223 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002224}
2225
2226static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2227{
2228 tHalHandle hHal;
2229 struct hdd_config *pCfg;
2230 uint8_t *value = command;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302231 tSmeConfigParams *sme_config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002232 int val = 0, temp = 0;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302233 int retval = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002234
2235 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2236 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2237 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002238 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002239 return -EINVAL;
2240 }
2241
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302242 sme_config = qdf_mem_malloc(sizeof(*sme_config));
2243 if (!sme_config) {
2244 hdd_err("failed to allocate memory for sme_config");
2245 return -ENOMEM;
2246 }
2247 qdf_mem_zero(sme_config, sizeof(*sme_config));
2248 sme_get_config_param(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002249
2250 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302251 if (drv_cmd_validate(command, 23))
2252 return -EINVAL;
2253
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002254 value = value + 24;
2255 temp = kstrtou32(value, 10, &val);
2256 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2257 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002258 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302259 retval = -EFAULT;
2260 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002261 }
2262 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302263 sme_config->csrConfig.nActiveMaxChnTime = val;
2264 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002265 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302266 if (drv_cmd_validate(command, 23))
2267 return -EINVAL;
2268
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002269 value = value + 24;
2270 temp = kstrtou32(value, 10, &val);
2271 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2272 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002273 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302274 retval = -EFAULT;
2275 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002276 }
2277 pCfg->nActiveMinChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302278 sme_config->csrConfig.nActiveMinChnTime = val;
2279 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002280 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302281 if (drv_cmd_validate(command, 24))
2282 return -EINVAL;
2283
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002284 value = value + 25;
2285 temp = kstrtou32(value, 10, &val);
2286 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2287 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002288 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302289 retval = -EFAULT;
2290 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002291 }
2292 pCfg->nPassiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302293 sme_config->csrConfig.nPassiveMaxChnTime = val;
2294 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002295 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302296 if (drv_cmd_validate(command, 24))
2297 return -EINVAL;
2298
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002299 value = value + 25;
2300 temp = kstrtou32(value, 10, &val);
2301 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2302 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002303 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302304 retval = -EFAULT;
2305 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002306 }
2307 pCfg->nPassiveMinChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302308 sme_config->csrConfig.nPassiveMinChnTime = val;
2309 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002310 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302311 if (drv_cmd_validate(command, 12))
2312 return -EINVAL;
2313
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002314 value = value + 13;
2315 temp = kstrtou32(value, 10, &val);
2316 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2317 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002318 hdd_err("argument passed for SETDWELLTIME is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302319 retval = -EFAULT;
2320 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002321 }
2322 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302323 sme_config->csrConfig.nActiveMaxChnTime = val;
2324 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002325 } else {
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302326 retval = -EINVAL;
2327 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002328 }
2329
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302330free:
2331 qdf_mem_free(sme_config);
2332 return retval;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002333}
2334
Jeff Johnson253c0c22017-01-23 16:59:38 -08002335struct link_status_priv {
2336 uint8_t link_status;
2337};
2338
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339static void hdd_get_link_status_cb(uint8_t status, void *context)
2340{
Jeff Johnson253c0c22017-01-23 16:59:38 -08002341 struct hdd_request *request;
2342 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002343
Jeff Johnson253c0c22017-01-23 16:59:38 -08002344 request = hdd_request_get(context);
2345 if (!request) {
2346 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002347 return;
2348 }
2349
Jeff Johnson253c0c22017-01-23 16:59:38 -08002350 priv = hdd_request_priv(request);
2351 priv->link_status = status;
2352 hdd_request_complete(request);
2353 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002354}
2355
2356/**
2357 * wlan_hdd_get_link_status() - get link status
2358 * @pAdapter: pointer to the adapter
2359 *
2360 * This function sends a request to query the link status and waits
2361 * on a timer to invoke the callback. if the callback is invoked then
2362 * latest link status shall be returned or otherwise cached value
2363 * will be returned.
2364 *
2365 * Return: On success, link status shall be returned.
2366 * On error or not associated, link status 0 will be returned.
2367 */
2368static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2369{
2370
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002371 hdd_station_ctx_t *pHddStaCtx =
2372 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302373 QDF_STATUS hstatus;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002374 int ret;
2375 void *cookie;
2376 struct hdd_request *request;
2377 struct link_status_priv *priv;
2378 static const struct hdd_request_params params = {
2379 .priv_size = sizeof(*priv),
2380 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2381 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002382
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05302383 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002384 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2385 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002386 return 0;
2387 }
2388
Krunal Sonibe766b02016-03-10 13:00:44 -08002389 if ((QDF_STA_MODE != adapter->device_mode) &&
2390 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002391 hdd_warn("Unsupported in mode %s(%d)",
2392 hdd_device_mode_to_string(adapter->device_mode),
2393 adapter->device_mode);
2394 return 0;
2395 }
2396
2397 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2398 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2399 /* If not associated, then expected link status return
2400 * value is 0
2401 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002402 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002403 return 0;
2404 }
2405
Jeff Johnson253c0c22017-01-23 16:59:38 -08002406 request = hdd_request_alloc(&params);
2407 if (!request) {
2408 hdd_err("Request allocation failure");
2409 return 0;
2410 }
2411 cookie = hdd_request_cookie(request);
2412
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002413 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2414 hdd_get_link_status_cb,
Jeff Johnson253c0c22017-01-23 16:59:38 -08002415 cookie, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302416 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002417 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002418 /* return a cached value */
2419 } else {
2420 /* request is sent -- wait for the response */
Jeff Johnson253c0c22017-01-23 16:59:38 -08002421 ret = hdd_request_wait_for_response(request);
2422 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002423 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002424 /* return a cached value */
2425 } else {
2426 /* update the adapter with the fresh results */
2427 priv = hdd_request_priv(request);
2428 adapter->linkStatus = priv->link_status;
2429 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002430 }
2431
Jeff Johnson253c0c22017-01-23 16:59:38 -08002432 /*
2433 * either we never sent a request, we sent a request and
2434 * received a response or we sent a request and timed out.
2435 * regardless we are done with the request.
2436 */
2437 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002438
2439 /* either callback updated adapter stats or it has cached data */
2440 return adapter->linkStatus;
2441}
2442
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002443static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2444{
2445 int payload_len;
2446 struct sk_buff *skb;
2447 struct nlmsghdr *nlh;
2448 uint8_t *data;
2449
2450 payload_len = ETH_ALEN;
2451
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002452 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002453 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002454 return;
2455 }
2456
2457 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2458 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002459 hdd_err("nlmsg_new() failed for msg size[%d]",
2460 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002461 return;
2462 }
2463
2464 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2465
2466 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002467 hdd_err("nlmsg_put() failed for msg size[%d]",
2468 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002469
2470 kfree_skb(skb);
2471 return;
2472 }
2473
2474 data = nlmsg_data(nlh);
2475 memcpy(data, MacAddr, ETH_ALEN);
2476
2477 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002478 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2479 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002480 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002481}
2482
2483
2484/**
2485 * hdd_ParseuserParams - return a pointer to the next argument
2486 * @pValue: Input argument string
2487 * @ppArg: Output pointer to the next argument
2488 *
2489 * This function parses argument stream and finds the pointer
2490 * to the next argument
2491 *
2492 * Return: 0 if the next argument found; -EINVAL otherwise
2493 */
2494static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2495{
2496 uint8_t *pVal;
2497
2498 pVal = strnchr(pValue, strlen(pValue), ' ');
2499
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002500 if (NULL == pVal) /* no argument remains */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002501 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002502 else if (SPACE_ASCII_VALUE != *pVal)/* no space after the current arg */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002503 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002504
2505 pVal++;
2506
2507 /* remove empty spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002508 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002509 pVal++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002510
2511 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002512 if ('\0' == *pVal)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002513 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002514
2515 *ppArg = pVal;
2516
2517 return 0;
2518}
2519
2520/**
2521 * hdd_parse_ibsstx_fail_event_params - Parse params
2522 * for SETIBSSTXFAILEVENT
2523 * @pValue: Input ibss tx fail event argument
2524 * @tx_fail_count: (Output parameter) Tx fail counter
2525 * @pid: (Output parameter) PID
2526 *
2527 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2528 */
2529static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2530 uint8_t *tx_fail_count,
2531 uint16_t *pid)
2532{
2533 uint8_t *param = NULL;
2534 int ret;
2535
2536 ret = hdd_parse_user_params(pValue, &param);
2537
2538 if (0 == ret && NULL != param) {
2539 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2540 ret = -EINVAL;
2541 goto done;
2542 }
2543 } else {
2544 goto done;
2545 }
2546
2547 if (0 == *tx_fail_count) {
2548 *pid = 0;
2549 goto done;
2550 }
2551
2552 pValue = param;
2553 pValue++;
2554
2555 ret = hdd_parse_user_params(pValue, &param);
2556
2557 if (0 == ret) {
2558 if (1 != sscanf(param, "%hu", pid)) {
2559 ret = -EINVAL;
2560 goto done;
2561 }
2562 } else {
2563 goto done;
2564 }
2565
2566done:
2567 return ret;
2568}
2569
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002570#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002571/**
2572 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2573 * @pValue: Pointer to data
2574 * @pEseBcnReq: Output pointer to store parsed ie information
2575 *
2576 * This function parses the ese beacon request passed in the format
2577 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2578 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2579 * <space>Scan Mode N<space>Meas Duration N
2580 *
2581 * If the Number of bcn req fields (N) does not match with the
2582 * actual number of fields passed then take N.
2583 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2584 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2585 * This function does not take care of removing duplicate channels from the
2586 * list
2587 *
2588 * Return: 0 for success non-zero for failure
2589 */
2590static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2591 tCsrEseBeaconReq *pEseBcnReq)
2592{
2593 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002594 uint8_t input = 0;
2595 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002596 int j = 0, i = 0, v = 0;
2597 char buf[32];
2598
2599 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002600 if (NULL == inPtr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002601 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002602 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002603 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002604
2605 /* remove empty spaces */
2606 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2607 inPtr++;
2608
2609 /* no argument followed by spaces */
2610 if ('\0' == *inPtr)
2611 return -EINVAL;
2612
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002613 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002614 v = sscanf(inPtr, "%31s ", buf);
2615 if (1 != v)
2616 return -EINVAL;
2617
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002618 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002619 if (v < 0)
2620 return -EINVAL;
2621
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002622 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2623 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002624
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002625 hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002626
2627 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2628 for (i = 0; i < 4; i++) {
2629 /*
2630 * inPtr pointing to the beginning of 1st space
2631 * after number of ie fields
2632 */
2633 inPtr = strpbrk(inPtr, " ");
2634 /* no ie data after the number of ie fields argument */
2635 if (NULL == inPtr)
2636 return -EINVAL;
2637
2638 /* remove empty space */
2639 while ((SPACE_ASCII_VALUE == *inPtr)
2640 && ('\0' != *inPtr))
2641 inPtr++;
2642
2643 /*
2644 * no ie data after the number of ie fields
2645 * argument and spaces
2646 */
2647 if ('\0' == *inPtr)
2648 return -EINVAL;
2649
2650 v = sscanf(inPtr, "%31s ", buf);
2651 if (1 != v)
2652 return -EINVAL;
2653
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002654 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002655 if (v < 0)
2656 return -EINVAL;
2657
2658 switch (i) {
2659 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002660 if (!tempInt) {
2661 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002662 tempInt);
2663 return -EINVAL;
2664 }
2665 pEseBcnReq->bcnReq[j].measurementToken =
2666 tempInt;
2667 break;
2668
2669 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002670 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002671 (tempInt >
2672 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002673 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002674 tempInt);
2675 return -EINVAL;
2676 }
2677 pEseBcnReq->bcnReq[j].channel = tempInt;
2678 break;
2679
2680 case 2: /* Scan mode */
2681 if ((tempInt < eSIR_PASSIVE_SCAN)
2682 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002683 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002684 tempInt);
2685 return -EINVAL;
2686 }
2687 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2688 break;
2689
2690 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002691 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002692 && (pEseBcnReq->bcnReq[j].scanMode !=
2693 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002694 (pEseBcnReq->bcnReq[j].scanMode ==
2695 eSIR_BEACON_TABLE)) {
2696 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002697 tempInt);
2698 return -EINVAL;
2699 }
2700 pEseBcnReq->bcnReq[j].measurementDuration =
2701 tempInt;
2702 break;
2703 }
2704 }
2705 }
2706
2707 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002708 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002709 j,
2710 pEseBcnReq->bcnReq[j].measurementToken,
2711 pEseBcnReq->bcnReq[j].channel,
2712 pEseBcnReq->bcnReq[j].scanMode,
2713 pEseBcnReq->bcnReq[j].measurementDuration);
2714 }
2715
2716 return 0;
2717}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002718
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002719/**
2720 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2721 * @pValue: Pointer to input data
2722 * @pCckmIe: Pointer to output cckm Ie
2723 * @pCckmIeLen: Pointer to output cckm ie length
2724 *
2725 * This function parses the SETCCKM IE command
2726 * SETCCKMIE<space><ie data>
2727 *
2728 * Return: 0 for success non-zero for failure
2729 */
2730static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2731 uint8_t *pCckmIeLen)
2732{
2733 uint8_t *inPtr = pValue;
2734 uint8_t *dataEnd;
2735 int j = 0;
2736 int i = 0;
2737 uint8_t tempByte = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002738
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002739 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2740 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002741 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002743 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002744 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002745
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002746 /* remove empty spaces */
2747 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2748 inPtr++;
2749 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002750 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002751 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002752
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002753 /* find the length of data */
2754 dataEnd = inPtr;
2755 while (('\0' != *dataEnd)) {
2756 dataEnd++;
2757 ++(*pCckmIeLen);
2758 }
2759 if (*pCckmIeLen <= 0)
2760 return -EINVAL;
2761 /*
2762 * Allocate the number of bytes based on the number of input characters
2763 * whether it is even or odd.
2764 * if the number of input characters are even, then we need N / 2 byte.
2765 * if the number of input characters are odd, then we need do
2766 * (N + 1) / 2 to compensate rounding off.
2767 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2768 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2769 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302770 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002771 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002772 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002773 return -ENOMEM;
2774 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002775 /*
2776 * the buffer received from the upper layer is character buffer,
2777 * we need to prepare the buffer taking 2 characters in to a U8 hex
2778 * decimal number for example 7f0000f0...form a buffer to contain
2779 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2780 */
2781 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2782 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2783 (hex_to_bin(inPtr[j + 1]));
2784 (*pCckmIe)[i++] = tempByte;
2785 }
2786 *pCckmIeLen = i;
2787 return 0;
2788}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002789#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002790
2791int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2792{
2793 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302794 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07002795 struct hdd_context *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002796 struct hdd_config *pConfig = NULL;
2797
2798 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002799 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002800 return -EINVAL;
2801 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002802 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2803 (QDF_SAP_MODE != pAdapter->device_mode) &&
2804 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002805 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2806 hdd_device_mode_to_string(pAdapter->device_mode),
2807 pAdapter->device_mode);
2808 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002809 return -EINVAL;
2810 }
2811 pConfig = pHddCtx->config;
2812 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2813 rateUpdate.dev_mode = pAdapter->device_mode;
2814 rateUpdate.mcastDataRate24GHz = targetRate;
2815 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2816 rateUpdate.mcastDataRate5GHz = targetRate;
2817 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302818 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002819 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002820 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2821 hdd_device_mode_to_string(pAdapter->device_mode),
2822 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002823 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302824 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002825 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002826 return -EFAULT;
2827 }
2828 return 0;
2829}
2830
2831static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002832 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002833 uint8_t *command,
2834 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002835 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836{
2837 int ret = 0;
2838
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302839 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002840 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2841 adapter->sessionId,
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002842 (unsigned int)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002843 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2844 + 3) << 16 | *(hdd_ctx->
2845 p2pDeviceAddress.bytes + 4) << 8 |
2846 *(hdd_ctx->p2pDeviceAddress.bytes +
2847 5))));
2848
2849 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2850 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002851 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002852 ret = -EFAULT;
2853 }
2854
2855 return ret;
2856}
2857
2858/**
2859 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2860 * @adapter: Adapter on which the command was received
2861 * @hdd_ctx: HDD global context
2862 * @command: Entire driver command received from userspace
2863 * @command_len: Length of @command
2864 * @priv_data: Pointer to ioctl private data structure
2865 *
2866 * This is a trivial command hander function which simply forwards the
2867 * command to the actual command processor within the P2P module.
2868 *
2869 * Return: 0 on success, non-zero on failure
2870 */
2871static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002872 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002873 uint8_t *command,
2874 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002875 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002876{
2877 return hdd_set_p2p_noa(adapter->dev, command);
2878}
2879
2880/**
2881 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2882 * @adapter: Adapter on which the command was received
2883 * @hdd_ctx: HDD global context
2884 * @command: Entire driver command received from userspace
2885 * @command_len: Length of @command
2886 * @priv_data: Pointer to ioctl private data structure
2887 *
2888 * This is a trivial command hander function which simply forwards the
2889 * command to the actual command processor within the P2P module.
2890 *
2891 * Return: 0 on success, non-zero on failure
2892 */
2893static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002894 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002895 uint8_t *command,
2896 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002897 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002898{
2899 return hdd_set_p2p_opps(adapter->dev, command);
2900}
2901
2902static int drv_cmd_set_band(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002903 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002904 uint8_t *command,
2905 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002906 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002907{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002908 int err;
2909 uint8_t band;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002910
2911 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002912 * Parse the band value passed from userspace. The first 8 bytes
2913 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002914 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002915 err = kstrtou8(command + command_len + 1, 10, &band);
2916 if (err) {
2917 hdd_err("error %d parsing userspace band parameter", err);
2918 return err;
2919 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002920
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002921 return hdd_reg_set_band(adapter->dev, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002922}
2923
2924static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002925 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002926 uint8_t *command,
2927 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002928 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002929{
2930 return hdd_wmmps_helper(adapter, command);
2931}
2932
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002933static inline int drv_cmd_country(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002934 struct hdd_context *hdd_ctx,
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002935 uint8_t *command,
2936 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002937 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002938{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002939 return hdd_reg_set_country(hdd_ctx, command + command_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002940}
2941
2942static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002943 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002944 uint8_t *command,
2945 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002946 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002947{
2948 int ret = 0;
2949 uint8_t *value = command;
2950 int8_t rssi = 0;
2951 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302952 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002953
2954 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2955 value = value + command_len + 1;
2956
2957 /* Convert the value from ascii to integer */
2958 ret = kstrtos8(value, 10, &rssi);
2959 if (ret < 0) {
2960 /*
2961 * If the input value is greater than max value of datatype,
2962 * then also kstrtou8 fails
2963 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002964 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2965 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2966 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002967 ret = -EINVAL;
2968 goto exit;
2969 }
2970
2971 lookUpThreshold = abs(rssi);
2972
2973 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
2974 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002975 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002976 lookUpThreshold,
2977 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2978 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
2979 ret = -EINVAL;
2980 goto exit;
2981 }
2982
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302983 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002984 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
2985 adapter->sessionId, lookUpThreshold));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002986 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002987 lookUpThreshold);
2988
2989 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
2990 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
2991 adapter->sessionId,
2992 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302993 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002994 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002995 ret = -EPERM;
2996 goto exit;
2997 }
2998
2999exit:
3000 return ret;
3001}
3002
3003static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003004 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003005 uint8_t *command,
3006 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003007 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003008{
3009 int ret = 0;
3010 uint8_t lookUpThreshold =
3011 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3012 int rssi = (-1) * lookUpThreshold;
3013 char extra[32];
3014 uint8_t len = 0;
3015
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303016 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003017 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3018 adapter->sessionId, lookUpThreshold));
3019
3020 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303021 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003022 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003023 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003024 ret = -EFAULT;
3025 }
3026
3027 return ret;
3028}
3029
3030static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003031 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003032 uint8_t *command,
3033 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003034 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003035{
3036 int ret = 0;
3037 uint8_t *value = command;
3038 uint8_t roamScanPeriod = 0;
3039 uint16_t neighborEmptyScanRefreshPeriod =
3040 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3041
3042 /* input refresh period is in terms of seconds */
3043
3044 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3045 value = value + command_len + 1;
3046
3047 /* Convert the value from ascii to integer */
3048 ret = kstrtou8(value, 10, &roamScanPeriod);
3049 if (ret < 0) {
3050 /*
3051 * If the input value is greater than max value of datatype,
3052 * then also kstrtou8 fails
3053 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003054 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3055 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3056 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003057 ret = -EINVAL;
3058 goto exit;
3059 }
3060
3061 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3062 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003063 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3064 roamScanPeriod,
3065 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3066 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003067 ret = -EINVAL;
3068 goto exit;
3069 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303070 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003071 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3072 adapter->sessionId, roamScanPeriod));
3073 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3074
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003075 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003076 roamScanPeriod);
3077
3078 hdd_ctx->config->nEmptyScanRefreshPeriod =
3079 neighborEmptyScanRefreshPeriod;
3080 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3081 adapter->sessionId,
3082 neighborEmptyScanRefreshPeriod);
3083
3084exit:
3085 return ret;
3086}
3087
3088static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003089 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003090 uint8_t *command,
3091 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003092 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003093{
3094 int ret = 0;
3095 uint16_t nEmptyScanRefreshPeriod =
3096 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3097 char extra[32];
3098 uint8_t len = 0;
3099
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303100 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3102 adapter->sessionId,
3103 nEmptyScanRefreshPeriod));
3104 len = scnprintf(extra, sizeof(extra), "%s %d",
3105 "GETROAMSCANPERIOD",
3106 (nEmptyScanRefreshPeriod / 1000));
3107 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303108 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003109 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003110 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003111 ret = -EFAULT;
3112 }
3113
3114 return ret;
3115}
3116
3117static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003118 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003119 uint8_t *command,
3120 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003121 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003122{
3123 int ret = 0;
3124 uint8_t *value = command;
3125 uint8_t roamScanRefreshPeriod = 0;
3126 uint16_t neighborScanRefreshPeriod =
3127 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3128
3129 /* input refresh period is in terms of seconds */
3130 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3131 value = value + command_len + 1;
3132
3133 /* Convert the value from ascii to integer */
3134 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3135 if (ret < 0) {
3136 /*
3137 * If the input value is greater than max value of datatype,
3138 * then also kstrtou8 fails
3139 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003140 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3141 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3142 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003143 ret = -EINVAL;
3144 goto exit;
3145 }
3146
3147 if ((roamScanRefreshPeriod <
3148 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3149 || (roamScanRefreshPeriod >
3150 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003151 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3152 roamScanRefreshPeriod,
3153 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3154 / 1000),
3155 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3156 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003157 ret = -EINVAL;
3158 goto exit;
3159 }
3160 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3161
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003162 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003163 roamScanRefreshPeriod);
3164
3165 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3166 neighborScanRefreshPeriod;
3167 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3168 adapter->sessionId,
3169 neighborScanRefreshPeriod);
3170
3171exit:
3172 return ret;
3173}
3174
3175static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003176 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003177 uint8_t *command,
3178 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003179 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003180{
3181 int ret = 0;
3182 uint16_t value =
3183 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3184 char extra[32];
3185 uint8_t len = 0;
3186
3187 len = scnprintf(extra, sizeof(extra), "%s %d",
3188 "GETROAMSCANREFRESHPERIOD",
3189 (value / 1000));
3190 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303191 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003192 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003193 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003194 ret = -EFAULT;
3195 }
3196
3197 return ret;
3198}
3199
3200static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003201 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003202 uint8_t *command,
3203 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003204 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003205{
3206 int ret = 0;
3207 uint8_t *value = command;
3208 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3209
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003210 if (!adapter->fast_roaming_allowed) {
3211 hdd_err("Roaming is always disabled on this interface");
3212 goto exit;
3213 }
3214
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003215 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3216 value = value + SIZE_OF_SETROAMMODE + 1;
3217
3218 /* Convert the value from ascii to integer */
Rajeev Kumar Sirasanagandla248697d2017-08-30 12:27:45 +05303219 ret = kstrtou8(value, 10, &roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003220 if (ret < 0) {
3221 /*
3222 * If the input value is greater than max value of datatype,
3223 * then also kstrtou8 fails
3224 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003225 hdd_err("kstrtou8 failed range [%d - %d]",
3226 CFG_LFR_FEATURE_ENABLED_MIN,
3227 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003228 ret = -EINVAL;
3229 goto exit;
3230 }
3231 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3232 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003233 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3234 roamMode,
3235 CFG_LFR_FEATURE_ENABLED_MIN,
3236 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003237 ret = -EINVAL;
3238 goto exit;
3239 }
3240
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003241 hdd_debug("Received Command to Set Roam Mode = %d",
3242 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003243 /*
3244 * Note that
3245 * SETROAMMODE 0 is to enable LFR while
3246 * SETROAMMODE 1 is to disable LFR, but
3247 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3248 * enable/disable. So, we have to invert the value
3249 * to call sme_update_is_fast_roam_ini_feature_enabled.
3250 */
3251 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3252 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3253 else
3254 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3255
3256 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3257 if (roamMode) {
3258 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3259 sme_update_roam_scan_offload_enabled(
3260 (tHalHandle)(hdd_ctx->hHal),
3261 hdd_ctx->config->isRoamOffloadScanEnabled);
3262 sme_update_is_fast_roam_ini_feature_enabled(
3263 hdd_ctx->hHal,
3264 adapter->sessionId,
3265 roamMode);
3266 } else {
3267 sme_update_is_fast_roam_ini_feature_enabled(
3268 hdd_ctx->hHal,
3269 adapter->sessionId,
3270 roamMode);
3271 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3272 sme_update_roam_scan_offload_enabled(
3273 (tHalHandle)(hdd_ctx->hHal),
3274 hdd_ctx->config->isRoamOffloadScanEnabled);
3275 }
3276
3277
3278exit:
3279 return ret;
3280}
3281
3282static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003283 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003284 uint8_t *command,
3285 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003286 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003287{
3288 int ret = 0;
3289 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3290 char extra[32];
3291 uint8_t len = 0;
3292
3293 /*
3294 * roamMode value shall be inverted because the sementics is different.
3295 */
3296 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3297 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3298 else
3299 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3300
3301 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
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 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003304 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003305 ret = -EFAULT;
3306 }
3307
3308 return ret;
3309}
3310
3311static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003312 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003313 uint8_t *command,
3314 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003315 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003316{
3317 int ret = 0;
3318 uint8_t *value = command;
3319 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3320
3321 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3322 value = value + command_len + 1;
3323
3324 /* Convert the value from ascii to integer */
3325 ret = kstrtou8(value, 10, &roamRssiDiff);
3326 if (ret < 0) {
3327 /*
3328 * If the input value is greater than max value of datatype,
3329 * then also kstrtou8 fails
3330 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003331 hdd_err("kstrtou8 failed range [%d - %d]",
3332 CFG_ROAM_RSSI_DIFF_MIN,
3333 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003334 ret = -EINVAL;
3335 goto exit;
3336 }
3337
3338 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3339 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003340 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3341 roamRssiDiff,
3342 CFG_ROAM_RSSI_DIFF_MIN,
3343 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003344 ret = -EINVAL;
3345 goto exit;
3346 }
3347
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003348 hdd_debug("Received Command to Set roam rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003349 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003350
3351 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3352 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3353 adapter->sessionId,
3354 roamRssiDiff);
3355
3356exit:
3357 return ret;
3358}
3359
3360static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003361 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003362 uint8_t *command,
3363 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003364 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003365{
3366 int ret = 0;
3367 uint8_t roamRssiDiff =
3368 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3369 char extra[32];
3370 uint8_t len = 0;
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_GETROAMDELTA_IOCTL,
3374 adapter->sessionId, roamRssiDiff));
3375
3376 len = scnprintf(extra, sizeof(extra), "%s %d",
3377 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303378 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003379
3380 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003381 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003382 ret = -EFAULT;
3383 }
3384
3385 return ret;
3386}
3387
3388static int drv_cmd_get_band(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003389 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003390 uint8_t *command,
3391 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003392 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003393{
3394 int ret = 0;
3395 int band = -1;
3396 char extra[32];
3397 uint8_t len = 0;
3398
3399 hdd_get_band_helper(hdd_ctx, &band);
3400
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303401 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003402 TRACE_CODE_HDD_GETBAND_IOCTL,
3403 adapter->sessionId, band));
3404
3405 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303406 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003407
3408 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003409 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410 ret = -EFAULT;
3411 }
3412
3413 return ret;
3414}
3415
3416static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003417 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418 uint8_t *command,
3419 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003420 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421{
3422 return hdd_parse_set_roam_scan_channels(adapter, command);
3423}
3424
3425static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003426 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003427 uint8_t *command,
3428 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003429 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003430{
3431 int ret = 0;
3432 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3433 uint8_t numChannels = 0;
3434 uint8_t j = 0;
3435 char extra[128] = { 0 };
3436 int len;
3437
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303438 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003439 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3440 ChannelList,
3441 &numChannels,
3442 adapter->sessionId)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003443 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003444 ret = -EFAULT;
3445 goto exit;
3446 }
3447
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303448 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003449 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3450 adapter->sessionId, numChannels));
3451 /*
3452 * output channel list is of the format
3453 * [Number of roam scan channels][Channel1][Channel2]...
3454 * copy the number of channels in the 0th index
3455 */
3456 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3457 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303458 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003459 len += scnprintf(extra + len, sizeof(extra) - len,
3460 " %d", ChannelList[j]);
3461
Anurag Chouhan6d760662016-02-20 16:05:43 +05303462 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003463 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003464 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003465 ret = -EFAULT;
3466 goto exit;
3467 }
3468
3469exit:
3470 return ret;
3471}
3472
3473static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003474 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003475 uint8_t *command,
3476 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003477 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003478{
3479 int ret = 0;
3480 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3481 char extra[32];
3482 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003483 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003484
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003485 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003486 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003487 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003488 * then this operation is not permitted (return FAILURE)
3489 */
3490 if (eseMode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003491 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003492 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003493 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003494 ret = -EPERM;
3495 goto exit;
3496 }
3497
3498 len = scnprintf(extra, sizeof(extra), "%s %d",
3499 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303500 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003501 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003502 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003503 ret = -EFAULT;
3504 goto exit;
3505 }
3506
3507exit:
3508 return ret;
3509}
3510
3511static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003512 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003513 uint8_t *command,
3514 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003515 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003516{
3517 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003518 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003519 char extra[32];
3520 uint8_t len = 0;
3521
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003522 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003523 /*
3524 * Check if the features OKC/ESE/11R are supported simultaneously,
3525 * then this operation is not permitted (return FAILURE)
3526 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003527 if (pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003528 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3529 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003530 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003531 ret = -EPERM;
3532 goto exit;
3533 }
3534
3535 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003536 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303537 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003538
3539 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003540 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003541 ret = -EFAULT;
3542 goto exit;
3543 }
3544
3545exit:
3546 return ret;
3547}
3548
3549static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003550 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003551 uint8_t *command,
3552 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003553 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003554{
3555 int ret = 0;
3556 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3557 char extra[32];
3558 uint8_t len = 0;
3559
3560 len = scnprintf(extra, sizeof(extra), "%s %d",
3561 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303562 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003563
3564 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003565 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003566 ret = -EFAULT;
3567 }
3568
3569 return ret;
3570}
3571
3572static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003573 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003574 uint8_t *command,
3575 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003576 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003577{
3578 int ret = 0;
3579 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3580 char extra[32];
3581 uint8_t len = 0;
3582
3583 len = scnprintf(extra, sizeof(extra), "%s %d",
3584 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303585 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003586
3587 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003588 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003589 ret = -EFAULT;
3590 }
3591
3592 return ret;
3593}
3594
3595static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003596 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003597 uint8_t *command,
3598 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003599 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003600{
3601 int ret = 0;
3602 uint8_t *value = command;
3603 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3604
3605 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3606 value = value + command_len + 1;
3607
3608 /* Convert the value from ascii to integer */
3609 ret = kstrtou8(value, 10, &minTime);
3610 if (ret < 0) {
3611 /*
3612 * If the input value is greater than max value of datatype,
3613 * then also kstrtou8 fails
3614 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003615 hdd_err("kstrtou8 failed range [%d - %d]",
3616 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3617 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003618 ret = -EINVAL;
3619 goto exit;
3620 }
3621
3622 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3623 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003624 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3625 minTime,
3626 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3627 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003628 ret = -EINVAL;
3629 goto exit;
3630 }
3631
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303632 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003633 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3634 adapter->sessionId, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003635 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003636 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003637
3638 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3639 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3640 minTime,
3641 adapter->sessionId);
3642
3643exit:
3644 return ret;
3645}
3646
3647static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003648 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003649 uint8_t *command,
3650 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003651 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003652{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003653 return hdd_parse_sendactionframe(adapter, command,
3654 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003655}
3656
3657static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003658 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003659 uint8_t *command,
3660 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003661 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003662{
3663 int ret = 0;
3664 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3665 adapter->sessionId);
3666 char extra[32];
3667 uint8_t len = 0;
3668
3669 /* value is interms of msec */
3670 len = scnprintf(extra, sizeof(extra), "%s %d",
3671 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303672 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003673
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303674 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003675 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3676 adapter->sessionId, val));
3677
3678 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003679 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003680 ret = -EFAULT;
3681 }
3682
3683 return ret;
3684}
3685
3686static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003687 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003688 uint8_t *command,
3689 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003690 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003691{
3692 int ret = 0;
3693 uint8_t *value = command;
3694 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3695
3696 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3697 value = value + command_len + 1;
3698
3699 /* Convert the value from ascii to integer */
3700 ret = kstrtou16(value, 10, &maxTime);
3701 if (ret < 0) {
3702 /*
3703 * If the input value is greater than max value of datatype,
3704 * then also kstrtou8 fails
3705 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003706 hdd_err("kstrtou16 failed range [%d - %d]",
3707 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3708 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003709 ret = -EINVAL;
3710 goto exit;
3711 }
3712
3713 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3714 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003715 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3716 maxTime,
3717 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3718 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003719 ret = -EINVAL;
3720 goto exit;
3721 }
3722
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003723 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003724 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003725
3726 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3727 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3728 adapter->sessionId,
3729 maxTime);
3730
3731exit:
3732 return ret;
3733}
3734
3735static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003736 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003737 uint8_t *command,
3738 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003739 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003740{
3741 int ret = 0;
3742 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3743 adapter->sessionId);
3744 char extra[32];
3745 uint8_t len = 0;
3746
3747 /* value is interms of msec */
3748 len = scnprintf(extra, sizeof(extra), "%s %d",
3749 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303750 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003751
3752 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003753 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003754 ret = -EFAULT;
3755 }
3756
3757 return ret;
3758}
3759
3760static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003761 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003762 uint8_t *command,
3763 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003764 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003765{
3766 int ret = 0;
3767 uint8_t *value = command;
3768 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3769
3770 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3771 value = value + command_len + 1;
3772
3773 /* Convert the value from ascii to integer */
3774 ret = kstrtou16(value, 10, &val);
3775 if (ret < 0) {
3776 /*
3777 * If the input value is greater than max value of datatype,
3778 * then also kstrtou8 fails
3779 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003780 hdd_err("kstrtou16 failed range [%d - %d]",
3781 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3782 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003783 ret = -EINVAL;
3784 goto exit;
3785 }
3786
3787 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3788 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003789 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3790 val,
3791 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3792 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003793 ret = -EINVAL;
3794 goto exit;
3795 }
3796
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003797 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003798 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003799
3800 hdd_ctx->config->nNeighborScanPeriod = val;
3801 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3802 adapter->sessionId, val);
3803
3804exit:
3805 return ret;
3806}
3807
3808static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003809 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003810 uint8_t *command,
3811 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003812 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003813{
3814 int ret = 0;
3815 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3816 adapter->
3817 sessionId);
3818 char extra[32];
3819 uint8_t len = 0;
3820
3821 /* value is interms of msec */
3822 len = scnprintf(extra, sizeof(extra), "%s %d",
3823 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303824 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003825
3826 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003827 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003828 ret = -EFAULT;
3829 }
3830
3831 return ret;
3832}
3833
3834static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003835 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003836 uint8_t *command,
3837 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003838 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003839{
3840 int ret = 0;
3841 uint8_t *value = command;
3842 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3843
3844 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3845 value = value + command_len + 1;
3846
3847 /* Convert the value from ascii to integer */
3848 ret = kstrtou8(value, 10, &val);
3849 if (ret < 0) {
3850 /*
3851 * If the input value is greater than max value of datatype,
3852 * then also kstrtou8 fails
3853 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003854 hdd_err("kstrtou8 failed range [%d - %d]",
3855 CFG_ROAM_INTRA_BAND_MIN,
3856 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003857 ret = -EINVAL;
3858 goto exit;
3859 }
3860
3861 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3862 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003863 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3864 val,
3865 CFG_ROAM_INTRA_BAND_MIN,
3866 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003867 ret = -EINVAL;
3868 goto exit;
3869 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003870 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003871 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003872
3873 hdd_ctx->config->nRoamIntraBand = val;
3874 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3875
3876exit:
3877 return ret;
3878}
3879
3880static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003881 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003882 uint8_t *command,
3883 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003884 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003885{
3886 int ret = 0;
3887 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3888 char extra[32];
3889 uint8_t len = 0;
3890
3891 /* value is interms of msec */
3892 len = scnprintf(extra, sizeof(extra), "%s %d",
3893 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303894 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003895 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003896 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897 ret = -EFAULT;
3898 }
3899
3900 return ret;
3901}
3902
3903static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003904 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003905 uint8_t *command,
3906 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003907 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003908{
3909 int ret = 0;
3910 uint8_t *value = command;
3911 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3912
3913 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3914 value = value + command_len + 1;
3915
3916 /* Convert the value from ascii to integer */
3917 ret = kstrtou8(value, 10, &nProbes);
3918 if (ret < 0) {
3919 /*
3920 * If the input value is greater than max value of datatype,
3921 * then also kstrtou8 fails
3922 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003923 hdd_err("kstrtou8 failed range [%d - %d]",
3924 CFG_ROAM_SCAN_N_PROBES_MIN,
3925 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003926 ret = -EINVAL;
3927 goto exit;
3928 }
3929
3930 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3931 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003932 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3933 nProbes,
3934 CFG_ROAM_SCAN_N_PROBES_MIN,
3935 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003936 ret = -EINVAL;
3937 goto exit;
3938 }
3939
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003940 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003941 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003942
3943 hdd_ctx->config->nProbes = nProbes;
3944 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3945 adapter->sessionId, nProbes);
3946
3947exit:
3948 return ret;
3949}
3950
3951static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003952 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003953 uint8_t *command,
3954 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003955 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003956{
3957 int ret = 0;
3958 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3959 char extra[32];
3960 uint8_t len = 0;
3961
3962 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303963 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003964 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003965 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003966 ret = -EFAULT;
3967 }
3968
3969 return ret;
3970}
3971
3972static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003973 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003974 uint8_t *command,
3975 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003976 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003977{
3978 int ret = 0;
3979 uint8_t *value = command;
3980 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3981
3982 /* input value is in units of msec */
3983
3984 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3985 value = value + command_len + 1;
3986
3987 /* Convert the value from ascii to integer */
3988 ret = kstrtou16(value, 10, &homeAwayTime);
3989 if (ret < 0) {
3990 /*
3991 * If the input value is greater than max value of datatype,
3992 * then also kstrtou8 fails
3993 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003994 hdd_err("kstrtou8 failed range [%d - %d]",
3995 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3996 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003997 ret = -EINVAL;
3998 goto exit;
3999 }
4000
4001 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4002 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004003 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004004 homeAwayTime,
4005 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4006 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4007 ret = -EINVAL;
4008 goto exit;
4009 }
4010
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004011 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004012 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004013
4014 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4015 homeAwayTime) {
4016 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4017 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4018 adapter->sessionId,
4019 homeAwayTime,
4020 true);
4021 }
4022
4023exit:
4024 return ret;
4025}
4026
4027static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004028 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004029 uint8_t *command,
4030 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004031 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004032{
4033 int ret = 0;
4034 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4035 char extra[32];
4036 uint8_t len = 0;
4037
4038 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304039 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004040
4041 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004042 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004043 ret = -EFAULT;
4044 }
4045
4046 return ret;
4047}
4048
4049static int drv_cmd_reassoc(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004050 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004051 uint8_t *command,
4052 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004053 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004054{
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05304055 return hdd_parse_reassoc(adapter, command, priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004056}
4057
4058static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004059 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004060 uint8_t *command,
4061 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004062 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004063{
4064 int ret = 0;
4065 uint8_t *value = command;
4066 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4067
4068 /* Move pointer to ahead of SETWESMODE<delimiter> */
4069 value = value + command_len + 1;
4070
4071 /* Convert the value from ascii to integer */
4072 ret = kstrtou8(value, 10, &wesMode);
4073 if (ret < 0) {
4074 /*
4075 * If the input value is greater than max value of datatype,
4076 * then also kstrtou8 fails
4077 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004078 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004079 CFG_ENABLE_WES_MODE_NAME_MIN,
4080 CFG_ENABLE_WES_MODE_NAME_MAX);
4081 ret = -EINVAL;
4082 goto exit;
4083 }
4084
4085 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4086 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004087 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004088 wesMode,
4089 CFG_ENABLE_WES_MODE_NAME_MIN,
4090 CFG_ENABLE_WES_MODE_NAME_MAX);
4091 ret = -EINVAL;
4092 goto exit;
4093 }
4094
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004095 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004096 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004097
4098 hdd_ctx->config->isWESModeEnabled = wesMode;
4099 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4100
4101exit:
4102 return ret;
4103}
4104
4105static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004106 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004107 uint8_t *command,
4108 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004109 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004110{
4111 int ret = 0;
4112 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4113 char extra[32];
4114 uint8_t len = 0;
4115
4116 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304117 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004118 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004119 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004120 ret = -EFAULT;
4121 }
4122
4123 return ret;
4124}
4125
4126static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004127 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004128 uint8_t *command,
4129 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004130 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004131{
4132 int ret = 0;
4133 uint8_t *value = command;
4134 uint8_t nOpportunisticThresholdDiff =
4135 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4136
4137 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4138 value = value + command_len + 1;
4139
4140 /* Convert the value from ascii to integer */
4141 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4142 if (ret < 0) {
4143 /*
4144 * If the input value is greater than max value of datatype,
4145 * then also kstrtou8 fails
4146 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004147 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004148 ret = -EINVAL;
4149 goto exit;
4150 }
4151
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004152 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004153 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004154
4155 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4156 adapter->sessionId,
4157 nOpportunisticThresholdDiff);
4158
4159exit:
4160 return ret;
4161}
4162
4163static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004164 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004165 uint8_t *command,
4166 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004167 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004168{
4169 int ret = 0;
4170 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4171 hdd_ctx->hHal);
4172 char extra[32];
4173 uint8_t len = 0;
4174
4175 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304176 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004177 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004178 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004179 ret = -EFAULT;
4180 }
4181
4182 return ret;
4183}
4184
4185static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004186 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004187 uint8_t *command,
4188 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004189 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190{
4191 int ret = 0;
4192 uint8_t *value = command;
4193 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4194
4195 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4196 value = value + command_len + 1;
4197
4198 /* Convert the value from ascii to integer */
4199 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4200 if (ret < 0) {
4201 /*
4202 * If the input value is greater than max value of datatype,
4203 * then also kstrtou8 fails
4204 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004205 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004206 ret = -EINVAL;
4207 goto exit;
4208 }
4209
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004210 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004211 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004212
4213 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4214 adapter->sessionId,
4215 nRoamRescanRssiDiff);
4216
4217exit:
4218 return ret;
4219}
4220
4221static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004222 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004223 uint8_t *command,
4224 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004225 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004226{
4227 int ret = 0;
4228 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4229 char extra[32];
4230 uint8_t len = 0;
4231
4232 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304233 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004234 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004235 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004236 ret = -EFAULT;
4237 }
4238
4239 return ret;
4240}
4241
4242static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004243 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004244 uint8_t *command,
4245 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004246 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004247{
4248 int ret = 0;
4249 uint8_t *value = command;
4250 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4251
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004252 if (!adapter->fast_roaming_allowed) {
4253 hdd_err("Roaming is always disabled on this interface");
4254 goto exit;
4255 }
4256
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4258 value = value + command_len + 1;
4259
4260 /* Convert the value from ascii to integer */
4261 ret = kstrtou8(value, 10, &lfrMode);
4262 if (ret < 0) {
4263 /*
4264 * If the input value is greater than max value of datatype,
4265 * then also kstrtou8 fails
4266 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004267 hdd_err("kstrtou8 failed range [%d - %d]",
4268 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004269 CFG_LFR_FEATURE_ENABLED_MAX);
4270 ret = -EINVAL;
4271 goto exit;
4272 }
4273
4274 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4275 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004276 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004277 lfrMode,
4278 CFG_LFR_FEATURE_ENABLED_MIN,
4279 CFG_LFR_FEATURE_ENABLED_MAX);
4280 ret = -EINVAL;
4281 goto exit;
4282 }
4283
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004284 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004285 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004286
4287 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4288 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4289 adapter->
4290 sessionId,
4291 lfrMode);
4292
4293exit:
4294 return ret;
4295}
4296
4297static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004298 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004299 uint8_t *command,
4300 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004301 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004302{
4303 int ret = 0;
4304 uint8_t *value = command;
4305 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4306
4307 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4308 value = value + command_len + 1;
4309
4310 /* Convert the value from ascii to integer */
4311 ret = kstrtou8(value, 10, &ft);
4312 if (ret < 0) {
4313 /*
4314 * If the input value is greater than max value of datatype,
4315 * then also kstrtou8 fails
4316 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004317 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004318 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4319 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4320 ret = -EINVAL;
4321 goto exit;
4322 }
4323
4324 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4325 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004326 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004327 ft,
4328 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4329 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4330 ret = -EINVAL;
4331 goto exit;
4332 }
4333
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004334 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004335
4336 hdd_ctx->config->isFastTransitionEnabled = ft;
4337 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4338
4339exit:
4340 return ret;
4341}
4342
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004343static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004344 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004345 uint8_t *command,
4346 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004347 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004348{
4349 int ret = 0;
4350 uint8_t *value = command;
4351 uint8_t channel = 0;
4352 tSirMacAddr targetApBssid;
4353 uint32_t roamId = 0;
4354 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004356 hdd_station_ctx_t *pHddStaCtx;
4357
Krunal Sonibe766b02016-03-10 13:00:44 -08004358 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004359 hdd_warn("Unsupported in mode %s(%d)",
4360 hdd_device_mode_to_string(adapter->device_mode),
4361 adapter->device_mode);
4362 return -EINVAL;
4363 }
4364
4365 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4366
4367 /* if not associated, no need to proceed with reassoc */
4368 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004369 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370 ret = -EINVAL;
4371 goto exit;
4372 }
4373
4374 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4375 &channel);
4376 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004377 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004378 goto exit;
4379 }
4380
4381 /*
4382 * if the target bssid is same as currently associated AP,
4383 * issue reassoc to same AP
4384 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004385 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304387 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004388 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304389 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004390 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304391 targetApBssid,
4392 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304393 } else {
4394 sme_get_modify_profile_fields(hdd_ctx->hHal,
4395 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004396 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304397 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4398 NULL, modProfileFields, &roamId, 1);
4399 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004400 return 0;
4401 }
4402
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304403 /* Check channel number is a valid channel number */
Selvaraj, Sridhar64b0a9c2017-05-11 16:50:15 +05304404 if (channel && (QDF_STATUS_SUCCESS !=
4405 wlan_hdd_validate_operation_channel(adapter, channel))) {
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304406 hdd_err("Invalid Channel [%d]", channel);
4407 return -EINVAL;
4408 }
4409
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004410 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004411 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004412 targetApBssid, (int)channel);
4413 goto exit;
4414 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004415 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004416 handoffInfo.channel = channel;
4417 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004418 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004419 sizeof(tSirMacAddr));
4420 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4421 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004422exit:
4423 return ret;
4424}
4425
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004426static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004427 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004428 uint8_t *command,
4429 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004430 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431{
4432 int ret = 0;
4433 uint8_t *value = command;
4434 uint8_t roamScanControl = 0;
4435
4436 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4437 value = value + command_len + 1;
4438
4439 /* Convert the value from ascii to integer */
4440 ret = kstrtou8(value, 10, &roamScanControl);
4441 if (ret < 0) {
4442 /*
4443 * If the input value is greater than max value of datatype,
4444 * then also kstrtou8 fails
4445 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004446 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004447 ret = -EINVAL;
4448 goto exit;
4449 }
4450
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004451 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004452 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004453
4454 if (0 != roamScanControl) {
4455 ret = 0; /* return success but ignore param value "true" */
4456 goto exit;
4457 }
4458
4459 sme_set_roam_scan_control(hdd_ctx->hHal,
4460 adapter->sessionId,
4461 roamScanControl);
4462
4463exit:
4464 return ret;
4465}
4466
4467static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004468 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004469 uint8_t *command,
4470 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004471 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004472{
4473 int ret = 0;
4474 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004475 uint32_t okc_mode;
4476 struct pmkid_mode_bits pmkid_modes;
4477
4478 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004479
4480 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004481 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004482 * then this operation is not permitted (return FAILURE)
4483 */
4484 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004485 pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004486 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004487 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004488 ret = -EPERM;
4489 goto exit;
4490 }
4491
4492 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4493 value = value + command_len + 1;
4494
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004495 /* get the current configured value */
4496 okc_mode = hdd_ctx->config->pmkid_modes & CFG_PMKID_MODES_OKC;
4497
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004499 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004500 if (ret < 0) {
4501 /*
4502 * If the input value is greater than max value of datatype,
4503 * then also kstrtou8 fails
4504 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004505 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004506 ret = -EINVAL;
4507 goto exit;
4508 }
4509
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004510 if ((okc_mode < 0) ||
4511 (okc_mode > 1)) {
4512 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4513 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004514 ret = -EINVAL;
4515 goto exit;
4516 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004517 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004518 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004519
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004520 if (okc_mode)
4521 hdd_ctx->config->pmkid_modes |= CFG_PMKID_MODES_OKC;
4522 else
4523 hdd_ctx->config->pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004524
4525exit:
4526 return ret;
4527}
4528
4529static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004530 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004531 uint8_t *command,
4532 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004533 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004534{
4535 int ret = 0;
4536 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4537 char extra[32];
4538 uint8_t len = 0;
4539
4540 len = scnprintf(extra, sizeof(extra), "%s %d",
4541 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304542 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004543 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004544 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004545 ret = -EFAULT;
4546 }
4547
4548 return ret;
4549}
4550
4551static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004552 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004553 uint8_t *command,
4554 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004555 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004556{
4557 int ret = 0;
4558 char *bcMode;
4559
4560 bcMode = command + 11;
4561 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004562 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563 hdd_ctx->btCoexModeSet = true;
4564 ret = wlan_hdd_scan_abort(adapter);
4565 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004566 hdd_err("Failed to abort existing scan status: %d",
4567 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004568 }
4569 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004570 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004571 hdd_ctx->btCoexModeSet = false;
4572 }
4573
4574 return ret;
4575}
4576
4577static int drv_cmd_scan_active(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004578 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004579 uint8_t *command,
4580 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004581 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004582{
4583 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4584 return 0;
4585}
4586
4587static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004588 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004589 uint8_t *command,
4590 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004591 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004592{
4593 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4594 return 0;
4595}
4596
4597static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004598 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004599 uint8_t *command,
4600 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004601 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004602{
4603 int ret = 0;
4604 struct hdd_config *pCfg =
4605 (WLAN_HDD_GET_CTX(adapter))->config;
4606 char extra[32];
4607 uint8_t len = 0;
4608
4609 memset(extra, 0, sizeof(extra));
4610 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304611 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004612 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004613 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004614 ret = -EFAULT;
4615 goto exit;
4616 }
4617 ret = len;
4618exit:
4619 return ret;
4620}
4621
4622static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004623 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004624 uint8_t *command,
4625 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004626 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004627{
4628 return hdd_set_dwell_time(adapter, command);
4629}
4630
4631static int drv_cmd_miracast(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004632 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004633 uint8_t *command,
4634 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004635 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004636{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304637 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 int ret = 0;
4639 tHalHandle hHal;
4640 uint8_t filterType = 0;
Jeff Johnson621cf972017-08-28 11:58:44 -07004641 struct hdd_context *pHddCtx = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004642 uint8_t *value;
4643
4644 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304645 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004646 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004647
4648 hHal = pHddCtx->hHal;
4649 value = command + 9;
4650
4651 /* Convert the value from ascii to integer */
4652 ret = kstrtou8(value, 10, &filterType);
4653 if (ret < 0) {
4654 /*
4655 * If the input value is greater than max value of datatype,
4656 * then also kstrtou8 fails
4657 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004658 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004659 ret = -EINVAL;
4660 goto exit;
4661 }
4662 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4663 || (filterType >
4664 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004665 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004666 ret = -EINVAL;
4667 goto exit;
4668 }
4669 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4670 pHddCtx->miracast_value = filterType;
4671
4672 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304673 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004674 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004675 return -EBUSY;
4676 }
4677
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004678 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4679 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004680
4681exit:
4682 return ret;
4683}
4684
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004685/* Function header is left blank intentionally */
4686static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4687 int32_t *oui_length, int32_t limit)
4688{
4689 uint8_t len;
4690 uint8_t data;
4691
4692 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4693 command++;
4694 limit--;
4695 }
4696
4697 len = 2;
4698
4699 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4700 (limit > 1)) {
4701 sscanf(command, "%02x", (unsigned int *)&data);
4702 ie[len++] = data;
4703 command += 2;
4704 limit -= 2;
4705 }
4706
4707 *oui_length = len - 2;
4708
4709 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4710 command++;
4711 limit--;
4712 }
4713
4714 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4715 (limit > 1)) {
4716 sscanf(command, "%02x", (unsigned int *)&data);
4717 ie[len++] = data;
4718 command += 2;
4719 limit -= 2;
4720 }
4721
4722 ie[0] = IE_EID_VENDOR;
4723 ie[1] = len - 2;
4724
4725 return len;
4726}
4727
4728/**
4729 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4730 * @adapter: Pointer to adapter
4731 * @hdd_ctx: Pointer to HDD context
4732 * @command: Pointer to command string
4733 * @command_len : Command length
4734 * @priv_data : Pointer to priv data
4735 *
4736 * Return:
4737 * int status code
4738 */
4739static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004740 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004741 uint8_t *command,
4742 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004743 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004744{
4745 int i = 0;
4746 int status;
4747 int ret = 0;
4748 uint8_t *ibss_ie;
4749 int32_t oui_length = 0;
4750 uint32_t ibss_ie_length;
4751 uint8_t *value = command;
4752 tSirModifyIE ibssModifyIE;
4753 tCsrRoamProfile *pRoamProfile;
4754 hdd_wext_state_t *pWextState;
4755
4756
Krunal Sonibe766b02016-03-10 13:00:44 -08004757 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004758 hdd_debug("Device_mode %s(%d) not IBSS",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004759 hdd_device_mode_to_string(adapter->device_mode),
4760 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004761 return ret;
4762 }
4763
4764 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4765
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004766 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004767
4768
4769 /* validate argument of command */
4770 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004771 hdd_err("No arguments in command length %zu",
4772 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004773 ret = -EFAULT;
4774 goto exit;
4775 }
4776
4777 /* moving to arguments of commands */
4778 value = value + command_len;
4779 command_len = strlen(value);
4780
4781 /* oui_data can't be less than 3 bytes */
4782 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004783 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4784 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004785 ret = -EFAULT;
4786 goto exit;
4787 }
4788
4789 ibss_ie = qdf_mem_malloc(command_len);
4790 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004791 hdd_err("Could not allocate memory for command length %d",
4792 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004793 ret = -ENOMEM;
4794 goto exit;
4795 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004796
4797 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4798 &oui_length,
4799 command_len);
4800 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004801 hdd_err("Could not parse command %s return length %d",
4802 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004803 ret = -EFAULT;
4804 qdf_mem_free(ibss_ie);
4805 goto exit;
4806 }
4807
4808 pRoamProfile = &pWextState->roamProfile;
4809
4810 qdf_copy_macaddr(&ibssModifyIE.bssid,
4811 pRoamProfile->BSSIDs.bssid);
4812
4813 ibssModifyIE.smeSessionId = adapter->sessionId;
4814 ibssModifyIE.notify = true;
4815 ibssModifyIE.ieID = IE_EID_VENDOR;
4816 ibssModifyIE.ieIDLen = ibss_ie_length;
4817 ibssModifyIE.ieBufferlength = ibss_ie_length;
4818 ibssModifyIE.pIEBuffer = ibss_ie;
4819 ibssModifyIE.oui_length = oui_length;
4820
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004821 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4822 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004823 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004824 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004825
4826 /* Probe Bcn modification */
4827 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4828 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4829
4830 /* Populating probe resp frame */
4831 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4832 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4833
4834 qdf_mem_free(ibss_ie);
4835
4836 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4837 adapter->sessionId);
4838 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004839 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004840 status);
4841 ret = -EINVAL;
4842 goto exit;
4843 }
4844
4845exit:
4846 return ret;
4847}
4848
4849static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004850 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004851 uint8_t *command,
4852 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004853 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004854{
4855 int ret = 0;
4856 uint8_t *value = command;
4857 uint8_t ucRmcEnable = 0;
4858 int status;
4859
Krunal Sonibe766b02016-03-10 13:00:44 -08004860 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4861 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004862 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4863 hdd_device_mode_to_string(adapter->device_mode),
4864 adapter->device_mode);
4865 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004866 ret = -EINVAL;
4867 goto exit;
4868 }
4869
4870 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4871 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004872 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004873 ret = -EINVAL;
4874 goto exit;
4875 }
4876
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004877 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004878
4879 if (true == ucRmcEnable) {
4880 status = sme_enable_rmc((tHalHandle)
4881 (hdd_ctx->hHal),
4882 adapter->sessionId);
4883 } else if (false == ucRmcEnable) {
4884 status = sme_disable_rmc((tHalHandle)
4885 (hdd_ctx->hHal),
4886 adapter->sessionId);
4887 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004888 hdd_err("Invalid SETRMCENABLE command %d",
4889 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004890 ret = -EINVAL;
4891 goto exit;
4892 }
4893
4894 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004895 hdd_err("SETRMC %d failed status %d",
4896 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004897 ret = -EINVAL;
4898 goto exit;
4899 }
4900
4901exit:
4902 return ret;
4903}
4904
4905static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004906 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004907 uint8_t *command,
4908 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004909 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004910{
4911 int ret = 0;
4912 uint8_t *value = command;
4913 uint32_t uActionPeriod = 0;
4914 int status;
4915
Krunal Sonibe766b02016-03-10 13:00:44 -08004916 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4917 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004918 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004919 hdd_device_mode_to_string(adapter->device_mode),
4920 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004921 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004922 ret = -EINVAL;
4923 goto exit;
4924 }
4925
4926 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4927 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004928 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004929 ret = -EINVAL;
4930 goto exit;
4931 }
4932
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004933 hdd_debug("uActionPeriod %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004934 uActionPeriod);
4935
4936 if (sme_cfg_set_int(hdd_ctx->hHal,
4937 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4938 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004939 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4940 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004941 ret = -EINVAL;
4942 goto exit;
4943 }
4944
4945 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4946 adapter->sessionId);
4947 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004948 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004949 status);
4950 ret = -EINVAL;
4951 goto exit;
4952 }
4953
4954exit:
4955 return ret;
4956}
4957
4958static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004959 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004960 uint8_t *command,
4961 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004962 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004963{
4964 int ret = 0;
4965 int status = QDF_STATUS_SUCCESS;
4966 hdd_station_ctx_t *pHddStaCtx = NULL;
4967 char *extra = NULL;
4968 int idx = 0;
4969 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004970 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004971 uint32_t numOfBytestoPrint = 0;
4972
Krunal Sonibe766b02016-03-10 13:00:44 -08004973 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004974 hdd_warn("Unsupported in mode %s(%d)",
4975 hdd_device_mode_to_string(adapter->device_mode),
4976 adapter->device_mode);
4977 return -EINVAL;
4978 }
4979
4980 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004981 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004982
4983 /* Handle the command */
4984 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
4985 if (QDF_STATUS_SUCCESS == status) {
4986 /*
4987 * The variable extra needed to be allocated on the heap since
4988 * amount of memory required to copy the data for 32 devices
4989 * exceeds the size of 1024 bytes of default stack size. On
4990 * 64 bit devices, the default max stack size of 2048 bytes
4991 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004992 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004993
4994 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004995 hdd_err("memory allocation failed");
4996 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004997 goto exit;
4998 }
4999
5000 /* Copy number of stations */
5001 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005002 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005003 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005004 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5005 idx++) {
5006 int8_t rssi;
5007 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005008
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005009 qdf_mem_copy(mac_addr,
5010 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5011 mac_addr, sizeof(mac_addr));
5012
5013 tx_rate =
5014 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5015 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305016 /*
5017 * Only lower 3 bytes are rate info. Mask of the MSByte
5018 */
5019 tx_rate &= 0x00FFFFFF;
5020
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005021 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5022 rssi;
5023
5024 length += scnprintf((extra + length),
5025 WLAN_MAX_BUF_SIZE - length,
5026 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5027 mac_addr[0], mac_addr[1], mac_addr[2],
5028 mac_addr[3], mac_addr[4], mac_addr[5],
5029 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005030 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005031 * cdf_trace_msg has limitation of 512 bytes for the
5032 * print buffer. Hence printing the data in two chunks.
5033 * The first chunk will have the data for 16 devices
5034 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005035 */
5036 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5037 numOfBytestoPrint = length;
5038 }
5039
5040 /*
5041 * Copy the data back into buffer, if the data to copy is
5042 * more than 512 bytes than we will split the data and do
5043 * it in two shots
5044 */
5045 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005046 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005047 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305048 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005049 }
5050
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005051 /* This overwrites the last space, which we already copied */
5052 extra[numOfBytestoPrint - 1] = '\0';
5053 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005054
5055 if (length > numOfBytestoPrint) {
5056 if (copy_to_user
5057 (priv_data->buf + numOfBytestoPrint,
5058 extra + numOfBytestoPrint,
5059 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005060 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005061 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305062 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005063 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005064 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005065 }
5066
5067 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005068 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005069 } else {
5070 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005071 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5072 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005073 ret = -EINVAL;
5074 goto exit;
5075 }
5076 ret = 0;
5077
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305078mem_free:
5079 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005080exit:
5081 return ret;
5082}
5083
5084/* Peer Info <Peer Addr> command */
5085static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005086 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005087 uint8_t *command,
5088 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005089 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005090{
5091 int ret = 0;
5092 uint8_t *value = command;
5093 QDF_STATUS status;
5094 hdd_station_ctx_t *pHddStaCtx = NULL;
5095 char extra[128] = { 0 };
5096 uint32_t length = 0;
5097 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005098 struct qdf_mac_addr peerMacAddr;
5099
Krunal Sonibe766b02016-03-10 13:00:44 -08005100 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005101 hdd_warn("Unsupported in mode %s(%d)",
5102 hdd_device_mode_to_string(adapter->device_mode),
5103 adapter->device_mode);
5104 return -EINVAL;
5105 }
5106
5107 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5108
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005109 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005110
5111 /* if there are no peers, no need to continue with the command */
5112 if (eConnectionState_IbssConnected !=
5113 pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005114 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005115 ret = -EINVAL;
5116 goto exit;
5117 }
5118
5119 /* Parse the incoming command buffer */
5120 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5121 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005122 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005123 ret = -EINVAL;
5124 goto exit;
5125 }
5126
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005127 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005128 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005129
Naveen Rawatc45d1622016-07-05 12:20:09 -07005130 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005131 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005132 ret = -EINVAL;
5133 goto exit;
5134 }
5135
5136 /* Handle the command */
5137 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5138 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005139 uint32_t txRate =
5140 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305141 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5142 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005143
5144 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005145 (int)txRate,
5146 (int)pHddStaCtx->ibss_peer_info.
5147 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005148
5149 /* Copy the data back into buffer */
5150 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005151 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005152 ret = -EFAULT;
5153 goto exit;
5154 }
5155 } else {
5156 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005157 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5158 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005159 ret = -EINVAL;
5160 goto exit;
5161 }
5162
5163 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005164 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005165 ret = 0;
5166
5167exit:
5168 return ret;
5169}
5170
5171static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005172 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005173 uint8_t *command,
5174 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005175 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005176{
5177 int ret = 0;
5178 uint8_t *value = command;
5179 uint32_t uRate = 0;
5180 tTxrateinfoflags txFlags = 0;
5181 tSirRateUpdateInd rateUpdateParams = {0};
5182 int status;
5183 struct hdd_config *pConfig = hdd_ctx->config;
5184
Krunal Sonibe766b02016-03-10 13:00:44 -08005185 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5186 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005187 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5188 hdd_device_mode_to_string(adapter->device_mode),
5189 adapter->device_mode);
5190 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005191 ret = -EINVAL;
5192 goto exit;
5193 }
5194
5195 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5196 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005197 hdd_err("Invalid SETRMCTXRATE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005198 ret = -EINVAL;
5199 goto exit;
5200 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005201 hdd_debug("uRate %d", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005202 /* -1 implies ignore this param */
5203 rateUpdateParams.ucastDataRate = -1;
5204
5205 /*
5206 * Fill the user specifieed RMC rate param
5207 * and the derived tx flags.
5208 */
5209 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5210 rateUpdateParams.reliableMcastDataRate = uRate;
5211 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5212 rateUpdateParams.dev_mode = adapter->device_mode;
5213 rateUpdateParams.bcastDataRate = -1;
5214 memcpy(rateUpdateParams.bssid.bytes,
5215 adapter->macAddressCurrent.bytes,
5216 sizeof(rateUpdateParams.bssid));
5217 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5218 &rateUpdateParams);
5219
5220exit:
5221 return ret;
5222}
5223
5224static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005225 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005226 uint8_t *command,
5227 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005228 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005229{
5230 int ret = 0;
5231 char *value;
5232 uint8_t tx_fail_count = 0;
5233 uint16_t pid = 0;
5234
5235 value = command;
5236
5237 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5238
5239 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005240 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005241 goto exit;
5242 }
5243
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005244 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005245
5246 if (0 == tx_fail_count) {
5247 /* Disable TX Fail Indication */
5248 if (QDF_STATUS_SUCCESS ==
5249 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5250 tx_fail_count,
5251 NULL)) {
5252 cesium_pid = 0;
5253 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005254 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005255 ret = -EINVAL;
5256 }
5257 } else {
5258 if (QDF_STATUS_SUCCESS ==
5259 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5260 tx_fail_count,
5261 (void *)hdd_tx_fail_ind_callback)) {
5262 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005263 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005264 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005265 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005266 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005267 ret = -EINVAL;
5268 }
5269 }
5270
5271exit:
5272 return ret;
5273}
5274
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005275#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005276static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005277 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005278 uint8_t *command,
5279 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005280 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005281{
5282 int ret = 0;
5283 uint8_t *value = command;
5284 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5285 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305286 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005287
5288 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5289 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005290 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005291 goto exit;
5292 }
5293 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005294 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005295 numChannels,
5296 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5297 ret = -EINVAL;
5298 goto exit;
5299 }
5300 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5301 adapter->sessionId,
5302 ChannelList,
5303 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305304 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005305 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005306 ret = -EINVAL;
5307 goto exit;
5308 }
5309
5310exit:
5311 return ret;
5312}
5313
5314static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005315 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005316 uint8_t *command,
5317 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005318 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005319{
5320 int ret = 0;
5321 uint8_t *value = command;
5322 char extra[128] = { 0 };
5323 int len = 0;
5324 uint8_t tid = 0;
5325 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005326 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005327
Krunal Sonibe766b02016-03-10 13:00:44 -08005328 if ((QDF_STA_MODE != adapter->device_mode) &&
5329 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005330 hdd_warn("Unsupported in mode %s(%d)",
5331 hdd_device_mode_to_string(adapter->device_mode),
5332 adapter->device_mode);
5333 return -EINVAL;
5334 }
5335
5336 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5337
5338 /* if not associated, return error */
5339 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005340 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005341 ret = -EINVAL;
5342 goto exit;
5343 }
5344
5345 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5346 value = value + command_len + 1;
5347
5348 /* Convert the value from ascii to integer */
5349 ret = kstrtou8(value, 10, &tid);
5350 if (ret < 0) {
5351 /*
5352 * If the input value is greater than max value of datatype,
5353 * then also kstrtou8 fails
5354 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005355 hdd_err("kstrtou8 failed range [%d - %d]",
5356 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005357 TID_MAX_VALUE);
5358 ret = -EINVAL;
5359 goto exit;
5360 }
5361 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005362 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005363 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5364 ret = -EINVAL;
5365 goto exit;
5366 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005367 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005368 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005369 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5370 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005371 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005372 goto exit;
5373 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005374 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005375 "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 -08005376 tsm_metrics.UplinkPktQueueDly,
5377 tsm_metrics.UplinkPktQueueDlyHist[0],
5378 tsm_metrics.UplinkPktQueueDlyHist[1],
5379 tsm_metrics.UplinkPktQueueDlyHist[2],
5380 tsm_metrics.UplinkPktQueueDlyHist[3],
5381 tsm_metrics.UplinkPktTxDly,
5382 tsm_metrics.UplinkPktLoss,
5383 tsm_metrics.UplinkPktCount,
5384 tsm_metrics.RoamingCount,
5385 tsm_metrics.RoamingDly);
5386 /*
5387 * Output TSM stats is of the format
5388 * GETTSMSTATS [PktQueueDly]
5389 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5390 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5391 */
5392 len = scnprintf(extra,
5393 sizeof(extra),
5394 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5395 command,
5396 tsm_metrics.UplinkPktQueueDly,
5397 tsm_metrics.UplinkPktQueueDlyHist[0],
5398 tsm_metrics.UplinkPktQueueDlyHist[1],
5399 tsm_metrics.UplinkPktQueueDlyHist[2],
5400 tsm_metrics.UplinkPktQueueDlyHist[3],
5401 tsm_metrics.UplinkPktTxDly,
5402 tsm_metrics.UplinkPktLoss,
5403 tsm_metrics.UplinkPktCount,
5404 tsm_metrics.RoamingCount,
5405 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305406 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005407 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005408 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005409 ret = -EFAULT;
5410 goto exit;
5411 }
5412
5413exit:
5414 return ret;
5415}
5416
5417static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005418 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005419 uint8_t *command,
5420 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005421 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005422{
5423 int ret;
5424 uint8_t *value = command;
5425 uint8_t *cckmIe = NULL;
5426 uint8_t cckmIeLen = 0;
5427
5428 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5429 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005430 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005431 goto exit;
5432 }
5433
5434 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005435 hdd_err("CCKM Ie input length is more than max[%d]",
5436 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005437 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305438 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005439 cckmIe = NULL;
5440 }
5441 ret = -EINVAL;
5442 goto exit;
5443 }
5444
5445 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5446 cckmIe, cckmIeLen);
5447 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305448 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005449 cckmIe = NULL;
5450 }
5451
5452exit:
5453 return ret;
5454}
5455
5456static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005457 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005458 uint8_t *command,
5459 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005460 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005461{
5462 int ret;
5463 uint8_t *value = command;
5464 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305465 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005466
Krunal Sonibe766b02016-03-10 13:00:44 -08005467 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005468 hdd_warn("Unsupported in mode %s(%d)",
5469 hdd_device_mode_to_string(adapter->device_mode),
5470 adapter->device_mode);
5471 return -EINVAL;
5472 }
5473
5474 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5475 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005476 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005477 goto exit;
5478 }
5479
5480 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005481 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005482 hdd_indicate_ese_bcn_report_no_results(adapter,
5483 eseBcnReq.bcnReq[0].measurementToken,
5484 0x02, /* BIT(1) set for measurement done */
5485 0); /* no BSS */
5486 goto exit;
5487 }
5488
5489 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5490 adapter->sessionId,
5491 &eseBcnReq);
5492
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305493 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005494 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005495 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005496 ret = -EBUSY;
5497 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305498 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005499 hdd_err("sme_set_ese_beacon_request failed (%d)",
5500 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005501 ret = -EINVAL;
5502 goto exit;
5503 }
5504
5505exit:
5506 return ret;
5507}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005508
5509/**
5510 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5511 * @adapter: Pointer to the HDD adapter
5512 * @hdd_ctx: Pointer to the HDD context
5513 * @command: Driver command string
5514 * @command_len: Driver command string length
5515 * @priv_data: Private data coming with the driver command. Unused here
5516 *
5517 * This function handles driver command that sets the ESE PLM request
5518 *
5519 * Return: 0 on success; negative errno otherwise
5520 */
5521static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005522 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005523 uint8_t *command,
5524 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005525 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005526{
5527 int ret = 0;
5528 uint8_t *value = command;
5529 QDF_STATUS status = QDF_STATUS_SUCCESS;
5530 tpSirPlmReq pPlmRequest = NULL;
5531
5532 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5533 if (NULL == pPlmRequest) {
5534 ret = -ENOMEM;
5535 goto exit;
5536 }
5537
5538 status = hdd_parse_plm_cmd(value, pPlmRequest);
5539 if (QDF_STATUS_SUCCESS != status) {
5540 qdf_mem_free(pPlmRequest);
5541 pPlmRequest = NULL;
5542 ret = -EINVAL;
5543 goto exit;
5544 }
5545 pPlmRequest->sessionId = adapter->sessionId;
5546
5547 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5548 if (QDF_STATUS_SUCCESS != status) {
5549 qdf_mem_free(pPlmRequest);
5550 pPlmRequest = NULL;
5551 ret = -EINVAL;
5552 goto exit;
5553 }
5554
5555exit:
5556 return ret;
5557}
5558
5559/**
5560 * drv_cmd_set_ccx_mode() - Set ESE mode
5561 * @adapter: Pointer to the HDD adapter
5562 * @hdd_ctx: Pointer to the HDD context
5563 * @command: Driver command string
5564 * @command_len: Driver command string length
5565 * @priv_data: Private data coming with the driver command. Unused here
5566 *
5567 * This function handles driver command that sets ESE mode
5568 *
5569 * Return: 0 on success; negative errno otherwise
5570 */
5571static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005572 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005573 uint8_t *command,
5574 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005575 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005576{
5577 int ret = 0;
5578 uint8_t *value = command;
5579 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005580 struct pmkid_mode_bits pmkid_modes;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005581
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005582 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005583 /*
5584 * Check if the features OKC/ESE/11R are supported simultaneously,
5585 * then this operation is not permitted (return FAILURE)
5586 */
5587 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005588 pmkid_modes.fw_okc &&
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005589 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5590 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5591 ret = -EPERM;
5592 goto exit;
5593 }
5594
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005595 if (!adapter->fast_roaming_allowed) {
5596 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5597 ret = -EPERM;
5598 goto exit;
5599 }
5600
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005601 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5602 value = value + command_len + 1;
5603
5604 /* Convert the value from ascii to integer */
5605 ret = kstrtou8(value, 10, &eseMode);
5606 if (ret < 0) {
5607 /*
5608 * If the input value is greater than max value of datatype,
5609 * then also kstrtou8 fails
5610 */
5611 hdd_err("kstrtou8 failed range [%d - %d]",
5612 CFG_ESE_FEATURE_ENABLED_MIN,
5613 CFG_ESE_FEATURE_ENABLED_MAX);
5614 ret = -EINVAL;
5615 goto exit;
5616 }
5617
5618 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5619 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5620 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5621 eseMode,
5622 CFG_ESE_FEATURE_ENABLED_MIN,
5623 CFG_ESE_FEATURE_ENABLED_MAX);
5624 ret = -EINVAL;
5625 goto exit;
5626 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005627 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005628
5629 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5630 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5631 adapter->sessionId,
5632 eseMode);
5633
5634exit:
5635 return ret;
5636}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005637#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005638
5639static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005640 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005641 uint8_t *command,
5642 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005643 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005644{
5645 int ret = 0;
5646 uint8_t *value = command;
5647 int targetRate;
5648
5649 /* input value is in units of hundred kbps */
5650
5651 /* Move pointer to ahead of SETMCRATE<delimiter> */
5652 value = value + command_len + 1;
5653
5654 /* Convert the value from ascii to integer, decimal base */
5655 ret = kstrtouint(value, 10, &targetRate);
5656
5657 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5658 return ret;
5659}
5660
5661static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005662 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005663 uint8_t *command,
5664 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005665 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005666{
5667 int ret = 0;
5668 int status;
5669 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305670 QDF_STATUS qdf_status;
5671 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005672 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305673 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5674 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005675 hdd_adapter_list_node_t *pAdapterNode = NULL;
5676 hdd_adapter_list_node_t *pNext = NULL;
5677
5678 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5679 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005680 hdd_err("Invalid MAXTXPOWER command");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005681 ret = -EINVAL;
5682 goto exit;
5683 }
5684
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305685 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005686 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305687 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005688 adapter = pAdapterNode->pAdapter;
5689 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305690 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005691 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305692 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005693 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005694
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005695 hdd_debug("Device mode %d max tx power %d selfMac: "
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005696 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005697 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005698 MAC_ADDR_ARRAY(selfMac.bytes),
5699 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005700
Srinivas Girigowda97215232015-09-24 12:26:28 -07005701 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5702 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305703 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005704 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005705 ret = -EINVAL;
5706 goto exit;
5707 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005708 hdd_debug("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305709 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005710 &pNext);
5711 pAdapterNode = pNext;
5712 }
5713
5714exit:
5715 return ret;
5716}
5717
5718static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005719 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005720 uint8_t *command,
5721 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005722 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005723{
5724 int ret = 0;
5725 uint8_t *value = command;
5726 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5727
5728 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5729 value = value + command_len + 1;
5730
5731 /* Convert the value from ascii to integer */
5732 ret = kstrtou8(value, 10, &dfsScanMode);
5733 if (ret < 0) {
5734 /*
5735 * If the input value is greater than max value of datatype,
5736 * then also kstrtou8 fails
5737 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005738 hdd_err("kstrtou8 failed range [%d - %d]",
5739 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005740 CFG_ROAMING_DFS_CHANNEL_MAX);
5741 ret = -EINVAL;
5742 goto exit;
5743 }
5744
5745 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5746 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005747 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005748 dfsScanMode,
5749 CFG_ROAMING_DFS_CHANNEL_MIN,
5750 CFG_ROAMING_DFS_CHANNEL_MAX);
5751 ret = -EINVAL;
5752 goto exit;
5753 }
5754
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005755 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005756 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005757
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005758 /* When DFS scanning is disabled, the DFS channels need to be
5759 * removed from the operation of device.
5760 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005761 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5762 dfsScanMode != CFG_ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005763 if (ret < 0) {
5764 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005765 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005766 goto exit;
5767 }
5768
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005769 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5770 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5771 dfsScanMode);
5772
5773exit:
5774 return ret;
5775}
5776
5777static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005778 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005779 uint8_t *command,
5780 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005781 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005782{
5783 int ret = 0;
5784 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5785 char extra[32];
5786 uint8_t len = 0;
5787
5788 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305789 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005790 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005791 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005792 ret = -EFAULT;
5793 }
5794
5795 return ret;
5796}
5797
5798static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005799 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005800 uint8_t *command,
5801 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005802 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005803{
5804 int ret = 0;
5805 int value = wlan_hdd_get_link_status(adapter);
5806 char extra[32];
5807 uint8_t len;
5808
5809 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305810 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005811 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005812 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005813 ret = -EFAULT;
5814 }
5815
5816 return ret;
5817}
5818
5819#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5820static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005821 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005822 uint8_t *command,
5823 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005824 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005825{
5826 uint8_t *value = command;
5827 int set_value;
5828
5829 /* Move pointer to ahead of ENABLEEXTWOW */
5830 value = value + command_len;
5831
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305832 if (!(sscanf(value, "%d", &set_value))) {
5833 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5834 ("No input identified"));
5835 return -EINVAL;
5836 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005837
5838 return hdd_enable_ext_wow_parser(adapter,
5839 adapter->sessionId,
5840 set_value);
5841}
5842
5843static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005844 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005845 uint8_t *command,
5846 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005847 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005848{
5849 int ret;
5850 uint8_t *value = command;
5851
5852 /* Move pointer to ahead of SETAPP1PARAMS */
5853 value = value + command_len;
5854
5855 ret = hdd_set_app_type1_parser(adapter,
5856 value, strlen(value));
5857 if (ret >= 0)
5858 hdd_ctx->is_extwow_app_type1_param_set = true;
5859
5860 return ret;
5861}
5862
5863static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005864 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005865 uint8_t *command,
5866 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005867 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005868{
5869 int ret;
5870 uint8_t *value = command;
5871
5872 /* Move pointer to ahead of SETAPP2PARAMS */
5873 value = value + command_len;
5874
5875 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5876 if (ret >= 0)
5877 hdd_ctx->is_extwow_app_type2_param_set = true;
5878
5879 return ret;
5880}
5881#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5882
5883#ifdef FEATURE_WLAN_TDLS
5884/**
5885 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5886 * @adapter: Pointer to the HDD adapter
5887 * @hdd_ctx: Pointer to the HDD context
5888 * @command: Driver command string
5889 * @command_len: Driver command string length
5890 * @priv_data: Private data coming with the driver command. Unused here
5891 *
5892 * This function handles driver command that sets the secondary tdls off channel
5893 * offset
5894 *
5895 * Return: 0 on success; negative errno otherwise
5896 */
5897static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005898 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005899 uint8_t *command,
5900 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005901 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005902{
5903 int ret;
5904 uint8_t *value = command;
5905 int set_value;
5906
5907 /* Move pointer to point the string */
5908 value += command_len;
5909
5910 ret = sscanf(value, "%d", &set_value);
5911 if (ret != 1)
5912 return -EINVAL;
5913
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005914 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005915
5916 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5917
5918 return ret;
5919}
5920
5921/**
5922 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5923 * @adapter: Pointer to the HDD adapter
5924 * @hdd_ctx: Pointer to the HDD context
5925 * @command: Driver command string
5926 * @command_len: Driver command string length
5927 * @priv_data: Private data coming with the driver command. Unused here
5928 *
5929 * This function handles driver command that sets tdls off channel mode
5930 *
5931 * Return: 0 on success; negative errno otherwise
5932 */
5933static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005934 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005935 uint8_t *command,
5936 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005937 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005938{
5939 int ret;
5940 uint8_t *value = command;
5941 int set_value;
5942
5943 /* Move pointer to point the string */
5944 value += command_len;
5945
5946 ret = sscanf(value, "%d", &set_value);
5947 if (ret != 1)
5948 return -EINVAL;
5949
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005950 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005951
5952 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5953
5954 return ret;
5955}
5956
5957/**
5958 * drv_cmd_tdls_off_channel() - set tdls off channel number
5959 * @adapter: Pointer to the HDD adapter
5960 * @hdd_ctx: Pointer to the HDD context
5961 * @command: Driver command string
5962 * @command_len: Driver command string length
5963 * @priv_data: Private data coming with the driver command. Unused here
5964 *
5965 * This function handles driver command that sets tdls off channel number
5966 *
5967 * Return: 0 on success; negative errno otherwise
5968 */
5969static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005970 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005971 uint8_t *command,
5972 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005973 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005974{
5975 int ret;
5976 uint8_t *value = command;
5977 int set_value;
5978
5979 /* Move pointer to point the string */
5980 value += command_len;
5981
5982 ret = sscanf(value, "%d", &set_value);
5983 if (ret != 1)
5984 return -EINVAL;
5985
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -07005986 if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, set_value)) {
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005987 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5988 set_value);
5989 return -EINVAL;
5990 }
5991
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005992 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005993
5994 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5995
5996 return ret;
5997}
5998
5999/**
6000 * drv_cmd_tdls_scan() - set tdls scan type
6001 * @adapter: Pointer to the HDD adapter
6002 * @hdd_ctx: Pointer to the HDD context
6003 * @command: Driver command string
6004 * @command_len: Driver command string length
6005 * @priv_data: Private data coming with the driver command. Unused here
6006 *
6007 * This function handles driver command that sets tdls scan type
6008 *
6009 * Return: 0 on success; negative errno otherwise
6010 */
6011static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006012 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006013 uint8_t *command,
6014 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006015 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006016{
6017 int ret;
6018 uint8_t *value = command;
6019 int set_value;
6020
6021 /* Move pointer to point the string */
6022 value += command_len;
6023
6024 ret = sscanf(value, "%d", &set_value);
6025 if (ret != 1)
6026 return -EINVAL;
6027
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006028 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006029
6030 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6031
6032 return ret;
6033}
6034#endif
6035
6036static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006037 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006038 uint8_t *command,
6039 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006040 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006041{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006042 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006043 int8_t rssi = 0;
6044 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006045
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006046 uint8_t len = 0;
6047
6048 wlan_hdd_get_rssi(adapter, &rssi);
6049
6050 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306051 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006052
6053 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006054 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006055 ret = -EFAULT;
6056 }
6057
6058 return ret;
6059}
6060
6061static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006062 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006063 uint8_t *command,
6064 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006065 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006066{
6067 int ret;
6068 uint32_t link_speed = 0;
6069 char extra[32];
6070 uint8_t len = 0;
6071
6072 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6073 if (0 != ret)
6074 return ret;
6075
6076 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306077 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006078 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006079 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006080 ret = -EFAULT;
6081 }
6082
6083 return ret;
6084}
6085
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006086/**
6087 * hdd_set_rx_filter() - set RX filter
6088 * @adapter: Pointer to adapter
6089 * @action: Filter action
6090 * @pattern: Address pattern
6091 *
6092 * Address pattern is most significant byte of address for example
6093 * 0x01 for IPV4 multicast address
6094 * 0x33 for IPV6 multicast address
6095 * 0xFF for broadcast address
6096 *
6097 * Return: 0 for success, non-zero for failure
6098 */
6099static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6100 uint8_t pattern)
6101{
6102 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006103 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006104 tHalHandle handle;
6105 tSirRcvFltMcAddrList *filter;
Jeff Johnson621cf972017-08-28 11:58:44 -07006106 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006107
6108 ret = wlan_hdd_validate_context(hdd_ctx);
6109 if (0 != ret)
6110 return ret;
6111
6112 handle = hdd_ctx->hHal;
6113
6114 if (NULL == handle) {
6115 hdd_err("HAL Handle is NULL");
6116 return -EINVAL;
6117 }
6118
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306119 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006120 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306121 return -EINVAL;
6122 }
6123
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006124 /*
6125 * If action is false it means start dropping packets
6126 * Set addr_filter_pattern which will be used when sending
6127 * MC/BC address list to target
6128 */
6129 if (!action)
6130 adapter->addr_filter_pattern = pattern;
6131 else
6132 adapter->addr_filter_pattern = 0;
6133
Krunal Sonibe766b02016-03-10 13:00:44 -08006134 if (((adapter->device_mode == QDF_STA_MODE) ||
6135 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006136 adapter->mc_addr_list.mc_cnt &&
6137 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6138
6139
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306140 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006141 if (NULL == filter) {
6142 hdd_err("Could not allocate Memory");
6143 return -ENOMEM;
6144 }
6145 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006146 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006147 if (!memcmp(adapter->mc_addr_list.addr[i],
6148 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006149 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006150 adapter->mc_addr_list.addr[i],
6151 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006152
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006153 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006154 MAC_ADDRESS_STR,
6155 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006156 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6157 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006158 }
SaidiReddy Yenuga0b2c9f42017-02-03 12:26:38 +05306159 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
6160 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006161 }
Frank Liuf95e8132016-09-29 19:01:30 +08006162 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006163 /* Set rx filter */
6164 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306165 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006166 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006167 hdd_debug("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006168 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6169 }
6170
6171 return 0;
6172}
6173
6174/**
6175 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6176 * @command: Pointer to input string driver command
6177 * @adapter: Pointer to adapter
6178 * @action: Action to enable/disable filtering
6179 *
6180 * If action == false
6181 * Start filtering out data packets based on type
6182 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6183 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6184 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6185 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6186 *
6187 * if action == true
6188 * Stop filtering data packets based on type
6189 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6190 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6191 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6192 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6193 *
6194 * Current implementation only supports IPV4 address filtering by
6195 * selectively allowing IPV4 multicast data packest based on
6196 * address list received in .ndo_set_rx_mode
6197 *
6198 * Return: 0 for success, non-zero for failure
6199 */
6200static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6201 hdd_adapter_t *adapter,
6202 bool action)
6203{
6204 int ret = 0;
6205 uint8_t *value;
6206 uint8_t type;
6207
6208 value = command;
6209 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6210 if (!action)
6211 value = command + 16;
6212 else
6213 value = command + 13;
6214 ret = kstrtou8(value, 10, &type);
6215 if (ret < 0) {
6216 hdd_err("kstrtou8 failed invalid input value %d", type);
6217 return -EINVAL;
6218 }
6219
6220 switch (type) {
6221 case 2:
6222 /* Set rx filter for IPV4 multicast data packets */
6223 ret = hdd_set_rx_filter(adapter, action, 0x01);
6224 break;
6225 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006226 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006227 break;
6228 }
6229
6230 return ret;
6231}
6232
6233/**
6234 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6235 * @adapter: Pointer to network adapter
6236 * @hdd_ctx: Pointer to hdd context
6237 * @command: Pointer to input command
6238 * @command_len: Command length
6239 * @priv_data: Pointer to private data in command
6240 */
6241static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006242 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006243 uint8_t *command,
6244 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006245 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006246{
6247 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6248}
6249
6250/**
6251 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6252 * @adapter: Pointer to network adapter
6253 * @hdd_ctx: Pointer to hdd context
6254 * @command: Pointer to input command
6255 * @command_len: Command length
6256 * @priv_data: Pointer to private data in command
6257 */
6258static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006259 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006260 uint8_t *command,
6261 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006262 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006263{
6264 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6265}
6266
Archana Ramachandran393f3792015-11-13 17:13:21 -08006267/**
6268 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6269 * command
6270 * @value: Pointer to SETANTENNAMODE command
6271 * @mode: Pointer to antenna mode
6272 * @reason: Pointer to reason for set antenna mode
6273 *
6274 * This function parses the SETANTENNAMODE command passed in the format
6275 * SETANTENNAMODE<space>mode
6276 *
6277 * Return: 0 for success non-zero for failure
6278 */
6279static int hdd_parse_setantennamode_command(const uint8_t *value)
6280{
6281 const uint8_t *in_ptr = value;
6282 int tmp, v;
6283 char arg1[32];
6284
6285 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6286
6287 /* no argument after the command */
6288 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006289 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006290 return -EINVAL;
6291 }
6292
6293 /* no space after the command */
6294 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006295 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006296 return -EINVAL;
6297 }
6298
6299 /* remove empty spaces */
6300 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6301 in_ptr++;
6302
6303 /* no argument followed by spaces */
6304 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006305 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006306 return -EINVAL;
6307 }
6308
6309 /* get the argument i.e. antenna mode */
6310 v = sscanf(in_ptr, "%31s ", arg1);
6311 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006312 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006313 return -EINVAL;
6314 }
6315
6316 v = kstrtos32(arg1, 10, &tmp);
6317 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006318 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006319 return -EINVAL;
6320 }
6321
6322 return tmp;
6323}
6324
6325/**
6326 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6327 * mask is 2x2 mode
6328 * @hdd_ctx: Pointer to hdd contex
6329 *
6330 * Return: true if supported chain mask 2x2 else false
6331 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006332static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006333{
6334 /*
6335 * Revisit and the update logic to determine the number
6336 * of TX/RX chains supported in the system when
6337 * antenna sharing per band chain mask support is
6338 * brought in
6339 */
6340 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6341}
6342
6343/**
6344 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6345 * chain mask is 1x1
6346 * @hdd_ctx: Pointer to hdd contex
6347 *
6348 * Return: true if supported chain mask 1x1 else false
6349 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006350static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006351{
6352 /*
6353 * Revisit and update the logic to determine the number
6354 * of TX/RX chains supported in the system when
6355 * antenna sharing per band chain mask support is
6356 * brought in
6357 */
6358 return (!hdd_ctx->config->enable2x2) ? true : false;
6359}
6360
Jeff Johnson621cf972017-08-28 11:58:44 -07006361QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
Nitesh Shahe50711f2017-04-26 16:30:45 +05306362{
6363 QDF_STATUS status;
6364 uint8_t smps_mode;
6365 uint8_t smps_enable;
6366
6367 /* Update SME SMPS config */
6368 if (HDD_ANTENNA_MODE_1X1 == mode) {
6369 smps_enable = true;
6370 smps_mode = HDD_SMPS_MODE_STATIC;
6371 } else {
6372 smps_enable = false;
6373 smps_mode = HDD_SMPS_MODE_DISABLED;
6374 }
6375
6376 hdd_debug("Update SME SMPS enable: %d mode: %d",
6377 smps_enable, smps_mode);
6378 status = sme_update_mimo_power_save(
6379 hdd_ctx->hHal, smps_enable, smps_mode, false);
6380 if (QDF_STATUS_SUCCESS != status) {
6381 hdd_err("Update SMPS config failed enable: %d mode: %d"
6382 "status: %d",
6383 smps_enable, smps_mode, status);
6384 return QDF_STATUS_E_FAILURE;
6385 }
6386
6387 hdd_ctx->current_antenna_mode = mode;
6388 /*
6389 * Update the user requested nss in the mac context.
6390 * This will be used in tdls protocol engine to form tdls
6391 * Management frames.
6392 */
6393 sme_update_user_configured_nss(
6394 hdd_ctx->hHal,
6395 hdd_ctx->current_antenna_mode);
6396
6397 hdd_debug("Successfully switched to mode: %d x %d",
6398 hdd_ctx->current_antenna_mode,
6399 hdd_ctx->current_antenna_mode);
6400
6401 return QDF_STATUS_SUCCESS;
6402}
6403
Archana Ramachandran393f3792015-11-13 17:13:21 -08006404/**
6405 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6406 * handler
6407 * @adapter: Pointer to network adapter
6408 * @hdd_ctx: Pointer to hdd context
6409 * @command: Pointer to input command
6410 * @command_len: Command length
6411 * @priv_data: Pointer to private data in command
6412 */
6413static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006414 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006415 uint8_t *command,
6416 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006417 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006418{
6419 struct sir_antenna_mode_param params;
6420 QDF_STATUS status;
6421 int ret = 0;
6422 int mode;
6423 uint8_t *value = command;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006424
6425 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6426 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6427 hdd_err("Operation invalid in non sta or concurrent mode");
6428 ret = -EPERM;
6429 goto exit;
6430 }
6431
6432 mode = hdd_parse_setantennamode_command(value);
6433 if (mode < 0) {
6434 hdd_err("Invalid SETANTENNA command");
6435 ret = mode;
6436 goto exit;
6437 }
6438
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006439 hdd_debug("Processing antenna mode switch to: %d", mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006440
6441 if (hdd_ctx->current_antenna_mode == mode) {
6442 hdd_err("System already in the requested mode");
6443 ret = 0;
6444 goto exit;
6445 }
6446
6447 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6448 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6449 hdd_err("System does not support 2x2 mode");
6450 ret = -EPERM;
6451 goto exit;
6452 }
6453
6454 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6455 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6456 hdd_err("System only supports 1x1 mode");
6457 ret = 0;
6458 goto exit;
6459 }
6460
6461 switch (mode) {
6462 case HDD_ANTENNA_MODE_1X1:
6463 params.num_rx_chains = 1;
6464 params.num_tx_chains = 1;
6465 break;
6466 case HDD_ANTENNA_MODE_2X2:
6467 params.num_rx_chains = 2;
6468 params.num_tx_chains = 2;
6469 break;
6470 default:
6471 hdd_err("unsupported antenna mode");
6472 ret = -EINVAL;
6473 goto exit;
6474 }
6475
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006476 /* Check TDLS status and update antenna mode */
6477 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006478 policy_mgr_is_sta_active_connection_exists(
6479 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006480 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6481 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006482 if (0 != ret)
6483 goto exit;
6484 }
6485
Archana Ramachandran393f3792015-11-13 17:13:21 -08006486 params.set_antenna_mode_resp =
6487 (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006488 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006489 params.num_rx_chains,
6490 params.num_tx_chains);
6491
6492
6493 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6494 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6495 if (QDF_STATUS_SUCCESS != status) {
6496 hdd_err("set antenna mode failed status : %d", status);
6497 ret = -EFAULT;
6498 goto exit;
6499 }
6500
6501 ret = wait_for_completion_timeout(
6502 &hdd_ctx->set_antenna_mode_cmpl,
6503 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6504 if (!ret) {
6505 ret = -EFAULT;
6506 hdd_err("send set antenna mode timed out");
6507 goto exit;
6508 }
6509
Nitesh Shahe50711f2017-04-26 16:30:45 +05306510 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006511 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006512 ret = -EFAULT;
6513 goto exit;
6514 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006515 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006516exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006517#ifdef FEATURE_WLAN_TDLS
6518 /* Reset tdls NSS flags */
6519 if (hdd_ctx->tdls_nss_switch_in_progress &&
6520 hdd_ctx->tdls_nss_teardown_complete) {
6521 hdd_ctx->tdls_nss_switch_in_progress = false;
6522 hdd_ctx->tdls_nss_teardown_complete = false;
6523 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006524 hdd_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
Kabilan Kannanff89f742016-08-15 18:14:10 -07006525 hdd_ctx->tdls_nss_switch_in_progress,
6526 hdd_ctx->tdls_nss_teardown_complete);
6527#endif
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006528 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006529 ret, hdd_ctx->current_antenna_mode);
6530 return ret;
6531
6532}
6533
6534/**
6535 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6536 * handler
6537 * @adapter: Pointer to hdd adapter
6538 * @hdd_ctx: Pointer to hdd context
6539 * @command: Pointer to input command
6540 * @command_len: length of the command
6541 * @priv_data: private data coming with the driver command
6542 *
6543 * Return: 0 for success non-zero for failure
6544 */
6545static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006546 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006547 uint8_t *command,
6548 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006549 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006550{
6551 uint32_t antenna_mode = 0;
6552 char extra[32];
6553 uint8_t len = 0;
6554
6555 antenna_mode = hdd_ctx->current_antenna_mode;
6556 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6557 antenna_mode);
6558 len = QDF_MIN(priv_data->total_len, len + 1);
6559 if (copy_to_user(priv_data->buf, &extra, len)) {
6560 hdd_err("Failed to copy data to user buffer");
6561 return -EFAULT;
6562 }
6563
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006564 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006565
6566 return 0;
6567}
6568
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006569/*
6570 * dummy (no-op) hdd driver command handler
6571 */
6572static int drv_cmd_dummy(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006573 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006574 uint8_t *command,
6575 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006576 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006577{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006578 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006579 adapter->dev->name, command);
6580 return 0;
6581}
6582
6583/*
6584 * handler for any unsupported wlan hdd driver command
6585 */
6586static int drv_cmd_invalid(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006587 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006588 uint8_t *command,
6589 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006590 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006591{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306592 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006593 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6594 adapter->sessionId, 0));
6595
6596 hdd_warn("%s: Unsupported driver command \"%s\"",
6597 adapter->dev->name, command);
6598
6599 return -ENOTSUPP;
6600}
6601
6602/**
6603 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6604 * @adapter: HDD adapter
6605 * @hdd_ctx: HDD context
6606 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6607 * @command_len: command len
6608 * @priv_data: private data
6609 *
6610 * Return: status
6611 */
6612static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006613 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006614 uint8_t *command,
6615 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006616 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006617{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306618 QDF_STATUS status;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006619 uint8_t fcc_constraint;
6620 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006621
6622 /*
6623 * this command would be called by user-space when it detects WLAN
6624 * ON after airplane mode is set. When APM is set, WLAN turns off.
6625 * But it can be turned back on. Otherwise; when APM is turned back
6626 * off, WLAN would turn back on. So at that point the command is
6627 * expected to come down. 0 means disable, 1 means enable. The
6628 * constraint is removed when parameter 1 is set or different
6629 * country code is set
6630 */
6631
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006632 err = kstrtou8(command + command_len + 1, 10, &fcc_constraint);
6633 if (err) {
6634 hdd_err("error %d parsing userspace fcc parameter", err);
6635 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006636 }
6637
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006638 status = ucfg_reg_set_fcc_constraint(hdd_ctx->hdd_pdev,
6639 fcc_constraint);
6640
6641 if (QDF_IS_STATUS_ERROR(status))
6642 hdd_err("Failed to %s tx power for channels 12/13",
6643 fcc_constraint ? "reduce" : "restore");
6644
6645 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006646}
6647
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306648/**
6649 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6650 * command
6651 * @value: Pointer to the command
6652 * @chan_number: Pointer to the channel number
6653 * @chan_bw: Pointer to the channel bandwidth
6654 *
6655 * Parses and provides the channel number and channel width from the input
6656 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6657 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6658 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6659 *
6660 * Return: 0 for success, non-zero for failure
6661 */
6662static int hdd_parse_set_channel_switch_command(uint8_t *value,
6663 uint32_t *chan_number,
6664 uint32_t *chan_bw)
6665{
6666 const uint8_t *in_ptr = value;
6667 int ret;
6668
6669 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6670
6671 /* no argument after the command */
6672 if (NULL == in_ptr) {
6673 hdd_err("No argument after the command");
6674 return -EINVAL;
6675 }
6676
6677 /* no space after the command */
6678 if (SPACE_ASCII_VALUE != *in_ptr) {
6679 hdd_err("No space after the command ");
6680 return -EINVAL;
6681 }
6682
6683 /* remove empty spaces and move the next argument */
6684 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6685 in_ptr++;
6686
6687 /* no argument followed by spaces */
6688 if ('\0' == *in_ptr) {
6689 hdd_err("No argument followed by spaces");
6690 return -EINVAL;
6691 }
6692
6693 /* get the two arguments: channel number and bandwidth */
6694 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6695 if (ret != 2) {
6696 hdd_err("Arguments retrieval from cmd string failed");
6697 return -EINVAL;
6698 }
6699
6700 return 0;
6701}
6702
6703/**
6704 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6705 * @adapter: HDD adapter
6706 * @hdd_ctx: HDD context
6707 * @command: Pointer to the input command CHANNEL_SWITCH
6708 * @command_len: Command len
6709 * @priv_data: Private data
6710 *
6711 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6712 * of SAP/P2P-GO
6713 *
6714 * Return: 0 for success, non-zero for failure
6715 */
6716static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006717 struct hdd_context *hdd_ctx,
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306718 uint8_t *command,
6719 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006720 struct hdd_priv_data *priv_data)
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306721{
6722 struct net_device *dev = adapter->dev;
6723 int status;
6724 uint32_t chan_number = 0, chan_bw = 0;
6725 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006726 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306727
Krunal Sonibe766b02016-03-10 13:00:44 -08006728 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6729 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306730 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6731 adapter->device_mode);
6732 return -EINVAL;
6733 }
6734
6735 status = hdd_parse_set_channel_switch_command(value,
6736 &chan_number, &chan_bw);
6737 if (status) {
6738 hdd_err("Invalid CHANNEL_SWITCH command");
6739 return status;
6740 }
6741
6742 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6743 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6744 return -EINVAL;
6745 }
6746
6747 if (chan_bw == 80)
6748 width = CH_WIDTH_80MHZ;
6749 else if (chan_bw == 40)
6750 width = CH_WIDTH_40MHZ;
6751 else
6752 width = CH_WIDTH_20MHZ;
6753
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006754 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306755
6756 status = hdd_softap_set_channel_change(dev, chan_number, width);
6757 if (status) {
6758 hdd_err("Set channel change fail");
6759 return status;
6760 }
6761
6762 return 0;
6763}
6764
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006765/*
6766 * The following table contains all supported WLAN HDD
6767 * IOCTL driver commands and the handler for each of them.
6768 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07006769static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306770 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false},
6771 {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true},
6772 {"P2P_SET_PS", drv_cmd_p2p_set_ps, true},
6773 {"SETBAND", drv_cmd_set_band, true},
6774 {"SETWMMPS", drv_cmd_set_wmmps, true},
6775 {"COUNTRY", drv_cmd_country, true},
6776 {"SETSUSPENDMODE", drv_cmd_dummy, false},
6777 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false},
6778 {"BTCOEXSCAN", drv_cmd_dummy, false},
6779 {"RXFILTER", drv_cmd_dummy, false},
6780 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true},
6781 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false},
6782 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true},
6783 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false},
6784 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period,
6785 true},
6786 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period,
6787 false},
6788 {"SETROAMMODE", drv_cmd_set_roam_mode, true},
6789 {"GETROAMMODE", drv_cmd_get_roam_mode, false},
6790 {"SETROAMDELTA", drv_cmd_set_roam_delta, true},
6791 {"GETROAMDELTA", drv_cmd_get_roam_delta, false},
6792 {"GETBAND", drv_cmd_get_band, false},
6793 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels, true},
6794 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels, false},
6795 {"GETCCXMODE", drv_cmd_get_ccx_mode, false},
6796 {"GETOKCMODE", drv_cmd_get_okc_mode, false},
6797 {"GETFASTROAM", drv_cmd_get_fast_roam, false},
6798 {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false},
6799 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
6800 true},
6801 {"SENDACTIONFRAME", drv_cmd_send_action_frame, true},
6802 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
6803 false},
6804 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true},
6805 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false},
6806 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true},
6807 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false},
6808 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true},
6809 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false},
6810 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true},
6811 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false},
6812 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true},
6813 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false},
6814 {"REASSOC", drv_cmd_reassoc, true},
6815 {"SETWESMODE", drv_cmd_set_wes_mode, true},
6816 {"GETWESMODE", drv_cmd_get_wes_mode, false},
6817 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff,
6818 true},
6819 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff,
6820 false},
6821 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true},
6822 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false},
6823 {"SETFASTROAM", drv_cmd_set_fast_roam, true},
6824 {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true},
6825 {"FASTREASSOC", drv_cmd_fast_reassoc, true},
6826 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control, true},
6827 {"SETOKCMODE", drv_cmd_set_okc_mode, true},
6828 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control, false},
6829 {"BTCOEXMODE", drv_cmd_bt_coex_mode, true},
6830 {"SCAN-ACTIVE", drv_cmd_scan_active, false},
6831 {"SCAN-PASSIVE", drv_cmd_scan_passive, false},
6832 {"GETDWELLTIME", drv_cmd_get_dwell_time, false},
6833 {"SETDWELLTIME", drv_cmd_set_dwell_time, true},
6834 {"MIRACAST", drv_cmd_miracast, true},
6835 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data, true},
6836 {"SETRMCENABLE", drv_cmd_set_rmc_enable, true},
6837 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period, true},
6838 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all, false},
6839 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info, true},
6840 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate, true},
6841 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006842#ifdef FEATURE_WLAN_ESE
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306843 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true},
6844 {"GETTSMSTATS", drv_cmd_get_tsm_stats, true},
6845 {"SETCCKMIE", drv_cmd_set_cckm_ie, true},
6846 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true},
6847 {"CCXPLMREQ", drv_cmd_ccx_plm_req, true},
6848 {"SETCCXMODE", drv_cmd_set_ccx_mode, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006849#endif /* FEATURE_WLAN_ESE */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306850 {"SETMCRATE", drv_cmd_set_mc_rate, true},
6851 {"MAXTXPOWER", drv_cmd_max_tx_power, true},
6852 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true},
6853 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false},
6854 {"GETLINKSTATUS", drv_cmd_get_link_status, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006855#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306856 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true},
6857 {"SETAPP1PARAMS", drv_cmd_set_app1_params, true},
6858 {"SETAPP2PARAMS", drv_cmd_set_app2_params, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006859#endif
6860#ifdef FEATURE_WLAN_TDLS
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306861 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
6862 true},
6863 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true},
6864 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true},
6865 {"TDLSSCAN", drv_cmd_tdls_scan, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006866#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306867 {"RSSI", drv_cmd_get_rssi, false},
6868 {"LINKSPEED", drv_cmd_get_linkspeed, false},
6869 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true},
6870 {"RXFILTER-ADD", drv_cmd_rx_filter_add, true},
6871 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true},
6872 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true},
6873 {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true},
6874 {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false},
6875 {"STOP", drv_cmd_dummy, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006876};
6877
6878/**
6879 * hdd_drv_cmd_process() - chooses and runs the proper
6880 * handler based on the input command
6881 * @adapter: Pointer to the hdd adapter
6882 * @cmd: Pointer to the driver command
6883 * @priv_data: Pointer to the data associated with the command
6884 *
6885 * This function parses the input hdd driver command and runs
6886 * the proper handler
6887 *
6888 * Return: 0 for success non-zero for failure
6889 */
6890static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
6891 uint8_t *cmd,
Jeff Johnson353cd292017-08-17 06:47:26 -07006892 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006893{
Jeff Johnson621cf972017-08-28 11:58:44 -07006894 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006895 int i;
6896 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6897 uint8_t *cmd_i = NULL;
6898 hdd_drv_cmd_handler_t handler = NULL;
6899 int len = 0;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306900 bool args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006901
6902 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006903 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006904 return -EINVAL;
6905 }
6906
Jeff Johnson621cf972017-08-28 11:58:44 -07006907 hdd_ctx = (struct hdd_context *)adapter->pHddCtx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006908
6909 for (i = 0; i < cmd_num_total; i++) {
6910
6911 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6912 handler = hdd_drv_cmds[i].handler;
6913 len = strlen(cmd_i);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306914 args = hdd_drv_cmds[i].args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006915
6916 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006917 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006918 return -EINVAL;
6919 }
6920
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306921 if (strncasecmp(cmd, cmd_i, len) == 0) {
6922 if (args && drv_cmd_validate(cmd, len))
6923 return -EINVAL;
6924
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006925 return handler(adapter, hdd_ctx,
6926 cmd, len, priv_data);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306927 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006928 }
6929
6930 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6931}
6932
6933/**
6934 * hdd_driver_command() - top level wlan hdd driver command handler
6935 * @adapter: Pointer to the hdd adapter
6936 * @priv_data: Pointer to the raw command data
6937 *
6938 * This function is the top level wlan hdd driver command handler. It
6939 * handles the command with the help of hdd_drv_cmd_process()
6940 *
6941 * Return: 0 for success non-zero for failure
6942 */
6943static int hdd_driver_command(hdd_adapter_t *adapter,
Jeff Johnson353cd292017-08-17 06:47:26 -07006944 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006945{
6946 uint8_t *command = NULL;
6947 int ret = 0;
Jeff Johnson621cf972017-08-28 11:58:44 -07006948 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006949
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306950 ENTER();
6951
Anurag Chouhan6d760662016-02-20 16:05:43 +05306952 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006953 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006954 return -EINVAL;
6955 }
6956
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306957 ret = wlan_hdd_validate_context(hdd_ctx);
6958 if (ret)
6959 return ret;
6960
6961 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
6962 hdd_err("Driver module is closed; command can not be processed");
6963 return -EINVAL;
6964 }
6965
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006966 /*
6967 * Note that valid pointers are provided by caller
6968 */
6969
6970 /* copy to local struct to avoid numerous changes to legacy code */
6971 if (priv_data->total_len <= 0 ||
6972 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006973 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006974 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006975 ret = -EINVAL;
6976 goto exit;
6977 }
6978
6979 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006980 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006981 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006982 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006983 ret = -ENOMEM;
6984 goto exit;
6985 }
6986
6987 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6988 ret = -EFAULT;
6989 goto exit;
6990 }
6991
6992 /* Make sure the command is NUL-terminated */
6993 command[priv_data->total_len] = '\0';
6994
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006995 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006996 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6997
6998exit:
6999 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007000 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307001 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007002 return ret;
7003}
7004
7005#ifdef CONFIG_COMPAT
7006static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7007{
7008 struct {
7009 compat_uptr_t buf;
7010 int used_len;
7011 int total_len;
7012 } compat_priv_data;
Jeff Johnson353cd292017-08-17 06:47:26 -07007013 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007014 int ret = 0;
7015
7016 /*
7017 * Note that adapter and ifr have already been verified by caller,
7018 * and HDD context has also been validated
7019 */
7020 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7021 sizeof(compat_priv_data))) {
7022 ret = -EFAULT;
7023 goto exit;
7024 }
7025 priv_data.buf = compat_ptr(compat_priv_data.buf);
7026 priv_data.used_len = compat_priv_data.used_len;
7027 priv_data.total_len = compat_priv_data.total_len;
7028 ret = hdd_driver_command(adapter, &priv_data);
7029exit:
7030 return ret;
7031}
7032#else /* CONFIG_COMPAT */
7033static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7034{
7035 /* will never be invoked */
7036 return 0;
7037}
7038#endif /* CONFIG_COMPAT */
7039
7040static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7041{
Jeff Johnson353cd292017-08-17 06:47:26 -07007042 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007043 int ret = 0;
7044
7045 /*
7046 * Note that adapter and ifr have already been verified by caller,
7047 * and HDD context has also been validated
7048 */
7049 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7050 ret = -EFAULT;
7051 else
7052 ret = hdd_driver_command(adapter, &priv_data);
7053
7054 return ret;
7055}
7056
7057/**
7058 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7059 * @dev: device upon which the ioctl was received
7060 * @ifr: ioctl request information
7061 * @cmd: ioctl command
7062 *
7063 * This function does initial processing of wlan device ioctls.
7064 * Currently two flavors of ioctls are supported. The primary ioctl
7065 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7066 * for Android "DRIVER" commands. The other ioctl that is
7067 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7068 * for FTM on some platforms. This function simply verifies that the
7069 * driver is in a sane state, and that the ioctl is one of the
7070 * supported flavors, in which case flavor-specific handlers are
7071 * dispatched.
7072 *
7073 * Return: 0 on success, non-zero on error
7074 */
7075static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7076{
7077 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson621cf972017-08-28 11:58:44 -07007078 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007079 int ret;
7080
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007081 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307082
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007083 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007084 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007085 ret = -ENODEV;
7086 goto exit;
7087 }
7088
7089 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007090 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007091 ret = -EINVAL;
7092 goto exit;
7093 }
7094#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307095 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007096 if (SIOCIOCTLTX99 == cmd) {
7097 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7098 goto exit;
7099 }
7100 }
7101#endif
7102
7103 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7104 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307105 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007106 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007107
7108 switch (cmd) {
7109 case (SIOCDEVPRIVATE + 1):
7110 if (is_compat_task())
7111 ret = hdd_driver_compat_ioctl(adapter, ifr);
7112 else
7113 ret = hdd_driver_ioctl(adapter, ifr);
7114 break;
7115 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007116 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007117 ret = -EINVAL;
7118 break;
7119 }
7120exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307121 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007122 return ret;
7123}
7124
7125/**
7126 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7127 * @dev: device upon which the ioctl was received
7128 * @ifr: ioctl request information
7129 * @cmd: ioctl command
7130 *
7131 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7132 * which is where the ioctls are really handled.
7133 *
7134 * Return: 0 on success, non-zero on error
7135 */
7136int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7137{
7138 int ret;
7139
7140 cds_ssr_protect(__func__);
7141 ret = __hdd_ioctl(dev, ifr, cmd);
7142 cds_ssr_unprotect(__func__);
7143 return ret;
7144}