blob: 748aaedc7a6de7bae8f339b6397f221ab6ec71e2 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Rajeev Kumarea95edd2017-01-11 20:49:36 -08002 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/* Include Files */
29
30#include <wlan_hdd_includes.h>
31#include <wlan_hdd_wowl.h>
32#include "wlan_hdd_trace.h"
33#include "wlan_hdd_ioctl.h"
34#include "wlan_hdd_power.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070035#include "wlan_hdd_regulatory.h"
Jeff Johnson253c0c22017-01-23 16:59:38 -080036#include "wlan_hdd_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080037#include "wlan_hdd_driver_ops.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080038#include "wlan_policy_mgr_api.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053039#include "wlan_hdd_hostapd.h"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080040#include "scheduler_api.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070041#include "wlan_reg_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080042#include "wlan_hdd_p2p.h"
43#include <linux/ctype.h>
44#include "wma.h"
45#include "wlan_hdd_napi.h"
46
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080047#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080048#include <sme_api.h>
49#include <sir_api.h>
50#endif
51#include "hif.h"
52
53#if defined(LINUX_QCMBR)
54#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
55#endif
56
57/*
58 * Size of Driver command strings from upper layer
59 */
60#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
61#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
62
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080063/*
64 * Ibss prop IE from command will be of size:
65 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
66 * OUI_DATA should be at least 3 bytes long
67 */
68#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080070#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071#define TID_MIN_VALUE 0
72#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080073#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080074
75/*
76 * Maximum buffer size used for returning the data back to user space
77 */
78#define WLAN_MAX_BUF_SIZE 1024
79#define WLAN_PRIV_DATA_MAX_LEN 8192
80
81/*
82 * Driver miracast parameters 0-Disabled
83 * 1-Source, 2-Sink
84 */
85#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
86#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
87
88/*
89 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
90 * we will split the printing.
91 */
92#define NUM_OF_STA_DATA_TO_PRINT 16
93
94/*
95 * Android DRIVER command structures
96 */
97struct android_wifi_reassoc_params {
98 unsigned char bssid[18];
99 int channel;
100};
101
102#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
103struct android_wifi_af_params {
104 unsigned char bssid[18];
105 int channel;
106 int dwell_time;
107 int len;
108 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
109};
110
111/*
112 * Define HDD driver command handling entry, each contains a command
113 * string and the handler.
114 */
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{
548 eCsrBand band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700549
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
551 switch (band) {
552 case eCSR_BAND_ALL:
553 *pBand = WLAN_HDD_UI_BAND_AUTO;
554 break;
555
556 case eCSR_BAND_24:
557 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
558 break;
559
560 case eCSR_BAND_5G:
561 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
562 break;
563
564 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700565 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800566 *pBand = -1;
567 break;
568 }
569}
570
571/**
572 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
573 * @data: input data
574 * @target_ap_bssid: pointer to bssid (output parameter)
575 * @channel: pointer to channel (output parameter)
576 *
577 * Return: 0 if parsing is successful; -EINVAL otherwise
578 */
579static int _hdd_parse_bssid_and_chan(const uint8_t **data,
580 uint8_t *bssid,
581 uint8_t *channel)
582{
583 const uint8_t *in_ptr;
584 int v = 0;
585 int temp_int;
586 uint8_t temp_buf[32];
587
588 /* 12 hexa decimal digits, 5 ':' and '\0' */
589 uint8_t mac_addr[18];
590
591 if (!data || !*data)
592 return -EINVAL;
593
594 in_ptr = *data;
595
596 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
597 /* no argument after the command */
598 if (NULL == in_ptr)
599 goto error;
600 /* no space after the command */
601 else if (SPACE_ASCII_VALUE != *in_ptr)
602 goto error;
603
604 /* remove empty spaces */
605 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
606 in_ptr++;
607
608 /* no argument followed by spaces */
609 if ('\0' == *in_ptr)
610 goto error;
611
612 v = sscanf(in_ptr, "%17s", mac_addr);
613 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700614 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
615 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800616 goto error;
617 }
618
619 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
620 hex_to_bin(mac_addr[1]);
621 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
622 hex_to_bin(mac_addr[4]);
623 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
624 hex_to_bin(mac_addr[7]);
625 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
626 hex_to_bin(mac_addr[10]);
627 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
628 hex_to_bin(mac_addr[13]);
629 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
630 hex_to_bin(mac_addr[16]);
631
632 /* point to the next argument */
633 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
634 /* no argument after the command */
635 if (NULL == in_ptr)
636 goto error;
637
638 /* remove empty spaces */
639 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
640 in_ptr++;
641
642 /* no argument followed by spaces */
643 if ('\0' == *in_ptr)
644 goto error;
645
646 /* get the next argument ie the channel number */
647 v = sscanf(in_ptr, "%31s ", temp_buf);
648 if (1 != v)
649 goto error;
650
651 v = kstrtos32(temp_buf, 10, &temp_int);
652 if ((v < 0) || (temp_int < 0) ||
653 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
654 return -EINVAL;
655
656 *channel = temp_int;
657 *data = in_ptr;
658 return 0;
659error:
660 *data = in_ptr;
661 return -EINVAL;
662}
663
664/**
665 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
666 * @pValue: Pointer to input data
667 * @pTargetApBssid: Pointer to target Ap bssid
668 * @pChannel: Pointer to the Target AP channel
669 * @pDwellTime: Pointer to the time to stay off-channel
670 * after transmitting action frame
671 * @pBuf: Pointer to data
672 * @pBufLen: Pointer to data length
673 *
674 * This function parses the send action frame data passed in the format
675 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
676 *
677 * Return: 0 for success non-zero for failure
678 */
679static int
680hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
681 uint8_t *pTargetApBssid,
682 uint8_t *pChannel, uint8_t *pDwellTime,
683 uint8_t **pBuf, uint8_t *pBufLen)
684{
685 const uint8_t *inPtr = pValue;
686 const uint8_t *dataEnd;
687 int tempInt;
688 int j = 0;
689 int i = 0;
690 int v = 0;
691 uint8_t tempBuf[32];
692 uint8_t tempByte = 0;
693
694 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
695 return -EINVAL;
696
697 /* point to the next argument */
698 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
699 /* no argument after the command */
700 if (NULL == inPtr)
701 return -EINVAL;
702 /* removing empty spaces */
703 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
704 inPtr++;
705
706 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700707 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800709
710 /* getting the next argument ie the dwell time */
711 v = sscanf(inPtr, "%31s ", tempBuf);
712 if (1 != v)
713 return -EINVAL;
714
715 v = kstrtos32(tempBuf, 10, &tempInt);
716 if (v < 0 || tempInt < 0)
717 return -EINVAL;
718
719 *pDwellTime = tempInt;
720
721 /* point to the next argument */
722 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
723 /* no argument after the command */
724 if (NULL == inPtr)
725 return -EINVAL;
726 /* removing empty spaces */
727 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
728 inPtr++;
729
730 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700731 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800733
734 /* find the length of data */
735 dataEnd = inPtr;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700736 while (('\0' != *dataEnd))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800737 dataEnd++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700738
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800739 *pBufLen = dataEnd - inPtr;
740 if (*pBufLen <= 0)
741 return -EINVAL;
742
743 /*
744 * Allocate the number of bytes based on the number of input characters
745 * whether it is even or odd.
746 * if the number of input characters are even, then we need N/2 byte.
747 * if the number of input characters are odd, then we need do (N+1)/2
748 * to compensate rounding off.
749 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
750 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
751 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530752 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800753 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700754 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800755 return -ENOMEM;
756 }
757
758 /* the buffer received from the upper layer is character buffer,
759 * we need to prepare the buffer taking 2 characters in to a U8 hex
760 * decimal number for example 7f0000f0...form a buffer to contain 7f
761 * in 0th location, 00 in 1st and f0 in 3rd location
762 */
763 for (i = 0, j = 0; j < *pBufLen; j += 2) {
764 if (j + 1 == *pBufLen) {
765 tempByte = hex_to_bin(inPtr[j]);
766 } else {
767 tempByte =
768 (hex_to_bin(inPtr[j]) << 4) |
769 (hex_to_bin(inPtr[j + 1]));
770 }
771 (*pBuf)[i++] = tempByte;
772 }
773 *pBufLen = i;
774 return 0;
775}
776
777/**
778 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
779 * @pValue: Pointer to input data (its a NULL terminated string)
780 * @pTargetApBssid: Pointer to target Ap bssid
781 * @pChannel: Pointer to the Target AP channel
782 *
783 * This function parses the reasoc command data passed in the format
784 * REASSOC<space><bssid><space><channel>
785 *
786 * Return: 0 for success non-zero for failure
787 */
788static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
789 uint8_t *pTargetApBssid,
790 uint8_t *pChannel)
791{
792 const uint8_t *inPtr = pValue;
793
794 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
795 return -EINVAL;
796
797 return 0;
798}
799
Naveen Rawat05376ee2016-07-18 16:43:32 -0700800#ifdef WLAN_FEATURE_ROAM_OFFLOAD
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),
Krunal Soni332f4af2017-06-01 14:36:17 -0700814 profile, bssid, channel, adapter->sessionId,
815 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);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800886 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
887 &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,
1099 adapter->sessionId);
1100 } 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,
1453 adapter->sessionId, num_chan));
1454
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,
1464 adapter->sessionId,
1465 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,
1519 adapter->sessionId, num_chan));
1520
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,
1533 adapter->sessionId,
1534 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));
2018 params.vdev_id = adapter->sessionId;
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
2107 params.vdev_id = adapter->sessionId;
2108 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 Johnson253c0c22017-01-23 16:59:38 -08002423 cookie, adapter->sessionId);
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);
2436 adapter->linkStatus = priv->link_status;
2437 }
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 */
2448 return adapter->linkStatus;
2449}
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,
2849 adapter->sessionId,
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002850 (unsigned int)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002851 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2852 + 3) << 16 | *(hdd_ctx->
2853 p2pDeviceAddress.bytes + 4) << 8 |
2854 *(hdd_ctx->p2pDeviceAddress.bytes +
2855 5))));
2856
2857 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2858 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,
2993 adapter->sessionId, 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,
2999 adapter->sessionId,
3000 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,
3026 adapter->sessionId, lookUpThreshold));
3027
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,
3080 adapter->sessionId, roamScanPeriod));
3081 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,
3089 adapter->sessionId,
3090 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,
3110 adapter->sessionId,
3111 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,
3176 adapter->sessionId,
3177 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
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003218 if (!adapter->fast_roaming_allowed) {
3219 hdd_err("Roaming is always disabled on this interface");
3220 goto exit;
3221 }
3222
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003223 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3224 value = value + SIZE_OF_SETROAMMODE + 1;
3225
3226 /* Convert the value from ascii to integer */
Rajeev Kumar Sirasanagandla248697d2017-08-30 12:27:45 +05303227 ret = kstrtou8(value, 10, &roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003228 if (ret < 0) {
3229 /*
3230 * If the input value is greater than max value of datatype,
3231 * then also kstrtou8 fails
3232 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003233 hdd_err("kstrtou8 failed range [%d - %d]",
3234 CFG_LFR_FEATURE_ENABLED_MIN,
3235 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003236 ret = -EINVAL;
3237 goto exit;
3238 }
3239 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3240 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003241 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3242 roamMode,
3243 CFG_LFR_FEATURE_ENABLED_MIN,
3244 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003245 ret = -EINVAL;
3246 goto exit;
3247 }
3248
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003249 hdd_debug("Received Command to Set Roam Mode = %d",
3250 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003251 /*
3252 * Note that
3253 * SETROAMMODE 0 is to enable LFR while
3254 * SETROAMMODE 1 is to disable LFR, but
3255 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3256 * enable/disable. So, we have to invert the value
3257 * to call sme_update_is_fast_roam_ini_feature_enabled.
3258 */
3259 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3260 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3261 else
3262 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3263
3264 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3265 if (roamMode) {
3266 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3267 sme_update_roam_scan_offload_enabled(
3268 (tHalHandle)(hdd_ctx->hHal),
3269 hdd_ctx->config->isRoamOffloadScanEnabled);
3270 sme_update_is_fast_roam_ini_feature_enabled(
3271 hdd_ctx->hHal,
3272 adapter->sessionId,
3273 roamMode);
3274 } else {
3275 sme_update_is_fast_roam_ini_feature_enabled(
3276 hdd_ctx->hHal,
3277 adapter->sessionId,
3278 roamMode);
3279 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3280 sme_update_roam_scan_offload_enabled(
3281 (tHalHandle)(hdd_ctx->hHal),
3282 hdd_ctx->config->isRoamOffloadScanEnabled);
3283 }
3284
3285
3286exit:
3287 return ret;
3288}
3289
Jeff Johnsone44b7012017-09-10 15:25:47 -07003290static int drv_cmd_get_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003291 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003292 uint8_t *command,
3293 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003294 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003295{
3296 int ret = 0;
3297 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3298 char extra[32];
3299 uint8_t len = 0;
3300
3301 /*
3302 * roamMode value shall be inverted because the sementics is different.
3303 */
3304 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3305 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3306 else
3307 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3308
3309 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303310 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003311 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003312 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003313 ret = -EFAULT;
3314 }
3315
3316 return ret;
3317}
3318
Jeff Johnsone44b7012017-09-10 15:25:47 -07003319static int drv_cmd_set_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003320 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003321 uint8_t *command,
3322 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003323 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003324{
3325 int ret = 0;
3326 uint8_t *value = command;
3327 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3328
3329 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3330 value = value + command_len + 1;
3331
3332 /* Convert the value from ascii to integer */
3333 ret = kstrtou8(value, 10, &roamRssiDiff);
3334 if (ret < 0) {
3335 /*
3336 * If the input value is greater than max value of datatype,
3337 * then also kstrtou8 fails
3338 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003339 hdd_err("kstrtou8 failed range [%d - %d]",
3340 CFG_ROAM_RSSI_DIFF_MIN,
3341 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003342 ret = -EINVAL;
3343 goto exit;
3344 }
3345
3346 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3347 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003348 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3349 roamRssiDiff,
3350 CFG_ROAM_RSSI_DIFF_MIN,
3351 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003352 ret = -EINVAL;
3353 goto exit;
3354 }
3355
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003356 hdd_debug("Received Command to Set roam rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003357 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003358
3359 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3360 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3361 adapter->sessionId,
3362 roamRssiDiff);
3363
3364exit:
3365 return ret;
3366}
3367
Jeff Johnsone44b7012017-09-10 15:25:47 -07003368static int drv_cmd_get_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003369 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003370 uint8_t *command,
3371 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003372 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003373{
3374 int ret = 0;
3375 uint8_t roamRssiDiff =
3376 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3377 char extra[32];
3378 uint8_t len = 0;
3379
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303380 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003381 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3382 adapter->sessionId, roamRssiDiff));
3383
3384 len = scnprintf(extra, sizeof(extra), "%s %d",
3385 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303386 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003387
3388 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003389 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003390 ret = -EFAULT;
3391 }
3392
3393 return ret;
3394}
3395
Jeff Johnsone44b7012017-09-10 15:25:47 -07003396static int drv_cmd_get_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003397 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003398 uint8_t *command,
3399 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003400 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003401{
3402 int ret = 0;
3403 int band = -1;
3404 char extra[32];
3405 uint8_t len = 0;
3406
3407 hdd_get_band_helper(hdd_ctx, &band);
3408
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303409 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410 TRACE_CODE_HDD_GETBAND_IOCTL,
3411 adapter->sessionId, band));
3412
3413 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303414 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003415
3416 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003417 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418 ret = -EFAULT;
3419 }
3420
3421 return ret;
3422}
3423
Jeff Johnsone44b7012017-09-10 15:25:47 -07003424static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003425 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003426 uint8_t *command,
3427 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003428 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003429{
3430 return hdd_parse_set_roam_scan_channels(adapter, command);
3431}
3432
Jeff Johnsone44b7012017-09-10 15:25:47 -07003433static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003434 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003435 uint8_t *command,
3436 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003437 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003438{
3439 int ret = 0;
3440 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3441 uint8_t numChannels = 0;
3442 uint8_t j = 0;
3443 char extra[128] = { 0 };
3444 int len;
3445
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303446 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003447 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3448 ChannelList,
3449 &numChannels,
3450 adapter->sessionId)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003451 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452 ret = -EFAULT;
3453 goto exit;
3454 }
3455
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303456 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3458 adapter->sessionId, numChannels));
3459 /*
3460 * output channel list is of the format
3461 * [Number of roam scan channels][Channel1][Channel2]...
3462 * copy the number of channels in the 0th index
3463 */
3464 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3465 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303466 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003467 len += scnprintf(extra + len, sizeof(extra) - len,
3468 " %d", ChannelList[j]);
3469
Anurag Chouhan6d760662016-02-20 16:05:43 +05303470 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003471 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003472 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003473 ret = -EFAULT;
3474 goto exit;
3475 }
3476
3477exit:
3478 return ret;
3479}
3480
Jeff Johnsone44b7012017-09-10 15:25:47 -07003481static int drv_cmd_get_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003482 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003483 uint8_t *command,
3484 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003485 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003486{
3487 int ret = 0;
3488 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3489 char extra[32];
3490 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003491 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003492
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003493 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003494 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003495 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003496 * then this operation is not permitted (return FAILURE)
3497 */
3498 if (eseMode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003499 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003500 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003501 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003502 ret = -EPERM;
3503 goto exit;
3504 }
3505
3506 len = scnprintf(extra, sizeof(extra), "%s %d",
3507 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303508 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003509 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003510 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003511 ret = -EFAULT;
3512 goto exit;
3513 }
3514
3515exit:
3516 return ret;
3517}
3518
Jeff Johnsone44b7012017-09-10 15:25:47 -07003519static int drv_cmd_get_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003520 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003521 uint8_t *command,
3522 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003523 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524{
3525 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003526 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003527 char extra[32];
3528 uint8_t len = 0;
3529
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003530 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003531 /*
3532 * Check if the features OKC/ESE/11R are supported simultaneously,
3533 * then this operation is not permitted (return FAILURE)
3534 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003535 if (pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003536 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3537 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003538 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003539 ret = -EPERM;
3540 goto exit;
3541 }
3542
3543 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003544 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303545 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003546
3547 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003548 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003549 ret = -EFAULT;
3550 goto exit;
3551 }
3552
3553exit:
3554 return ret;
3555}
3556
Jeff Johnsone44b7012017-09-10 15:25:47 -07003557static int drv_cmd_get_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003558 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003559 uint8_t *command,
3560 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003561 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003562{
3563 int ret = 0;
3564 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3565 char extra[32];
3566 uint8_t len = 0;
3567
3568 len = scnprintf(extra, sizeof(extra), "%s %d",
3569 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303570 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003571
3572 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003573 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003574 ret = -EFAULT;
3575 }
3576
3577 return ret;
3578}
3579
Jeff Johnsone44b7012017-09-10 15:25:47 -07003580static int drv_cmd_get_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003581 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003582 uint8_t *command,
3583 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003584 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003585{
3586 int ret = 0;
3587 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3588 char extra[32];
3589 uint8_t len = 0;
3590
3591 len = scnprintf(extra, sizeof(extra), "%s %d",
3592 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303593 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003594
3595 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003596 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003597 ret = -EFAULT;
3598 }
3599
3600 return ret;
3601}
3602
Jeff Johnsone44b7012017-09-10 15:25:47 -07003603static int drv_cmd_set_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003604 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003605 uint8_t *command,
3606 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003607 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003608{
3609 int ret = 0;
3610 uint8_t *value = command;
3611 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3612
3613 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3614 value = value + command_len + 1;
3615
3616 /* Convert the value from ascii to integer */
3617 ret = kstrtou8(value, 10, &minTime);
3618 if (ret < 0) {
3619 /*
3620 * If the input value is greater than max value of datatype,
3621 * then also kstrtou8 fails
3622 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003623 hdd_err("kstrtou8 failed range [%d - %d]",
3624 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3625 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003626 ret = -EINVAL;
3627 goto exit;
3628 }
3629
3630 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3631 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003632 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3633 minTime,
3634 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3635 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636 ret = -EINVAL;
3637 goto exit;
3638 }
3639
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303640 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003641 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3642 adapter->sessionId, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003643 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003644 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003645
3646 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3647 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3648 minTime,
3649 adapter->sessionId);
3650
3651exit:
3652 return ret;
3653}
3654
Jeff Johnsone44b7012017-09-10 15:25:47 -07003655static int drv_cmd_send_action_frame(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003656 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003657 uint8_t *command,
3658 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003659 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003660{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003661 return hdd_parse_sendactionframe(adapter, command,
3662 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003663}
3664
Jeff Johnsone44b7012017-09-10 15:25:47 -07003665static int drv_cmd_get_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003666 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003667 uint8_t *command,
3668 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003669 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003670{
3671 int ret = 0;
3672 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3673 adapter->sessionId);
3674 char extra[32];
3675 uint8_t len = 0;
3676
3677 /* value is interms of msec */
3678 len = scnprintf(extra, sizeof(extra), "%s %d",
3679 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303680 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003681
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303682 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003683 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3684 adapter->sessionId, val));
3685
3686 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003687 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003688 ret = -EFAULT;
3689 }
3690
3691 return ret;
3692}
3693
Jeff Johnsone44b7012017-09-10 15:25:47 -07003694static int drv_cmd_set_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003695 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003696 uint8_t *command,
3697 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003698 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003699{
3700 int ret = 0;
3701 uint8_t *value = command;
3702 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3703
3704 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3705 value = value + command_len + 1;
3706
3707 /* Convert the value from ascii to integer */
3708 ret = kstrtou16(value, 10, &maxTime);
3709 if (ret < 0) {
3710 /*
3711 * If the input value is greater than max value of datatype,
3712 * then also kstrtou8 fails
3713 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003714 hdd_err("kstrtou16 failed range [%d - %d]",
3715 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3716 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003717 ret = -EINVAL;
3718 goto exit;
3719 }
3720
3721 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3722 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003723 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3724 maxTime,
3725 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3726 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003727 ret = -EINVAL;
3728 goto exit;
3729 }
3730
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003731 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003732 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003733
3734 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3735 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3736 adapter->sessionId,
3737 maxTime);
3738
3739exit:
3740 return ret;
3741}
3742
Jeff Johnsone44b7012017-09-10 15:25:47 -07003743static int drv_cmd_get_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003744 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745 uint8_t *command,
3746 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003747 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003748{
3749 int ret = 0;
3750 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3751 adapter->sessionId);
3752 char extra[32];
3753 uint8_t len = 0;
3754
3755 /* value is interms of msec */
3756 len = scnprintf(extra, sizeof(extra), "%s %d",
3757 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303758 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003759
3760 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003761 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003762 ret = -EFAULT;
3763 }
3764
3765 return ret;
3766}
3767
Jeff Johnsone44b7012017-09-10 15:25:47 -07003768static int drv_cmd_set_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003769 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003770 uint8_t *command,
3771 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003772 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003773{
3774 int ret = 0;
3775 uint8_t *value = command;
3776 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3777
3778 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3779 value = value + command_len + 1;
3780
3781 /* Convert the value from ascii to integer */
3782 ret = kstrtou16(value, 10, &val);
3783 if (ret < 0) {
3784 /*
3785 * If the input value is greater than max value of datatype,
3786 * then also kstrtou8 fails
3787 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003788 hdd_err("kstrtou16 failed range [%d - %d]",
3789 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3790 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791 ret = -EINVAL;
3792 goto exit;
3793 }
3794
3795 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3796 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003797 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3798 val,
3799 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3800 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003801 ret = -EINVAL;
3802 goto exit;
3803 }
3804
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003805 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003806 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003807
3808 hdd_ctx->config->nNeighborScanPeriod = val;
3809 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3810 adapter->sessionId, val);
3811
3812exit:
3813 return ret;
3814}
3815
Jeff Johnsone44b7012017-09-10 15:25:47 -07003816static int drv_cmd_get_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003817 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003818 uint8_t *command,
3819 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003820 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003821{
3822 int ret = 0;
3823 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3824 adapter->
3825 sessionId);
3826 char extra[32];
3827 uint8_t len = 0;
3828
3829 /* value is interms of msec */
3830 len = scnprintf(extra, sizeof(extra), "%s %d",
3831 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303832 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003833
3834 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003835 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003836 ret = -EFAULT;
3837 }
3838
3839 return ret;
3840}
3841
Jeff Johnsone44b7012017-09-10 15:25:47 -07003842static int drv_cmd_set_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003843 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003844 uint8_t *command,
3845 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003846 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003847{
3848 int ret = 0;
3849 uint8_t *value = command;
3850 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3851
3852 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3853 value = value + command_len + 1;
3854
3855 /* Convert the value from ascii to integer */
3856 ret = kstrtou8(value, 10, &val);
3857 if (ret < 0) {
3858 /*
3859 * If the input value is greater than max value of datatype,
3860 * then also kstrtou8 fails
3861 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003862 hdd_err("kstrtou8 failed range [%d - %d]",
3863 CFG_ROAM_INTRA_BAND_MIN,
3864 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003865 ret = -EINVAL;
3866 goto exit;
3867 }
3868
3869 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3870 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003871 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3872 val,
3873 CFG_ROAM_INTRA_BAND_MIN,
3874 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003875 ret = -EINVAL;
3876 goto exit;
3877 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003878 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003879 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003880
3881 hdd_ctx->config->nRoamIntraBand = val;
3882 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3883
3884exit:
3885 return ret;
3886}
3887
Jeff Johnsone44b7012017-09-10 15:25:47 -07003888static int drv_cmd_get_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003889 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003890 uint8_t *command,
3891 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003892 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003893{
3894 int ret = 0;
3895 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3896 char extra[32];
3897 uint8_t len = 0;
3898
3899 /* value is interms of msec */
3900 len = scnprintf(extra, sizeof(extra), "%s %d",
3901 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303902 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003904 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003905 ret = -EFAULT;
3906 }
3907
3908 return ret;
3909}
3910
Jeff Johnsone44b7012017-09-10 15:25:47 -07003911static int drv_cmd_set_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003912 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003913 uint8_t *command,
3914 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003915 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003916{
3917 int ret = 0;
3918 uint8_t *value = command;
3919 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3920
3921 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3922 value = value + command_len + 1;
3923
3924 /* Convert the value from ascii to integer */
3925 ret = kstrtou8(value, 10, &nProbes);
3926 if (ret < 0) {
3927 /*
3928 * If the input value is greater than max value of datatype,
3929 * then also kstrtou8 fails
3930 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003931 hdd_err("kstrtou8 failed range [%d - %d]",
3932 CFG_ROAM_SCAN_N_PROBES_MIN,
3933 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003934 ret = -EINVAL;
3935 goto exit;
3936 }
3937
3938 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3939 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003940 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3941 nProbes,
3942 CFG_ROAM_SCAN_N_PROBES_MIN,
3943 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003944 ret = -EINVAL;
3945 goto exit;
3946 }
3947
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003948 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003949 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003950
3951 hdd_ctx->config->nProbes = nProbes;
3952 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3953 adapter->sessionId, nProbes);
3954
3955exit:
3956 return ret;
3957}
3958
Jeff Johnsone44b7012017-09-10 15:25:47 -07003959static int drv_cmd_get_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003960 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003961 uint8_t *command,
3962 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003963 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003964{
3965 int ret = 0;
3966 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3967 char extra[32];
3968 uint8_t len = 0;
3969
3970 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303971 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003972 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003973 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003974 ret = -EFAULT;
3975 }
3976
3977 return ret;
3978}
3979
Jeff Johnsone44b7012017-09-10 15:25:47 -07003980static int drv_cmd_set_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003981 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982 uint8_t *command,
3983 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003984 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003985{
3986 int ret = 0;
3987 uint8_t *value = command;
3988 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3989
3990 /* input value is in units of msec */
3991
3992 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3993 value = value + command_len + 1;
3994
3995 /* Convert the value from ascii to integer */
3996 ret = kstrtou16(value, 10, &homeAwayTime);
3997 if (ret < 0) {
3998 /*
3999 * If the input value is greater than max value of datatype,
4000 * then also kstrtou8 fails
4001 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004002 hdd_err("kstrtou8 failed range [%d - %d]",
4003 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4004 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004005 ret = -EINVAL;
4006 goto exit;
4007 }
4008
4009 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4010 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004011 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012 homeAwayTime,
4013 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4014 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4015 ret = -EINVAL;
4016 goto exit;
4017 }
4018
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004019 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004020 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004021
4022 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4023 homeAwayTime) {
4024 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4025 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4026 adapter->sessionId,
4027 homeAwayTime,
4028 true);
4029 }
4030
4031exit:
4032 return ret;
4033}
4034
Jeff Johnsone44b7012017-09-10 15:25:47 -07004035static int drv_cmd_get_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004036 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004037 uint8_t *command,
4038 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004039 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004040{
4041 int ret = 0;
4042 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4043 char extra[32];
4044 uint8_t len = 0;
4045
4046 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304047 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004048
4049 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004050 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004051 ret = -EFAULT;
4052 }
4053
4054 return ret;
4055}
4056
Jeff Johnsone44b7012017-09-10 15:25:47 -07004057static int drv_cmd_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004058 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004059 uint8_t *command,
4060 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004061 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004062{
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05304063 return hdd_parse_reassoc(adapter, command, priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004064}
4065
Jeff Johnsone44b7012017-09-10 15:25:47 -07004066static int drv_cmd_set_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004067 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004068 uint8_t *command,
4069 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004070 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071{
4072 int ret = 0;
4073 uint8_t *value = command;
4074 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4075
4076 /* Move pointer to ahead of SETWESMODE<delimiter> */
4077 value = value + command_len + 1;
4078
4079 /* Convert the value from ascii to integer */
4080 ret = kstrtou8(value, 10, &wesMode);
4081 if (ret < 0) {
4082 /*
4083 * If the input value is greater than max value of datatype,
4084 * then also kstrtou8 fails
4085 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004086 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004087 CFG_ENABLE_WES_MODE_NAME_MIN,
4088 CFG_ENABLE_WES_MODE_NAME_MAX);
4089 ret = -EINVAL;
4090 goto exit;
4091 }
4092
4093 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4094 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004095 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004096 wesMode,
4097 CFG_ENABLE_WES_MODE_NAME_MIN,
4098 CFG_ENABLE_WES_MODE_NAME_MAX);
4099 ret = -EINVAL;
4100 goto exit;
4101 }
4102
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004103 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004104 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004105
4106 hdd_ctx->config->isWESModeEnabled = wesMode;
4107 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4108
4109exit:
4110 return ret;
4111}
4112
Jeff Johnsone44b7012017-09-10 15:25:47 -07004113static int drv_cmd_get_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004114 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115 uint8_t *command,
4116 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004117 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004118{
4119 int ret = 0;
4120 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4121 char extra[32];
4122 uint8_t len = 0;
4123
4124 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304125 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004126 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004127 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004128 ret = -EFAULT;
4129 }
4130
4131 return ret;
4132}
4133
Jeff Johnsone44b7012017-09-10 15:25:47 -07004134static int drv_cmd_set_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004135 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004136 uint8_t *command,
4137 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004138 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004139{
4140 int ret = 0;
4141 uint8_t *value = command;
4142 uint8_t nOpportunisticThresholdDiff =
4143 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4144
4145 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4146 value = value + command_len + 1;
4147
4148 /* Convert the value from ascii to integer */
4149 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4150 if (ret < 0) {
4151 /*
4152 * If the input value is greater than max value of datatype,
4153 * then also kstrtou8 fails
4154 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004155 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004156 ret = -EINVAL;
4157 goto exit;
4158 }
4159
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004160 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004161 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004162
4163 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4164 adapter->sessionId,
4165 nOpportunisticThresholdDiff);
4166
4167exit:
4168 return ret;
4169}
4170
Jeff Johnsone44b7012017-09-10 15:25:47 -07004171static int drv_cmd_get_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004172 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004173 uint8_t *command,
4174 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004175 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004176{
4177 int ret = 0;
4178 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4179 hdd_ctx->hHal);
4180 char extra[32];
4181 uint8_t len = 0;
4182
4183 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304184 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004185 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004186 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004187 ret = -EFAULT;
4188 }
4189
4190 return ret;
4191}
4192
Jeff Johnsone44b7012017-09-10 15:25:47 -07004193static int drv_cmd_set_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004194 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004195 uint8_t *command,
4196 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004197 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004198{
4199 int ret = 0;
4200 uint8_t *value = command;
4201 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4202
4203 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4204 value = value + command_len + 1;
4205
4206 /* Convert the value from ascii to integer */
4207 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4208 if (ret < 0) {
4209 /*
4210 * If the input value is greater than max value of datatype,
4211 * then also kstrtou8 fails
4212 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004213 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004214 ret = -EINVAL;
4215 goto exit;
4216 }
4217
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004218 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004219 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004220
4221 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4222 adapter->sessionId,
4223 nRoamRescanRssiDiff);
4224
4225exit:
4226 return ret;
4227}
4228
Jeff Johnsone44b7012017-09-10 15:25:47 -07004229static int drv_cmd_get_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004230 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004231 uint8_t *command,
4232 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004233 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004234{
4235 int ret = 0;
4236 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4237 char extra[32];
4238 uint8_t len = 0;
4239
4240 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304241 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004242 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004243 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004244 ret = -EFAULT;
4245 }
4246
4247 return ret;
4248}
4249
Jeff Johnsone44b7012017-09-10 15:25:47 -07004250static int drv_cmd_set_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004251 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004252 uint8_t *command,
4253 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004254 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004255{
4256 int ret = 0;
4257 uint8_t *value = command;
4258 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4259
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004260 if (!adapter->fast_roaming_allowed) {
4261 hdd_err("Roaming is always disabled on this interface");
4262 goto exit;
4263 }
4264
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004265 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4266 value = value + command_len + 1;
4267
4268 /* Convert the value from ascii to integer */
4269 ret = kstrtou8(value, 10, &lfrMode);
4270 if (ret < 0) {
4271 /*
4272 * If the input value is greater than max value of datatype,
4273 * then also kstrtou8 fails
4274 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004275 hdd_err("kstrtou8 failed range [%d - %d]",
4276 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004277 CFG_LFR_FEATURE_ENABLED_MAX);
4278 ret = -EINVAL;
4279 goto exit;
4280 }
4281
4282 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4283 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004284 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004285 lfrMode,
4286 CFG_LFR_FEATURE_ENABLED_MIN,
4287 CFG_LFR_FEATURE_ENABLED_MAX);
4288 ret = -EINVAL;
4289 goto exit;
4290 }
4291
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004292 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004293 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004294
4295 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4296 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4297 adapter->
4298 sessionId,
4299 lfrMode);
4300
4301exit:
4302 return ret;
4303}
4304
Jeff Johnsone44b7012017-09-10 15:25:47 -07004305static int drv_cmd_set_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004306 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004307 uint8_t *command,
4308 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004309 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004310{
4311 int ret = 0;
4312 uint8_t *value = command;
4313 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4314
4315 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4316 value = value + command_len + 1;
4317
4318 /* Convert the value from ascii to integer */
4319 ret = kstrtou8(value, 10, &ft);
4320 if (ret < 0) {
4321 /*
4322 * If the input value is greater than max value of datatype,
4323 * then also kstrtou8 fails
4324 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004325 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004326 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4327 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4328 ret = -EINVAL;
4329 goto exit;
4330 }
4331
4332 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4333 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004334 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004335 ft,
4336 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4337 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4338 ret = -EINVAL;
4339 goto exit;
4340 }
4341
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004342 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004343
4344 hdd_ctx->config->isFastTransitionEnabled = ft;
4345 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4346
4347exit:
4348 return ret;
4349}
4350
Jeff Johnsone44b7012017-09-10 15:25:47 -07004351static int drv_cmd_fast_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004352 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004353 uint8_t *command,
4354 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004355 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004356{
4357 int ret = 0;
4358 uint8_t *value = command;
4359 uint8_t channel = 0;
4360 tSirMacAddr targetApBssid;
Krunal Sonibfd05492017-10-03 15:48:37 -07004361 uint32_t roamId = INVALID_ROAM_ID;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004362 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363 tCsrHandoffRequest handoffInfo;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004364 struct hdd_station_ctx *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004365
Krunal Sonibe766b02016-03-10 13:00:44 -08004366 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004367 hdd_warn("Unsupported in mode %s(%d)",
4368 hdd_device_mode_to_string(adapter->device_mode),
4369 adapter->device_mode);
4370 return -EINVAL;
4371 }
4372
Jeff Johnsond377dce2017-10-04 10:32:42 -07004373 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004374
4375 /* if not associated, no need to proceed with reassoc */
Jeff Johnsond377dce2017-10-04 10:32:42 -07004376 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004377 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004378 ret = -EINVAL;
4379 goto exit;
4380 }
4381
4382 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4383 &channel);
4384 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004385 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386 goto exit;
4387 }
4388
4389 /*
4390 * if the target bssid is same as currently associated AP,
4391 * issue reassoc to same AP
4392 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004393 if (!qdf_mem_cmp(targetApBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004394 sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304395 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004396 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304397 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004398 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304399 targetApBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004400 sta_ctx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304401 } else {
4402 sme_get_modify_profile_fields(hdd_ctx->hHal,
4403 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004404 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304405 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4406 NULL, modProfileFields, &roamId, 1);
4407 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004408 return 0;
4409 }
4410
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304411 /* Check channel number is a valid channel number */
Selvaraj, Sridhar64b0a9c2017-05-11 16:50:15 +05304412 if (channel && (QDF_STATUS_SUCCESS !=
4413 wlan_hdd_validate_operation_channel(adapter, channel))) {
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304414 hdd_err("Invalid Channel [%d]", channel);
4415 return -EINVAL;
4416 }
4417
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004418 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004419 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004420 targetApBssid, (int)channel);
4421 goto exit;
4422 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004424 handoffInfo.channel = channel;
4425 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004426 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 sizeof(tSirMacAddr));
4428 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4429 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430exit:
4431 return ret;
4432}
4433
Jeff Johnsone44b7012017-09-10 15:25:47 -07004434static int drv_cmd_set_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004435 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004436 uint8_t *command,
4437 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004438 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004439{
4440 int ret = 0;
4441 uint8_t *value = command;
4442 uint8_t roamScanControl = 0;
4443
4444 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4445 value = value + command_len + 1;
4446
4447 /* Convert the value from ascii to integer */
4448 ret = kstrtou8(value, 10, &roamScanControl);
4449 if (ret < 0) {
4450 /*
4451 * If the input value is greater than max value of datatype,
4452 * then also kstrtou8 fails
4453 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004454 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004455 ret = -EINVAL;
4456 goto exit;
4457 }
4458
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004459 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004460 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004461
4462 if (0 != roamScanControl) {
4463 ret = 0; /* return success but ignore param value "true" */
4464 goto exit;
4465 }
4466
4467 sme_set_roam_scan_control(hdd_ctx->hHal,
4468 adapter->sessionId,
4469 roamScanControl);
4470
4471exit:
4472 return ret;
4473}
4474
Jeff Johnsone44b7012017-09-10 15:25:47 -07004475static int drv_cmd_set_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004476 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004477 uint8_t *command,
4478 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004479 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004480{
4481 int ret = 0;
4482 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004483 uint32_t okc_mode;
4484 struct pmkid_mode_bits pmkid_modes;
4485
4486 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004487
4488 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004489 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004490 * then this operation is not permitted (return FAILURE)
4491 */
4492 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004493 pmkid_modes.fw_okc &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004495 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004496 ret = -EPERM;
4497 goto exit;
4498 }
4499
4500 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4501 value = value + command_len + 1;
4502
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004503 /* get the current configured value */
4504 okc_mode = hdd_ctx->config->pmkid_modes & CFG_PMKID_MODES_OKC;
4505
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004506 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004507 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004508 if (ret < 0) {
4509 /*
4510 * If the input value is greater than max value of datatype,
4511 * then also kstrtou8 fails
4512 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004513 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004514 ret = -EINVAL;
4515 goto exit;
4516 }
4517
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004518 if ((okc_mode < 0) ||
4519 (okc_mode > 1)) {
4520 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4521 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004522 ret = -EINVAL;
4523 goto exit;
4524 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004525 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004526 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004527
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004528 if (okc_mode)
4529 hdd_ctx->config->pmkid_modes |= CFG_PMKID_MODES_OKC;
4530 else
4531 hdd_ctx->config->pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004532
4533exit:
4534 return ret;
4535}
4536
Jeff Johnsone44b7012017-09-10 15:25:47 -07004537static int drv_cmd_get_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004538 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004539 uint8_t *command,
4540 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004541 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004542{
4543 int ret = 0;
4544 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4545 char extra[32];
4546 uint8_t len = 0;
4547
4548 len = scnprintf(extra, sizeof(extra), "%s %d",
4549 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304550 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004551 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004552 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004553 ret = -EFAULT;
4554 }
4555
4556 return ret;
4557}
4558
Jeff Johnsone44b7012017-09-10 15:25:47 -07004559static int drv_cmd_bt_coex_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004560 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004561 uint8_t *command,
4562 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004563 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004564{
4565 int ret = 0;
4566 char *bcMode;
4567
4568 bcMode = command + 11;
4569 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004570 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004571 hdd_ctx->btCoexModeSet = true;
4572 ret = wlan_hdd_scan_abort(adapter);
4573 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004574 hdd_err("Failed to abort existing scan status: %d",
4575 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004576 }
4577 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004578 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004579 hdd_ctx->btCoexModeSet = false;
4580 }
4581
4582 return ret;
4583}
4584
Jeff Johnsone44b7012017-09-10 15:25:47 -07004585static int drv_cmd_scan_active(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004586 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004587 uint8_t *command,
4588 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004589 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004590{
4591 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4592 return 0;
4593}
4594
Jeff Johnsone44b7012017-09-10 15:25:47 -07004595static int drv_cmd_scan_passive(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004596 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004597 uint8_t *command,
4598 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004599 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004600{
4601 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4602 return 0;
4603}
4604
Jeff Johnsone44b7012017-09-10 15:25:47 -07004605static int drv_cmd_get_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004606 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004607 uint8_t *command,
4608 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004609 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004610{
4611 int ret = 0;
4612 struct hdd_config *pCfg =
4613 (WLAN_HDD_GET_CTX(adapter))->config;
4614 char extra[32];
4615 uint8_t len = 0;
4616
4617 memset(extra, 0, sizeof(extra));
4618 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304619 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004620 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004621 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004622 ret = -EFAULT;
4623 goto exit;
4624 }
4625 ret = len;
4626exit:
4627 return ret;
4628}
4629
Jeff Johnsone44b7012017-09-10 15:25:47 -07004630static int drv_cmd_set_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004631 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004632 uint8_t *command,
4633 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004634 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004635{
4636 return hdd_set_dwell_time(adapter, command);
4637}
4638
Jeff Johnsone44b7012017-09-10 15:25:47 -07004639static int drv_cmd_miracast(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004640 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004641 uint8_t *command,
4642 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004643 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304645 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004646 int ret = 0;
4647 tHalHandle hHal;
4648 uint8_t filterType = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004649 uint8_t *value;
4650
Jeff Johnson6da2db12017-09-03 09:18:52 -07004651 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004652 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004653
Jeff Johnson6da2db12017-09-03 09:18:52 -07004654 hHal = hdd_ctx->hHal;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004655 value = command + 9;
4656
4657 /* Convert the value from ascii to integer */
4658 ret = kstrtou8(value, 10, &filterType);
4659 if (ret < 0) {
4660 /*
4661 * If the input value is greater than max value of datatype,
4662 * then also kstrtou8 fails
4663 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004664 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004665 ret = -EINVAL;
4666 goto exit;
4667 }
4668 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4669 || (filterType >
4670 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004671 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004672 ret = -EINVAL;
4673 goto exit;
4674 }
4675 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
Jeff Johnson6da2db12017-09-03 09:18:52 -07004676 hdd_ctx->miracast_value = filterType;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004677
4678 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304679 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004680 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004681 return -EBUSY;
4682 }
4683
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004684 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4685 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004686
4687exit:
4688 return ret;
4689}
4690
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004691/* Function header is left blank intentionally */
4692static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4693 int32_t *oui_length, int32_t limit)
4694{
4695 uint8_t len;
4696 uint8_t data;
4697
4698 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4699 command++;
4700 limit--;
4701 }
4702
4703 len = 2;
4704
4705 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4706 (limit > 1)) {
4707 sscanf(command, "%02x", (unsigned int *)&data);
4708 ie[len++] = data;
4709 command += 2;
4710 limit -= 2;
4711 }
4712
4713 *oui_length = len - 2;
4714
4715 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4716 command++;
4717 limit--;
4718 }
4719
4720 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4721 (limit > 1)) {
4722 sscanf(command, "%02x", (unsigned int *)&data);
4723 ie[len++] = data;
4724 command += 2;
4725 limit -= 2;
4726 }
4727
4728 ie[0] = IE_EID_VENDOR;
4729 ie[1] = len - 2;
4730
4731 return len;
4732}
4733
4734/**
4735 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4736 * @adapter: Pointer to adapter
4737 * @hdd_ctx: Pointer to HDD context
4738 * @command: Pointer to command string
4739 * @command_len : Command length
4740 * @priv_data : Pointer to priv data
4741 *
4742 * Return:
4743 * int status code
4744 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07004745static int drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004746 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004747 uint8_t *command,
4748 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004749 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004750{
4751 int i = 0;
4752 int status;
4753 int ret = 0;
4754 uint8_t *ibss_ie;
4755 int32_t oui_length = 0;
4756 uint32_t ibss_ie_length;
4757 uint8_t *value = command;
4758 tSirModifyIE ibssModifyIE;
Jeff Johnson5b34fce2017-10-13 13:24:51 -07004759 tCsrRoamProfile *roam_profile;
Jeff Johnson2a722002017-09-30 20:02:35 -07004760 struct hdd_wext_state *pWextState;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004761
4762
Krunal Sonibe766b02016-03-10 13:00:44 -08004763 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004764 hdd_debug("Device_mode %s(%d) not IBSS",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004765 hdd_device_mode_to_string(adapter->device_mode),
4766 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004767 return ret;
4768 }
4769
4770 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4771
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004772 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004773
4774
4775 /* validate argument of command */
4776 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004777 hdd_err("No arguments in command length %zu",
4778 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004779 ret = -EFAULT;
4780 goto exit;
4781 }
4782
4783 /* moving to arguments of commands */
4784 value = value + command_len;
4785 command_len = strlen(value);
4786
4787 /* oui_data can't be less than 3 bytes */
4788 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004789 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4790 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004791 ret = -EFAULT;
4792 goto exit;
4793 }
4794
4795 ibss_ie = qdf_mem_malloc(command_len);
4796 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004797 hdd_err("Could not allocate memory for command length %d",
4798 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004799 ret = -ENOMEM;
4800 goto exit;
4801 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004802
4803 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4804 &oui_length,
4805 command_len);
4806 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004807 hdd_err("Could not parse command %s return length %d",
4808 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004809 ret = -EFAULT;
4810 qdf_mem_free(ibss_ie);
4811 goto exit;
4812 }
4813
Jeff Johnson5b34fce2017-10-13 13:24:51 -07004814 roam_profile = &pWextState->roamProfile;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004815
4816 qdf_copy_macaddr(&ibssModifyIE.bssid,
Jeff Johnson5b34fce2017-10-13 13:24:51 -07004817 roam_profile->BSSIDs.bssid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004818
4819 ibssModifyIE.smeSessionId = adapter->sessionId;
4820 ibssModifyIE.notify = true;
4821 ibssModifyIE.ieID = IE_EID_VENDOR;
4822 ibssModifyIE.ieIDLen = ibss_ie_length;
4823 ibssModifyIE.ieBufferlength = ibss_ie_length;
4824 ibssModifyIE.pIEBuffer = ibss_ie;
4825 ibssModifyIE.oui_length = oui_length;
4826
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004827 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4828 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004829 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004830 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004831
4832 /* Probe Bcn modification */
4833 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4834 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4835
4836 /* Populating probe resp frame */
4837 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4838 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4839
4840 qdf_mem_free(ibss_ie);
4841
4842 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4843 adapter->sessionId);
4844 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004845 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004846 status);
4847 ret = -EINVAL;
4848 goto exit;
4849 }
4850
4851exit:
4852 return ret;
4853}
4854
Jeff Johnsone44b7012017-09-10 15:25:47 -07004855static int drv_cmd_set_rmc_enable(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004856 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004857 uint8_t *command,
4858 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004859 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004860{
4861 int ret = 0;
4862 uint8_t *value = command;
4863 uint8_t ucRmcEnable = 0;
4864 int status;
4865
Krunal Sonibe766b02016-03-10 13:00:44 -08004866 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4867 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004868 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4869 hdd_device_mode_to_string(adapter->device_mode),
4870 adapter->device_mode);
4871 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004872 ret = -EINVAL;
4873 goto exit;
4874 }
4875
4876 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4877 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004878 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004879 ret = -EINVAL;
4880 goto exit;
4881 }
4882
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004883 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004884
4885 if (true == ucRmcEnable) {
4886 status = sme_enable_rmc((tHalHandle)
4887 (hdd_ctx->hHal),
4888 adapter->sessionId);
4889 } else if (false == ucRmcEnable) {
4890 status = sme_disable_rmc((tHalHandle)
4891 (hdd_ctx->hHal),
4892 adapter->sessionId);
4893 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004894 hdd_err("Invalid SETRMCENABLE command %d",
4895 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004896 ret = -EINVAL;
4897 goto exit;
4898 }
4899
4900 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004901 hdd_err("SETRMC %d failed status %d",
4902 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004903 ret = -EINVAL;
4904 goto exit;
4905 }
4906
4907exit:
4908 return ret;
4909}
4910
Jeff Johnsone44b7012017-09-10 15:25:47 -07004911static int drv_cmd_set_rmc_action_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004912 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004913 uint8_t *command,
4914 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004915 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004916{
4917 int ret = 0;
4918 uint8_t *value = command;
4919 uint32_t uActionPeriod = 0;
4920 int status;
4921
Krunal Sonibe766b02016-03-10 13:00:44 -08004922 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4923 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004924 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004925 hdd_device_mode_to_string(adapter->device_mode),
4926 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004927 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004928 ret = -EINVAL;
4929 goto exit;
4930 }
4931
4932 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4933 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004934 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004935 ret = -EINVAL;
4936 goto exit;
4937 }
4938
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004939 hdd_debug("uActionPeriod %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004940 uActionPeriod);
4941
4942 if (sme_cfg_set_int(hdd_ctx->hHal,
4943 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4944 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004945 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4946 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004947 ret = -EINVAL;
4948 goto exit;
4949 }
4950
4951 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4952 adapter->sessionId);
4953 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004954 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004955 status);
4956 ret = -EINVAL;
4957 goto exit;
4958 }
4959
4960exit:
4961 return ret;
4962}
4963
Jeff Johnsone44b7012017-09-10 15:25:47 -07004964static int drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004965 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004966 uint8_t *command,
4967 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004968 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004969{
4970 int ret = 0;
4971 int status = QDF_STATUS_SUCCESS;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004972 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004973 char *extra = NULL;
4974 int idx = 0;
4975 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004976 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004977 uint32_t numOfBytestoPrint = 0;
4978
Krunal Sonibe766b02016-03-10 13:00:44 -08004979 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004980 hdd_warn("Unsupported in mode %s(%d)",
4981 hdd_device_mode_to_string(adapter->device_mode),
4982 adapter->device_mode);
4983 return -EINVAL;
4984 }
4985
Jeff Johnsond377dce2017-10-04 10:32:42 -07004986 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004987 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004988
4989 /* Handle the command */
4990 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
4991 if (QDF_STATUS_SUCCESS == status) {
4992 /*
4993 * The variable extra needed to be allocated on the heap since
4994 * amount of memory required to copy the data for 32 devices
4995 * exceeds the size of 1024 bytes of default stack size. On
4996 * 64 bit devices, the default max stack size of 2048 bytes
4997 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004998 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004999
5000 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005001 hdd_err("memory allocation failed");
5002 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005003 goto exit;
5004 }
5005
5006 /* Copy number of stations */
5007 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Jeff Johnsond377dce2017-10-04 10:32:42 -07005008 sta_ctx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005009 numOfBytestoPrint = length;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005010 for (idx = 0; idx < sta_ctx->ibss_peer_info.numPeers;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005011 idx++) {
5012 int8_t rssi;
5013 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005014
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005015 qdf_mem_copy(mac_addr,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005016 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005017 mac_addr, sizeof(mac_addr));
5018
5019 tx_rate =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005020 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005021 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305022 /*
5023 * Only lower 3 bytes are rate info. Mask of the MSByte
5024 */
5025 tx_rate &= 0x00FFFFFF;
5026
Jeff Johnsond377dce2017-10-04 10:32:42 -07005027 rssi = sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005028 rssi;
5029
5030 length += scnprintf((extra + length),
5031 WLAN_MAX_BUF_SIZE - length,
5032 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5033 mac_addr[0], mac_addr[1], mac_addr[2],
5034 mac_addr[3], mac_addr[4], mac_addr[5],
5035 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005036 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005037 * cdf_trace_msg has limitation of 512 bytes for the
5038 * print buffer. Hence printing the data in two chunks.
5039 * The first chunk will have the data for 16 devices
5040 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005041 */
5042 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5043 numOfBytestoPrint = length;
5044 }
5045
5046 /*
5047 * Copy the data back into buffer, if the data to copy is
5048 * more than 512 bytes than we will split the data and do
5049 * it in two shots
5050 */
5051 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005052 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005053 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305054 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005055 }
5056
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005057 /* This overwrites the last space, which we already copied */
5058 extra[numOfBytestoPrint - 1] = '\0';
5059 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005060
5061 if (length > numOfBytestoPrint) {
5062 if (copy_to_user
5063 (priv_data->buf + numOfBytestoPrint,
5064 extra + numOfBytestoPrint,
5065 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005066 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005067 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305068 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005069 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005070 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005071 }
5072
5073 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005074 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005075 } else {
5076 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005077 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5078 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005079 ret = -EINVAL;
5080 goto exit;
5081 }
5082 ret = 0;
5083
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305084mem_free:
5085 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005086exit:
5087 return ret;
5088}
5089
5090/* Peer Info <Peer Addr> command */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005091static int drv_cmd_get_ibss_peer_info(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005092 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005093 uint8_t *command,
5094 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005095 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005096{
5097 int ret = 0;
5098 uint8_t *value = command;
5099 QDF_STATUS status;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005100 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005101 char extra[128] = { 0 };
5102 uint32_t length = 0;
5103 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005104 struct qdf_mac_addr peerMacAddr;
5105
Krunal Sonibe766b02016-03-10 13:00:44 -08005106 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005107 hdd_warn("Unsupported in mode %s(%d)",
5108 hdd_device_mode_to_string(adapter->device_mode),
5109 adapter->device_mode);
5110 return -EINVAL;
5111 }
5112
Jeff Johnsond377dce2017-10-04 10:32:42 -07005113 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005114
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005115 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005116
5117 /* if there are no peers, no need to continue with the command */
5118 if (eConnectionState_IbssConnected !=
Jeff Johnsond377dce2017-10-04 10:32:42 -07005119 sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005120 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005121 ret = -EINVAL;
5122 goto exit;
5123 }
5124
5125 /* Parse the incoming command buffer */
5126 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5127 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005128 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005129 ret = -EINVAL;
5130 goto exit;
5131 }
5132
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005133 /* Get station index for the peer mac address and sanitize it */
Jeff Johnsond377dce2017-10-04 10:32:42 -07005134 hdd_get_peer_sta_id(sta_ctx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005135
Naveen Rawatc45d1622016-07-05 12:20:09 -07005136 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005137 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005138 ret = -EINVAL;
5139 goto exit;
5140 }
5141
5142 /* Handle the command */
5143 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5144 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005145 uint32_t txRate =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005146 sta_ctx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305147 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5148 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005149
5150 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005151 (int)txRate,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005152 (int)sta_ctx->ibss_peer_info.
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005153 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005154
5155 /* Copy the data back into buffer */
5156 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005157 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005158 ret = -EFAULT;
5159 goto exit;
5160 }
5161 } else {
5162 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005163 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5164 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005165 ret = -EINVAL;
5166 goto exit;
5167 }
5168
5169 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005170 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005171 ret = 0;
5172
5173exit:
5174 return ret;
5175}
5176
Jeff Johnsone44b7012017-09-10 15:25:47 -07005177static int drv_cmd_set_rmc_tx_rate(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005178 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005179 uint8_t *command,
5180 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005181 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005182{
5183 int ret = 0;
5184 uint8_t *value = command;
5185 uint32_t uRate = 0;
5186 tTxrateinfoflags txFlags = 0;
5187 tSirRateUpdateInd rateUpdateParams = {0};
5188 int status;
5189 struct hdd_config *pConfig = hdd_ctx->config;
5190
Krunal Sonibe766b02016-03-10 13:00:44 -08005191 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5192 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005193 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5194 hdd_device_mode_to_string(adapter->device_mode),
5195 adapter->device_mode);
5196 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005197 ret = -EINVAL;
5198 goto exit;
5199 }
5200
5201 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5202 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005203 hdd_err("Invalid SETRMCTXRATE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005204 ret = -EINVAL;
5205 goto exit;
5206 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005207 hdd_debug("uRate %d", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005208 /* -1 implies ignore this param */
5209 rateUpdateParams.ucastDataRate = -1;
5210
5211 /*
5212 * Fill the user specifieed RMC rate param
5213 * and the derived tx flags.
5214 */
5215 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5216 rateUpdateParams.reliableMcastDataRate = uRate;
5217 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5218 rateUpdateParams.dev_mode = adapter->device_mode;
5219 rateUpdateParams.bcastDataRate = -1;
5220 memcpy(rateUpdateParams.bssid.bytes,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005221 adapter->mac_addr.bytes,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005222 sizeof(rateUpdateParams.bssid));
5223 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5224 &rateUpdateParams);
5225
5226exit:
5227 return ret;
5228}
5229
Jeff Johnsone44b7012017-09-10 15:25:47 -07005230static int drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005231 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005232 uint8_t *command,
5233 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005234 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005235{
5236 int ret = 0;
5237 char *value;
5238 uint8_t tx_fail_count = 0;
5239 uint16_t pid = 0;
5240
5241 value = command;
5242
5243 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5244
5245 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005246 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005247 goto exit;
5248 }
5249
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005250 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005251
5252 if (0 == tx_fail_count) {
5253 /* Disable TX Fail Indication */
5254 if (QDF_STATUS_SUCCESS ==
5255 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5256 tx_fail_count,
5257 NULL)) {
5258 cesium_pid = 0;
5259 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005260 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005261 ret = -EINVAL;
5262 }
5263 } else {
5264 if (QDF_STATUS_SUCCESS ==
5265 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5266 tx_fail_count,
5267 (void *)hdd_tx_fail_ind_callback)) {
5268 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005269 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005270 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005271 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005272 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005273 ret = -EINVAL;
5274 }
5275 }
5276
5277exit:
5278 return ret;
5279}
5280
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005281#ifdef FEATURE_WLAN_ESE
Jeff Johnsone44b7012017-09-10 15:25:47 -07005282static int drv_cmd_set_ccx_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005283 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005284 uint8_t *command,
5285 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005286 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005287{
5288 int ret = 0;
5289 uint8_t *value = command;
5290 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5291 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305292 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005293
5294 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5295 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005296 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005297 goto exit;
5298 }
5299 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005300 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005301 numChannels,
5302 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5303 ret = -EINVAL;
5304 goto exit;
5305 }
5306 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5307 adapter->sessionId,
5308 ChannelList,
5309 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305310 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005311 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005312 ret = -EINVAL;
5313 goto exit;
5314 }
5315
5316exit:
5317 return ret;
5318}
5319
Jeff Johnsone44b7012017-09-10 15:25:47 -07005320static int drv_cmd_get_tsm_stats(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005321 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005322 uint8_t *command,
5323 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005324 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005325{
5326 int ret = 0;
5327 uint8_t *value = command;
5328 char extra[128] = { 0 };
5329 int len = 0;
5330 uint8_t tid = 0;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005331 struct hdd_station_ctx *sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005332 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005333
Krunal Sonibe766b02016-03-10 13:00:44 -08005334 if ((QDF_STA_MODE != adapter->device_mode) &&
5335 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005336 hdd_warn("Unsupported in mode %s(%d)",
5337 hdd_device_mode_to_string(adapter->device_mode),
5338 adapter->device_mode);
5339 return -EINVAL;
5340 }
5341
Jeff Johnsond377dce2017-10-04 10:32:42 -07005342 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005343
5344 /* if not associated, return error */
Jeff Johnsond377dce2017-10-04 10:32:42 -07005345 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005346 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005347 ret = -EINVAL;
5348 goto exit;
5349 }
5350
5351 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5352 value = value + command_len + 1;
5353
5354 /* Convert the value from ascii to integer */
5355 ret = kstrtou8(value, 10, &tid);
5356 if (ret < 0) {
5357 /*
5358 * If the input value is greater than max value of datatype,
5359 * then also kstrtou8 fails
5360 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005361 hdd_err("kstrtou8 failed range [%d - %d]",
5362 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005363 TID_MAX_VALUE);
5364 ret = -EINVAL;
5365 goto exit;
5366 }
5367 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005368 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005369 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5370 ret = -EINVAL;
5371 goto exit;
5372 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005373 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005374 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005375 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5376 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005377 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005378 goto exit;
5379 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005380 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005381 "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 -08005382 tsm_metrics.UplinkPktQueueDly,
5383 tsm_metrics.UplinkPktQueueDlyHist[0],
5384 tsm_metrics.UplinkPktQueueDlyHist[1],
5385 tsm_metrics.UplinkPktQueueDlyHist[2],
5386 tsm_metrics.UplinkPktQueueDlyHist[3],
5387 tsm_metrics.UplinkPktTxDly,
5388 tsm_metrics.UplinkPktLoss,
5389 tsm_metrics.UplinkPktCount,
5390 tsm_metrics.RoamingCount,
5391 tsm_metrics.RoamingDly);
5392 /*
5393 * Output TSM stats is of the format
5394 * GETTSMSTATS [PktQueueDly]
5395 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5396 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5397 */
5398 len = scnprintf(extra,
5399 sizeof(extra),
5400 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5401 command,
5402 tsm_metrics.UplinkPktQueueDly,
5403 tsm_metrics.UplinkPktQueueDlyHist[0],
5404 tsm_metrics.UplinkPktQueueDlyHist[1],
5405 tsm_metrics.UplinkPktQueueDlyHist[2],
5406 tsm_metrics.UplinkPktQueueDlyHist[3],
5407 tsm_metrics.UplinkPktTxDly,
5408 tsm_metrics.UplinkPktLoss,
5409 tsm_metrics.UplinkPktCount,
5410 tsm_metrics.RoamingCount,
5411 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305412 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005413 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005414 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005415 ret = -EFAULT;
5416 goto exit;
5417 }
5418
5419exit:
5420 return ret;
5421}
5422
Jeff Johnsone44b7012017-09-10 15:25:47 -07005423static int drv_cmd_set_cckm_ie(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005424 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005425 uint8_t *command,
5426 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005427 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005428{
5429 int ret;
5430 uint8_t *value = command;
5431 uint8_t *cckmIe = NULL;
5432 uint8_t cckmIeLen = 0;
5433
5434 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5435 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005436 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005437 goto exit;
5438 }
5439
5440 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005441 hdd_err("CCKM Ie input length is more than max[%d]",
5442 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005443 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305444 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005445 cckmIe = NULL;
5446 }
5447 ret = -EINVAL;
5448 goto exit;
5449 }
5450
5451 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5452 cckmIe, cckmIeLen);
5453 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305454 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005455 cckmIe = NULL;
5456 }
5457
5458exit:
5459 return ret;
5460}
5461
Jeff Johnsone44b7012017-09-10 15:25:47 -07005462static int drv_cmd_ccx_beacon_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005463 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005464 uint8_t *command,
5465 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005466 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005467{
5468 int ret;
5469 uint8_t *value = command;
5470 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305471 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005472
Krunal Sonibe766b02016-03-10 13:00:44 -08005473 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005474 hdd_warn("Unsupported in mode %s(%d)",
5475 hdd_device_mode_to_string(adapter->device_mode),
5476 adapter->device_mode);
5477 return -EINVAL;
5478 }
5479
5480 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5481 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005482 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005483 goto exit;
5484 }
5485
5486 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005487 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005488 hdd_indicate_ese_bcn_report_no_results(adapter,
5489 eseBcnReq.bcnReq[0].measurementToken,
5490 0x02, /* BIT(1) set for measurement done */
5491 0); /* no BSS */
5492 goto exit;
5493 }
5494
5495 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5496 adapter->sessionId,
5497 &eseBcnReq);
5498
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305499 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005500 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005501 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005502 ret = -EBUSY;
5503 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305504 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005505 hdd_err("sme_set_ese_beacon_request failed (%d)",
5506 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005507 ret = -EINVAL;
5508 goto exit;
5509 }
5510
5511exit:
5512 return ret;
5513}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005514
5515/**
5516 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5517 * @adapter: Pointer to the HDD adapter
5518 * @hdd_ctx: Pointer to the HDD context
5519 * @command: Driver command string
5520 * @command_len: Driver command string length
5521 * @priv_data: Private data coming with the driver command. Unused here
5522 *
5523 * This function handles driver command that sets the ESE PLM request
5524 *
5525 * Return: 0 on success; negative errno otherwise
5526 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005527static int drv_cmd_ccx_plm_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005528 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005529 uint8_t *command,
5530 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005531 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005532{
5533 int ret = 0;
5534 uint8_t *value = command;
5535 QDF_STATUS status = QDF_STATUS_SUCCESS;
5536 tpSirPlmReq pPlmRequest = NULL;
5537
5538 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5539 if (NULL == pPlmRequest) {
5540 ret = -ENOMEM;
5541 goto exit;
5542 }
5543
5544 status = hdd_parse_plm_cmd(value, pPlmRequest);
5545 if (QDF_STATUS_SUCCESS != status) {
5546 qdf_mem_free(pPlmRequest);
5547 pPlmRequest = NULL;
5548 ret = -EINVAL;
5549 goto exit;
5550 }
5551 pPlmRequest->sessionId = adapter->sessionId;
5552
5553 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5554 if (QDF_STATUS_SUCCESS != status) {
5555 qdf_mem_free(pPlmRequest);
5556 pPlmRequest = NULL;
5557 ret = -EINVAL;
5558 goto exit;
5559 }
5560
5561exit:
5562 return ret;
5563}
5564
5565/**
5566 * drv_cmd_set_ccx_mode() - Set ESE mode
5567 * @adapter: Pointer to the HDD adapter
5568 * @hdd_ctx: Pointer to the HDD context
5569 * @command: Driver command string
5570 * @command_len: Driver command string length
5571 * @priv_data: Private data coming with the driver command. Unused here
5572 *
5573 * This function handles driver command that sets ESE mode
5574 *
5575 * Return: 0 on success; negative errno otherwise
5576 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005577static int drv_cmd_set_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005578 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005579 uint8_t *command,
5580 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005581 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005582{
5583 int ret = 0;
5584 uint8_t *value = command;
5585 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005586 struct pmkid_mode_bits pmkid_modes;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005587
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005588 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005589 /*
5590 * Check if the features OKC/ESE/11R are supported simultaneously,
5591 * then this operation is not permitted (return FAILURE)
5592 */
5593 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005594 pmkid_modes.fw_okc &&
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005595 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5596 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5597 ret = -EPERM;
5598 goto exit;
5599 }
5600
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005601 if (!adapter->fast_roaming_allowed) {
5602 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5603 ret = -EPERM;
5604 goto exit;
5605 }
5606
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005607 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5608 value = value + command_len + 1;
5609
5610 /* Convert the value from ascii to integer */
5611 ret = kstrtou8(value, 10, &eseMode);
5612 if (ret < 0) {
5613 /*
5614 * If the input value is greater than max value of datatype,
5615 * then also kstrtou8 fails
5616 */
5617 hdd_err("kstrtou8 failed range [%d - %d]",
5618 CFG_ESE_FEATURE_ENABLED_MIN,
5619 CFG_ESE_FEATURE_ENABLED_MAX);
5620 ret = -EINVAL;
5621 goto exit;
5622 }
5623
5624 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5625 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5626 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5627 eseMode,
5628 CFG_ESE_FEATURE_ENABLED_MIN,
5629 CFG_ESE_FEATURE_ENABLED_MAX);
5630 ret = -EINVAL;
5631 goto exit;
5632 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005633 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005634
5635 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5636 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5637 adapter->sessionId,
5638 eseMode);
5639
5640exit:
5641 return ret;
5642}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005643#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005644
Jeff Johnsone44b7012017-09-10 15:25:47 -07005645static int drv_cmd_set_mc_rate(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005646 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005647 uint8_t *command,
5648 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005649 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005650{
5651 int ret = 0;
5652 uint8_t *value = command;
5653 int targetRate;
5654
5655 /* input value is in units of hundred kbps */
5656
5657 /* Move pointer to ahead of SETMCRATE<delimiter> */
5658 value = value + command_len + 1;
5659
5660 /* Convert the value from ascii to integer, decimal base */
5661 ret = kstrtouint(value, 10, &targetRate);
5662
5663 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5664 return ret;
5665}
5666
Jeff Johnsone44b7012017-09-10 15:25:47 -07005667static int drv_cmd_max_tx_power(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005668 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005669 uint8_t *command,
5670 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005671 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005672{
5673 int ret = 0;
5674 int status;
5675 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305676 QDF_STATUS qdf_status;
5677 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005678 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305679 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5680 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005681 hdd_adapter_list_node_t *pAdapterNode = NULL;
5682 hdd_adapter_list_node_t *pNext = NULL;
5683
5684 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5685 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005686 hdd_err("Invalid MAXTXPOWER command");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005687 ret = -EINVAL;
5688 goto exit;
5689 }
5690
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305691 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005692 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305693 && QDF_STATUS_SUCCESS == qdf_status) {
Jeff Johnson57eb2732017-10-02 11:40:20 -07005694 adapter = pAdapterNode->adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005695 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305696 qdf_copy_macaddr(&bssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005697 &adapter->mac_addr);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305698 qdf_copy_macaddr(&selfMac,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005699 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005700
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005701 hdd_debug("Device mode %d max tx power %d selfMac: "
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005702 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005703 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005704 MAC_ADDR_ARRAY(selfMac.bytes),
5705 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005706
Srinivas Girigowda97215232015-09-24 12:26:28 -07005707 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5708 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305709 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005710 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005711 ret = -EINVAL;
5712 goto exit;
5713 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005714 hdd_debug("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305715 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005716 &pNext);
5717 pAdapterNode = pNext;
5718 }
5719
5720exit:
5721 return ret;
5722}
5723
Jeff Johnsone44b7012017-09-10 15:25:47 -07005724static int drv_cmd_set_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005725 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005726 uint8_t *command,
5727 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005728 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005729{
5730 int ret = 0;
5731 uint8_t *value = command;
5732 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5733
5734 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5735 value = value + command_len + 1;
5736
5737 /* Convert the value from ascii to integer */
5738 ret = kstrtou8(value, 10, &dfsScanMode);
5739 if (ret < 0) {
5740 /*
5741 * If the input value is greater than max value of datatype,
5742 * then also kstrtou8 fails
5743 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005744 hdd_err("kstrtou8 failed range [%d - %d]",
5745 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005746 CFG_ROAMING_DFS_CHANNEL_MAX);
5747 ret = -EINVAL;
5748 goto exit;
5749 }
5750
5751 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5752 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005753 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005754 dfsScanMode,
5755 CFG_ROAMING_DFS_CHANNEL_MIN,
5756 CFG_ROAMING_DFS_CHANNEL_MAX);
5757 ret = -EINVAL;
5758 goto exit;
5759 }
5760
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005761 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005762 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005763
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005764 /* When DFS scanning is disabled, the DFS channels need to be
5765 * removed from the operation of device.
5766 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005767 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5768 dfsScanMode != CFG_ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005769 if (ret < 0) {
5770 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005771 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005772 goto exit;
5773 }
5774
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005775 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5776 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5777 dfsScanMode);
5778
5779exit:
5780 return ret;
5781}
5782
Jeff Johnsone44b7012017-09-10 15:25:47 -07005783static int drv_cmd_get_dfs_scan_mode(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 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5791 char extra[32];
5792 uint8_t len = 0;
5793
5794 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
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
Jeff Johnsone44b7012017-09-10 15:25:47 -07005804static int drv_cmd_get_link_status(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005805 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005806 uint8_t *command,
5807 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005808 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005809{
5810 int ret = 0;
5811 int value = wlan_hdd_get_link_status(adapter);
5812 char extra[32];
5813 uint8_t len;
5814
5815 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305816 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005817 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005818 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005819 ret = -EFAULT;
5820 }
5821
5822 return ret;
5823}
5824
5825#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Jeff Johnsone44b7012017-09-10 15:25:47 -07005826static int drv_cmd_enable_ext_wow(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005827 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005828 uint8_t *command,
5829 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005830 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005831{
5832 uint8_t *value = command;
5833 int set_value;
5834
5835 /* Move pointer to ahead of ENABLEEXTWOW */
5836 value = value + command_len;
5837
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305838 if (!(sscanf(value, "%d", &set_value))) {
5839 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5840 ("No input identified"));
5841 return -EINVAL;
5842 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005843
5844 return hdd_enable_ext_wow_parser(adapter,
5845 adapter->sessionId,
5846 set_value);
5847}
5848
Jeff Johnsone44b7012017-09-10 15:25:47 -07005849static int drv_cmd_set_app1_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005850 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005851 uint8_t *command,
5852 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005853 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005854{
5855 int ret;
5856 uint8_t *value = command;
5857
5858 /* Move pointer to ahead of SETAPP1PARAMS */
5859 value = value + command_len;
5860
5861 ret = hdd_set_app_type1_parser(adapter,
5862 value, strlen(value));
5863 if (ret >= 0)
5864 hdd_ctx->is_extwow_app_type1_param_set = true;
5865
5866 return ret;
5867}
5868
Jeff Johnsone44b7012017-09-10 15:25:47 -07005869static int drv_cmd_set_app2_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005870 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005871 uint8_t *command,
5872 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005873 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005874{
5875 int ret;
5876 uint8_t *value = command;
5877
5878 /* Move pointer to ahead of SETAPP2PARAMS */
5879 value = value + command_len;
5880
5881 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5882 if (ret >= 0)
5883 hdd_ctx->is_extwow_app_type2_param_set = true;
5884
5885 return ret;
5886}
5887#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5888
5889#ifdef FEATURE_WLAN_TDLS
5890/**
5891 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5892 * @adapter: Pointer to the HDD adapter
5893 * @hdd_ctx: Pointer to the HDD context
5894 * @command: Driver command string
5895 * @command_len: Driver command string length
5896 * @priv_data: Private data coming with the driver command. Unused here
5897 *
5898 * This function handles driver command that sets the secondary tdls off channel
5899 * offset
5900 *
5901 * Return: 0 on success; negative errno otherwise
5902 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005903static int drv_cmd_tdls_secondary_channel_offset(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005904 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005905 uint8_t *command,
5906 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005907 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005908{
5909 int ret;
5910 uint8_t *value = command;
5911 int set_value;
5912
5913 /* Move pointer to point the string */
5914 value += command_len;
5915
5916 ret = sscanf(value, "%d", &set_value);
5917 if (ret != 1)
5918 return -EINVAL;
5919
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005920 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005921
5922 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5923
5924 return ret;
5925}
5926
5927/**
5928 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5929 * @adapter: Pointer to the HDD adapter
5930 * @hdd_ctx: Pointer to the HDD context
5931 * @command: Driver command string
5932 * @command_len: Driver command string length
5933 * @priv_data: Private data coming with the driver command. Unused here
5934 *
5935 * This function handles driver command that sets tdls off channel mode
5936 *
5937 * Return: 0 on success; negative errno otherwise
5938 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005939static int drv_cmd_tdls_off_channel_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005940 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005941 uint8_t *command,
5942 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005943 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005944{
5945 int ret;
5946 uint8_t *value = command;
5947 int set_value;
5948
5949 /* Move pointer to point the string */
5950 value += command_len;
5951
5952 ret = sscanf(value, "%d", &set_value);
5953 if (ret != 1)
5954 return -EINVAL;
5955
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005956 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005957
5958 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5959
5960 return ret;
5961}
5962
5963/**
5964 * drv_cmd_tdls_off_channel() - set tdls off channel number
5965 * @adapter: Pointer to the HDD adapter
5966 * @hdd_ctx: Pointer to the HDD context
5967 * @command: Driver command string
5968 * @command_len: Driver command string length
5969 * @priv_data: Private data coming with the driver command. Unused here
5970 *
5971 * This function handles driver command that sets tdls off channel number
5972 *
5973 * Return: 0 on success; negative errno otherwise
5974 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005975static int drv_cmd_tdls_off_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005976 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005977 uint8_t *command,
5978 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005979 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005980{
5981 int ret;
5982 uint8_t *value = command;
5983 int set_value;
5984
5985 /* Move pointer to point the string */
5986 value += command_len;
5987
5988 ret = sscanf(value, "%d", &set_value);
5989 if (ret != 1)
5990 return -EINVAL;
5991
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -07005992 if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, set_value)) {
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005993 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5994 set_value);
5995 return -EINVAL;
5996 }
5997
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005998 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005999
6000 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6001
6002 return ret;
6003}
6004
6005/**
6006 * drv_cmd_tdls_scan() - set tdls scan type
6007 * @adapter: Pointer to the HDD adapter
6008 * @hdd_ctx: Pointer to the HDD context
6009 * @command: Driver command string
6010 * @command_len: Driver command string length
6011 * @priv_data: Private data coming with the driver command. Unused here
6012 *
6013 * This function handles driver command that sets tdls scan type
6014 *
6015 * Return: 0 on success; negative errno otherwise
6016 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006017static int drv_cmd_tdls_scan(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006018 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006019 uint8_t *command,
6020 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006021 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006022{
6023 int ret;
6024 uint8_t *value = command;
6025 int set_value;
6026
6027 /* Move pointer to point the string */
6028 value += command_len;
6029
6030 ret = sscanf(value, "%d", &set_value);
6031 if (ret != 1)
6032 return -EINVAL;
6033
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006034 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006035
6036 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6037
6038 return ret;
6039}
6040#endif
6041
Jeff Johnsone44b7012017-09-10 15:25:47 -07006042static int drv_cmd_get_rssi(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006043 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006044 uint8_t *command,
6045 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006046 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006047{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006048 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006049 int8_t rssi = 0;
6050 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006051
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006052 uint8_t len = 0;
6053
6054 wlan_hdd_get_rssi(adapter, &rssi);
6055
6056 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306057 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006058
6059 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006060 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006061 ret = -EFAULT;
6062 }
6063
6064 return ret;
6065}
6066
Jeff Johnsone44b7012017-09-10 15:25:47 -07006067static int drv_cmd_get_linkspeed(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006068 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006069 uint8_t *command,
6070 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006071 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006072{
6073 int ret;
6074 uint32_t link_speed = 0;
6075 char extra[32];
6076 uint8_t len = 0;
6077
6078 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6079 if (0 != ret)
6080 return ret;
6081
6082 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306083 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006084 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006085 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006086 ret = -EFAULT;
6087 }
6088
6089 return ret;
6090}
6091
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092/**
6093 * hdd_set_rx_filter() - set RX filter
6094 * @adapter: Pointer to adapter
6095 * @action: Filter action
6096 * @pattern: Address pattern
6097 *
6098 * Address pattern is most significant byte of address for example
6099 * 0x01 for IPV4 multicast address
6100 * 0x33 for IPV6 multicast address
6101 * 0xFF for broadcast address
6102 *
6103 * Return: 0 for success, non-zero for failure
6104 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006105static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006106 uint8_t pattern)
6107{
6108 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006109 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006110 tHalHandle handle;
6111 tSirRcvFltMcAddrList *filter;
Jeff Johnson621cf972017-08-28 11:58:44 -07006112 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006113
6114 ret = wlan_hdd_validate_context(hdd_ctx);
6115 if (0 != ret)
6116 return ret;
6117
6118 handle = hdd_ctx->hHal;
6119
6120 if (NULL == handle) {
6121 hdd_err("HAL Handle is NULL");
6122 return -EINVAL;
6123 }
6124
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306125 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006126 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306127 return -EINVAL;
6128 }
6129
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006130 /*
6131 * If action is false it means start dropping packets
6132 * Set addr_filter_pattern which will be used when sending
6133 * MC/BC address list to target
6134 */
6135 if (!action)
6136 adapter->addr_filter_pattern = pattern;
6137 else
6138 adapter->addr_filter_pattern = 0;
6139
Krunal Sonibe766b02016-03-10 13:00:44 -08006140 if (((adapter->device_mode == QDF_STA_MODE) ||
6141 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006142 adapter->mc_addr_list.mc_cnt &&
6143 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6144
6145
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306146 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006147 if (NULL == filter) {
6148 hdd_err("Could not allocate Memory");
6149 return -ENOMEM;
6150 }
6151 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006152 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006153 if (!memcmp(adapter->mc_addr_list.addr[i],
6154 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006155 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006156 adapter->mc_addr_list.addr[i],
6157 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006158
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006159 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006160 MAC_ADDRESS_STR,
6161 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006162 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6163 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006164 }
SaidiReddy Yenuga0b2c9f42017-02-03 12:26:38 +05306165 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
6166 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006167 }
Frank Liuf95e8132016-09-29 19:01:30 +08006168 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006169 /* Set rx filter */
6170 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306171 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006172 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006173 hdd_debug("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006174 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6175 }
6176
6177 return 0;
6178}
6179
6180/**
6181 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6182 * @command: Pointer to input string driver command
6183 * @adapter: Pointer to adapter
6184 * @action: Action to enable/disable filtering
6185 *
6186 * If action == false
6187 * Start filtering out data packets based on type
6188 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6189 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6190 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6191 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6192 *
6193 * if action == true
6194 * Stop filtering data packets based on type
6195 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6196 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6197 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6198 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6199 *
6200 * Current implementation only supports IPV4 address filtering by
6201 * selectively allowing IPV4 multicast data packest based on
6202 * address list received in .ndo_set_rx_mode
6203 *
6204 * Return: 0 for success, non-zero for failure
6205 */
6206static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
Jeff Johnsone44b7012017-09-10 15:25:47 -07006207 struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006208 bool action)
6209{
6210 int ret = 0;
6211 uint8_t *value;
6212 uint8_t type;
6213
6214 value = command;
6215 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6216 if (!action)
6217 value = command + 16;
6218 else
6219 value = command + 13;
6220 ret = kstrtou8(value, 10, &type);
6221 if (ret < 0) {
6222 hdd_err("kstrtou8 failed invalid input value %d", type);
6223 return -EINVAL;
6224 }
6225
6226 switch (type) {
6227 case 2:
6228 /* Set rx filter for IPV4 multicast data packets */
6229 ret = hdd_set_rx_filter(adapter, action, 0x01);
6230 break;
6231 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006232 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006233 break;
6234 }
6235
6236 return ret;
6237}
6238
6239/**
6240 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6241 * @adapter: Pointer to network adapter
6242 * @hdd_ctx: Pointer to hdd context
6243 * @command: Pointer to input command
6244 * @command_len: Command length
6245 * @priv_data: Pointer to private data in command
6246 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006247static int drv_cmd_rx_filter_remove(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006248 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006249 uint8_t *command,
6250 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006251 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006252{
6253 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6254}
6255
6256/**
6257 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6258 * @adapter: Pointer to network adapter
6259 * @hdd_ctx: Pointer to hdd context
6260 * @command: Pointer to input command
6261 * @command_len: Command length
6262 * @priv_data: Pointer to private data in command
6263 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006264static int drv_cmd_rx_filter_add(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006265 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006266 uint8_t *command,
6267 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006268 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006269{
6270 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6271}
6272
Archana Ramachandran393f3792015-11-13 17:13:21 -08006273/**
6274 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6275 * command
6276 * @value: Pointer to SETANTENNAMODE command
6277 * @mode: Pointer to antenna mode
6278 * @reason: Pointer to reason for set antenna mode
6279 *
6280 * This function parses the SETANTENNAMODE command passed in the format
6281 * SETANTENNAMODE<space>mode
6282 *
6283 * Return: 0 for success non-zero for failure
6284 */
6285static int hdd_parse_setantennamode_command(const uint8_t *value)
6286{
6287 const uint8_t *in_ptr = value;
6288 int tmp, v;
6289 char arg1[32];
6290
6291 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6292
6293 /* no argument after the command */
6294 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006295 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006296 return -EINVAL;
6297 }
6298
6299 /* no space after the command */
6300 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006301 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006302 return -EINVAL;
6303 }
6304
6305 /* remove empty spaces */
6306 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6307 in_ptr++;
6308
6309 /* no argument followed by spaces */
6310 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006311 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006312 return -EINVAL;
6313 }
6314
6315 /* get the argument i.e. antenna mode */
6316 v = sscanf(in_ptr, "%31s ", arg1);
6317 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006318 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006319 return -EINVAL;
6320 }
6321
6322 v = kstrtos32(arg1, 10, &tmp);
6323 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006324 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006325 return -EINVAL;
6326 }
6327
6328 return tmp;
6329}
6330
6331/**
6332 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6333 * mask is 2x2 mode
6334 * @hdd_ctx: Pointer to hdd contex
6335 *
6336 * Return: true if supported chain mask 2x2 else false
6337 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006338static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006339{
6340 /*
6341 * Revisit and the update logic to determine the number
6342 * of TX/RX chains supported in the system when
6343 * antenna sharing per band chain mask support is
6344 * brought in
6345 */
6346 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6347}
6348
6349/**
6350 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6351 * chain mask is 1x1
6352 * @hdd_ctx: Pointer to hdd contex
6353 *
6354 * Return: true if supported chain mask 1x1 else false
6355 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006356static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006357{
6358 /*
6359 * Revisit and update the logic to determine the number
6360 * of TX/RX chains supported in the system when
6361 * antenna sharing per band chain mask support is
6362 * brought in
6363 */
6364 return (!hdd_ctx->config->enable2x2) ? true : false;
6365}
6366
Jeff Johnson621cf972017-08-28 11:58:44 -07006367QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
Nitesh Shahe50711f2017-04-26 16:30:45 +05306368{
6369 QDF_STATUS status;
6370 uint8_t smps_mode;
6371 uint8_t smps_enable;
6372
6373 /* Update SME SMPS config */
6374 if (HDD_ANTENNA_MODE_1X1 == mode) {
6375 smps_enable = true;
6376 smps_mode = HDD_SMPS_MODE_STATIC;
6377 } else {
6378 smps_enable = false;
6379 smps_mode = HDD_SMPS_MODE_DISABLED;
6380 }
6381
6382 hdd_debug("Update SME SMPS enable: %d mode: %d",
6383 smps_enable, smps_mode);
6384 status = sme_update_mimo_power_save(
6385 hdd_ctx->hHal, smps_enable, smps_mode, false);
6386 if (QDF_STATUS_SUCCESS != status) {
6387 hdd_err("Update SMPS config failed enable: %d mode: %d"
6388 "status: %d",
6389 smps_enable, smps_mode, status);
6390 return QDF_STATUS_E_FAILURE;
6391 }
6392
6393 hdd_ctx->current_antenna_mode = mode;
6394 /*
6395 * Update the user requested nss in the mac context.
6396 * This will be used in tdls protocol engine to form tdls
6397 * Management frames.
6398 */
6399 sme_update_user_configured_nss(
6400 hdd_ctx->hHal,
6401 hdd_ctx->current_antenna_mode);
6402
6403 hdd_debug("Successfully switched to mode: %d x %d",
6404 hdd_ctx->current_antenna_mode,
6405 hdd_ctx->current_antenna_mode);
6406
6407 return QDF_STATUS_SUCCESS;
6408}
6409
Archana Ramachandran393f3792015-11-13 17:13:21 -08006410/**
6411 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6412 * handler
6413 * @adapter: Pointer to network adapter
6414 * @hdd_ctx: Pointer to hdd context
6415 * @command: Pointer to input command
6416 * @command_len: Command length
6417 * @priv_data: Pointer to private data in command
6418 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006419static int drv_cmd_set_antenna_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006420 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006421 uint8_t *command,
6422 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006423 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006424{
6425 struct sir_antenna_mode_param params;
6426 QDF_STATUS status;
6427 int ret = 0;
6428 int mode;
6429 uint8_t *value = command;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006430
6431 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6432 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6433 hdd_err("Operation invalid in non sta or concurrent mode");
6434 ret = -EPERM;
6435 goto exit;
6436 }
6437
6438 mode = hdd_parse_setantennamode_command(value);
6439 if (mode < 0) {
6440 hdd_err("Invalid SETANTENNA command");
6441 ret = mode;
6442 goto exit;
6443 }
6444
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006445 hdd_debug("Processing antenna mode switch to: %d", mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006446
6447 if (hdd_ctx->current_antenna_mode == mode) {
6448 hdd_err("System already in the requested mode");
6449 ret = 0;
6450 goto exit;
6451 }
6452
6453 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6454 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6455 hdd_err("System does not support 2x2 mode");
6456 ret = -EPERM;
6457 goto exit;
6458 }
6459
6460 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6461 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6462 hdd_err("System only supports 1x1 mode");
6463 ret = 0;
6464 goto exit;
6465 }
6466
6467 switch (mode) {
6468 case HDD_ANTENNA_MODE_1X1:
6469 params.num_rx_chains = 1;
6470 params.num_tx_chains = 1;
6471 break;
6472 case HDD_ANTENNA_MODE_2X2:
6473 params.num_rx_chains = 2;
6474 params.num_tx_chains = 2;
6475 break;
6476 default:
6477 hdd_err("unsupported antenna mode");
6478 ret = -EINVAL;
6479 goto exit;
6480 }
6481
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006482 /* Check TDLS status and update antenna mode */
6483 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006484 policy_mgr_is_sta_active_connection_exists(
6485 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006486 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6487 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006488 if (0 != ret)
6489 goto exit;
6490 }
6491
Archana Ramachandran393f3792015-11-13 17:13:21 -08006492 params.set_antenna_mode_resp =
6493 (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006494 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006495 params.num_rx_chains,
6496 params.num_tx_chains);
6497
6498
6499 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6500 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6501 if (QDF_STATUS_SUCCESS != status) {
6502 hdd_err("set antenna mode failed status : %d", status);
6503 ret = -EFAULT;
6504 goto exit;
6505 }
6506
6507 ret = wait_for_completion_timeout(
6508 &hdd_ctx->set_antenna_mode_cmpl,
6509 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6510 if (!ret) {
6511 ret = -EFAULT;
6512 hdd_err("send set antenna mode timed out");
6513 goto exit;
6514 }
6515
Nitesh Shahe50711f2017-04-26 16:30:45 +05306516 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006517 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006518 ret = -EFAULT;
6519 goto exit;
6520 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006521 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006522exit:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006523 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006524 ret, hdd_ctx->current_antenna_mode);
6525 return ret;
6526
6527}
6528
6529/**
6530 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6531 * handler
6532 * @adapter: Pointer to hdd adapter
6533 * @hdd_ctx: Pointer to hdd context
6534 * @command: Pointer to input command
6535 * @command_len: length of the command
6536 * @priv_data: private data coming with the driver command
6537 *
6538 * Return: 0 for success non-zero for failure
6539 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006540static inline int drv_cmd_get_antenna_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006541 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006542 uint8_t *command,
6543 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006544 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006545{
6546 uint32_t antenna_mode = 0;
6547 char extra[32];
6548 uint8_t len = 0;
6549
6550 antenna_mode = hdd_ctx->current_antenna_mode;
6551 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6552 antenna_mode);
6553 len = QDF_MIN(priv_data->total_len, len + 1);
6554 if (copy_to_user(priv_data->buf, &extra, len)) {
6555 hdd_err("Failed to copy data to user buffer");
6556 return -EFAULT;
6557 }
6558
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006559 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006560
6561 return 0;
6562}
6563
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006564/*
6565 * dummy (no-op) hdd driver command handler
6566 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006567static int drv_cmd_dummy(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006568 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006569 uint8_t *command,
6570 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006571 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006572{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006573 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006574 adapter->dev->name, command);
6575 return 0;
6576}
6577
6578/*
6579 * handler for any unsupported wlan hdd driver command
6580 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006581static int drv_cmd_invalid(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006582 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006583 uint8_t *command,
6584 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006585 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006586{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306587 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006588 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6589 adapter->sessionId, 0));
6590
6591 hdd_warn("%s: Unsupported driver command \"%s\"",
6592 adapter->dev->name, command);
6593
6594 return -ENOTSUPP;
6595}
6596
6597/**
6598 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6599 * @adapter: HDD adapter
6600 * @hdd_ctx: HDD context
6601 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6602 * @command_len: command len
6603 * @priv_data: private data
6604 *
6605 * Return: status
6606 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006607static int drv_cmd_set_fcc_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006608 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006609 uint8_t *command,
6610 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006611 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006612{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306613 QDF_STATUS status;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006614 uint8_t fcc_constraint;
6615 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006616
6617 /*
6618 * this command would be called by user-space when it detects WLAN
6619 * ON after airplane mode is set. When APM is set, WLAN turns off.
6620 * But it can be turned back on. Otherwise; when APM is turned back
6621 * off, WLAN would turn back on. So at that point the command is
6622 * expected to come down. 0 means disable, 1 means enable. The
6623 * constraint is removed when parameter 1 is set or different
6624 * country code is set
6625 */
6626
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006627 err = kstrtou8(command + command_len + 1, 10, &fcc_constraint);
6628 if (err) {
6629 hdd_err("error %d parsing userspace fcc parameter", err);
6630 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006631 }
6632
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006633 status = ucfg_reg_set_fcc_constraint(hdd_ctx->hdd_pdev,
6634 fcc_constraint);
6635
6636 if (QDF_IS_STATUS_ERROR(status))
6637 hdd_err("Failed to %s tx power for channels 12/13",
6638 fcc_constraint ? "reduce" : "restore");
6639
6640 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006641}
6642
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306643/**
6644 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6645 * command
6646 * @value: Pointer to the command
6647 * @chan_number: Pointer to the channel number
6648 * @chan_bw: Pointer to the channel bandwidth
6649 *
6650 * Parses and provides the channel number and channel width from the input
6651 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6652 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6653 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6654 *
6655 * Return: 0 for success, non-zero for failure
6656 */
6657static int hdd_parse_set_channel_switch_command(uint8_t *value,
6658 uint32_t *chan_number,
6659 uint32_t *chan_bw)
6660{
6661 const uint8_t *in_ptr = value;
6662 int ret;
6663
6664 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6665
6666 /* no argument after the command */
6667 if (NULL == in_ptr) {
6668 hdd_err("No argument after the command");
6669 return -EINVAL;
6670 }
6671
6672 /* no space after the command */
6673 if (SPACE_ASCII_VALUE != *in_ptr) {
6674 hdd_err("No space after the command ");
6675 return -EINVAL;
6676 }
6677
6678 /* remove empty spaces and move the next argument */
6679 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6680 in_ptr++;
6681
6682 /* no argument followed by spaces */
6683 if ('\0' == *in_ptr) {
6684 hdd_err("No argument followed by spaces");
6685 return -EINVAL;
6686 }
6687
6688 /* get the two arguments: channel number and bandwidth */
6689 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6690 if (ret != 2) {
6691 hdd_err("Arguments retrieval from cmd string failed");
6692 return -EINVAL;
6693 }
6694
6695 return 0;
6696}
6697
6698/**
6699 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6700 * @adapter: HDD adapter
6701 * @hdd_ctx: HDD context
6702 * @command: Pointer to the input command CHANNEL_SWITCH
6703 * @command_len: Command len
6704 * @priv_data: Private data
6705 *
6706 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6707 * of SAP/P2P-GO
6708 *
6709 * Return: 0 for success, non-zero for failure
6710 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006711static int drv_cmd_set_channel_switch(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006712 struct hdd_context *hdd_ctx,
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306713 uint8_t *command,
6714 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006715 struct hdd_priv_data *priv_data)
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306716{
6717 struct net_device *dev = adapter->dev;
6718 int status;
6719 uint32_t chan_number = 0, chan_bw = 0;
6720 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006721 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306722
Krunal Sonibe766b02016-03-10 13:00:44 -08006723 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6724 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306725 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6726 adapter->device_mode);
6727 return -EINVAL;
6728 }
6729
6730 status = hdd_parse_set_channel_switch_command(value,
6731 &chan_number, &chan_bw);
6732 if (status) {
6733 hdd_err("Invalid CHANNEL_SWITCH command");
6734 return status;
6735 }
6736
6737 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6738 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6739 return -EINVAL;
6740 }
6741
6742 if (chan_bw == 80)
6743 width = CH_WIDTH_80MHZ;
6744 else if (chan_bw == 40)
6745 width = CH_WIDTH_40MHZ;
6746 else
6747 width = CH_WIDTH_20MHZ;
6748
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006749 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306750
6751 status = hdd_softap_set_channel_change(dev, chan_number, width);
6752 if (status) {
6753 hdd_err("Set channel change fail");
6754 return status;
6755 }
6756
6757 return 0;
6758}
6759
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006760/*
6761 * The following table contains all supported WLAN HDD
6762 * IOCTL driver commands and the handler for each of them.
6763 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07006764static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306765 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false},
6766 {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true},
6767 {"P2P_SET_PS", drv_cmd_p2p_set_ps, true},
6768 {"SETBAND", drv_cmd_set_band, true},
6769 {"SETWMMPS", drv_cmd_set_wmmps, true},
6770 {"COUNTRY", drv_cmd_country, true},
6771 {"SETSUSPENDMODE", drv_cmd_dummy, false},
6772 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false},
6773 {"BTCOEXSCAN", drv_cmd_dummy, false},
6774 {"RXFILTER", drv_cmd_dummy, false},
6775 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true},
6776 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false},
6777 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true},
6778 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false},
6779 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period,
6780 true},
6781 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period,
6782 false},
6783 {"SETROAMMODE", drv_cmd_set_roam_mode, true},
6784 {"GETROAMMODE", drv_cmd_get_roam_mode, false},
6785 {"SETROAMDELTA", drv_cmd_set_roam_delta, true},
6786 {"GETROAMDELTA", drv_cmd_get_roam_delta, false},
6787 {"GETBAND", drv_cmd_get_band, false},
6788 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels, true},
6789 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels, false},
6790 {"GETCCXMODE", drv_cmd_get_ccx_mode, false},
6791 {"GETOKCMODE", drv_cmd_get_okc_mode, false},
6792 {"GETFASTROAM", drv_cmd_get_fast_roam, false},
6793 {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false},
6794 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
6795 true},
6796 {"SENDACTIONFRAME", drv_cmd_send_action_frame, true},
6797 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
6798 false},
6799 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true},
6800 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false},
6801 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true},
6802 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false},
6803 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true},
6804 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false},
6805 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true},
6806 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false},
6807 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true},
6808 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false},
6809 {"REASSOC", drv_cmd_reassoc, true},
6810 {"SETWESMODE", drv_cmd_set_wes_mode, true},
6811 {"GETWESMODE", drv_cmd_get_wes_mode, false},
6812 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff,
6813 true},
6814 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff,
6815 false},
6816 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true},
6817 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false},
6818 {"SETFASTROAM", drv_cmd_set_fast_roam, true},
6819 {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true},
6820 {"FASTREASSOC", drv_cmd_fast_reassoc, true},
6821 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control, true},
6822 {"SETOKCMODE", drv_cmd_set_okc_mode, true},
6823 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control, false},
6824 {"BTCOEXMODE", drv_cmd_bt_coex_mode, true},
6825 {"SCAN-ACTIVE", drv_cmd_scan_active, false},
6826 {"SCAN-PASSIVE", drv_cmd_scan_passive, false},
6827 {"GETDWELLTIME", drv_cmd_get_dwell_time, false},
6828 {"SETDWELLTIME", drv_cmd_set_dwell_time, true},
6829 {"MIRACAST", drv_cmd_miracast, true},
6830 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data, true},
6831 {"SETRMCENABLE", drv_cmd_set_rmc_enable, true},
6832 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period, true},
6833 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all, false},
6834 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info, true},
6835 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate, true},
6836 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006837#ifdef FEATURE_WLAN_ESE
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306838 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true},
6839 {"GETTSMSTATS", drv_cmd_get_tsm_stats, true},
6840 {"SETCCKMIE", drv_cmd_set_cckm_ie, true},
6841 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true},
6842 {"CCXPLMREQ", drv_cmd_ccx_plm_req, true},
6843 {"SETCCXMODE", drv_cmd_set_ccx_mode, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006844#endif /* FEATURE_WLAN_ESE */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306845 {"SETMCRATE", drv_cmd_set_mc_rate, true},
6846 {"MAXTXPOWER", drv_cmd_max_tx_power, true},
6847 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true},
6848 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false},
6849 {"GETLINKSTATUS", drv_cmd_get_link_status, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006850#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306851 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true},
6852 {"SETAPP1PARAMS", drv_cmd_set_app1_params, true},
6853 {"SETAPP2PARAMS", drv_cmd_set_app2_params, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006854#endif
6855#ifdef FEATURE_WLAN_TDLS
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306856 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
6857 true},
6858 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true},
6859 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true},
6860 {"TDLSSCAN", drv_cmd_tdls_scan, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006861#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306862 {"RSSI", drv_cmd_get_rssi, false},
6863 {"LINKSPEED", drv_cmd_get_linkspeed, false},
6864 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true},
6865 {"RXFILTER-ADD", drv_cmd_rx_filter_add, true},
6866 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true},
6867 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true},
6868 {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true},
6869 {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false},
6870 {"STOP", drv_cmd_dummy, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006871};
6872
6873/**
6874 * hdd_drv_cmd_process() - chooses and runs the proper
6875 * handler based on the input command
6876 * @adapter: Pointer to the hdd adapter
6877 * @cmd: Pointer to the driver command
6878 * @priv_data: Pointer to the data associated with the command
6879 *
6880 * This function parses the input hdd driver command and runs
6881 * the proper handler
6882 *
6883 * Return: 0 for success non-zero for failure
6884 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006885static int hdd_drv_cmd_process(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006886 uint8_t *cmd,
Jeff Johnson353cd292017-08-17 06:47:26 -07006887 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006888{
Jeff Johnson621cf972017-08-28 11:58:44 -07006889 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006890 int i;
6891 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6892 uint8_t *cmd_i = NULL;
6893 hdd_drv_cmd_handler_t handler = NULL;
6894 int len = 0;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306895 bool args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006896
6897 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006898 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006899 return -EINVAL;
6900 }
6901
Jeff Johnson399c6272017-08-30 10:51:00 -07006902 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006903
6904 for (i = 0; i < cmd_num_total; i++) {
6905
6906 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6907 handler = hdd_drv_cmds[i].handler;
6908 len = strlen(cmd_i);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306909 args = hdd_drv_cmds[i].args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006910
6911 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006912 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006913 return -EINVAL;
6914 }
6915
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306916 if (strncasecmp(cmd, cmd_i, len) == 0) {
6917 if (args && drv_cmd_validate(cmd, len))
6918 return -EINVAL;
6919
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006920 return handler(adapter, hdd_ctx,
6921 cmd, len, priv_data);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05306922 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006923 }
6924
6925 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6926}
6927
6928/**
6929 * hdd_driver_command() - top level wlan hdd driver command handler
6930 * @adapter: Pointer to the hdd adapter
6931 * @priv_data: Pointer to the raw command data
6932 *
6933 * This function is the top level wlan hdd driver command handler. It
6934 * handles the command with the help of hdd_drv_cmd_process()
6935 *
6936 * Return: 0 for success non-zero for failure
6937 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006938static int hdd_driver_command(struct hdd_adapter *adapter,
Jeff Johnson353cd292017-08-17 06:47:26 -07006939 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006940{
6941 uint8_t *command = NULL;
6942 int ret = 0;
Jeff Johnson621cf972017-08-28 11:58:44 -07006943 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006944
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306945 ENTER();
6946
Anurag Chouhan6d760662016-02-20 16:05:43 +05306947 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006948 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006949 return -EINVAL;
6950 }
6951
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306952 ret = wlan_hdd_validate_context(hdd_ctx);
6953 if (ret)
6954 return ret;
6955
6956 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
6957 hdd_err("Driver module is closed; command can not be processed");
6958 return -EINVAL;
6959 }
6960
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006961 /*
6962 * Note that valid pointers are provided by caller
6963 */
6964
6965 /* copy to local struct to avoid numerous changes to legacy code */
6966 if (priv_data->total_len <= 0 ||
6967 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006968 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006969 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006970 ret = -EINVAL;
6971 goto exit;
6972 }
6973
6974 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006975 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006976 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006977 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006978 ret = -ENOMEM;
6979 goto exit;
6980 }
6981
6982 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6983 ret = -EFAULT;
6984 goto exit;
6985 }
6986
6987 /* Make sure the command is NUL-terminated */
6988 command[priv_data->total_len] = '\0';
6989
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006990 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006991 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6992
6993exit:
6994 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006995 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306996 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006997 return ret;
6998}
6999
7000#ifdef CONFIG_COMPAT
Jeff Johnsone44b7012017-09-10 15:25:47 -07007001static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007002{
7003 struct {
7004 compat_uptr_t buf;
7005 int used_len;
7006 int total_len;
7007 } compat_priv_data;
Jeff Johnson353cd292017-08-17 06:47:26 -07007008 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007009 int ret = 0;
7010
7011 /*
7012 * Note that adapter and ifr have already been verified by caller,
7013 * and HDD context has also been validated
7014 */
7015 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7016 sizeof(compat_priv_data))) {
7017 ret = -EFAULT;
7018 goto exit;
7019 }
7020 priv_data.buf = compat_ptr(compat_priv_data.buf);
7021 priv_data.used_len = compat_priv_data.used_len;
7022 priv_data.total_len = compat_priv_data.total_len;
7023 ret = hdd_driver_command(adapter, &priv_data);
7024exit:
7025 return ret;
7026}
7027#else /* CONFIG_COMPAT */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007028static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007029{
7030 /* will never be invoked */
7031 return 0;
7032}
7033#endif /* CONFIG_COMPAT */
7034
Jeff Johnsone44b7012017-09-10 15:25:47 -07007035static int hdd_driver_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007036{
Jeff Johnson353cd292017-08-17 06:47:26 -07007037 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007038 int ret = 0;
7039
7040 /*
7041 * Note that adapter and ifr have already been verified by caller,
7042 * and HDD context has also been validated
7043 */
7044 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7045 ret = -EFAULT;
7046 else
7047 ret = hdd_driver_command(adapter, &priv_data);
7048
7049 return ret;
7050}
7051
7052/**
7053 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7054 * @dev: device upon which the ioctl was received
7055 * @ifr: ioctl request information
7056 * @cmd: ioctl command
7057 *
7058 * This function does initial processing of wlan device ioctls.
7059 * Currently two flavors of ioctls are supported. The primary ioctl
7060 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7061 * for Android "DRIVER" commands. The other ioctl that is
7062 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7063 * for FTM on some platforms. This function simply verifies that the
7064 * driver is in a sane state, and that the ioctl is one of the
7065 * supported flavors, in which case flavor-specific handlers are
7066 * dispatched.
7067 *
7068 * Return: 0 on success, non-zero on error
7069 */
7070static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7071{
Jeff Johnsone44b7012017-09-10 15:25:47 -07007072 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson621cf972017-08-28 11:58:44 -07007073 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007074 int ret;
7075
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007076 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307077
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007078 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007079 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007080 ret = -ENODEV;
7081 goto exit;
7082 }
7083
7084 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007085 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007086 ret = -EINVAL;
7087 goto exit;
7088 }
7089#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307090 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007091 if (SIOCIOCTLTX99 == cmd) {
7092 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7093 goto exit;
7094 }
7095 }
7096#endif
7097
7098 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7099 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307100 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007101 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007102
7103 switch (cmd) {
7104 case (SIOCDEVPRIVATE + 1):
7105 if (is_compat_task())
7106 ret = hdd_driver_compat_ioctl(adapter, ifr);
7107 else
7108 ret = hdd_driver_ioctl(adapter, ifr);
7109 break;
7110 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007111 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007112 ret = -EINVAL;
7113 break;
7114 }
7115exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307116 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007117 return ret;
7118}
7119
7120/**
7121 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7122 * @dev: device upon which the ioctl was received
7123 * @ifr: ioctl request information
7124 * @cmd: ioctl command
7125 *
7126 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7127 * which is where the ioctls are really handled.
7128 *
7129 * Return: 0 on success, non-zero on error
7130 */
7131int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7132{
7133 int ret;
7134
7135 cds_ssr_protect(__func__);
7136 ret = __hdd_ioctl(dev, ifr, cmd);
7137 cds_ssr_unprotect(__func__);
7138 return ret;
7139}