blob: f3b5276204c05dd52cbb486a61a81c80031b4544 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Abhishek Singh1f217ec2017-12-22 11:48:27 +05302 * Copyright (c) 2012-2018 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 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700115typedef int (*hdd_drv_cmd_handler_t)(struct hdd_adapter *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 Johnsone44b7012017-09-10 15:25:47 -0700182static int hdd_get_tsm_stats(struct hdd_adapter *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 Johnson40dae4e2017-08-29 14:00:25 -0700187 struct hdd_station_ctx *hdd_sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800188 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,
Jeff Johnson30f84552017-09-13 14:55:25 -0700216 cookie, tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800217 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{
Jeff Johnsone44b7012017-09-10 15:25:47 -0700397 struct hdd_adapter *adapter = (struct hdd_adapter *) pUserData;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700398 struct hdd_station_ctx *pStaCtx;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800399 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
Jeff Johnsone44b7012017-09-10 15:25:47 -0700442QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(struct hdd_adapter *adapter)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800443{
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
Jeff Johnsone44b7012017-09-10 15:25:47 -0700482hdd_cfg80211_get_ibss_peer_info(struct hdd_adapter *adapter, uint8_t staIdx)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800483{
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{
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800548 enum band_info 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) {
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800552 case BAND_ALL:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800553 *pBand = WLAN_HDD_UI_BAND_AUTO;
554 break;
555
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800556 case BAND_2G:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800557 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
558 break;
559
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800560 case BAND_5G:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800561 *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
Jeff Johnsone44b7012017-09-10 15:25:47 -0700801void hdd_wma_send_fastreassoc_cmd(struct hdd_adapter *adapter,
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800802 const tSirMacAddr bssid, int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700803{
Jeff Johnson2a722002017-09-30 20:02:35 -0700804 struct hdd_wext_state *wext_state =
805 WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
Krunal Soni332f4af2017-06-01 14:36:17 -0700806 struct hdd_station_ctx *hdd_sta_ctx =
807 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800808 tCsrRoamProfile *profile = &wext_state->roamProfile;
Krunal Soni332f4af2017-06-01 14:36:17 -0700809 tSirMacAddr connected_bssid;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700810
Krunal Soni332f4af2017-06-01 14:36:17 -0700811 qdf_mem_copy(connected_bssid, hdd_sta_ctx->conn_info.bssId.bytes,
812 ETH_ALEN);
Naveen Rawat4195c5e2017-05-22 17:07:45 -0700813 sme_fast_reassoc(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -0700814 profile, bssid, channel, adapter->session_id,
Krunal Soni332f4af2017-06-01 14:36:17 -0700815 connected_bssid);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700816}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700817#endif
818
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800819/**
820 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800821 * @adapter: Adapter upon which the command was received
822 * @bssid: BSSID with which to reassociate
823 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700824 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800825 *
826 * This function performs a userspace-directed reassoc operation
827 *
828 * Return: 0 for success non-zero for failure
829 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700830int hdd_reassoc(struct hdd_adapter *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800831 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800832{
Jeff Johnsond377dce2017-10-04 10:32:42 -0700833 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -0700834 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800835 int ret = 0;
836
Naveen Rawat05376ee2016-07-18 16:43:32 -0700837 if (hdd_ctx == NULL) {
838 hdd_err("Invalid hdd ctx");
839 return -EINVAL;
840 }
841
Krunal Sonibe766b02016-03-10 13:00:44 -0800842 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800843 hdd_warn("Unsupported in mode %s(%d)",
844 hdd_device_mode_to_string(adapter->device_mode),
845 adapter->device_mode);
846 return -EINVAL;
847 }
848
Jeff Johnsond377dce2017-10-04 10:32:42 -0700849 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800850
851 /* if not associated, no need to proceed with reassoc */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700852 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800853 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 ret = -EINVAL;
855 goto exit;
856 }
857
858 /*
859 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800860 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800861 */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700862 if (!memcmp(bssid, sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530863 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800864 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Jeff Johnsond377dce2017-10-04 10:32:42 -0700865 channel = sta_ctx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 }
867
868 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530869 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800870 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800871 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800872 ret = -EINVAL;
873 goto exit;
874 }
875
876 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700877 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800878 hdd_wma_send_fastreassoc_cmd(adapter,
Naveen Rawat05376ee2016-07-18 16:43:32 -0700879 bssid, (int)channel);
880 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800881 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882
883 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700884 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530885 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson1b780e42017-10-31 14:11:45 -0700886 sme_handoff_request(hdd_ctx->hHal, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800887 &handoffInfo);
888 }
889exit:
890 return ret;
891}
892
893/**
894 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
895 * @adapter: Adapter upon which the command was received
896 * @command: ASCII text command that was received
897 *
898 * This function parses the v1 REASSOC command with the format
899 *
900 * REASSOC xx:xx:xx:xx:xx:xx CH
901 *
902 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
903 * BSSID and CH is the ASCII representation of the channel. For
904 * example
905 *
906 * REASSOC 00:0a:0b:11:22:33 48
907 *
908 * Return: 0 for success non-zero for failure
909 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700910static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800911{
912 uint8_t channel = 0;
913 tSirMacAddr bssid;
914 int ret;
915
916 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700917 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700918 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700919 else
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700920 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700921
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800922 return ret;
923}
924
925/**
926 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
927 * @adapter: Adapter upon which the command was received
928 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700929 * followed by binary data
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530930 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931 *
932 * This function parses the v2 REASSOC command with the format
933 *
934 * REASSOC <android_wifi_reassoc_params>
935 *
936 * Return: 0 for success non-zero for failure
937 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700938static int hdd_parse_reassoc_v2(struct hdd_adapter *adapter,
939 const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530940 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941{
942 struct android_wifi_reassoc_params params;
943 tSirMacAddr bssid;
944 int ret;
945
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530946 if (total_len < sizeof(params) + 8) {
947 hdd_err("Invalid command length");
948 return -EINVAL;
949 }
950
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951 /* The params are located after "REASSOC " */
952 memcpy(&params, command + 8, sizeof(params));
953
954 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700955 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800956 ret = -EINVAL;
957 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700958 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800959 }
960 return ret;
961}
962
963/**
964 * hdd_parse_reassoc() - parse the REASSOC command
965 * @adapter: Adapter upon which the command was received
966 * @command: Command that was received
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530967 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800968 *
969 * There are two different versions of the REASSOC command. Version 1
970 * of the command contains a parameter list that is ASCII characters
971 * whereas version 2 contains a combination of ASCII and binary
972 * payload. Determine if a version 1 or a version 2 command is being
973 * parsed by examining the parameters, and then dispatch the parser
974 * that is appropriate for the command.
975 *
976 * Return: 0 for success non-zero for failure
977 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700978static int hdd_parse_reassoc(struct hdd_adapter *adapter, const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530979 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800980{
981 int ret;
982
983 /* both versions start with "REASSOC "
984 * v1 has a bssid and channel # as an ASCII string
985 * REASSOC xx:xx:xx:xx:xx:xx CH
986 * v2 has a C struct
987 * REASSOC <binary c struct>
988 *
989 * The first field in the v2 struct is also the bssid in ASCII.
990 * But in the case of a v2 message the BSSID is NUL-terminated.
991 * Hence we can peek at that offset to see if this is V1 or V2
992 * REASSOC xx:xx:xx:xx:xx:xx*
993 * 1111111111222222
994 * 01234567890123456789012345
995 */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530996
997 if (total_len < 26) {
998 hdd_err("Invalid command, total_len = %d", total_len);
999 return -EINVAL;
1000 }
1001
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001002 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001003 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001004 else
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301005 ret = hdd_parse_reassoc_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006
1007 return ret;
1008}
1009
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001010/**
1011 * hdd_sendactionframe() - send a userspace-supplied action frame
1012 * @adapter: Adapter upon which the command was received
1013 * @bssid: BSSID target of the action frame
1014 * @channel: Channel upon which to send the frame
1015 * @dwell_time: Amount of time to dwell when the frame is sent
1016 * @payload_len:Length of the payload
1017 * @payload: Payload of the frame
1018 *
1019 * This function sends a userspace-supplied action frame
1020 *
1021 * Return: 0 for success non-zero for failure
1022 */
1023static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001024hdd_sendactionframe(struct hdd_adapter *adapter, const uint8_t *bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001025 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001026 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027{
1028 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001029 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001030 uint8_t *frame;
1031 struct ieee80211_hdr_3addr *hdr;
1032 u64 cookie;
Jeff Johnsond377dce2017-10-04 10:32:42 -07001033 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -07001034 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1036 (tpSirMacVendorSpecificFrameHdr) payload;
1037#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1038 struct cfg80211_mgmt_tx_params params;
1039#endif
1040
Krunal Sonibe766b02016-03-10 13:00:44 -08001041 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042 hdd_warn("Unsupported in mode %s(%d)",
1043 hdd_device_mode_to_string(adapter->device_mode),
1044 adapter->device_mode);
1045 return -EINVAL;
1046 }
1047
Jeff Johnsond377dce2017-10-04 10:32:42 -07001048 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001049 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1050
1051 /* if not associated, no need to send action frame */
Jeff Johnsond377dce2017-10-04 10:32:42 -07001052 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001053 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054 ret = -EINVAL;
1055 goto exit;
1056 }
1057
1058 /*
1059 * if the target bssid is different from currently associated AP,
1060 * then no need to send action frame
1061 */
Jeff Johnsond377dce2017-10-04 10:32:42 -07001062 if (memcmp(bssid, sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301063 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001064 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 ret = -EINVAL;
1066 goto exit;
1067 }
1068
1069 chan.center_freq = sme_chn_to_freq(channel);
1070 /* Check if it is specific action frame */
1071 if (pVendorSpecific->category ==
1072 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1073 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001074
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301075 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076 /*
1077 * if the channel number is different from operating
1078 * channel then no need to send action frame
1079 */
1080 if (channel != 0) {
1081 if (channel !=
Jeff Johnsond377dce2017-10-04 10:32:42 -07001082 sta_ctx->conn_info.operationChannel) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001083 hdd_warn("channel(%d) is different from operating channel(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001084 channel,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001085 sta_ctx->conn_info.
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001086 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001087 ret = -EINVAL;
1088 goto exit;
1089 }
1090 /*
1091 * If channel number is specified and same
1092 * as home channel, ensure that action frame
1093 * is sent immediately by cancelling
1094 * roaming scans. Otherwise large dwell times
1095 * may cause long delays in sending action
1096 * frames.
1097 */
1098 sme_abort_roam_scan(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001099 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001100 } else {
1101 /*
1102 * 0 is accepted as current home channel,
1103 * delayed transmission of action frame is ok.
1104 */
1105 chan.center_freq =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001106 sme_chn_to_freq(sta_ctx->conn_info.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107 operationChannel);
1108 }
1109 }
1110 }
1111 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001112 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001113 ret = -EINVAL;
1114 goto exit;
1115 }
1116
1117 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301118 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001119 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001120 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001121 ret = -ENOMEM;
1122 goto exit;
1123 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001124
1125 hdr = (struct ieee80211_hdr_3addr *)frame;
1126 hdr->frame_control =
1127 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301128 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson1e851a12017-10-28 14:36:12 -07001129 qdf_mem_copy(hdr->addr2, adapter->mac_addr.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301130 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301131 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1132 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133
1134#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1135 params.chan = &chan;
1136 params.offchan = 0;
1137 params.wait = dwell_time;
1138 params.buf = frame;
1139 params.len = frame_len;
1140 params.no_cck = 1;
1141 params.dont_wait_for_ack = 1;
1142 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1143#else
1144 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001146 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001147
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148 dwell_time, frame, frame_len, 1, 1, &cookie);
1149#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1150
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301151 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001152exit:
1153 return ret;
1154}
1155
1156/**
1157 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1158 * SENDACTIONFRAME command
1159 * @adapter: Adapter upon which the command was received
1160 * @command: ASCII text command that was received
1161 *
1162 * This function parses the v1 SENDACTIONFRAME command with the format
1163 *
1164 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1165 *
1166 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1167 * BSSID, CH is the ASCII representation of the channel, DW is the
1168 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1169 * payload. For example
1170 *
1171 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1172 *
1173 * Return: 0 for success non-zero for failure
1174 */
1175static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001176hdd_parse_sendactionframe_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001177{
1178 uint8_t channel = 0;
1179 uint8_t dwell_time = 0;
1180 uint8_t payload_len = 0;
1181 uint8_t *payload = NULL;
1182 tSirMacAddr bssid;
1183 int ret;
1184
1185 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1186 &dwell_time, &payload,
1187 &payload_len);
1188 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001189 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190 } else {
1191 ret = hdd_sendactionframe(adapter, bssid, channel,
1192 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301193 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001194 }
1195
1196 return ret;
1197}
1198
1199/**
1200 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1201 * SENDACTIONFRAME command
1202 * @adapter: Adapter upon which the command was received
1203 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001204 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001205 *
1206 * This function parses the v2 SENDACTIONFRAME command with the format
1207 *
1208 * SENDACTIONFRAME <android_wifi_af_params>
1209 *
1210 * Return: 0 for success non-zero for failure
1211 */
1212static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001213hdd_parse_sendactionframe_v2(struct hdd_adapter *adapter,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001214 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001215{
1216 struct android_wifi_af_params *params;
1217 tSirMacAddr bssid;
1218 int ret;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301219 int len_wo_payload = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001220
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001221 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001222 total_len -= 16;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301223 len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE;
1224 if (total_len <= len_wo_payload) {
1225 hdd_err("Invalid command len");
1226 return -EINVAL;
1227 }
1228
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001229 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001231 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301232 (params->len > (total_len - len_wo_payload))) {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001233 hdd_err("Invalid payload length: %d", params->len);
1234 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001235 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001236
1237 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1238 hdd_err("MAC address parsing failed");
1239 return -EINVAL;
1240 }
1241
1242 if (params->channel < 0 ||
1243 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1244 hdd_err("Invalid channel: %d", params->channel);
1245 return -EINVAL;
1246 }
1247
1248 if (params->dwell_time < 0) {
1249 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1250 return -EINVAL;
1251 }
1252
1253 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1254 params->dwell_time, params->len, params->data);
1255
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001256 return ret;
1257}
1258
1259/**
1260 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1261 * @adapter: Adapter upon which the command was received
1262 * @command: Command that was received
1263 *
1264 * There are two different versions of the SENDACTIONFRAME command.
1265 * Version 1 of the command contains a parameter list that is ASCII
1266 * characters whereas version 2 contains a combination of ASCII and
1267 * binary payload. Determine if a version 1 or a version 2 command is
1268 * being parsed by examining the parameters, and then dispatch the
1269 * parser that is appropriate for the version of the command.
1270 *
1271 * Return: 0 for success non-zero for failure
1272 */
1273static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001274hdd_parse_sendactionframe(struct hdd_adapter *adapter, const char *command,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001275 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001276{
1277 int ret;
1278
1279 /*
1280 * both versions start with "SENDACTIONFRAME "
1281 * v1 has a bssid and other parameters as an ASCII string
1282 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1283 * v2 has a C struct
1284 * SENDACTIONFRAME <binary c struct>
1285 *
1286 * The first field in the v2 struct is also the bssid in ASCII.
1287 * But in the case of a v2 message the BSSID is NUL-terminated.
1288 * Hence we can peek at that offset to see if this is V1 or V2
1289 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1290 * 111111111122222222223333
1291 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001292 * For both the commands, a valid command must have atleast
1293 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001294 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001295 if (total_len < 34) {
1296 hdd_err("Invalid command (total_len=%d)", total_len);
1297 return -EINVAL;
1298 }
1299
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001300 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001301 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001302 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001303 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001304
1305 return ret;
1306}
1307
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001308/**
1309 * hdd_parse_channellist() - HDD Parse channel list
1310 * @pValue: Pointer to input channel list
1311 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001312 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001313 * @pNumChannels: Pointer to number of roam scan channels
1314 *
1315 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001316 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1317 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001318 * if the Number of channels (N) does not match with the actual number
1319 * of channels passed then take the minimum of N and count of
1320 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1321 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1322 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1323 * removing duplicate channels from the list
1324 *
1325 * Return: 0 for success non-zero for failure
1326 */
1327static int
1328hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1329 uint8_t *pNumChannels)
1330{
1331 const uint8_t *inPtr = pValue;
1332 int tempInt;
1333 int j = 0;
1334 int v = 0;
1335 char buf[32];
1336
1337 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1338 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001339 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001340 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001341 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001342 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001343
1344 /* remove empty spaces */
1345 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1346 inPtr++;
1347
1348 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001349 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001350 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001351
1352 /* get the first argument ie the number of channels */
1353 v = sscanf(inPtr, "%31s ", buf);
1354 if (1 != v)
1355 return -EINVAL;
1356
1357 v = kstrtos32(buf, 10, &tempInt);
1358 if ((v < 0) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001359 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001360 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001361
1362 *pNumChannels = tempInt;
1363
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001364 hdd_debug("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001365
1366 for (j = 0; j < (*pNumChannels); j++) {
1367 /*
1368 * inPtr pointing to the beginning of first space after number
1369 * of channels
1370 */
1371 inPtr = strpbrk(inPtr, " ");
1372 /* no channel list after the number of channels argument */
1373 if (NULL == inPtr) {
1374 if (0 != j) {
1375 *pNumChannels = j;
1376 return 0;
1377 } else {
1378 return -EINVAL;
1379 }
1380 }
1381
1382 /* remove empty space */
1383 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1384 inPtr++;
1385
1386 /*
1387 * no channel list after the number of channels
1388 * argument and spaces
1389 */
1390 if ('\0' == *inPtr) {
1391 if (0 != j) {
1392 *pNumChannels = j;
1393 return 0;
1394 } else {
1395 return -EINVAL;
1396 }
1397 }
1398
1399 v = sscanf(inPtr, "%31s ", buf);
1400 if (1 != v)
1401 return -EINVAL;
1402
1403 v = kstrtos32(buf, 10, &tempInt);
1404 if ((v < 0) ||
1405 (tempInt <= 0) ||
1406 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1407 return -EINVAL;
1408 }
1409 pChannelList[j] = tempInt;
1410
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001411 hdd_debug("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001412 pChannelList[j]);
1413 }
1414
1415 return 0;
1416}
1417
1418/**
1419 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1420 * SETROAMSCANCHANNELS command
1421 * @adapter: Adapter upon which the command was received
1422 * @command: ASCII text command that was received
1423 *
1424 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1425 *
1426 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1427 *
1428 * Where "N" is the ASCII representation of the number of channels and
1429 * C1 thru Cn is the ASCII representation of the channels. For example
1430 *
1431 * SETROAMSCANCHANNELS 4 36 40 44 48
1432 *
1433 * Return: 0 for success non-zero for failure
1434 */
1435static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001436hdd_parse_set_roam_scan_channels_v1(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001437 const char *command)
1438{
1439 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1440 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301441 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001442 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001443 int ret;
1444
1445 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1446 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001447 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001448 goto exit;
1449 }
1450
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301451 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001452 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001453 adapter->session_id, num_chan));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001454
1455 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001456 hdd_err("number of channels (%d) supported exceeded max (%d)",
1457 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001458 ret = -EINVAL;
1459 goto exit;
1460 }
1461
1462 status =
1463 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001464 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001465 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301466 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001467 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468 ret = -EINVAL;
1469 goto exit;
1470 }
1471exit:
1472 return ret;
1473}
1474
1475/**
1476 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1477 * SETROAMSCANCHANNELS command
1478 * @adapter: Adapter upon which the command was received
1479 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001480 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001481 *
1482 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1483 *
1484 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1485 *
1486 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1487 * what follows the space is an array of u08 parameters. For example
1488 *
1489 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1490 *
1491 * Return: 0 for success non-zero for failure
1492 */
1493static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001494hdd_parse_set_roam_scan_channels_v2(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001495 const char *command)
1496{
1497 const uint8_t *value;
1498 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1499 uint8_t channel;
1500 uint8_t num_chan;
1501 int i;
Jeff Johnson621cf972017-08-28 11:58:44 -07001502 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301503 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001504 int ret = 0;
1505
1506 /* array of values begins after "SETROAMSCANCHANNELS " */
1507 value = command + 20;
1508
1509 num_chan = *value++;
1510 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001511 hdd_err("number of channels (%d) supported exceeded max (%d)",
1512 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513 ret = -EINVAL;
1514 goto exit;
1515 }
1516
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301517 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001518 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001519 adapter->session_id, num_chan));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001520
1521 for (i = 0; i < num_chan; i++) {
1522 channel = *value++;
1523 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001524 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001525 i, channel);
1526 ret = -EINVAL;
1527 goto exit;
1528 }
1529 channel_list[i] = channel;
1530 }
1531 status =
1532 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001533 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001534 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301535 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001536 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001537 ret = -EINVAL;
1538 goto exit;
1539 }
1540exit:
1541 return ret;
1542}
1543
1544/**
1545 * hdd_parse_set_roam_scan_channels() - parse the
1546 * SETROAMSCANCHANNELS command
1547 * @adapter: Adapter upon which the command was received
1548 * @command: Command that was received
1549 *
1550 * There are two different versions of the SETROAMSCANCHANNELS command.
1551 * Version 1 of the command contains a parameter list that is ASCII
1552 * characters whereas version 2 contains a binary payload. Determine
1553 * if a version 1 or a version 2 command is being parsed by examining
1554 * the parameters, and then dispatch the parser that is appropriate for
1555 * the command.
1556 *
1557 * Return: 0 for success non-zero for failure
1558 */
1559static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001560hdd_parse_set_roam_scan_channels(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001561{
1562 const char *cursor;
1563 char ch;
1564 bool v1;
1565 int ret;
1566
1567 /* start after "SETROAMSCANCHANNELS " */
1568 cursor = command + 20;
1569
1570 /* assume we have a version 1 command until proven otherwise */
1571 v1 = true;
1572
1573 /* v1 params will only contain ASCII digits and space */
1574 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001575 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001576 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001577 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001578
1579 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001581 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001582 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001583
1584 return ret;
1585}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001587#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001588/**
1589 * hdd_parse_plm_cmd() - HDD Parse Plm command
1590 * @pValue: Pointer to input data
1591 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1592 *
1593 * This function parses the plm command passed in the format
1594 * CCXPLMREQ<space><enable><space><dialog_token><space>
1595 * <meas_token><space><num_of_bursts><space><burst_int><space>
1596 * <measu duration><space><burst_len><space><desired_tx_pwr>
1597 * <space><multcast_addr><space><number_of_channels>
1598 * <space><channel_numbers>
1599 *
1600 * Return: 0 for success non-zero for failure
1601 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001602static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603{
1604 uint8_t *cmdPtr = NULL;
1605 int count, content = 0, ret = 0;
1606 char buf[32];
1607
1608 /* move to argument list */
1609 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1610 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301611 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001612
1613 /* no space after the command */
1614 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301615 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001616
1617 /* remove empty spaces */
1618 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1619 cmdPtr++;
1620
1621 /* START/STOP PLM req */
1622 ret = sscanf(cmdPtr, "%31s ", buf);
1623 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301624 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625
1626 ret = kstrtos32(buf, 10, &content);
1627 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301628 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629
1630 pPlmRequest->enable = content;
1631 cmdPtr = strpbrk(cmdPtr, " ");
1632
1633 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301634 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001635
1636 /* remove empty spaces */
1637 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1638 cmdPtr++;
1639
1640 /* Dialog token of radio meas req containing meas reqIE */
1641 ret = sscanf(cmdPtr, "%31s ", buf);
1642 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301643 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001644
1645 ret = kstrtos32(buf, 10, &content);
1646 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301647 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001648
1649 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001650 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001651 cmdPtr = strpbrk(cmdPtr, " ");
1652
1653 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301654 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001655
1656 /* remove empty spaces */
1657 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1658 cmdPtr++;
1659
1660 /* measurement token of meas req IE */
1661 ret = sscanf(cmdPtr, "%31s ", buf);
1662 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301663 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001664
1665 ret = kstrtos32(buf, 10, &content);
1666 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301667 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668
1669 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001670 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001671
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001672 hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001673 if (pPlmRequest->enable) {
1674
1675 cmdPtr = strpbrk(cmdPtr, " ");
1676
1677 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301678 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001679
1680 /* remove empty spaces */
1681 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1682 cmdPtr++;
1683
1684 /* total number of bursts after which STA stops sending */
1685 ret = sscanf(cmdPtr, "%31s ", buf);
1686 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301687 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688
1689 ret = kstrtos32(buf, 10, &content);
1690 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301691 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692
1693 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301694 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695
1696 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001697 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698 cmdPtr = strpbrk(cmdPtr, " ");
1699
1700 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301701 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
1703 /* remove empty spaces */
1704 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1705 cmdPtr++;
1706
1707 /* burst interval in seconds */
1708 ret = sscanf(cmdPtr, "%31s ", buf);
1709 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301710 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711
1712 ret = kstrtos32(buf, 10, &content);
1713 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301714 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001715
1716 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301717 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718
1719 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001720 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721 cmdPtr = strpbrk(cmdPtr, " ");
1722
1723 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301724 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725
1726 /* remove empty spaces */
1727 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1728 cmdPtr++;
1729
1730 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1731 ret = sscanf(cmdPtr, "%31s ", buf);
1732 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301733 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734
1735 ret = kstrtos32(buf, 10, &content);
1736 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301737 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738
1739 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301740 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001741
1742 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001743 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001744 cmdPtr = strpbrk(cmdPtr, " ");
1745
1746 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301747 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748
1749 /* remove empty spaces */
1750 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1751 cmdPtr++;
1752
1753 /* burst length of PLM bursts */
1754 ret = sscanf(cmdPtr, "%31s ", buf);
1755 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301756 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757
1758 ret = kstrtos32(buf, 10, &content);
1759 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301760 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001761
1762 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301763 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001764
1765 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001766 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767 cmdPtr = strpbrk(cmdPtr, " ");
1768
1769 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301770 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001771
1772 /* remove empty spaces */
1773 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1774 cmdPtr++;
1775
1776 /* desired tx power for transmission of PLM bursts */
1777 ret = sscanf(cmdPtr, "%31s ", buf);
1778 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301779 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001780
1781 ret = kstrtos32(buf, 10, &content);
1782 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301783 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784
1785 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301786 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001787
1788 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001789 hdd_debug("desiredTxPwr %d",
1790 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001791
Anurag Chouhan6d760662016-02-20 16:05:43 +05301792 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001793 cmdPtr = strpbrk(cmdPtr, " ");
1794
1795 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301796 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001797
1798 /* remove empty spaces */
1799 while ((SPACE_ASCII_VALUE == *cmdPtr)
1800 && ('\0' != *cmdPtr))
1801 cmdPtr++;
1802
1803 ret = sscanf(cmdPtr, "%31s ", buf);
1804 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301805 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806
1807 ret = kstrtos32(buf, 16, &content);
1808 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301809 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001810
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001811 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812 }
1813
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001814 hdd_debug("MC addr " MAC_ADDRESS_STR,
1815 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001816
1817 cmdPtr = strpbrk(cmdPtr, " ");
1818
1819 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301820 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821
1822 /* remove empty spaces */
1823 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1824 cmdPtr++;
1825
1826 /* number of channels */
1827 ret = sscanf(cmdPtr, "%31s ", buf);
1828 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301829 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830
1831 ret = kstrtos32(buf, 10, &content);
1832 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301833 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001834
1835 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301836 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001837
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001838 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001840 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001841
1842 /* Channel numbers */
1843 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1844 cmdPtr = strpbrk(cmdPtr, " ");
1845
1846 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301847 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848
1849 /* remove empty spaces */
1850 while ((SPACE_ASCII_VALUE == *cmdPtr)
1851 && ('\0' != *cmdPtr))
1852 cmdPtr++;
1853
1854 ret = sscanf(cmdPtr, "%31s ", buf);
1855 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301856 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857
1858 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001859 if (ret < 0 || content <= 0 ||
1860 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301861 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862
1863 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001864 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001865 }
1866 }
1867 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301868 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001869}
1870#endif
1871
1872#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1873static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1874{
Jeff Johnson621cf972017-08-28 11:58:44 -07001875 struct hdd_context *hdd_ctx = (struct hdd_context *) callbackContext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876 int rc;
1877
1878 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301879 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001880 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881 hdd_ctx->ext_wow_should_suspend = is_success;
1882 complete(&hdd_ctx->ready_to_extwow);
1883}
1884
Jeff Johnsone44b7012017-09-10 15:25:47 -07001885static int hdd_enable_ext_wow(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001886 tpSirExtWoWParams arg_params)
1887{
1888 tSirExtWoWParams params;
Jeff Johnson17d62672017-03-27 08:00:11 -07001889 QDF_STATUS qdf_ret_status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001890 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1892 int rc;
1893
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301894 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895
1896 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1897
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301898 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001899 &wlan_hdd_ready_to_extwow,
1900 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301901 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001902 hdd_err("sme_configure_ext_wow returned failure %d",
1903 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001904 return -EPERM;
1905 }
1906
1907 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1908 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1909 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001910 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911 return -EPERM;
1912 }
1913
Jeff Johnson17d62672017-03-27 08:00:11 -07001914 if (!hdd_ctx->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001915 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001916 return -EPERM;
1917 }
1918
Jeff Johnson17d62672017-03-27 08:00:11 -07001919 if (hdd_ctx->config->extWowGotoSuspend) {
1920 hdd_info("Received ready to ExtWoW. Going to suspend");
1921
1922 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1923 if (rc < 0) {
1924 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1925 rc);
1926 return rc;
1927 }
1928 rc = wlan_hdd_bus_suspend();
1929 if (rc) {
1930 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1931 rc);
1932 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1933 return rc;
1934 }
1935 }
1936
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937 return 0;
1938}
1939
Jeff Johnsone44b7012017-09-10 15:25:47 -07001940static int hdd_enable_ext_wow_parser(struct hdd_adapter *adapter, int vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941 int value)
1942{
1943 tSirExtWoWParams params;
Jeff Johnson621cf972017-08-28 11:58:44 -07001944 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945 int rc;
1946
1947 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301948 if (rc)
1949 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950
1951 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1952 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001953 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 return -EINVAL;
1955 }
1956
1957 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1958 hdd_ctx->is_extwow_app_type1_param_set)
1959 params.type = value;
1960 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1961 hdd_ctx->is_extwow_app_type2_param_set)
1962 params.type = value;
1963 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1964 hdd_ctx->is_extwow_app_type1_param_set &&
1965 hdd_ctx->is_extwow_app_type2_param_set)
1966 params.type = value;
1967 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001968 hdd_err("Set app params before enable it value %d",
1969 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 return -EINVAL;
1971 }
1972
1973 params.vdev_id = vdev_id;
1974 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1975 (hdd_ctx->config->extWowApp2WakeupPinNumber
1976 << 8);
1977
1978 return hdd_enable_ext_wow(adapter, &params);
1979}
1980
1981static int hdd_set_app_type1_params(tHalHandle hHal,
1982 tpSirAppType1Params arg_params)
1983{
1984 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301985 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301987 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001988
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301989 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1990 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001991 hdd_err("sme_configure_app_type1_params returned failure %d",
1992 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 return -EPERM;
1994 }
1995
1996 return 0;
1997}
1998
Jeff Johnsone44b7012017-09-10 15:25:47 -07001999static int hdd_set_app_type1_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002000 char *arg, int len)
2001{
Jeff Johnson621cf972017-08-28 11:58:44 -07002002 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2004 char id[20], password[20];
2005 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002006 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002007
2008 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302009 if (rc)
2010 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011
2012 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002013 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002014 return -EINVAL;
2015 }
2016
2017 memset(&params, 0, sizeof(tSirAppType1Params));
Jeff Johnson1b780e42017-10-31 14:11:45 -07002018 params.vdev_id = adapter->session_id;
Jeff Johnson1e851a12017-10-28 14:36:12 -07002019 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020
2021 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302022 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002023 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302024 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002025
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002026 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002027 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002028 params.identification_id, params.id_length,
2029 params.password, params.pass_length);
2030
2031 return hdd_set_app_type1_params(hHal, &params);
2032}
2033
2034static int hdd_set_app_type2_params(tHalHandle hHal,
2035 tpSirAppType2Params arg_params)
2036{
2037 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302038 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002039
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302040 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002041
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302042 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2043 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002044 hdd_err("sme_configure_app_type2_params returned failure %d",
2045 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046 return -EPERM;
2047 }
2048
2049 return 0;
2050}
2051
Jeff Johnsone44b7012017-09-10 15:25:47 -07002052static int hdd_set_app_type2_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002053 char *arg, int len)
2054{
Jeff Johnson621cf972017-08-28 11:58:44 -07002055 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002056 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2057 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302058 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002059 tSirAppType2Params params;
2060 int ret;
2061
2062 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302063 if (ret)
2064 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002065
2066 memset(&params, 0, sizeof(tSirAppType2Params));
2067
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302068 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 -08002069 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2070 (unsigned int *)&params.ip_device_ip,
2071 (unsigned int *)&params.ip_server_ip,
2072 (unsigned int *)&params.tcp_seq,
2073 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302074 (uint16_t *)&params.tcp_src_port,
2075 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 (unsigned int *)&params.keepalive_init,
2077 (unsigned int *)&params.keepalive_min,
2078 (unsigned int *)&params.keepalive_max,
2079 (unsigned int *)&params.keepalive_inc,
2080 (unsigned int *)&params.tcp_tx_timeout_val,
2081 (unsigned int *)&params.tcp_rx_timeout_val);
2082
2083 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002084 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085 return -EINVAL;
2086 }
2087
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002088 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
2089 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2090 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002091 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002092 return -EINVAL;
2093 }
2094
2095 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2096 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002097 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002098 return -EINVAL;
2099 }
2100
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302101 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302102 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002103
2104 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302105 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002106
Jeff Johnson1b780e42017-10-31 14:11:45 -07002107 params.vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002108 params.tcp_src_port = (params.tcp_src_port != 0) ?
2109 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2110 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2111 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2112 params.keepalive_init = (params.keepalive_init != 0) ?
2113 params.keepalive_init : hdd_ctx->config->
2114 extWowApp2KAInitPingInterval;
2115 params.keepalive_min =
2116 (params.keepalive_min != 0) ?
2117 params.keepalive_min :
2118 hdd_ctx->config->extWowApp2KAMinPingInterval;
2119 params.keepalive_max =
2120 (params.keepalive_max != 0) ?
2121 params.keepalive_max :
2122 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2123 params.keepalive_inc =
2124 (params.keepalive_inc != 0) ?
2125 params.keepalive_inc :
2126 hdd_ctx->config->extWowApp2KAIncPingInterval;
2127 params.tcp_tx_timeout_val =
2128 (params.tcp_tx_timeout_val != 0) ?
2129 params.tcp_tx_timeout_val :
2130 hdd_ctx->config->extWowApp2TcpTxTimeout;
2131 params.tcp_rx_timeout_val =
2132 (params.tcp_rx_timeout_val != 0) ?
2133 params.tcp_rx_timeout_val :
2134 hdd_ctx->config->extWowApp2TcpRxTimeout;
2135
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002136 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002137 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002138 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2139 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2140 params.keepalive_init, params.keepalive_min,
2141 params.keepalive_max, params.keepalive_inc,
2142 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2143
2144 return hdd_set_app_type2_params(hHal, &params);
2145}
2146#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2147
2148/**
2149 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2150 * @pValue: Pointer to MAXTXPOWER command
2151 * @pDbm: Pointer to tx power
2152 *
2153 * This function parses the MAXTXPOWER command passed in the format
2154 * MAXTXPOWER<space>X(Tx power in dbm)
2155 *
2156 * For example input commands:
2157 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2158 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2159 *
2160 * Return: 0 for success non-zero for failure
2161 */
2162static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2163{
2164 uint8_t *inPtr = pValue;
2165 int tempInt;
2166 int v = 0;
2167 *pTxPower = 0;
2168
2169 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2170 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002171 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002172 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002173 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002174 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002175
2176 /* remove empty spaces */
2177 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2178 inPtr++;
2179
2180 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002181 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002182 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002183
2184 v = kstrtos32(inPtr, 10, &tempInt);
2185
2186 /* Range checking for passed parameter */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002187 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002188 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002189
2190 *pTxPower = tempInt;
2191
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002192 hdd_debug("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002193
2194 return 0;
2195} /* End of hdd_parse_setmaxtxpower_command */
2196
2197static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2198 char *extra, uint8_t n, uint8_t *len)
2199{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002200 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002201 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002202 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002203 }
2204
2205 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2206 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2207 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002208 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002209 }
2210 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2212 (int)pCfg->nActiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002213 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002214 }
2215 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002216 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2217 (int)pCfg->nPassiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002218 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002219 }
2220 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002221 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2222 (int)pCfg->nPassiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002223 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002224 }
2225 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Srinivas Girigowdab9086af2017-10-14 14:41:13 -07002226 *len = scnprintf(extra, n, "GETDWELLTIME %u\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002227 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002228 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002229 }
2230
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002231 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002232}
2233
Jeff Johnsone44b7012017-09-10 15:25:47 -07002234static int hdd_set_dwell_time(struct hdd_adapter *adapter, uint8_t *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002235{
2236 tHalHandle hHal;
2237 struct hdd_config *pCfg;
2238 uint8_t *value = command;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302239 tSmeConfigParams *sme_config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002240 int val = 0, temp = 0;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302241 int retval = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002242
2243 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2244 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2245 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002246 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002247 return -EINVAL;
2248 }
2249
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302250 sme_config = qdf_mem_malloc(sizeof(*sme_config));
2251 if (!sme_config) {
2252 hdd_err("failed to allocate memory for sme_config");
2253 return -ENOMEM;
2254 }
2255 qdf_mem_zero(sme_config, sizeof(*sme_config));
2256 sme_get_config_param(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002257
2258 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302259 if (drv_cmd_validate(command, 23))
2260 return -EINVAL;
2261
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002262 value = value + 24;
2263 temp = kstrtou32(value, 10, &val);
2264 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2265 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002266 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302267 retval = -EFAULT;
2268 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002269 }
2270 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302271 sme_config->csrConfig.nActiveMaxChnTime = val;
2272 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002273 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302274 if (drv_cmd_validate(command, 23))
2275 return -EINVAL;
2276
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002277 value = value + 24;
2278 temp = kstrtou32(value, 10, &val);
2279 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2280 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002281 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302282 retval = -EFAULT;
2283 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002284 }
2285 pCfg->nActiveMinChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302286 sme_config->csrConfig.nActiveMinChnTime = val;
2287 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002288 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302289 if (drv_cmd_validate(command, 24))
2290 return -EINVAL;
2291
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002292 value = value + 25;
2293 temp = kstrtou32(value, 10, &val);
2294 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2295 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002296 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302297 retval = -EFAULT;
2298 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002299 }
2300 pCfg->nPassiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302301 sme_config->csrConfig.nPassiveMaxChnTime = val;
2302 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002303 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302304 if (drv_cmd_validate(command, 24))
2305 return -EINVAL;
2306
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002307 value = value + 25;
2308 temp = kstrtou32(value, 10, &val);
2309 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2310 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002311 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302312 retval = -EFAULT;
2313 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002314 }
2315 pCfg->nPassiveMinChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302316 sme_config->csrConfig.nPassiveMinChnTime = val;
2317 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002318 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302319 if (drv_cmd_validate(command, 12))
2320 return -EINVAL;
2321
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002322 value = value + 13;
2323 temp = kstrtou32(value, 10, &val);
2324 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2325 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002326 hdd_err("argument passed for SETDWELLTIME is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302327 retval = -EFAULT;
2328 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329 }
2330 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302331 sme_config->csrConfig.nActiveMaxChnTime = val;
2332 sme_update_config(hHal, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002333 } else {
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302334 retval = -EINVAL;
2335 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002336 }
2337
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302338free:
2339 qdf_mem_free(sme_config);
2340 return retval;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002341}
2342
Jeff Johnson253c0c22017-01-23 16:59:38 -08002343struct link_status_priv {
2344 uint8_t link_status;
2345};
2346
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002347static void hdd_get_link_status_cb(uint8_t status, void *context)
2348{
Jeff Johnson253c0c22017-01-23 16:59:38 -08002349 struct hdd_request *request;
2350 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002351
Jeff Johnson253c0c22017-01-23 16:59:38 -08002352 request = hdd_request_get(context);
2353 if (!request) {
2354 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002355 return;
2356 }
2357
Jeff Johnson253c0c22017-01-23 16:59:38 -08002358 priv = hdd_request_priv(request);
2359 priv->link_status = status;
2360 hdd_request_complete(request);
2361 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002362}
2363
2364/**
2365 * wlan_hdd_get_link_status() - get link status
Jeff Johnson25c77342017-10-02 13:28:03 -07002366 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002367 *
2368 * This function sends a request to query the link status and waits
2369 * on a timer to invoke the callback. if the callback is invoked then
2370 * latest link status shall be returned or otherwise cached value
2371 * will be returned.
2372 *
2373 * Return: On success, link status shall be returned.
2374 * On error or not associated, link status 0 will be returned.
2375 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002376static int wlan_hdd_get_link_status(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002377{
2378
Jeff Johnsond377dce2017-10-04 10:32:42 -07002379 struct hdd_station_ctx *sta_ctx =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002380 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302381 QDF_STATUS hstatus;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002382 int ret;
2383 void *cookie;
2384 struct hdd_request *request;
2385 struct link_status_priv *priv;
2386 static const struct hdd_request_params params = {
2387 .priv_size = sizeof(*priv),
2388 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2389 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002390
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05302391 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002392 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2393 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002394 return 0;
2395 }
2396
Krunal Sonibe766b02016-03-10 13:00:44 -08002397 if ((QDF_STA_MODE != adapter->device_mode) &&
2398 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002399 hdd_warn("Unsupported in mode %s(%d)",
2400 hdd_device_mode_to_string(adapter->device_mode),
2401 adapter->device_mode);
2402 return 0;
2403 }
2404
Jeff Johnsond377dce2017-10-04 10:32:42 -07002405 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2406 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002407 /* If not associated, then expected link status return
2408 * value is 0
2409 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002410 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002411 return 0;
2412 }
2413
Jeff Johnson253c0c22017-01-23 16:59:38 -08002414 request = hdd_request_alloc(&params);
2415 if (!request) {
2416 hdd_err("Request allocation failure");
2417 return 0;
2418 }
2419 cookie = hdd_request_cookie(request);
2420
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002421 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2422 hdd_get_link_status_cb,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002423 cookie, adapter->session_id);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302424 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002425 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002426 /* return a cached value */
2427 } else {
2428 /* request is sent -- wait for the response */
Jeff Johnson253c0c22017-01-23 16:59:38 -08002429 ret = hdd_request_wait_for_response(request);
2430 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002431 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002432 /* return a cached value */
2433 } else {
2434 /* update the adapter with the fresh results */
2435 priv = hdd_request_priv(request);
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07002436 adapter->link_status = priv->link_status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002437 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002438 }
2439
Jeff Johnson253c0c22017-01-23 16:59:38 -08002440 /*
2441 * either we never sent a request, we sent a request and
2442 * received a response or we sent a request and timed out.
2443 * regardless we are done with the request.
2444 */
2445 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002446
2447 /* either callback updated adapter stats or it has cached data */
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07002448 return adapter->link_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002449}
2450
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002451static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2452{
2453 int payload_len;
2454 struct sk_buff *skb;
2455 struct nlmsghdr *nlh;
2456 uint8_t *data;
2457
2458 payload_len = ETH_ALEN;
2459
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002460 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002461 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002462 return;
2463 }
2464
2465 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2466 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002467 hdd_err("nlmsg_new() failed for msg size[%d]",
2468 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002469 return;
2470 }
2471
2472 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2473
2474 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002475 hdd_err("nlmsg_put() failed for msg size[%d]",
2476 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002477
2478 kfree_skb(skb);
2479 return;
2480 }
2481
2482 data = nlmsg_data(nlh);
2483 memcpy(data, MacAddr, ETH_ALEN);
2484
2485 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002486 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2487 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002488 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002489}
2490
2491
2492/**
2493 * hdd_ParseuserParams - return a pointer to the next argument
2494 * @pValue: Input argument string
2495 * @ppArg: Output pointer to the next argument
2496 *
2497 * This function parses argument stream and finds the pointer
2498 * to the next argument
2499 *
2500 * Return: 0 if the next argument found; -EINVAL otherwise
2501 */
2502static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2503{
2504 uint8_t *pVal;
2505
2506 pVal = strnchr(pValue, strlen(pValue), ' ');
2507
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002508 if (NULL == pVal) /* no argument remains */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002509 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002510 else if (SPACE_ASCII_VALUE != *pVal)/* no space after the current arg */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002511 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002512
2513 pVal++;
2514
2515 /* remove empty spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002516 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002517 pVal++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002518
2519 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002520 if ('\0' == *pVal)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002521 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002522
2523 *ppArg = pVal;
2524
2525 return 0;
2526}
2527
2528/**
2529 * hdd_parse_ibsstx_fail_event_params - Parse params
2530 * for SETIBSSTXFAILEVENT
2531 * @pValue: Input ibss tx fail event argument
2532 * @tx_fail_count: (Output parameter) Tx fail counter
2533 * @pid: (Output parameter) PID
2534 *
2535 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2536 */
2537static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2538 uint8_t *tx_fail_count,
2539 uint16_t *pid)
2540{
2541 uint8_t *param = NULL;
2542 int ret;
2543
2544 ret = hdd_parse_user_params(pValue, &param);
2545
2546 if (0 == ret && NULL != param) {
2547 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2548 ret = -EINVAL;
2549 goto done;
2550 }
2551 } else {
2552 goto done;
2553 }
2554
2555 if (0 == *tx_fail_count) {
2556 *pid = 0;
2557 goto done;
2558 }
2559
2560 pValue = param;
2561 pValue++;
2562
2563 ret = hdd_parse_user_params(pValue, &param);
2564
2565 if (0 == ret) {
2566 if (1 != sscanf(param, "%hu", pid)) {
2567 ret = -EINVAL;
2568 goto done;
2569 }
2570 } else {
2571 goto done;
2572 }
2573
2574done:
2575 return ret;
2576}
2577
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002578#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002579/**
2580 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2581 * @pValue: Pointer to data
2582 * @pEseBcnReq: Output pointer to store parsed ie information
2583 *
2584 * This function parses the ese beacon request passed in the format
2585 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2586 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2587 * <space>Scan Mode N<space>Meas Duration N
2588 *
2589 * If the Number of bcn req fields (N) does not match with the
2590 * actual number of fields passed then take N.
2591 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2592 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2593 * This function does not take care of removing duplicate channels from the
2594 * list
2595 *
2596 * Return: 0 for success non-zero for failure
2597 */
2598static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2599 tCsrEseBeaconReq *pEseBcnReq)
2600{
2601 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002602 uint8_t input = 0;
2603 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002604 int j = 0, i = 0, v = 0;
2605 char buf[32];
2606
2607 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002608 if (NULL == inPtr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002609 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002610 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002611 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612
2613 /* remove empty spaces */
2614 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2615 inPtr++;
2616
2617 /* no argument followed by spaces */
2618 if ('\0' == *inPtr)
2619 return -EINVAL;
2620
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002621 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002622 v = sscanf(inPtr, "%31s ", buf);
2623 if (1 != v)
2624 return -EINVAL;
2625
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002626 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002627 if (v < 0)
2628 return -EINVAL;
2629
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002630 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2631 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002632
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002633 hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002634
2635 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2636 for (i = 0; i < 4; i++) {
2637 /*
2638 * inPtr pointing to the beginning of 1st space
2639 * after number of ie fields
2640 */
2641 inPtr = strpbrk(inPtr, " ");
2642 /* no ie data after the number of ie fields argument */
2643 if (NULL == inPtr)
2644 return -EINVAL;
2645
2646 /* remove empty space */
2647 while ((SPACE_ASCII_VALUE == *inPtr)
2648 && ('\0' != *inPtr))
2649 inPtr++;
2650
2651 /*
2652 * no ie data after the number of ie fields
2653 * argument and spaces
2654 */
2655 if ('\0' == *inPtr)
2656 return -EINVAL;
2657
2658 v = sscanf(inPtr, "%31s ", buf);
2659 if (1 != v)
2660 return -EINVAL;
2661
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002662 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002663 if (v < 0)
2664 return -EINVAL;
2665
2666 switch (i) {
2667 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002668 if (!tempInt) {
2669 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002670 tempInt);
2671 return -EINVAL;
2672 }
2673 pEseBcnReq->bcnReq[j].measurementToken =
2674 tempInt;
2675 break;
2676
2677 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002678 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002679 (tempInt >
2680 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002681 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002682 tempInt);
2683 return -EINVAL;
2684 }
2685 pEseBcnReq->bcnReq[j].channel = tempInt;
2686 break;
2687
2688 case 2: /* Scan mode */
2689 if ((tempInt < eSIR_PASSIVE_SCAN)
2690 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002691 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002692 tempInt);
2693 return -EINVAL;
2694 }
2695 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2696 break;
2697
2698 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002699 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002700 && (pEseBcnReq->bcnReq[j].scanMode !=
2701 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002702 (pEseBcnReq->bcnReq[j].scanMode ==
2703 eSIR_BEACON_TABLE)) {
2704 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002705 tempInt);
2706 return -EINVAL;
2707 }
2708 pEseBcnReq->bcnReq[j].measurementDuration =
2709 tempInt;
2710 break;
2711 }
2712 }
2713 }
2714
2715 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002716 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002717 j,
2718 pEseBcnReq->bcnReq[j].measurementToken,
2719 pEseBcnReq->bcnReq[j].channel,
2720 pEseBcnReq->bcnReq[j].scanMode,
2721 pEseBcnReq->bcnReq[j].measurementDuration);
2722 }
2723
2724 return 0;
2725}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002726
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002727/**
2728 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2729 * @pValue: Pointer to input data
2730 * @pCckmIe: Pointer to output cckm Ie
2731 * @pCckmIeLen: Pointer to output cckm ie length
2732 *
2733 * This function parses the SETCCKM IE command
2734 * SETCCKMIE<space><ie data>
2735 *
2736 * Return: 0 for success non-zero for failure
2737 */
2738static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2739 uint8_t *pCckmIeLen)
2740{
2741 uint8_t *inPtr = pValue;
2742 uint8_t *dataEnd;
2743 int j = 0;
2744 int i = 0;
2745 uint8_t tempByte = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002746
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002747 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2748 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002749 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002750 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002751 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002752 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002753
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002754 /* remove empty spaces */
2755 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2756 inPtr++;
2757 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002758 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002759 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002760
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002761 /* find the length of data */
2762 dataEnd = inPtr;
2763 while (('\0' != *dataEnd)) {
2764 dataEnd++;
2765 ++(*pCckmIeLen);
2766 }
2767 if (*pCckmIeLen <= 0)
2768 return -EINVAL;
2769 /*
2770 * Allocate the number of bytes based on the number of input characters
2771 * whether it is even or odd.
2772 * if the number of input characters are even, then we need N / 2 byte.
2773 * if the number of input characters are odd, then we need do
2774 * (N + 1) / 2 to compensate rounding off.
2775 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2776 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2777 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302778 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002779 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002780 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002781 return -ENOMEM;
2782 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002783 /*
2784 * the buffer received from the upper layer is character buffer,
2785 * we need to prepare the buffer taking 2 characters in to a U8 hex
2786 * decimal number for example 7f0000f0...form a buffer to contain
2787 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2788 */
2789 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2790 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2791 (hex_to_bin(inPtr[j + 1]));
2792 (*pCckmIe)[i++] = tempByte;
2793 }
2794 *pCckmIeLen = i;
2795 return 0;
2796}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002797#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002798
Jeff Johnson25c77342017-10-02 13:28:03 -07002799int wlan_hdd_set_mc_rate(struct hdd_adapter *adapter, int targetRate)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002800{
2801 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302802 QDF_STATUS status;
Jeff Johnson25c77342017-10-02 13:28:03 -07002803 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002804 struct hdd_config *pConfig = NULL;
2805
Jeff Johnson6da2db12017-09-03 09:18:52 -07002806 if (hdd_ctx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002807 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002808 return -EINVAL;
2809 }
Jeff Johnson25c77342017-10-02 13:28:03 -07002810 if ((QDF_IBSS_MODE != adapter->device_mode) &&
2811 (QDF_SAP_MODE != adapter->device_mode) &&
2812 (QDF_STA_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002813 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
Jeff Johnson25c77342017-10-02 13:28:03 -07002814 hdd_device_mode_to_string(adapter->device_mode),
2815 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002816 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002817 return -EINVAL;
2818 }
Jeff Johnson6da2db12017-09-03 09:18:52 -07002819 pConfig = hdd_ctx->config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002820 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
Jeff Johnson25c77342017-10-02 13:28:03 -07002821 rateUpdate.dev_mode = adapter->device_mode;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002822 rateUpdate.mcastDataRate24GHz = targetRate;
2823 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2824 rateUpdate.mcastDataRate5GHz = targetRate;
2825 rateUpdate.bcastDataRate = -1;
Jeff Johnson1e851a12017-10-28 14:36:12 -07002826 qdf_copy_macaddr(&rateUpdate.bssid, &adapter->mac_addr);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002827 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002828 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
Jeff Johnson25c77342017-10-02 13:28:03 -07002829 hdd_device_mode_to_string(adapter->device_mode),
2830 adapter->device_mode);
Jeff Johnson6da2db12017-09-03 09:18:52 -07002831 status = sme_send_rate_update_ind(hdd_ctx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302832 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002833 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002834 return -EFAULT;
2835 }
2836 return 0;
2837}
2838
Jeff Johnsone44b7012017-09-10 15:25:47 -07002839static int drv_cmd_p2p_dev_addr(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002840 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002841 uint8_t *command,
2842 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002843 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002844{
2845 int ret = 0;
2846
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302847 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002848 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002849 adapter->session_id,
Jeff Johnsonacbdb1c2017-11-02 20:42:02 -07002850 (unsigned int)(*(hdd_ctx->p2p_device_address.bytes + 2)
2851 << 24 | *(hdd_ctx->p2p_device_address.bytes
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002852 + 3) << 16 | *(hdd_ctx->
Jeff Johnsonacbdb1c2017-11-02 20:42:02 -07002853 p2p_device_address.bytes + 4) << 8 |
2854 *(hdd_ctx->p2p_device_address.bytes +
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002855 5))));
2856
Jeff Johnsonacbdb1c2017-11-02 20:42:02 -07002857 if (copy_to_user(priv_data->buf, hdd_ctx->p2p_device_address.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002858 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002859 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002860 ret = -EFAULT;
2861 }
2862
2863 return ret;
2864}
2865
2866/**
2867 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2868 * @adapter: Adapter on which the command was received
2869 * @hdd_ctx: HDD global context
2870 * @command: Entire driver command received from userspace
2871 * @command_len: Length of @command
2872 * @priv_data: Pointer to ioctl private data structure
2873 *
2874 * This is a trivial command hander function which simply forwards the
2875 * command to the actual command processor within the P2P module.
2876 *
2877 * Return: 0 on success, non-zero on failure
2878 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002879static int drv_cmd_p2p_set_noa(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002880 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002881 uint8_t *command,
2882 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002883 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002884{
2885 return hdd_set_p2p_noa(adapter->dev, command);
2886}
2887
2888/**
2889 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2890 * @adapter: Adapter on which the command was received
2891 * @hdd_ctx: HDD global context
2892 * @command: Entire driver command received from userspace
2893 * @command_len: Length of @command
2894 * @priv_data: Pointer to ioctl private data structure
2895 *
2896 * This is a trivial command hander function which simply forwards the
2897 * command to the actual command processor within the P2P module.
2898 *
2899 * Return: 0 on success, non-zero on failure
2900 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002901static int drv_cmd_p2p_set_ps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002902 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002903 uint8_t *command,
2904 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002905 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002906{
2907 return hdd_set_p2p_opps(adapter->dev, command);
2908}
2909
Jeff Johnsone44b7012017-09-10 15:25:47 -07002910static int drv_cmd_set_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002911 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002912 uint8_t *command,
2913 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002914 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002915{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002916 int err;
2917 uint8_t band;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002918
2919 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002920 * Parse the band value passed from userspace. The first 8 bytes
2921 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002922 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002923 err = kstrtou8(command + command_len + 1, 10, &band);
2924 if (err) {
2925 hdd_err("error %d parsing userspace band parameter", err);
2926 return err;
2927 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002928
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002929 return hdd_reg_set_band(adapter->dev, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002930}
2931
Jeff Johnsone44b7012017-09-10 15:25:47 -07002932static int drv_cmd_set_wmmps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002933 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002934 uint8_t *command,
2935 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002936 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002937{
2938 return hdd_wmmps_helper(adapter, command);
2939}
2940
Jeff Johnsone44b7012017-09-10 15:25:47 -07002941static inline int drv_cmd_country(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002942 struct hdd_context *hdd_ctx,
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002943 uint8_t *command,
2944 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002945 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002946{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002947 return hdd_reg_set_country(hdd_ctx, command + command_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002948}
2949
Jeff Johnsone44b7012017-09-10 15:25:47 -07002950static int drv_cmd_set_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002951 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002952 uint8_t *command,
2953 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002954 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002955{
2956 int ret = 0;
2957 uint8_t *value = command;
2958 int8_t rssi = 0;
2959 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302960 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002961
2962 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2963 value = value + command_len + 1;
2964
2965 /* Convert the value from ascii to integer */
2966 ret = kstrtos8(value, 10, &rssi);
2967 if (ret < 0) {
2968 /*
2969 * If the input value is greater than max value of datatype,
2970 * then also kstrtou8 fails
2971 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002972 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2973 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2974 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002975 ret = -EINVAL;
2976 goto exit;
2977 }
2978
2979 lookUpThreshold = abs(rssi);
2980
2981 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
2982 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002983 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002984 lookUpThreshold,
2985 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2986 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
2987 ret = -EINVAL;
2988 goto exit;
2989 }
2990
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302991 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002992 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002993 adapter->session_id, lookUpThreshold));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002994 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002995 lookUpThreshold);
2996
2997 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
2998 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002999 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003000 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303001 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003002 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003003 ret = -EPERM;
3004 goto exit;
3005 }
3006
3007exit:
3008 return ret;
3009}
3010
Jeff Johnsone44b7012017-09-10 15:25:47 -07003011static int drv_cmd_get_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003012 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003013 uint8_t *command,
3014 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003015 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003016{
3017 int ret = 0;
3018 uint8_t lookUpThreshold =
3019 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3020 int rssi = (-1) * lookUpThreshold;
3021 char extra[32];
3022 uint8_t len = 0;
3023
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303024 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003025 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003026 adapter->session_id, lookUpThreshold));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003027
3028 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303029 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003030 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003031 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003032 ret = -EFAULT;
3033 }
3034
3035 return ret;
3036}
3037
Jeff Johnsone44b7012017-09-10 15:25:47 -07003038static int drv_cmd_set_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003039 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003040 uint8_t *command,
3041 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003042 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003043{
3044 int ret = 0;
3045 uint8_t *value = command;
3046 uint8_t roamScanPeriod = 0;
3047 uint16_t neighborEmptyScanRefreshPeriod =
3048 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3049
3050 /* input refresh period is in terms of seconds */
3051
3052 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3053 value = value + command_len + 1;
3054
3055 /* Convert the value from ascii to integer */
3056 ret = kstrtou8(value, 10, &roamScanPeriod);
3057 if (ret < 0) {
3058 /*
3059 * If the input value is greater than max value of datatype,
3060 * then also kstrtou8 fails
3061 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003062 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3063 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3064 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003065 ret = -EINVAL;
3066 goto exit;
3067 }
3068
3069 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3070 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003071 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3072 roamScanPeriod,
3073 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3074 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003075 ret = -EINVAL;
3076 goto exit;
3077 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303078 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003079 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003080 adapter->session_id, roamScanPeriod));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003081 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3082
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003083 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003084 roamScanPeriod);
3085
3086 hdd_ctx->config->nEmptyScanRefreshPeriod =
3087 neighborEmptyScanRefreshPeriod;
3088 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003089 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003090 neighborEmptyScanRefreshPeriod);
3091
3092exit:
3093 return ret;
3094}
3095
Jeff Johnsone44b7012017-09-10 15:25:47 -07003096static int drv_cmd_get_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003097 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003098 uint8_t *command,
3099 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003100 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101{
3102 int ret = 0;
3103 uint16_t nEmptyScanRefreshPeriod =
3104 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3105 char extra[32];
3106 uint8_t len = 0;
3107
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303108 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003109 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003110 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003111 nEmptyScanRefreshPeriod));
3112 len = scnprintf(extra, sizeof(extra), "%s %d",
3113 "GETROAMSCANPERIOD",
3114 (nEmptyScanRefreshPeriod / 1000));
3115 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303116 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003117 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003118 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003119 ret = -EFAULT;
3120 }
3121
3122 return ret;
3123}
3124
Jeff Johnsone44b7012017-09-10 15:25:47 -07003125static int drv_cmd_set_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003126 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003127 uint8_t *command,
3128 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003129 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003130{
3131 int ret = 0;
3132 uint8_t *value = command;
3133 uint8_t roamScanRefreshPeriod = 0;
3134 uint16_t neighborScanRefreshPeriod =
3135 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3136
3137 /* input refresh period is in terms of seconds */
3138 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3139 value = value + command_len + 1;
3140
3141 /* Convert the value from ascii to integer */
3142 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3143 if (ret < 0) {
3144 /*
3145 * If the input value is greater than max value of datatype,
3146 * then also kstrtou8 fails
3147 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003148 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3149 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3150 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003151 ret = -EINVAL;
3152 goto exit;
3153 }
3154
3155 if ((roamScanRefreshPeriod <
3156 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3157 || (roamScanRefreshPeriod >
3158 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003159 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3160 roamScanRefreshPeriod,
3161 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3162 / 1000),
3163 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3164 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003165 ret = -EINVAL;
3166 goto exit;
3167 }
3168 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3169
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003170 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003171 roamScanRefreshPeriod);
3172
3173 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3174 neighborScanRefreshPeriod;
3175 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003176 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003177 neighborScanRefreshPeriod);
3178
3179exit:
3180 return ret;
3181}
3182
Jeff Johnsone44b7012017-09-10 15:25:47 -07003183static int drv_cmd_get_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003184 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003185 uint8_t *command,
3186 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003187 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003188{
3189 int ret = 0;
3190 uint16_t value =
3191 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3192 char extra[32];
3193 uint8_t len = 0;
3194
3195 len = scnprintf(extra, sizeof(extra), "%s %d",
3196 "GETROAMSCANREFRESHPERIOD",
3197 (value / 1000));
3198 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303199 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003200 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003201 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003202 ret = -EFAULT;
3203 }
3204
3205 return ret;
3206}
3207
Jeff Johnsone44b7012017-09-10 15:25:47 -07003208static int drv_cmd_set_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003209 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003210 uint8_t *command,
3211 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003212 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003213{
3214 int ret = 0;
3215 uint8_t *value = command;
3216 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3217
3218 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3219 value = value + SIZE_OF_SETROAMMODE + 1;
3220
3221 /* Convert the value from ascii to integer */
Rajeev Kumar Sirasanagandla248697d2017-08-30 12:27:45 +05303222 ret = kstrtou8(value, 10, &roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003223 if (ret < 0) {
3224 /*
3225 * If the input value is greater than max value of datatype,
3226 * then also kstrtou8 fails
3227 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003228 hdd_err("kstrtou8 failed range [%d - %d]",
3229 CFG_LFR_FEATURE_ENABLED_MIN,
3230 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003231 ret = -EINVAL;
3232 goto exit;
3233 }
3234 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3235 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003236 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3237 roamMode,
3238 CFG_LFR_FEATURE_ENABLED_MIN,
3239 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003240 ret = -EINVAL;
3241 goto exit;
3242 }
3243
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003244 hdd_debug("Received Command to Set Roam Mode = %d",
3245 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003246 /*
3247 * Note that
3248 * SETROAMMODE 0 is to enable LFR while
3249 * SETROAMMODE 1 is to disable LFR, but
3250 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3251 * enable/disable. So, we have to invert the value
3252 * to call sme_update_is_fast_roam_ini_feature_enabled.
3253 */
3254 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3255 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3256 else
3257 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3258
3259 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3260 if (roamMode) {
3261 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3262 sme_update_roam_scan_offload_enabled(
3263 (tHalHandle)(hdd_ctx->hHal),
3264 hdd_ctx->config->isRoamOffloadScanEnabled);
3265 sme_update_is_fast_roam_ini_feature_enabled(
3266 hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003267 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003268 roamMode);
3269 } else {
3270 sme_update_is_fast_roam_ini_feature_enabled(
3271 hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003272 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003273 roamMode);
3274 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3275 sme_update_roam_scan_offload_enabled(
3276 (tHalHandle)(hdd_ctx->hHal),
3277 hdd_ctx->config->isRoamOffloadScanEnabled);
3278 }
3279
3280
3281exit:
3282 return ret;
3283}
3284
Jeff Johnsone44b7012017-09-10 15:25:47 -07003285static int drv_cmd_get_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003286 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003287 uint8_t *command,
3288 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003289 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003290{
3291 int ret = 0;
3292 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3293 char extra[32];
3294 uint8_t len = 0;
3295
3296 /*
3297 * roamMode value shall be inverted because the sementics is different.
3298 */
3299 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3300 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3301 else
3302 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3303
3304 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303305 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003306 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003307 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003308 ret = -EFAULT;
3309 }
3310
3311 return ret;
3312}
3313
Jeff Johnsone44b7012017-09-10 15:25:47 -07003314static int drv_cmd_set_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003315 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003316 uint8_t *command,
3317 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003318 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003319{
3320 int ret = 0;
3321 uint8_t *value = command;
3322 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3323
3324 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3325 value = value + command_len + 1;
3326
3327 /* Convert the value from ascii to integer */
3328 ret = kstrtou8(value, 10, &roamRssiDiff);
3329 if (ret < 0) {
3330 /*
3331 * If the input value is greater than max value of datatype,
3332 * then also kstrtou8 fails
3333 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003334 hdd_err("kstrtou8 failed range [%d - %d]",
3335 CFG_ROAM_RSSI_DIFF_MIN,
3336 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003337 ret = -EINVAL;
3338 goto exit;
3339 }
3340
3341 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3342 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003343 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3344 roamRssiDiff,
3345 CFG_ROAM_RSSI_DIFF_MIN,
3346 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003347 ret = -EINVAL;
3348 goto exit;
3349 }
3350
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003351 hdd_debug("Received Command to Set roam rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003352 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003353
3354 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3355 sme_update_roam_rssi_diff(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003356 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003357 roamRssiDiff);
3358
3359exit:
3360 return ret;
3361}
3362
Jeff Johnsone44b7012017-09-10 15:25:47 -07003363static int drv_cmd_get_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003364 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003365 uint8_t *command,
3366 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003367 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003368{
3369 int ret = 0;
3370 uint8_t roamRssiDiff =
3371 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3372 char extra[32];
3373 uint8_t len = 0;
3374
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303375 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003376 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003377 adapter->session_id, roamRssiDiff));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003378
3379 len = scnprintf(extra, sizeof(extra), "%s %d",
3380 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303381 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003382
3383 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003384 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003385 ret = -EFAULT;
3386 }
3387
3388 return ret;
3389}
3390
Jeff Johnsone44b7012017-09-10 15:25:47 -07003391static int drv_cmd_get_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003392 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003393 uint8_t *command,
3394 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003395 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003396{
3397 int ret = 0;
3398 int band = -1;
3399 char extra[32];
3400 uint8_t len = 0;
3401
3402 hdd_get_band_helper(hdd_ctx, &band);
3403
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303404 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003405 TRACE_CODE_HDD_GETBAND_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003406 adapter->session_id, band));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003407
3408 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303409 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410
3411 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003412 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413 ret = -EFAULT;
3414 }
3415
3416 return ret;
3417}
3418
Jeff Johnsone44b7012017-09-10 15:25:47 -07003419static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003420 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421 uint8_t *command,
3422 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003423 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003424{
3425 return hdd_parse_set_roam_scan_channels(adapter, command);
3426}
3427
Jeff Johnsone44b7012017-09-10 15:25:47 -07003428static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003429 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003430 uint8_t *command,
3431 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003432 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433{
3434 int ret = 0;
3435 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3436 uint8_t numChannels = 0;
3437 uint8_t j = 0;
3438 char extra[128] = { 0 };
3439 int len;
3440
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303441 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003442 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3443 ChannelList,
3444 &numChannels,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003445 adapter->session_id)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003446 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003447 ret = -EFAULT;
3448 goto exit;
3449 }
3450
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303451 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003453 adapter->session_id, numChannels));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003454 /*
3455 * output channel list is of the format
3456 * [Number of roam scan channels][Channel1][Channel2]...
3457 * copy the number of channels in the 0th index
3458 */
3459 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3460 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303461 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003462 len += scnprintf(extra + len, sizeof(extra) - len,
3463 " %d", ChannelList[j]);
3464
Anurag Chouhan6d760662016-02-20 16:05:43 +05303465 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003466 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003467 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003468 ret = -EFAULT;
3469 goto exit;
3470 }
3471
3472exit:
3473 return ret;
3474}
3475
Jeff Johnsone44b7012017-09-10 15:25:47 -07003476static int drv_cmd_get_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003477 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003478 uint8_t *command,
3479 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003480 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003481{
3482 int ret = 0;
3483 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3484 char extra[32];
3485 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003486 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003487
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003488 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003489 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003490 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003491 * then this operation is not permitted (return FAILURE)
3492 */
3493 if (eseMode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003494 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003495 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003496 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003497 ret = -EPERM;
3498 goto exit;
3499 }
3500
3501 len = scnprintf(extra, sizeof(extra), "%s %d",
3502 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303503 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003504 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003505 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003506 ret = -EFAULT;
3507 goto exit;
3508 }
3509
3510exit:
3511 return ret;
3512}
3513
Jeff Johnsone44b7012017-09-10 15:25:47 -07003514static int drv_cmd_get_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003515 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003516 uint8_t *command,
3517 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003518 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003519{
3520 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003521 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003522 char extra[32];
3523 uint8_t len = 0;
3524
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003525 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003526 /*
3527 * Check if the features OKC/ESE/11R are supported simultaneously,
3528 * then this operation is not permitted (return FAILURE)
3529 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003530 if (pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003531 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3532 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003533 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003534 ret = -EPERM;
3535 goto exit;
3536 }
3537
3538 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003539 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303540 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003541
3542 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003543 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003544 ret = -EFAULT;
3545 goto exit;
3546 }
3547
3548exit:
3549 return ret;
3550}
3551
Jeff Johnsone44b7012017-09-10 15:25:47 -07003552static int drv_cmd_get_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003553 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003554 uint8_t *command,
3555 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003556 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003557{
3558 int ret = 0;
3559 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3560 char extra[32];
3561 uint8_t len = 0;
3562
3563 len = scnprintf(extra, sizeof(extra), "%s %d",
3564 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303565 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003566
3567 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003568 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003569 ret = -EFAULT;
3570 }
3571
3572 return ret;
3573}
3574
Jeff Johnsone44b7012017-09-10 15:25:47 -07003575static int drv_cmd_get_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003576 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003577 uint8_t *command,
3578 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003579 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003580{
3581 int ret = 0;
3582 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3583 char extra[32];
3584 uint8_t len = 0;
3585
3586 len = scnprintf(extra, sizeof(extra), "%s %d",
3587 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303588 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003589
3590 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003591 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003592 ret = -EFAULT;
3593 }
3594
3595 return ret;
3596}
3597
Jeff Johnsone44b7012017-09-10 15:25:47 -07003598static int drv_cmd_set_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003599 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003600 uint8_t *command,
3601 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003602 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003603{
3604 int ret = 0;
3605 uint8_t *value = command;
3606 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3607
3608 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3609 value = value + command_len + 1;
3610
3611 /* Convert the value from ascii to integer */
3612 ret = kstrtou8(value, 10, &minTime);
3613 if (ret < 0) {
3614 /*
3615 * If the input value is greater than max value of datatype,
3616 * then also kstrtou8 fails
3617 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003618 hdd_err("kstrtou8 failed range [%d - %d]",
3619 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3620 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003621 ret = -EINVAL;
3622 goto exit;
3623 }
3624
3625 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3626 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003627 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3628 minTime,
3629 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3630 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003631 ret = -EINVAL;
3632 goto exit;
3633 }
3634
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303635 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003637 adapter->session_id, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003638 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003639 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003640
3641 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3642 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3643 minTime,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003644 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003645
3646exit:
3647 return ret;
3648}
3649
Jeff Johnsone44b7012017-09-10 15:25:47 -07003650static int drv_cmd_send_action_frame(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003651 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003652 uint8_t *command,
3653 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003654 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003655{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003656 return hdd_parse_sendactionframe(adapter, command,
3657 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658}
3659
Jeff Johnsone44b7012017-09-10 15:25:47 -07003660static int drv_cmd_get_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003661 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003662 uint8_t *command,
3663 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003664 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003665{
3666 int ret = 0;
3667 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003668 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003669 char extra[32];
3670 uint8_t len = 0;
3671
3672 /* value is interms of msec */
3673 len = scnprintf(extra, sizeof(extra), "%s %d",
3674 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303675 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003676
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303677 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003678 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003679 adapter->session_id, val));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003680
3681 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003682 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003683 ret = -EFAULT;
3684 }
3685
3686 return ret;
3687}
3688
Jeff Johnsone44b7012017-09-10 15:25:47 -07003689static int drv_cmd_set_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003690 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003691 uint8_t *command,
3692 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003693 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003694{
3695 int ret = 0;
3696 uint8_t *value = command;
3697 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3698
3699 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3700 value = value + command_len + 1;
3701
3702 /* Convert the value from ascii to integer */
3703 ret = kstrtou16(value, 10, &maxTime);
3704 if (ret < 0) {
3705 /*
3706 * If the input value is greater than max value of datatype,
3707 * then also kstrtou8 fails
3708 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003709 hdd_err("kstrtou16 failed range [%d - %d]",
3710 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3711 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003712 ret = -EINVAL;
3713 goto exit;
3714 }
3715
3716 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3717 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003718 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3719 maxTime,
3720 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3721 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003722 ret = -EINVAL;
3723 goto exit;
3724 }
3725
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003726 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003727 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003728
3729 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3730 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003731 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003732 maxTime);
3733
3734exit:
3735 return ret;
3736}
3737
Jeff Johnsone44b7012017-09-10 15:25:47 -07003738static int drv_cmd_get_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003739 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003740 uint8_t *command,
3741 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003742 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003743{
3744 int ret = 0;
3745 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003746 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003747 char extra[32];
3748 uint8_t len = 0;
3749
3750 /* value is interms of msec */
3751 len = scnprintf(extra, sizeof(extra), "%s %d",
3752 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303753 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003754
3755 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003756 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003757 ret = -EFAULT;
3758 }
3759
3760 return ret;
3761}
3762
Jeff Johnsone44b7012017-09-10 15:25:47 -07003763static int drv_cmd_set_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003764 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003765 uint8_t *command,
3766 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003767 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003768{
3769 int ret = 0;
3770 uint8_t *value = command;
3771 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3772
3773 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3774 value = value + command_len + 1;
3775
3776 /* Convert the value from ascii to integer */
3777 ret = kstrtou16(value, 10, &val);
3778 if (ret < 0) {
3779 /*
3780 * If the input value is greater than max value of datatype,
3781 * then also kstrtou8 fails
3782 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003783 hdd_err("kstrtou16 failed range [%d - %d]",
3784 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3785 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003786 ret = -EINVAL;
3787 goto exit;
3788 }
3789
3790 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3791 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003792 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3793 val,
3794 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3795 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003796 ret = -EINVAL;
3797 goto exit;
3798 }
3799
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003800 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003801 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003802
3803 hdd_ctx->config->nNeighborScanPeriod = val;
3804 sme_set_neighbor_scan_period(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003805 adapter->session_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003806
3807exit:
3808 return ret;
3809}
3810
Jeff Johnsone44b7012017-09-10 15:25:47 -07003811static int drv_cmd_get_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003812 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003813 uint8_t *command,
3814 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003815 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003816{
3817 int ret = 0;
3818 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003819 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003820 char extra[32];
3821 uint8_t len = 0;
3822
3823 /* value is interms of msec */
3824 len = scnprintf(extra, sizeof(extra), "%s %d",
3825 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303826 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003827
3828 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003829 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003830 ret = -EFAULT;
3831 }
3832
3833 return ret;
3834}
3835
Jeff Johnsone44b7012017-09-10 15:25:47 -07003836static int drv_cmd_set_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003837 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003838 uint8_t *command,
3839 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003840 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003841{
3842 int ret = 0;
3843 uint8_t *value = command;
3844 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3845
3846 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3847 value = value + command_len + 1;
3848
3849 /* Convert the value from ascii to integer */
3850 ret = kstrtou8(value, 10, &val);
3851 if (ret < 0) {
3852 /*
3853 * If the input value is greater than max value of datatype,
3854 * then also kstrtou8 fails
3855 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003856 hdd_err("kstrtou8 failed range [%d - %d]",
3857 CFG_ROAM_INTRA_BAND_MIN,
3858 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003859 ret = -EINVAL;
3860 goto exit;
3861 }
3862
3863 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3864 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003865 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3866 val,
3867 CFG_ROAM_INTRA_BAND_MIN,
3868 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003869 ret = -EINVAL;
3870 goto exit;
3871 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003872 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003873 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003874
3875 hdd_ctx->config->nRoamIntraBand = val;
3876 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3877
3878exit:
3879 return ret;
3880}
3881
Jeff Johnsone44b7012017-09-10 15:25:47 -07003882static int drv_cmd_get_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003883 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003884 uint8_t *command,
3885 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003886 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003887{
3888 int ret = 0;
3889 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3890 char extra[32];
3891 uint8_t len = 0;
3892
3893 /* value is interms of msec */
3894 len = scnprintf(extra, sizeof(extra), "%s %d",
3895 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303896 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003898 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003899 ret = -EFAULT;
3900 }
3901
3902 return ret;
3903}
3904
Jeff Johnsone44b7012017-09-10 15:25:47 -07003905static int drv_cmd_set_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003906 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003907 uint8_t *command,
3908 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003909 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003910{
3911 int ret = 0;
3912 uint8_t *value = command;
3913 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3914
3915 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3916 value = value + command_len + 1;
3917
3918 /* Convert the value from ascii to integer */
3919 ret = kstrtou8(value, 10, &nProbes);
3920 if (ret < 0) {
3921 /*
3922 * If the input value is greater than max value of datatype,
3923 * then also kstrtou8 fails
3924 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003925 hdd_err("kstrtou8 failed range [%d - %d]",
3926 CFG_ROAM_SCAN_N_PROBES_MIN,
3927 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003928 ret = -EINVAL;
3929 goto exit;
3930 }
3931
3932 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3933 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003934 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3935 nProbes,
3936 CFG_ROAM_SCAN_N_PROBES_MIN,
3937 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003938 ret = -EINVAL;
3939 goto exit;
3940 }
3941
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003942 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003943 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003944
3945 hdd_ctx->config->nProbes = nProbes;
3946 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003947 adapter->session_id, nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003948
3949exit:
3950 return ret;
3951}
3952
Jeff Johnsone44b7012017-09-10 15:25:47 -07003953static int drv_cmd_get_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003954 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003955 uint8_t *command,
3956 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003957 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003958{
3959 int ret = 0;
3960 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3961 char extra[32];
3962 uint8_t len = 0;
3963
3964 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303965 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003966 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003967 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003968 ret = -EFAULT;
3969 }
3970
3971 return ret;
3972}
3973
Jeff Johnsone44b7012017-09-10 15:25:47 -07003974static int drv_cmd_set_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003975 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003976 uint8_t *command,
3977 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003978 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003979{
3980 int ret = 0;
3981 uint8_t *value = command;
3982 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3983
3984 /* input value is in units of msec */
3985
3986 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3987 value = value + command_len + 1;
3988
3989 /* Convert the value from ascii to integer */
3990 ret = kstrtou16(value, 10, &homeAwayTime);
3991 if (ret < 0) {
3992 /*
3993 * If the input value is greater than max value of datatype,
3994 * then also kstrtou8 fails
3995 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003996 hdd_err("kstrtou8 failed range [%d - %d]",
3997 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3998 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003999 ret = -EINVAL;
4000 goto exit;
4001 }
4002
4003 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4004 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004005 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004006 homeAwayTime,
4007 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4008 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4009 ret = -EINVAL;
4010 goto exit;
4011 }
4012
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004013 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004014 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004015
4016 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4017 homeAwayTime) {
4018 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4019 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004020 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004021 homeAwayTime,
4022 true);
4023 }
4024
4025exit:
4026 return ret;
4027}
4028
Jeff Johnsone44b7012017-09-10 15:25:47 -07004029static int drv_cmd_get_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004030 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004031 uint8_t *command,
4032 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004033 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004034{
4035 int ret = 0;
4036 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4037 char extra[32];
4038 uint8_t len = 0;
4039
4040 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304041 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004042
4043 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004044 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004045 ret = -EFAULT;
4046 }
4047
4048 return ret;
4049}
4050
Jeff Johnsone44b7012017-09-10 15:25:47 -07004051static int drv_cmd_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004052 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004053 uint8_t *command,
4054 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004055 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004056{
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05304057 return hdd_parse_reassoc(adapter, command, priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004058}
4059
Jeff Johnsone44b7012017-09-10 15:25:47 -07004060static int drv_cmd_set_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004061 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004062 uint8_t *command,
4063 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004064 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004065{
4066 int ret = 0;
4067 uint8_t *value = command;
4068 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4069
4070 /* Move pointer to ahead of SETWESMODE<delimiter> */
4071 value = value + command_len + 1;
4072
4073 /* Convert the value from ascii to integer */
4074 ret = kstrtou8(value, 10, &wesMode);
4075 if (ret < 0) {
4076 /*
4077 * If the input value is greater than max value of datatype,
4078 * then also kstrtou8 fails
4079 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004080 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004081 CFG_ENABLE_WES_MODE_NAME_MIN,
4082 CFG_ENABLE_WES_MODE_NAME_MAX);
4083 ret = -EINVAL;
4084 goto exit;
4085 }
4086
4087 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4088 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004089 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004090 wesMode,
4091 CFG_ENABLE_WES_MODE_NAME_MIN,
4092 CFG_ENABLE_WES_MODE_NAME_MAX);
4093 ret = -EINVAL;
4094 goto exit;
4095 }
4096
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004097 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004098 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004099
4100 hdd_ctx->config->isWESModeEnabled = wesMode;
Jeff Johnson1b780e42017-10-31 14:11:45 -07004101 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004102
4103exit:
4104 return ret;
4105}
4106
Jeff Johnsone44b7012017-09-10 15:25:47 -07004107static int drv_cmd_get_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004108 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004109 uint8_t *command,
4110 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004111 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004112{
4113 int ret = 0;
4114 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4115 char extra[32];
4116 uint8_t len = 0;
4117
4118 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304119 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004120 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004121 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004122 ret = -EFAULT;
4123 }
4124
4125 return ret;
4126}
4127
Jeff Johnsone44b7012017-09-10 15:25:47 -07004128static int drv_cmd_set_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004129 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004130 uint8_t *command,
4131 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004132 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004133{
4134 int ret = 0;
4135 uint8_t *value = command;
4136 uint8_t nOpportunisticThresholdDiff =
4137 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4138
4139 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4140 value = value + command_len + 1;
4141
4142 /* Convert the value from ascii to integer */
4143 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4144 if (ret < 0) {
4145 /*
4146 * If the input value is greater than max value of datatype,
4147 * then also kstrtou8 fails
4148 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004149 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004150 ret = -EINVAL;
4151 goto exit;
4152 }
4153
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004154 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004155 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004156
4157 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004158 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004159 nOpportunisticThresholdDiff);
4160
4161exit:
4162 return ret;
4163}
4164
Jeff Johnsone44b7012017-09-10 15:25:47 -07004165static int drv_cmd_get_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004166 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004167 uint8_t *command,
4168 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004169 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004170{
4171 int ret = 0;
4172 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4173 hdd_ctx->hHal);
4174 char extra[32];
4175 uint8_t len = 0;
4176
4177 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304178 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004179 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004180 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004181 ret = -EFAULT;
4182 }
4183
4184 return ret;
4185}
4186
Jeff Johnsone44b7012017-09-10 15:25:47 -07004187static int drv_cmd_set_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004188 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004189 uint8_t *command,
4190 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004191 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004192{
4193 int ret = 0;
4194 uint8_t *value = command;
4195 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4196
4197 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4198 value = value + command_len + 1;
4199
4200 /* Convert the value from ascii to integer */
4201 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4202 if (ret < 0) {
4203 /*
4204 * If the input value is greater than max value of datatype,
4205 * then also kstrtou8 fails
4206 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004207 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004208 ret = -EINVAL;
4209 goto exit;
4210 }
4211
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004212 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004213 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004214
4215 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004216 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004217 nRoamRescanRssiDiff);
4218
4219exit:
4220 return ret;
4221}
4222
Jeff Johnsone44b7012017-09-10 15:25:47 -07004223static int drv_cmd_get_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004224 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004225 uint8_t *command,
4226 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004227 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004228{
4229 int ret = 0;
4230 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4231 char extra[32];
4232 uint8_t len = 0;
4233
4234 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304235 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004236 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004237 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004238 ret = -EFAULT;
4239 }
4240
4241 return ret;
4242}
4243
Jeff Johnsone44b7012017-09-10 15:25:47 -07004244static int drv_cmd_set_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004245 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004246 uint8_t *command,
4247 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004248 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004249{
4250 int ret = 0;
4251 uint8_t *value = command;
4252 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4253
4254 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4255 value = value + command_len + 1;
4256
4257 /* Convert the value from ascii to integer */
4258 ret = kstrtou8(value, 10, &lfrMode);
4259 if (ret < 0) {
4260 /*
4261 * If the input value is greater than max value of datatype,
4262 * then also kstrtou8 fails
4263 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004264 hdd_err("kstrtou8 failed range [%d - %d]",
4265 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004266 CFG_LFR_FEATURE_ENABLED_MAX);
4267 ret = -EINVAL;
4268 goto exit;
4269 }
4270
4271 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4272 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004273 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004274 lfrMode,
4275 CFG_LFR_FEATURE_ENABLED_MIN,
4276 CFG_LFR_FEATURE_ENABLED_MAX);
4277 ret = -EINVAL;
4278 goto exit;
4279 }
4280
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004281 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004282 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004283
4284 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4285 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004286 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004287 lfrMode);
4288
4289exit:
4290 return ret;
4291}
4292
Jeff Johnsone44b7012017-09-10 15:25:47 -07004293static int drv_cmd_set_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004294 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004295 uint8_t *command,
4296 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004297 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004298{
4299 int ret = 0;
4300 uint8_t *value = command;
4301 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4302
4303 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4304 value = value + command_len + 1;
4305
4306 /* Convert the value from ascii to integer */
4307 ret = kstrtou8(value, 10, &ft);
4308 if (ret < 0) {
4309 /*
4310 * If the input value is greater than max value of datatype,
4311 * then also kstrtou8 fails
4312 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004313 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004314 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4315 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4316 ret = -EINVAL;
4317 goto exit;
4318 }
4319
4320 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4321 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004322 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004323 ft,
4324 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4325 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4326 ret = -EINVAL;
4327 goto exit;
4328 }
4329
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004330 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004331
4332 hdd_ctx->config->isFastTransitionEnabled = ft;
4333 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4334
4335exit:
4336 return ret;
4337}
4338
Jeff Johnsone44b7012017-09-10 15:25:47 -07004339static int drv_cmd_fast_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004340 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004341 uint8_t *command,
4342 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004343 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344{
4345 int ret = 0;
4346 uint8_t *value = command;
4347 uint8_t channel = 0;
4348 tSirMacAddr targetApBssid;
Krunal Sonibfd05492017-10-03 15:48:37 -07004349 uint32_t roamId = INVALID_ROAM_ID;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004350 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004351 tCsrHandoffRequest handoffInfo;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004352 struct hdd_station_ctx *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004353
Krunal Sonibe766b02016-03-10 13:00:44 -08004354 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355 hdd_warn("Unsupported in mode %s(%d)",
4356 hdd_device_mode_to_string(adapter->device_mode),
4357 adapter->device_mode);
4358 return -EINVAL;
4359 }
4360
Jeff Johnsond377dce2017-10-04 10:32:42 -07004361 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004362
4363 /* if not associated, no need to proceed with reassoc */
Jeff Johnsond377dce2017-10-04 10:32:42 -07004364 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004365 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004366 ret = -EINVAL;
4367 goto exit;
4368 }
4369
4370 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4371 &channel);
4372 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004373 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004374 goto exit;
4375 }
4376
4377 /*
4378 * if the target bssid is same as currently associated AP,
4379 * issue reassoc to same AP
4380 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004381 if (!qdf_mem_cmp(targetApBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004382 sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304383 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004384 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304385 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004386 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304387 targetApBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004388 sta_ctx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304389 } else {
4390 sme_get_modify_profile_fields(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004391 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004392 &modProfileFields);
Jeff Johnson1b780e42017-10-31 14:11:45 -07004393 sme_roam_reassoc(hdd_ctx->hHal, adapter->session_id,
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304394 NULL, modProfileFields, &roamId, 1);
4395 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004396 return 0;
4397 }
4398
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304399 /* Check channel number is a valid channel number */
Selvaraj, Sridhar64b0a9c2017-05-11 16:50:15 +05304400 if (channel && (QDF_STATUS_SUCCESS !=
4401 wlan_hdd_validate_operation_channel(adapter, channel))) {
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304402 hdd_err("Invalid Channel [%d]", channel);
4403 return -EINVAL;
4404 }
4405
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004406 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004407 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004408 targetApBssid, (int)channel);
4409 goto exit;
4410 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004411 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004412 handoffInfo.channel = channel;
4413 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004414 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004415 sizeof(tSirMacAddr));
Jeff Johnson1b780e42017-10-31 14:11:45 -07004416 sme_handoff_request(hdd_ctx->hHal, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004418exit:
4419 return ret;
4420}
4421
Jeff Johnsone44b7012017-09-10 15:25:47 -07004422static int drv_cmd_set_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004423 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004424 uint8_t *command,
4425 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004426 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427{
4428 int ret = 0;
4429 uint8_t *value = command;
4430 uint8_t roamScanControl = 0;
4431
4432 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4433 value = value + command_len + 1;
4434
4435 /* Convert the value from ascii to integer */
4436 ret = kstrtou8(value, 10, &roamScanControl);
4437 if (ret < 0) {
4438 /*
4439 * If the input value is greater than max value of datatype,
4440 * then also kstrtou8 fails
4441 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004442 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443 ret = -EINVAL;
4444 goto exit;
4445 }
4446
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004447 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004448 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004449
4450 if (0 != roamScanControl) {
4451 ret = 0; /* return success but ignore param value "true" */
4452 goto exit;
4453 }
4454
4455 sme_set_roam_scan_control(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004456 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004457 roamScanControl);
4458
4459exit:
4460 return ret;
4461}
4462
Jeff Johnsone44b7012017-09-10 15:25:47 -07004463static int drv_cmd_set_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004464 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004465 uint8_t *command,
4466 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004467 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468{
4469 int ret = 0;
4470 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004471 uint32_t okc_mode;
4472 struct pmkid_mode_bits pmkid_modes;
4473
4474 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004475
4476 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004477 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004478 * then this operation is not permitted (return FAILURE)
4479 */
4480 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004481 pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004482 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004483 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484 ret = -EPERM;
4485 goto exit;
4486 }
4487
4488 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4489 value = value + command_len + 1;
4490
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004491 /* get the current configured value */
4492 okc_mode = hdd_ctx->config->pmkid_modes & CFG_PMKID_MODES_OKC;
4493
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004495 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004496 if (ret < 0) {
4497 /*
4498 * If the input value is greater than max value of datatype,
4499 * then also kstrtou8 fails
4500 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004501 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502 ret = -EINVAL;
4503 goto exit;
4504 }
4505
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004506 if ((okc_mode < 0) ||
4507 (okc_mode > 1)) {
4508 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4509 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004510 ret = -EINVAL;
4511 goto exit;
4512 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004513 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004514 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004515
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004516 if (okc_mode)
4517 hdd_ctx->config->pmkid_modes |= CFG_PMKID_MODES_OKC;
4518 else
4519 hdd_ctx->config->pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004520
4521exit:
4522 return ret;
4523}
4524
Jeff Johnsone44b7012017-09-10 15:25:47 -07004525static int drv_cmd_get_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004526 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004527 uint8_t *command,
4528 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004529 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004530{
4531 int ret = 0;
4532 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4533 char extra[32];
4534 uint8_t len = 0;
4535
4536 len = scnprintf(extra, sizeof(extra), "%s %d",
4537 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304538 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004539 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004540 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004541 ret = -EFAULT;
4542 }
4543
4544 return ret;
4545}
4546
Jeff Johnsone44b7012017-09-10 15:25:47 -07004547static int drv_cmd_bt_coex_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004548 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004549 uint8_t *command,
4550 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004551 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004552{
4553 int ret = 0;
4554 char *bcMode;
4555
4556 bcMode = command + 11;
4557 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004558 hdd_debug("BTCOEXMODE %d", *bcMode);
Jeff Johnson59b19312017-11-02 21:14:33 -07004559 hdd_ctx->bt_coex_mode_set = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004560 ret = wlan_hdd_scan_abort(adapter);
4561 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004562 hdd_err("Failed to abort existing scan status: %d",
4563 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004564 }
4565 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004566 hdd_debug("BTCOEXMODE %d", *bcMode);
Jeff Johnson59b19312017-11-02 21:14:33 -07004567 hdd_ctx->bt_coex_mode_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004568 }
4569
4570 return ret;
4571}
4572
Jeff Johnsone44b7012017-09-10 15:25:47 -07004573static int drv_cmd_scan_active(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004574 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004575 uint8_t *command,
4576 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004577 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004578{
4579 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4580 return 0;
4581}
4582
Jeff Johnsone44b7012017-09-10 15:25:47 -07004583static int drv_cmd_scan_passive(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004584 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004585 uint8_t *command,
4586 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004587 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004588{
4589 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4590 return 0;
4591}
4592
Jeff Johnsone44b7012017-09-10 15:25:47 -07004593static int drv_cmd_get_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004594 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004595 uint8_t *command,
4596 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004597 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004598{
4599 int ret = 0;
4600 struct hdd_config *pCfg =
4601 (WLAN_HDD_GET_CTX(adapter))->config;
4602 char extra[32];
4603 uint8_t len = 0;
4604
4605 memset(extra, 0, sizeof(extra));
4606 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304607 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004608 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004609 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004610 ret = -EFAULT;
4611 goto exit;
4612 }
4613 ret = len;
4614exit:
4615 return ret;
4616}
4617
Jeff Johnsone44b7012017-09-10 15:25:47 -07004618static int drv_cmd_set_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004619 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004620 uint8_t *command,
4621 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004622 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623{
4624 return hdd_set_dwell_time(adapter, command);
4625}
4626
Jeff Johnsone44b7012017-09-10 15:25:47 -07004627static int drv_cmd_miracast(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004628 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004629 uint8_t *command,
4630 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004631 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004632{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304633 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 int ret = 0;
4635 tHalHandle hHal;
4636 uint8_t filterType = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637 uint8_t *value;
4638
Jeff Johnson6da2db12017-09-03 09:18:52 -07004639 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004641
Jeff Johnson6da2db12017-09-03 09:18:52 -07004642 hHal = hdd_ctx->hHal;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004643 value = command + 9;
4644
4645 /* Convert the value from ascii to integer */
4646 ret = kstrtou8(value, 10, &filterType);
4647 if (ret < 0) {
4648 /*
4649 * If the input value is greater than max value of datatype,
4650 * then also kstrtou8 fails
4651 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004652 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004653 ret = -EINVAL;
4654 goto exit;
4655 }
4656 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4657 || (filterType >
4658 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004659 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004660 ret = -EINVAL;
4661 goto exit;
4662 }
4663 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
Jeff Johnson6da2db12017-09-03 09:18:52 -07004664 hdd_ctx->miracast_value = filterType;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004665
4666 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304667 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004668 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669 return -EBUSY;
4670 }
Abhishek Singhc87bb042018-01-30 17:10:42 +05304671 ret_status = ucfg_scan_set_miracast(hdd_ctx->hdd_psoc,
4672 filterType ? true : false);
4673 if (QDF_IS_STATUS_ERROR(ret_status)) {
4674 hdd_err("Failed to set miracastn scan");
4675 return -EBUSY;
4676 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004677
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 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07004739static int drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *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;
Jeff Johnson5b34fce2017-10-13 13:24:51 -07004753 tCsrRoamProfile *roam_profile;
Jeff Johnson2a722002017-09-30 20:02:35 -07004754 struct hdd_wext_state *pWextState;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004755
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
Jeff Johnson5b34fce2017-10-13 13:24:51 -07004808 roam_profile = &pWextState->roamProfile;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004809
4810 qdf_copy_macaddr(&ibssModifyIE.bssid,
Jeff Johnson5b34fce2017-10-13 13:24:51 -07004811 roam_profile->BSSIDs.bssid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004812
Jeff Johnson1b780e42017-10-31 14:11:45 -07004813 ibssModifyIE.smeSessionId = adapter->session_id;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004814 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),
Jeff Johnson1b780e42017-10-31 14:11:45 -07004837 adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004838 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
Jeff Johnsone44b7012017-09-10 15:25:47 -07004849static int drv_cmd_set_rmc_enable(struct hdd_adapter *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),
Jeff Johnson1b780e42017-10-31 14:11:45 -07004882 adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004883 } else if (false == ucRmcEnable) {
4884 status = sme_disable_rmc((tHalHandle)
4885 (hdd_ctx->hHal),
Jeff Johnson1b780e42017-10-31 14:11:45 -07004886 adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004887 } 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
Jeff Johnsone44b7012017-09-10 15:25:47 -07004905static int drv_cmd_set_rmc_action_period(struct hdd_adapter *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),
Jeff Johnson1b780e42017-10-31 14:11:45 -07004946 adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004947 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
Jeff Johnsone44b7012017-09-10 15:25:47 -07004958static int drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *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;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004966 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004967 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
Jeff Johnsond377dce2017-10-04 10:32:42 -07004980 sta_ctx = 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 ",
Jeff Johnsond377dce2017-10-04 10:32:42 -07005002 sta_ctx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005003 numOfBytestoPrint = length;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005004 for (idx = 0; idx < sta_ctx->ibss_peer_info.numPeers;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005005 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,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005010 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005011 mac_addr, sizeof(mac_addr));
5012
5013 tx_rate =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005014 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005015 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
Jeff Johnsond377dce2017-10-04 10:32:42 -07005021 rssi = sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005022 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 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005085static int drv_cmd_get_ibss_peer_info(struct hdd_adapter *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;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005094 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005095 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
Jeff Johnsond377dce2017-10-04 10:32:42 -07005107 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005108
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 !=
Jeff Johnsond377dce2017-10-04 10:32:42 -07005113 sta_ctx->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 */
Jeff Johnsond377dce2017-10-04 10:32:42 -07005128 hdd_get_peer_sta_id(sta_ctx, &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 =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005140 sta_ctx->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,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005146 (int)sta_ctx->ibss_peer_info.
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005147 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
Jeff Johnsone44b7012017-09-10 15:25:47 -07005171static int drv_cmd_set_rmc_tx_rate(struct hdd_adapter *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,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005215 adapter->mac_addr.bytes,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005216 sizeof(rateUpdateParams.bssid));
5217 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5218 &rateUpdateParams);
5219
5220exit:
5221 return ret;
5222}
5223
Jeff Johnsone44b7012017-09-10 15:25:47 -07005224static int drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *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
Jeff Johnsone44b7012017-09-10 15:25:47 -07005276static int drv_cmd_set_ccx_roam_scan_channels(struct hdd_adapter *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,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005301 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005302 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
Jeff Johnsone44b7012017-09-10 15:25:47 -07005314static int drv_cmd_get_tsm_stats(struct hdd_adapter *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;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005325 struct hdd_station_ctx *sta_ctx;
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
Jeff Johnsond377dce2017-10-04 10:32:42 -07005336 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005337
5338 /* if not associated, return error */
Jeff Johnsond377dce2017-10-04 10:32:42 -07005339 if (eConnectionState_Associated != sta_ctx->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
Jeff Johnsone44b7012017-09-10 15:25:47 -07005417static int drv_cmd_set_cckm_ie(struct hdd_adapter *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
Jeff Johnson1b780e42017-10-31 14:11:45 -07005445 sme_set_cckm_ie(hdd_ctx->hHal, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005446 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
Jeff Johnsone44b7012017-09-10 15:25:47 -07005456static int drv_cmd_ccx_beacon_req(struct hdd_adapter *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,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005490 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005491 &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 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005521static int drv_cmd_ccx_plm_req(struct hdd_adapter *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 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07005545 pPlmRequest->sessionId = adapter->session_id;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005546
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 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005571static int drv_cmd_set_ccx_mode(struct hdd_adapter *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
5595 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5596 value = value + command_len + 1;
5597
5598 /* Convert the value from ascii to integer */
5599 ret = kstrtou8(value, 10, &eseMode);
5600 if (ret < 0) {
5601 /*
5602 * If the input value is greater than max value of datatype,
5603 * then also kstrtou8 fails
5604 */
5605 hdd_err("kstrtou8 failed range [%d - %d]",
5606 CFG_ESE_FEATURE_ENABLED_MIN,
5607 CFG_ESE_FEATURE_ENABLED_MAX);
5608 ret = -EINVAL;
5609 goto exit;
5610 }
5611
5612 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5613 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5614 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5615 eseMode,
5616 CFG_ESE_FEATURE_ENABLED_MIN,
5617 CFG_ESE_FEATURE_ENABLED_MAX);
5618 ret = -EINVAL;
5619 goto exit;
5620 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005621 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005622
5623 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5624 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005625 adapter->session_id,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005626 eseMode);
5627
5628exit:
5629 return ret;
5630}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005631#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005632
Jeff Johnsone44b7012017-09-10 15:25:47 -07005633static int drv_cmd_set_mc_rate(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005634 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005635 uint8_t *command,
5636 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005637 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005638{
5639 int ret = 0;
5640 uint8_t *value = command;
5641 int targetRate;
5642
5643 /* input value is in units of hundred kbps */
5644
5645 /* Move pointer to ahead of SETMCRATE<delimiter> */
5646 value = value + command_len + 1;
5647
5648 /* Convert the value from ascii to integer, decimal base */
5649 ret = kstrtouint(value, 10, &targetRate);
5650
5651 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5652 return ret;
5653}
5654
Jeff Johnsone44b7012017-09-10 15:25:47 -07005655static int drv_cmd_max_tx_power(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005656 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005657 uint8_t *command,
5658 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005659 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005660{
5661 int ret = 0;
5662 int status;
5663 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305664 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005665 uint8_t *value = command;
Dustin Brownce5b3d32018-01-17 15:07:38 -08005666 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
5667 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BCAST_INIT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005668
5669 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5670 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005671 hdd_err("Invalid MAXTXPOWER command");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005672 ret = -EINVAL;
5673 goto exit;
5674 }
5675
Dustin Brown920397d2017-12-13 16:27:50 -08005676 hdd_for_each_adapter(hdd_ctx, adapter) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005677 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305678 qdf_copy_macaddr(&bssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005679 &adapter->mac_addr);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305680 qdf_copy_macaddr(&selfMac,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005681 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005682
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005683 hdd_debug("Device mode %d max tx power %d selfMac: "
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005684 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005685 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005686 MAC_ADDR_ARRAY(selfMac.bytes),
5687 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005688
Srinivas Girigowda97215232015-09-24 12:26:28 -07005689 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5690 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305691 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005692 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005693 ret = -EINVAL;
5694 goto exit;
5695 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005696 hdd_debug("Set max tx power success");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005697 }
5698
5699exit:
5700 return ret;
5701}
5702
Jeff Johnsone44b7012017-09-10 15:25:47 -07005703static int drv_cmd_set_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005704 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005705 uint8_t *command,
5706 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005707 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005708{
5709 int ret = 0;
5710 uint8_t *value = command;
5711 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5712
5713 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5714 value = value + command_len + 1;
5715
5716 /* Convert the value from ascii to integer */
5717 ret = kstrtou8(value, 10, &dfsScanMode);
5718 if (ret < 0) {
5719 /*
5720 * If the input value is greater than max value of datatype,
5721 * then also kstrtou8 fails
5722 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005723 hdd_err("kstrtou8 failed range [%d - %d]",
5724 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005725 CFG_ROAMING_DFS_CHANNEL_MAX);
5726 ret = -EINVAL;
5727 goto exit;
5728 }
5729
5730 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5731 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005732 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005733 dfsScanMode,
5734 CFG_ROAMING_DFS_CHANNEL_MIN,
5735 CFG_ROAMING_DFS_CHANNEL_MAX);
5736 ret = -EINVAL;
5737 goto exit;
5738 }
5739
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005740 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005741 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005742
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005743 /* When DFS scanning is disabled, the DFS channels need to be
5744 * removed from the operation of device.
5745 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005746 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5747 dfsScanMode != CFG_ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005748 if (ret < 0) {
5749 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005750 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005751 goto exit;
5752 }
5753
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005754 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
Jeff Johnson1b780e42017-10-31 14:11:45 -07005755 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005756 dfsScanMode);
5757
5758exit:
5759 return ret;
5760}
5761
Jeff Johnsone44b7012017-09-10 15:25:47 -07005762static int drv_cmd_get_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005763 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005764 uint8_t *command,
5765 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005766 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005767{
5768 int ret = 0;
5769 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5770 char extra[32];
5771 uint8_t len = 0;
5772
5773 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305774 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005775 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005776 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005777 ret = -EFAULT;
5778 }
5779
5780 return ret;
5781}
5782
Jeff Johnsone44b7012017-09-10 15:25:47 -07005783static int drv_cmd_get_link_status(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005784 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005785 uint8_t *command,
5786 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005787 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005788{
5789 int ret = 0;
5790 int value = wlan_hdd_get_link_status(adapter);
5791 char extra[32];
5792 uint8_t len;
5793
5794 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305795 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005796 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005797 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005798 ret = -EFAULT;
5799 }
5800
5801 return ret;
5802}
5803
5804#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Jeff Johnsone44b7012017-09-10 15:25:47 -07005805static int drv_cmd_enable_ext_wow(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005806 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005807 uint8_t *command,
5808 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005809 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005810{
5811 uint8_t *value = command;
5812 int set_value;
5813
5814 /* Move pointer to ahead of ENABLEEXTWOW */
5815 value = value + command_len;
5816
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305817 if (!(sscanf(value, "%d", &set_value))) {
5818 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5819 ("No input identified"));
5820 return -EINVAL;
5821 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005822
5823 return hdd_enable_ext_wow_parser(adapter,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005824 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005825 set_value);
5826}
5827
Jeff Johnsone44b7012017-09-10 15:25:47 -07005828static int drv_cmd_set_app1_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005829 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005830 uint8_t *command,
5831 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005832 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005833{
5834 int ret;
5835 uint8_t *value = command;
5836
5837 /* Move pointer to ahead of SETAPP1PARAMS */
5838 value = value + command_len;
5839
5840 ret = hdd_set_app_type1_parser(adapter,
5841 value, strlen(value));
5842 if (ret >= 0)
5843 hdd_ctx->is_extwow_app_type1_param_set = true;
5844
5845 return ret;
5846}
5847
Jeff Johnsone44b7012017-09-10 15:25:47 -07005848static int drv_cmd_set_app2_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005849 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005850 uint8_t *command,
5851 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005852 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005853{
5854 int ret;
5855 uint8_t *value = command;
5856
5857 /* Move pointer to ahead of SETAPP2PARAMS */
5858 value = value + command_len;
5859
5860 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5861 if (ret >= 0)
5862 hdd_ctx->is_extwow_app_type2_param_set = true;
5863
5864 return ret;
5865}
5866#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5867
5868#ifdef FEATURE_WLAN_TDLS
5869/**
5870 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5871 * @adapter: Pointer to the HDD adapter
5872 * @hdd_ctx: Pointer to the HDD context
5873 * @command: Driver command string
5874 * @command_len: Driver command string length
5875 * @priv_data: Private data coming with the driver command. Unused here
5876 *
5877 * This function handles driver command that sets the secondary tdls off channel
5878 * offset
5879 *
5880 * Return: 0 on success; negative errno otherwise
5881 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005882static int drv_cmd_tdls_secondary_channel_offset(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005883 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005884 uint8_t *command,
5885 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005886 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005887{
5888 int ret;
5889 uint8_t *value = command;
5890 int set_value;
5891
5892 /* Move pointer to point the string */
5893 value += command_len;
5894
5895 ret = sscanf(value, "%d", &set_value);
5896 if (ret != 1)
5897 return -EINVAL;
5898
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005899 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005900
5901 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5902
5903 return ret;
5904}
5905
5906/**
5907 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5908 * @adapter: Pointer to the HDD adapter
5909 * @hdd_ctx: Pointer to the HDD context
5910 * @command: Driver command string
5911 * @command_len: Driver command string length
5912 * @priv_data: Private data coming with the driver command. Unused here
5913 *
5914 * This function handles driver command that sets tdls off channel mode
5915 *
5916 * Return: 0 on success; negative errno otherwise
5917 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005918static int drv_cmd_tdls_off_channel_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005919 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005920 uint8_t *command,
5921 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005922 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005923{
5924 int ret;
5925 uint8_t *value = command;
5926 int set_value;
5927
5928 /* Move pointer to point the string */
5929 value += command_len;
5930
5931 ret = sscanf(value, "%d", &set_value);
5932 if (ret != 1)
5933 return -EINVAL;
5934
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005935 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005936
5937 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5938
5939 return ret;
5940}
5941
5942/**
5943 * drv_cmd_tdls_off_channel() - set tdls off channel number
5944 * @adapter: Pointer to the HDD adapter
5945 * @hdd_ctx: Pointer to the HDD context
5946 * @command: Driver command string
5947 * @command_len: Driver command string length
5948 * @priv_data: Private data coming with the driver command. Unused here
5949 *
5950 * This function handles driver command that sets tdls off channel number
5951 *
5952 * Return: 0 on success; negative errno otherwise
5953 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005954static int drv_cmd_tdls_off_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005955 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005956 uint8_t *command,
5957 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005958 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005959{
5960 int ret;
5961 uint8_t *value = command;
5962 int set_value;
5963
5964 /* Move pointer to point the string */
5965 value += command_len;
5966
5967 ret = sscanf(value, "%d", &set_value);
5968 if (ret != 1)
5969 return -EINVAL;
5970
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -07005971 if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, set_value)) {
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005972 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5973 set_value);
5974 return -EINVAL;
5975 }
5976
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005977 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005978
5979 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5980
5981 return ret;
5982}
5983
5984/**
5985 * drv_cmd_tdls_scan() - set tdls scan type
5986 * @adapter: Pointer to the HDD adapter
5987 * @hdd_ctx: Pointer to the HDD context
5988 * @command: Driver command string
5989 * @command_len: Driver command string length
5990 * @priv_data: Private data coming with the driver command. Unused here
5991 *
5992 * This function handles driver command that sets tdls scan type
5993 *
5994 * Return: 0 on success; negative errno otherwise
5995 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005996static int drv_cmd_tdls_scan(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005997 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005998 uint8_t *command,
5999 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006000 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006001{
6002 int ret;
6003 uint8_t *value = command;
6004 int set_value;
6005
6006 /* Move pointer to point the string */
6007 value += command_len;
6008
6009 ret = sscanf(value, "%d", &set_value);
6010 if (ret != 1)
6011 return -EINVAL;
6012
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006013 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006014
6015 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6016
6017 return ret;
6018}
6019#endif
6020
Jeff Johnsone44b7012017-09-10 15:25:47 -07006021static int drv_cmd_get_rssi(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006022 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006023 uint8_t *command,
6024 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006025 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006026{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006027 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006028 int8_t rssi = 0;
6029 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006030
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006031 uint8_t len = 0;
6032
6033 wlan_hdd_get_rssi(adapter, &rssi);
6034
6035 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306036 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006037
6038 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006039 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006040 ret = -EFAULT;
6041 }
6042
6043 return ret;
6044}
6045
Jeff Johnsone44b7012017-09-10 15:25:47 -07006046static int drv_cmd_get_linkspeed(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006047 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006048 uint8_t *command,
6049 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006050 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006051{
6052 int ret;
6053 uint32_t link_speed = 0;
6054 char extra[32];
6055 uint8_t len = 0;
6056
6057 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6058 if (0 != ret)
6059 return ret;
6060
6061 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306062 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006063 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006064 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006065 ret = -EFAULT;
6066 }
6067
6068 return ret;
6069}
6070
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006071/**
6072 * hdd_set_rx_filter() - set RX filter
6073 * @adapter: Pointer to adapter
6074 * @action: Filter action
6075 * @pattern: Address pattern
6076 *
6077 * Address pattern is most significant byte of address for example
6078 * 0x01 for IPV4 multicast address
6079 * 0x33 for IPV6 multicast address
6080 * 0xFF for broadcast address
6081 *
6082 * Return: 0 for success, non-zero for failure
6083 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006084static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006085 uint8_t pattern)
6086{
6087 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006088 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006089 tHalHandle handle;
6090 tSirRcvFltMcAddrList *filter;
Jeff Johnson621cf972017-08-28 11:58:44 -07006091 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092
6093 ret = wlan_hdd_validate_context(hdd_ctx);
6094 if (0 != ret)
6095 return ret;
6096
6097 handle = hdd_ctx->hHal;
6098
6099 if (NULL == handle) {
6100 hdd_err("HAL Handle is NULL");
6101 return -EINVAL;
6102 }
6103
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306104 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006105 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306106 return -EINVAL;
6107 }
6108
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006109 /*
6110 * If action is false it means start dropping packets
6111 * Set addr_filter_pattern which will be used when sending
6112 * MC/BC address list to target
6113 */
6114 if (!action)
6115 adapter->addr_filter_pattern = pattern;
6116 else
6117 adapter->addr_filter_pattern = 0;
6118
Krunal Sonibe766b02016-03-10 13:00:44 -08006119 if (((adapter->device_mode == QDF_STA_MODE) ||
6120 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006121 adapter->mc_addr_list.mc_cnt &&
6122 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6123
6124
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306125 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006126 if (NULL == filter) {
6127 hdd_err("Could not allocate Memory");
6128 return -ENOMEM;
6129 }
6130 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006131 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006132 if (!memcmp(adapter->mc_addr_list.addr[i],
6133 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006134 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006135 adapter->mc_addr_list.addr[i],
6136 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006137
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006138 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006139 MAC_ADDRESS_STR,
6140 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006141 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6142 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006143 }
SaidiReddy Yenuga0b2c9f42017-02-03 12:26:38 +05306144 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
6145 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006146 }
Frank Liuf95e8132016-09-29 19:01:30 +08006147 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006148 /* Set rx filter */
Jeff Johnson1b780e42017-10-31 14:11:45 -07006149 sme_8023_multicast_list(handle, adapter->session_id, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306150 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006151 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006152 hdd_debug("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006153 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6154 }
6155
6156 return 0;
6157}
6158
6159/**
6160 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6161 * @command: Pointer to input string driver command
6162 * @adapter: Pointer to adapter
6163 * @action: Action to enable/disable filtering
6164 *
6165 * If action == false
6166 * Start filtering out data packets based on type
6167 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6168 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6169 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6170 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6171 *
6172 * if action == true
6173 * Stop filtering data packets based on type
6174 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6175 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6176 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6177 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6178 *
6179 * Current implementation only supports IPV4 address filtering by
6180 * selectively allowing IPV4 multicast data packest based on
6181 * address list received in .ndo_set_rx_mode
6182 *
6183 * Return: 0 for success, non-zero for failure
6184 */
6185static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
Jeff Johnsone44b7012017-09-10 15:25:47 -07006186 struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006187 bool action)
6188{
6189 int ret = 0;
6190 uint8_t *value;
6191 uint8_t type;
6192
6193 value = command;
6194 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6195 if (!action)
6196 value = command + 16;
6197 else
6198 value = command + 13;
6199 ret = kstrtou8(value, 10, &type);
6200 if (ret < 0) {
6201 hdd_err("kstrtou8 failed invalid input value %d", type);
6202 return -EINVAL;
6203 }
6204
6205 switch (type) {
6206 case 2:
6207 /* Set rx filter for IPV4 multicast data packets */
6208 ret = hdd_set_rx_filter(adapter, action, 0x01);
6209 break;
6210 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006211 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006212 break;
6213 }
6214
6215 return ret;
6216}
6217
6218/**
6219 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6220 * @adapter: Pointer to network adapter
6221 * @hdd_ctx: Pointer to hdd context
6222 * @command: Pointer to input command
6223 * @command_len: Command length
6224 * @priv_data: Pointer to private data in command
6225 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006226static int drv_cmd_rx_filter_remove(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006227 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006228 uint8_t *command,
6229 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006230 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006231{
6232 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6233}
6234
6235/**
6236 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6237 * @adapter: Pointer to network adapter
6238 * @hdd_ctx: Pointer to hdd context
6239 * @command: Pointer to input command
6240 * @command_len: Command length
6241 * @priv_data: Pointer to private data in command
6242 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006243static int drv_cmd_rx_filter_add(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006244 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006245 uint8_t *command,
6246 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006247 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006248{
6249 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6250}
6251
Archana Ramachandran393f3792015-11-13 17:13:21 -08006252/**
6253 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6254 * command
6255 * @value: Pointer to SETANTENNAMODE command
6256 * @mode: Pointer to antenna mode
6257 * @reason: Pointer to reason for set antenna mode
6258 *
6259 * This function parses the SETANTENNAMODE command passed in the format
6260 * SETANTENNAMODE<space>mode
6261 *
6262 * Return: 0 for success non-zero for failure
6263 */
6264static int hdd_parse_setantennamode_command(const uint8_t *value)
6265{
6266 const uint8_t *in_ptr = value;
6267 int tmp, v;
6268 char arg1[32];
6269
6270 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6271
6272 /* no argument after the command */
6273 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006274 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006275 return -EINVAL;
6276 }
6277
6278 /* no space after the command */
6279 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006280 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006281 return -EINVAL;
6282 }
6283
6284 /* remove empty spaces */
6285 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6286 in_ptr++;
6287
6288 /* no argument followed by spaces */
6289 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006290 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006291 return -EINVAL;
6292 }
6293
6294 /* get the argument i.e. antenna mode */
6295 v = sscanf(in_ptr, "%31s ", arg1);
6296 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006297 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006298 return -EINVAL;
6299 }
6300
6301 v = kstrtos32(arg1, 10, &tmp);
6302 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006303 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006304 return -EINVAL;
6305 }
6306
6307 return tmp;
6308}
6309
6310/**
6311 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6312 * mask is 2x2 mode
6313 * @hdd_ctx: Pointer to hdd contex
6314 *
6315 * Return: true if supported chain mask 2x2 else false
6316 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006317static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006318{
6319 /*
6320 * Revisit and the update logic to determine the number
6321 * of TX/RX chains supported in the system when
6322 * antenna sharing per band chain mask support is
6323 * brought in
6324 */
6325 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6326}
6327
6328/**
6329 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6330 * chain mask is 1x1
6331 * @hdd_ctx: Pointer to hdd contex
6332 *
6333 * Return: true if supported chain mask 1x1 else false
6334 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006335static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006336{
6337 /*
6338 * Revisit and update the logic to determine the number
6339 * of TX/RX chains supported in the system when
6340 * antenna sharing per band chain mask support is
6341 * brought in
6342 */
6343 return (!hdd_ctx->config->enable2x2) ? true : false;
6344}
6345
Jeff Johnson621cf972017-08-28 11:58:44 -07006346QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
Nitesh Shahe50711f2017-04-26 16:30:45 +05306347{
6348 QDF_STATUS status;
6349 uint8_t smps_mode;
6350 uint8_t smps_enable;
6351
6352 /* Update SME SMPS config */
6353 if (HDD_ANTENNA_MODE_1X1 == mode) {
6354 smps_enable = true;
6355 smps_mode = HDD_SMPS_MODE_STATIC;
6356 } else {
6357 smps_enable = false;
6358 smps_mode = HDD_SMPS_MODE_DISABLED;
6359 }
6360
6361 hdd_debug("Update SME SMPS enable: %d mode: %d",
6362 smps_enable, smps_mode);
6363 status = sme_update_mimo_power_save(
6364 hdd_ctx->hHal, smps_enable, smps_mode, false);
6365 if (QDF_STATUS_SUCCESS != status) {
6366 hdd_err("Update SMPS config failed enable: %d mode: %d"
6367 "status: %d",
6368 smps_enable, smps_mode, status);
6369 return QDF_STATUS_E_FAILURE;
6370 }
6371
6372 hdd_ctx->current_antenna_mode = mode;
6373 /*
6374 * Update the user requested nss in the mac context.
6375 * This will be used in tdls protocol engine to form tdls
6376 * Management frames.
6377 */
6378 sme_update_user_configured_nss(
6379 hdd_ctx->hHal,
6380 hdd_ctx->current_antenna_mode);
6381
6382 hdd_debug("Successfully switched to mode: %d x %d",
6383 hdd_ctx->current_antenna_mode,
6384 hdd_ctx->current_antenna_mode);
6385
6386 return QDF_STATUS_SUCCESS;
6387}
6388
Archana Ramachandran393f3792015-11-13 17:13:21 -08006389/**
6390 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6391 * handler
6392 * @adapter: Pointer to network adapter
6393 * @hdd_ctx: Pointer to hdd context
6394 * @command: Pointer to input command
6395 * @command_len: Command length
6396 * @priv_data: Pointer to private data in command
6397 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006398static int drv_cmd_set_antenna_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006399 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006400 uint8_t *command,
6401 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006402 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006403{
6404 struct sir_antenna_mode_param params;
6405 QDF_STATUS status;
6406 int ret = 0;
6407 int mode;
6408 uint8_t *value = command;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006409
Frank Liuc0c25fd2017-07-24 19:14:57 +08006410 if (((1 << QDF_STA_MODE) !=
6411 policy_mgr_get_concurrency_mode(hdd_ctx->hdd_psoc)) ||
6412 (policy_mgr_is_multiple_active_sta_sessions(hdd_ctx->hdd_psoc))) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006413 hdd_err("Operation invalid in non sta or concurrent mode");
6414 ret = -EPERM;
6415 goto exit;
6416 }
6417
6418 mode = hdd_parse_setantennamode_command(value);
6419 if (mode < 0) {
6420 hdd_err("Invalid SETANTENNA command");
6421 ret = mode;
6422 goto exit;
6423 }
6424
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006425 hdd_debug("Processing antenna mode switch to: %d", mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006426
6427 if (hdd_ctx->current_antenna_mode == mode) {
6428 hdd_err("System already in the requested mode");
6429 ret = 0;
6430 goto exit;
6431 }
6432
6433 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6434 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6435 hdd_err("System does not support 2x2 mode");
6436 ret = -EPERM;
6437 goto exit;
6438 }
6439
6440 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6441 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6442 hdd_err("System only supports 1x1 mode");
6443 ret = 0;
6444 goto exit;
6445 }
6446
6447 switch (mode) {
6448 case HDD_ANTENNA_MODE_1X1:
6449 params.num_rx_chains = 1;
6450 params.num_tx_chains = 1;
6451 break;
6452 case HDD_ANTENNA_MODE_2X2:
6453 params.num_rx_chains = 2;
6454 params.num_tx_chains = 2;
6455 break;
6456 default:
6457 hdd_err("unsupported antenna mode");
6458 ret = -EINVAL;
6459 goto exit;
6460 }
6461
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006462 /* Check TDLS status and update antenna mode */
6463 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006464 policy_mgr_is_sta_active_connection_exists(
6465 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006466 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6467 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006468 if (0 != ret)
6469 goto exit;
6470 }
6471
Archana Ramachandran393f3792015-11-13 17:13:21 -08006472 params.set_antenna_mode_resp =
6473 (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006474 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006475 params.num_rx_chains,
6476 params.num_tx_chains);
6477
6478
6479 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6480 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6481 if (QDF_STATUS_SUCCESS != status) {
6482 hdd_err("set antenna mode failed status : %d", status);
6483 ret = -EFAULT;
6484 goto exit;
6485 }
6486
6487 ret = wait_for_completion_timeout(
6488 &hdd_ctx->set_antenna_mode_cmpl,
6489 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6490 if (!ret) {
6491 ret = -EFAULT;
6492 hdd_err("send set antenna mode timed out");
6493 goto exit;
6494 }
6495
Nitesh Shahe50711f2017-04-26 16:30:45 +05306496 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006497 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006498 ret = -EFAULT;
6499 goto exit;
6500 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006501 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006502exit:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006503 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006504 ret, hdd_ctx->current_antenna_mode);
6505 return ret;
6506
6507}
6508
6509/**
6510 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6511 * handler
6512 * @adapter: Pointer to hdd adapter
6513 * @hdd_ctx: Pointer to hdd context
6514 * @command: Pointer to input command
6515 * @command_len: length of the command
6516 * @priv_data: private data coming with the driver command
6517 *
6518 * Return: 0 for success non-zero for failure
6519 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006520static inline int drv_cmd_get_antenna_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006521 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006522 uint8_t *command,
6523 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006524 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006525{
6526 uint32_t antenna_mode = 0;
6527 char extra[32];
6528 uint8_t len = 0;
6529
6530 antenna_mode = hdd_ctx->current_antenna_mode;
6531 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6532 antenna_mode);
6533 len = QDF_MIN(priv_data->total_len, len + 1);
6534 if (copy_to_user(priv_data->buf, &extra, len)) {
6535 hdd_err("Failed to copy data to user buffer");
6536 return -EFAULT;
6537 }
6538
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006539 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006540
6541 return 0;
6542}
6543
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006544/*
6545 * dummy (no-op) hdd driver command handler
6546 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006547static int drv_cmd_dummy(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006548 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006549 uint8_t *command,
6550 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006551 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006552{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006553 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006554 adapter->dev->name, command);
6555 return 0;
6556}
6557
6558/*
6559 * handler for any unsupported wlan hdd driver command
6560 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006561static int drv_cmd_invalid(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006562 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006563 uint8_t *command,
6564 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006565 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006566{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306567 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006568 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07006569 adapter->session_id, 0));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006570
6571 hdd_warn("%s: Unsupported driver command \"%s\"",
6572 adapter->dev->name, command);
6573
6574 return -ENOTSUPP;
6575}
6576
6577/**
6578 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6579 * @adapter: HDD adapter
6580 * @hdd_ctx: HDD context
6581 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6582 * @command_len: command len
6583 * @priv_data: private data
6584 *
6585 * Return: status
6586 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006587static int drv_cmd_set_fcc_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006588 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006589 uint8_t *command,
6590 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006591 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006592{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306593 QDF_STATUS status;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006594 uint8_t fcc_constraint;
6595 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006596
6597 /*
6598 * this command would be called by user-space when it detects WLAN
6599 * ON after airplane mode is set. When APM is set, WLAN turns off.
6600 * But it can be turned back on. Otherwise; when APM is turned back
6601 * off, WLAN would turn back on. So at that point the command is
6602 * expected to come down. 0 means disable, 1 means enable. The
6603 * constraint is removed when parameter 1 is set or different
6604 * country code is set
6605 */
6606
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006607 err = kstrtou8(command + command_len + 1, 10, &fcc_constraint);
6608 if (err) {
6609 hdd_err("error %d parsing userspace fcc parameter", err);
6610 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006611 }
6612
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006613 status = ucfg_reg_set_fcc_constraint(hdd_ctx->hdd_pdev,
6614 fcc_constraint);
6615
6616 if (QDF_IS_STATUS_ERROR(status))
6617 hdd_err("Failed to %s tx power for channels 12/13",
6618 fcc_constraint ? "reduce" : "restore");
6619
6620 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006621}
6622
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306623/**
6624 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6625 * command
6626 * @value: Pointer to the command
6627 * @chan_number: Pointer to the channel number
6628 * @chan_bw: Pointer to the channel bandwidth
6629 *
6630 * Parses and provides the channel number and channel width from the input
6631 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6632 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6633 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6634 *
6635 * Return: 0 for success, non-zero for failure
6636 */
6637static int hdd_parse_set_channel_switch_command(uint8_t *value,
6638 uint32_t *chan_number,
6639 uint32_t *chan_bw)
6640{
6641 const uint8_t *in_ptr = value;
6642 int ret;
6643
6644 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6645
6646 /* no argument after the command */
6647 if (NULL == in_ptr) {
6648 hdd_err("No argument after the command");
6649 return -EINVAL;
6650 }
6651
6652 /* no space after the command */
6653 if (SPACE_ASCII_VALUE != *in_ptr) {
6654 hdd_err("No space after the command ");
6655 return -EINVAL;
6656 }
6657
6658 /* remove empty spaces and move the next argument */
6659 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6660 in_ptr++;
6661
6662 /* no argument followed by spaces */
6663 if ('\0' == *in_ptr) {
6664 hdd_err("No argument followed by spaces");
6665 return -EINVAL;
6666 }
6667
6668 /* get the two arguments: channel number and bandwidth */
6669 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6670 if (ret != 2) {
6671 hdd_err("Arguments retrieval from cmd string failed");
6672 return -EINVAL;
6673 }
6674
6675 return 0;
6676}
6677
6678/**
6679 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6680 * @adapter: HDD adapter
6681 * @hdd_ctx: HDD context
6682 * @command: Pointer to the input command CHANNEL_SWITCH
6683 * @command_len: Command len
6684 * @priv_data: Private data
6685 *
6686 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6687 * of SAP/P2P-GO
6688 *
6689 * Return: 0 for success, non-zero for failure
6690 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006691static int drv_cmd_set_channel_switch(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006692 struct hdd_context *hdd_ctx,
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306693 uint8_t *command,
6694 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006695 struct hdd_priv_data *priv_data)
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306696{
6697 struct net_device *dev = adapter->dev;
6698 int status;
6699 uint32_t chan_number = 0, chan_bw = 0;
6700 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006701 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306702
Krunal Sonibe766b02016-03-10 13:00:44 -08006703 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6704 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306705 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6706 adapter->device_mode);
6707 return -EINVAL;
6708 }
6709
6710 status = hdd_parse_set_channel_switch_command(value,
6711 &chan_number, &chan_bw);
6712 if (status) {
6713 hdd_err("Invalid CHANNEL_SWITCH command");
6714 return status;
6715 }
6716
6717 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6718 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6719 return -EINVAL;
6720 }
6721
6722 if (chan_bw == 80)
6723 width = CH_WIDTH_80MHZ;
6724 else if (chan_bw == 40)
6725 width = CH_WIDTH_40MHZ;
6726 else
6727 width = CH_WIDTH_20MHZ;
6728
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006729 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306730
Min Liu2fef5792018-01-19 17:59:42 +08006731 status = hdd_softap_set_channel_change(dev, chan_number, width, false);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306732 if (status) {
6733 hdd_err("Set channel change fail");
6734 return status;
6735 }
6736
6737 return 0;
6738}
6739
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006740/*
6741 * The following table contains all supported WLAN HDD
6742 * IOCTL driver commands and the handler for each of them.
6743 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07006744static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306745 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false},
6746 {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true},
6747 {"P2P_SET_PS", drv_cmd_p2p_set_ps, true},
6748 {"SETBAND", drv_cmd_set_band, true},
6749 {"SETWMMPS", drv_cmd_set_wmmps, true},
6750 {"COUNTRY", drv_cmd_country, true},
6751 {"SETSUSPENDMODE", drv_cmd_dummy, false},
6752 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false},
6753 {"BTCOEXSCAN", drv_cmd_dummy, false},
6754 {"RXFILTER", drv_cmd_dummy, false},
6755 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true},
6756 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false},
6757 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true},
6758 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false},
6759 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period,
6760 true},
6761 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period,
6762 false},
6763 {"SETROAMMODE", drv_cmd_set_roam_mode, true},
6764 {"GETROAMMODE", drv_cmd_get_roam_mode, false},
6765 {"SETROAMDELTA", drv_cmd_set_roam_delta, true},
6766 {"GETROAMDELTA", drv_cmd_get_roam_delta, false},
6767 {"GETBAND", drv_cmd_get_band, false},
6768 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels, true},
6769 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels, false},
6770 {"GETCCXMODE", drv_cmd_get_ccx_mode, false},
6771 {"GETOKCMODE", drv_cmd_get_okc_mode, false},
6772 {"GETFASTROAM", drv_cmd_get_fast_roam, false},
6773 {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false},
6774 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
6775 true},
6776 {"SENDACTIONFRAME", drv_cmd_send_action_frame, true},
6777 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
6778 false},
6779 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true},
6780 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false},
6781 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true},
6782 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false},
6783 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true},
6784 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false},
6785 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true},
6786 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false},
6787 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true},
6788 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false},
6789 {"REASSOC", drv_cmd_reassoc, true},
6790 {"SETWESMODE", drv_cmd_set_wes_mode, true},
6791 {"GETWESMODE", drv_cmd_get_wes_mode, false},
6792 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff,
6793 true},
6794 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff,
6795 false},
6796 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true},
6797 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false},
6798 {"SETFASTROAM", drv_cmd_set_fast_roam, true},
6799 {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true},
6800 {"FASTREASSOC", drv_cmd_fast_reassoc, true},
6801 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control, true},
6802 {"SETOKCMODE", drv_cmd_set_okc_mode, true},
6803 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control, false},
6804 {"BTCOEXMODE", drv_cmd_bt_coex_mode, true},
6805 {"SCAN-ACTIVE", drv_cmd_scan_active, false},
6806 {"SCAN-PASSIVE", drv_cmd_scan_passive, false},
6807 {"GETDWELLTIME", drv_cmd_get_dwell_time, false},
6808 {"SETDWELLTIME", drv_cmd_set_dwell_time, true},
6809 {"MIRACAST", drv_cmd_miracast, true},
6810 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data, true},
6811 {"SETRMCENABLE", drv_cmd_set_rmc_enable, true},
6812 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period, true},
6813 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all, false},
6814 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info, true},
6815 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate, true},
6816 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006817#ifdef FEATURE_WLAN_ESE
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306818 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true},
6819 {"GETTSMSTATS", drv_cmd_get_tsm_stats, true},
6820 {"SETCCKMIE", drv_cmd_set_cckm_ie, true},
6821 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true},
6822 {"CCXPLMREQ", drv_cmd_ccx_plm_req, true},
6823 {"SETCCXMODE", drv_cmd_set_ccx_mode, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006824#endif /* FEATURE_WLAN_ESE */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306825 {"SETMCRATE", drv_cmd_set_mc_rate, true},
6826 {"MAXTXPOWER", drv_cmd_max_tx_power, true},
6827 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true},
6828 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false},
6829 {"GETLINKSTATUS", drv_cmd_get_link_status, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006830#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306831 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true},
6832 {"SETAPP1PARAMS", drv_cmd_set_app1_params, true},
6833 {"SETAPP2PARAMS", drv_cmd_set_app2_params, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006834#endif
6835#ifdef FEATURE_WLAN_TDLS
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306836 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
6837 true},
6838 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true},
6839 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true},
6840 {"TDLSSCAN", drv_cmd_tdls_scan, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006841#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306842 {"RSSI", drv_cmd_get_rssi, false},
6843 {"LINKSPEED", drv_cmd_get_linkspeed, false},
6844 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true},
6845 {"RXFILTER-ADD", drv_cmd_rx_filter_add, true},
6846 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true},
6847 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true},
6848 {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true},
6849 {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false},
6850 {"STOP", drv_cmd_dummy, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006851};
6852
6853/**
6854 * hdd_drv_cmd_process() - chooses and runs the proper
6855 * handler based on the input command
6856 * @adapter: Pointer to the hdd adapter
6857 * @cmd: Pointer to the driver command
6858 * @priv_data: Pointer to the data associated with the command
6859 *
6860 * This function parses the input hdd driver command and runs
6861 * the proper handler
6862 *
6863 * Return: 0 for success non-zero for failure
6864 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006865static int hdd_drv_cmd_process(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006866 uint8_t *cmd,
Jeff Johnson353cd292017-08-17 06:47:26 -07006867 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006868{
Jeff Johnson621cf972017-08-28 11:58:44 -07006869 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006870 int i;
6871 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6872 uint8_t *cmd_i = NULL;
6873 hdd_drv_cmd_handler_t handler = NULL;
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05306874 int len = 0, cmd_len = 0;
6875 uint8_t *ptr;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306876 bool args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006877
6878 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006879 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006880 return -EINVAL;
6881 }
6882
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05306883 /* Calculate length of the first word */
6884 ptr = strchrnul(cmd, ' ');
6885 cmd_len = ptr - cmd;
6886
Jeff Johnson399c6272017-08-30 10:51:00 -07006887 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006888
6889 for (i = 0; i < cmd_num_total; i++) {
6890
6891 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6892 handler = hdd_drv_cmds[i].handler;
6893 len = strlen(cmd_i);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306894 args = hdd_drv_cmds[i].args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006895
6896 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006897 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006898 return -EINVAL;
6899 }
6900
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05306901 if (len == cmd_len && strncasecmp(cmd, cmd_i, len) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306902 if (args && drv_cmd_validate(cmd, len))
6903 return -EINVAL;
6904
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006905 return handler(adapter, hdd_ctx,
6906 cmd, len, priv_data);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306907 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006908 }
6909
6910 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6911}
6912
6913/**
6914 * hdd_driver_command() - top level wlan hdd driver command handler
6915 * @adapter: Pointer to the hdd adapter
6916 * @priv_data: Pointer to the raw command data
6917 *
6918 * This function is the top level wlan hdd driver command handler. It
6919 * handles the command with the help of hdd_drv_cmd_process()
6920 *
6921 * Return: 0 for success non-zero for failure
6922 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006923static int hdd_driver_command(struct hdd_adapter *adapter,
Jeff Johnson353cd292017-08-17 06:47:26 -07006924 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006925{
6926 uint8_t *command = NULL;
6927 int ret = 0;
Jeff Johnson621cf972017-08-28 11:58:44 -07006928 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006929
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306930 ENTER();
6931
Anurag Chouhan6d760662016-02-20 16:05:43 +05306932 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006933 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006934 return -EINVAL;
6935 }
6936
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306937 ret = wlan_hdd_validate_context(hdd_ctx);
6938 if (ret)
6939 return ret;
6940
6941 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
6942 hdd_err("Driver module is closed; command can not be processed");
6943 return -EINVAL;
6944 }
6945
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006946 /*
6947 * Note that valid pointers are provided by caller
6948 */
6949
6950 /* copy to local struct to avoid numerous changes to legacy code */
6951 if (priv_data->total_len <= 0 ||
6952 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006953 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006954 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006955 ret = -EINVAL;
6956 goto exit;
6957 }
6958
6959 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006960 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006961 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006962 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006963 ret = -ENOMEM;
6964 goto exit;
6965 }
6966
6967 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6968 ret = -EFAULT;
6969 goto exit;
6970 }
6971
6972 /* Make sure the command is NUL-terminated */
6973 command[priv_data->total_len] = '\0';
6974
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006975 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006976 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6977
6978exit:
6979 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006980 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306981 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006982 return ret;
6983}
6984
6985#ifdef CONFIG_COMPAT
Jeff Johnsone44b7012017-09-10 15:25:47 -07006986static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006987{
6988 struct {
6989 compat_uptr_t buf;
6990 int used_len;
6991 int total_len;
6992 } compat_priv_data;
Jeff Johnson353cd292017-08-17 06:47:26 -07006993 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006994 int ret = 0;
6995
6996 /*
6997 * Note that adapter and ifr have already been verified by caller,
6998 * and HDD context has also been validated
6999 */
7000 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7001 sizeof(compat_priv_data))) {
7002 ret = -EFAULT;
7003 goto exit;
7004 }
7005 priv_data.buf = compat_ptr(compat_priv_data.buf);
7006 priv_data.used_len = compat_priv_data.used_len;
7007 priv_data.total_len = compat_priv_data.total_len;
7008 ret = hdd_driver_command(adapter, &priv_data);
7009exit:
7010 return ret;
7011}
7012#else /* CONFIG_COMPAT */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007013static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007014{
7015 /* will never be invoked */
7016 return 0;
7017}
7018#endif /* CONFIG_COMPAT */
7019
Jeff Johnsone44b7012017-09-10 15:25:47 -07007020static int hdd_driver_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007021{
Jeff Johnson353cd292017-08-17 06:47:26 -07007022 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007023 int ret = 0;
7024
7025 /*
7026 * Note that adapter and ifr have already been verified by caller,
7027 * and HDD context has also been validated
7028 */
7029 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7030 ret = -EFAULT;
7031 else
7032 ret = hdd_driver_command(adapter, &priv_data);
7033
7034 return ret;
7035}
7036
7037/**
7038 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7039 * @dev: device upon which the ioctl was received
7040 * @ifr: ioctl request information
7041 * @cmd: ioctl command
7042 *
7043 * This function does initial processing of wlan device ioctls.
7044 * Currently two flavors of ioctls are supported. The primary ioctl
7045 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7046 * for Android "DRIVER" commands. The other ioctl that is
7047 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7048 * for FTM on some platforms. This function simply verifies that the
7049 * driver is in a sane state, and that the ioctl is one of the
7050 * supported flavors, in which case flavor-specific handlers are
7051 * dispatched.
7052 *
7053 * Return: 0 on success, non-zero on error
7054 */
7055static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7056{
Jeff Johnsone44b7012017-09-10 15:25:47 -07007057 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson621cf972017-08-28 11:58:44 -07007058 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007059 int ret;
7060
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007061 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307062
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007063 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007064 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007065 ret = -ENODEV;
7066 goto exit;
7067 }
7068
7069 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007070 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007071 ret = -EINVAL;
7072 goto exit;
7073 }
7074#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307075 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007076 if (SIOCIOCTLTX99 == cmd) {
7077 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7078 goto exit;
7079 }
7080 }
7081#endif
7082
7083 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7084 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307085 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007086 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007087
7088 switch (cmd) {
7089 case (SIOCDEVPRIVATE + 1):
7090 if (is_compat_task())
7091 ret = hdd_driver_compat_ioctl(adapter, ifr);
7092 else
7093 ret = hdd_driver_ioctl(adapter, ifr);
7094 break;
7095 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007096 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007097 ret = -EINVAL;
7098 break;
7099 }
7100exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307101 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007102 return ret;
7103}
7104
7105/**
7106 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7107 * @dev: device upon which the ioctl was received
7108 * @ifr: ioctl request information
7109 * @cmd: ioctl command
7110 *
7111 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7112 * which is where the ioctls are really handled.
7113 *
7114 * Return: 0 on success, non-zero on error
7115 */
7116int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7117{
7118 int ret;
7119
7120 cds_ssr_protect(__func__);
7121 ret = __hdd_ioctl(dev, ifr, cmd);
7122 cds_ssr_unprotect(__func__);
7123 return ret;
7124}