blob: 778d9b31e5602623c7e2052284554b04a2ac4132 [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"
Jeff Johnson253c0c22017-01-23 16:59:38 -080035#include "wlan_hdd_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080036#include "wlan_hdd_driver_ops.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080037#include "wlan_policy_mgr_api.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053038#include "wlan_hdd_hostapd.h"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080039#include "scheduler_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080040
41#include "wlan_hdd_p2p.h"
42#include <linux/ctype.h>
43#include "wma.h"
44#include "wlan_hdd_napi.h"
45
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080046#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080047#include <sme_api.h>
48#include <sir_api.h>
49#endif
50#include "hif.h"
51
52#if defined(LINUX_QCMBR)
53#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
54#endif
55
56/*
57 * Size of Driver command strings from upper layer
58 */
59#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
60#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
61
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080062/*
63 * Ibss prop IE from command will be of size:
64 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
65 * OUI_DATA should be at least 3 bytes long
66 */
67#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080068
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080069#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080070#define TID_MIN_VALUE 0
71#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080072#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080073
74/*
75 * Maximum buffer size used for returning the data back to user space
76 */
77#define WLAN_MAX_BUF_SIZE 1024
78#define WLAN_PRIV_DATA_MAX_LEN 8192
79
80/*
81 * Driver miracast parameters 0-Disabled
82 * 1-Source, 2-Sink
83 */
84#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
85#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
86
87/*
88 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
89 * we will split the printing.
90 */
91#define NUM_OF_STA_DATA_TO_PRINT 16
92
93/*
94 * Android DRIVER command structures
95 */
96struct android_wifi_reassoc_params {
97 unsigned char bssid[18];
98 int channel;
99};
100
101#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
102struct android_wifi_af_params {
103 unsigned char bssid[18];
104 int channel;
105 int dwell_time;
106 int len;
107 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
108};
109
110/*
111 * Define HDD driver command handling entry, each contains a command
112 * string and the handler.
113 */
114typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
115 hdd_context_t *hdd_ctx,
116 uint8_t *cmd,
117 uint8_t cmd_name_len,
118 hdd_priv_data_t *priv_data);
119
120typedef struct {
121 const char *cmd;
122 hdd_drv_cmd_handler_t handler;
123} hdd_drv_cmd_t;
124
125#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
126#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
127#define WLAN_HDD_MAX_TCP_PORT 65535
128#endif
129
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800130static uint16_t cesium_pid;
131extern struct sock *cesium_nl_srv_sock;
132
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800133#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800134struct tsm_priv {
135 tAniTrafStrmMetrics tsm_metrics;
136};
137
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800138static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
139 const uint32_t staId, void *context)
140{
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800141 struct hdd_request *request;
142 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800144 request = hdd_request_get(context);
145 if (!request) {
146 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800147 return;
148 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800149 priv = hdd_request_priv(request);
150 priv->tsm_metrics = tsm_metrics;
151 hdd_request_complete(request);
152 hdd_request_put(request);
153 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800154
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800155}
156
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800157static int hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800158 const uint8_t tid,
159 tAniTrafStrmMetrics *tsm_metrics)
160{
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800161 hdd_context_t *hdd_ctx;
162 hdd_station_ctx_t *hdd_sta_ctx;
163 QDF_STATUS status;
164 int ret;
165 void *cookie;
166 struct hdd_request *request;
167 struct tsm_priv *priv;
168 static const struct hdd_request_params params = {
169 .priv_size = sizeof(*priv),
170 .timeout_ms = WLAN_WAIT_TIME_STATS,
171 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800172
173 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700174 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800175 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176 }
177
178 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
179 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
180
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800181 request = hdd_request_alloc(&params);
182 if (!request) {
183 hdd_err("Request allocation failure");
184 return -ENOMEM;
185 }
186 cookie = hdd_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800187
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800188 status = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
189 hdd_sta_ctx->conn_info.staId[0],
190 hdd_sta_ctx->conn_info.bssId,
191 cookie, hdd_ctx->pcds_context, tid);
192 if (QDF_STATUS_SUCCESS != status) {
193 hdd_err("Unable to retrieve tsm statistics");
194 ret = qdf_status_to_os_return(status);
195 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800196 }
197
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800198 ret = hdd_request_wait_for_response(request);
199 if (ret) {
200 hdd_err("SME timed out while retrieving tsm statistics");
201 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800203
204 priv = hdd_request_priv(request);
205 *tsm_metrics = priv->tsm_metrics;
206
207 cleanup:
208 hdd_request_put(request);
209
210 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800212#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800213
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800214/* Function header is left blank intentionally */
215static int hdd_parse_setrmcenable_command(uint8_t *pValue,
216 uint8_t *pRmcEnable)
217{
218 uint8_t *inPtr = pValue;
219 int tempInt;
220 int v = 0;
221 char buf[32];
222 *pRmcEnable = 0;
223
224 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
225
226 if (NULL == inPtr) {
227 return 0;
228 }
229
230 else if (SPACE_ASCII_VALUE != *inPtr) {
231 return 0;
232 }
233
234 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
235 inPtr++;
236
237 if ('\0' == *inPtr) {
238 return 0;
239 }
240
241 sscanf(inPtr, "%32s ", buf);
242 v = kstrtos32(buf, 10, &tempInt);
243 if (v < 0) {
244 return -EINVAL;
245 }
246
247 *pRmcEnable = tempInt;
248
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700249 hdd_info("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800250
251 return 0;
252}
253
254/* Function header is left blank intentionally */
255static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
256 uint32_t *pActionPeriod)
257{
258 uint8_t *inPtr = pValue;
259 int tempInt;
260 int v = 0;
261 char buf[32];
262 *pActionPeriod = 0;
263
264 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
265
266 if (NULL == inPtr) {
267 return -EINVAL;
268 }
269
270 else if (SPACE_ASCII_VALUE != *inPtr) {
271 return -EINVAL;
272 }
273
274 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
275 inPtr++;
276
277 if ('\0' == *inPtr) {
278 return 0;
279 }
280
281 sscanf(inPtr, "%32s ", buf);
282 v = kstrtos32(buf, 10, &tempInt);
283 if (v < 0) {
284 return -EINVAL;
285 }
286
287 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
288 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) {
289 return -EINVAL;
290 }
291
292 *pActionPeriod = tempInt;
293
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700294 hdd_info("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800295
296 return 0;
297}
298
299/* Function header is left blank intentionally */
300static int hdd_parse_setrmcrate_command(uint8_t *pValue,
301 uint32_t *pRate,
302 tTxrateinfoflags *pTxFlags)
303{
304 uint8_t *inPtr = pValue;
305 int tempInt;
306 int v = 0;
307 char buf[32];
308 *pRate = 0;
309 *pTxFlags = 0;
310
311 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
312
313 if (NULL == inPtr) {
314 return -EINVAL;
315 }
316
317 else if (SPACE_ASCII_VALUE != *inPtr) {
318 return -EINVAL;
319 }
320
321 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
322 inPtr++;
323
324 if ('\0' == *inPtr) {
325 return 0;
326 }
327
328 sscanf(inPtr, "%32s ", buf);
329 v = kstrtos32(buf, 10, &tempInt);
330 if (v < 0) {
331 return -EINVAL;
332 }
333
334 switch (tempInt) {
335 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700336 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800337 return -EINVAL;
338 case 0:
339 case 6:
340 case 9:
341 case 12:
342 case 18:
343 case 24:
344 case 36:
345 case 48:
346 case 54:
347 *pTxFlags = eHAL_TX_RATE_LEGACY;
348 *pRate = tempInt * 10;
349 break;
350 case 65:
351 *pTxFlags = eHAL_TX_RATE_HT20;
352 *pRate = tempInt * 10;
353 break;
354 case 72:
355 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
356 *pRate = 722;
357 break;
358 }
359
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700360 hdd_info("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800361
362 return 0;
363}
364
365/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700366 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
367 * @UserData: Adapter private data
368 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800369 *
370 * This is an asynchronous callback function from SME when the peer info
371 * is received
372 *
373 * Return: 0 for success non-zero for failure
374 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700375void
376hdd_get_ibss_peer_info_cb(void *pUserData,
377 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800378{
379 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800380 hdd_station_ctx_t *pStaCtx;
381 uint8_t i;
382
383 /* Sanity check */
384 if ((NULL == adapter) ||
385 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700386 hdd_alert("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800387 return;
388 }
389
390 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
391 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700392 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530393 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
394 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700395 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530396 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800397 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530398 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
399 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
400
401 for (i = 0; i < pPeerInfo->numPeers; i++)
402 pStaCtx->ibss_peer_info.peerInfoParams[i] =
403 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800404 } else {
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530405 hdd_err("peerInfo %s: status %u, numPeers %u",
406 pPeerInfo ? "valid" : "null",
407 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
408 pPeerInfo ? pPeerInfo->numPeers : 0);
409 pStaCtx->ibss_peer_info.numPeers = 0;
410 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800411 }
412
413 complete(&adapter->ibss_peer_info_comp);
414}
415
416/**
417 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
418 * @adapter: Adapter context
419 *
420 * Request function to get IBSS peer info from lower layers
421 *
422 * Return: 0 for success non-zero for failure
423 */
424static
425QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
426{
427 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
428 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
429 unsigned long rc;
430
431 INIT_COMPLETION(adapter->ibss_peer_info_comp);
432
433 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700434 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800435 true, 0xFF);
436
437 if (QDF_STATUS_SUCCESS == retStatus) {
438 rc = wait_for_completion_timeout
439 (&adapter->ibss_peer_info_comp,
440 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
441
442 /* status will be 0 if timed out */
443 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700444 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800445 retStatus = QDF_STATUS_E_FAILURE;
446 return retStatus;
447 }
448 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700449 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800450 }
451
452 return retStatus;
453}
454
455/**
456 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
457 * @adapter: Adapter context
458 * @staIdx: Sta index for which the peer info is requested
459 *
460 * Request function to get IBSS peer info from lower layers
461 *
462 * Return: 0 for success non-zero for failure
463 */
464static QDF_STATUS
465hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
466{
467 unsigned long rc;
468 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
469 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
470
471 INIT_COMPLETION(adapter->ibss_peer_info_comp);
472
473 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700474 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800475 false, staIdx);
476
477 if (QDF_STATUS_SUCCESS == retStatus) {
478 rc = wait_for_completion_timeout(
479 &adapter->ibss_peer_info_comp,
480 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
481
482 /* status = 0 on timeout */
483 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700484 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800485 retStatus = QDF_STATUS_E_FAILURE;
486 return retStatus;
487 }
488 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700489 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800490 }
491
492 return retStatus;
493}
494
495/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700496static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800497hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
498{
499 uint8_t *inPtr = pValue;
500 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
501
502 if (NULL == inPtr) {
503 return QDF_STATUS_E_FAILURE;;
504 }
505
506 else if (SPACE_ASCII_VALUE != *inPtr) {
507 return QDF_STATUS_E_FAILURE;;
508 }
509
510 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
511 inPtr++;
512
513 if ('\0' == *inPtr) {
514 return QDF_STATUS_E_FAILURE;;
515 }
516
517 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
518 inPtr[11] != ':' || inPtr[14] != ':') {
519 return QDF_STATUS_E_FAILURE;;
520 }
521 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
522 (unsigned int *)&pPeerMacAddr->bytes[0],
523 (unsigned int *)&pPeerMacAddr->bytes[1],
524 (unsigned int *)&pPeerMacAddr->bytes[2],
525 (unsigned int *)&pPeerMacAddr->bytes[3],
526 (unsigned int *)&pPeerMacAddr->bytes[4],
527 (unsigned int *)&pPeerMacAddr->bytes[5]);
528
529 return QDF_STATUS_SUCCESS;
530}
531
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800532static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
533{
534 eCsrBand band = -1;
535 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
536 switch (band) {
537 case eCSR_BAND_ALL:
538 *pBand = WLAN_HDD_UI_BAND_AUTO;
539 break;
540
541 case eCSR_BAND_24:
542 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
543 break;
544
545 case eCSR_BAND_5G:
546 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
547 break;
548
549 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700550 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800551 *pBand = -1;
552 break;
553 }
554}
555
556/**
557 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
558 * @data: input data
559 * @target_ap_bssid: pointer to bssid (output parameter)
560 * @channel: pointer to channel (output parameter)
561 *
562 * Return: 0 if parsing is successful; -EINVAL otherwise
563 */
564static int _hdd_parse_bssid_and_chan(const uint8_t **data,
565 uint8_t *bssid,
566 uint8_t *channel)
567{
568 const uint8_t *in_ptr;
569 int v = 0;
570 int temp_int;
571 uint8_t temp_buf[32];
572
573 /* 12 hexa decimal digits, 5 ':' and '\0' */
574 uint8_t mac_addr[18];
575
576 if (!data || !*data)
577 return -EINVAL;
578
579 in_ptr = *data;
580
581 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
582 /* no argument after the command */
583 if (NULL == in_ptr)
584 goto error;
585 /* no space after the command */
586 else if (SPACE_ASCII_VALUE != *in_ptr)
587 goto error;
588
589 /* remove empty spaces */
590 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
591 in_ptr++;
592
593 /* no argument followed by spaces */
594 if ('\0' == *in_ptr)
595 goto error;
596
597 v = sscanf(in_ptr, "%17s", mac_addr);
598 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700599 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
600 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800601 goto error;
602 }
603
604 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
605 hex_to_bin(mac_addr[1]);
606 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
607 hex_to_bin(mac_addr[4]);
608 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
609 hex_to_bin(mac_addr[7]);
610 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
611 hex_to_bin(mac_addr[10]);
612 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
613 hex_to_bin(mac_addr[13]);
614 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
615 hex_to_bin(mac_addr[16]);
616
617 /* point to the next argument */
618 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
619 /* no argument after the command */
620 if (NULL == in_ptr)
621 goto error;
622
623 /* remove empty spaces */
624 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
625 in_ptr++;
626
627 /* no argument followed by spaces */
628 if ('\0' == *in_ptr)
629 goto error;
630
631 /* get the next argument ie the channel number */
632 v = sscanf(in_ptr, "%31s ", temp_buf);
633 if (1 != v)
634 goto error;
635
636 v = kstrtos32(temp_buf, 10, &temp_int);
637 if ((v < 0) || (temp_int < 0) ||
638 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
639 return -EINVAL;
640
641 *channel = temp_int;
642 *data = in_ptr;
643 return 0;
644error:
645 *data = in_ptr;
646 return -EINVAL;
647}
648
649/**
650 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
651 * @pValue: Pointer to input data
652 * @pTargetApBssid: Pointer to target Ap bssid
653 * @pChannel: Pointer to the Target AP channel
654 * @pDwellTime: Pointer to the time to stay off-channel
655 * after transmitting action frame
656 * @pBuf: Pointer to data
657 * @pBufLen: Pointer to data length
658 *
659 * This function parses the send action frame data passed in the format
660 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
661 *
662 * Return: 0 for success non-zero for failure
663 */
664static int
665hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
666 uint8_t *pTargetApBssid,
667 uint8_t *pChannel, uint8_t *pDwellTime,
668 uint8_t **pBuf, uint8_t *pBufLen)
669{
670 const uint8_t *inPtr = pValue;
671 const uint8_t *dataEnd;
672 int tempInt;
673 int j = 0;
674 int i = 0;
675 int v = 0;
676 uint8_t tempBuf[32];
677 uint8_t tempByte = 0;
678
679 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
680 return -EINVAL;
681
682 /* point to the next argument */
683 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
684 /* no argument after the command */
685 if (NULL == inPtr)
686 return -EINVAL;
687 /* removing empty spaces */
688 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
689 inPtr++;
690
691 /* no argument followed by spaces */
692 if ('\0' == *inPtr) {
693 return -EINVAL;
694 }
695
696 /* getting the next argument ie the dwell time */
697 v = sscanf(inPtr, "%31s ", tempBuf);
698 if (1 != v)
699 return -EINVAL;
700
701 v = kstrtos32(tempBuf, 10, &tempInt);
702 if (v < 0 || tempInt < 0)
703 return -EINVAL;
704
705 *pDwellTime = tempInt;
706
707 /* point to the next argument */
708 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
709 /* no argument after the command */
710 if (NULL == inPtr)
711 return -EINVAL;
712 /* removing empty spaces */
713 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
714 inPtr++;
715
716 /* no argument followed by spaces */
717 if ('\0' == *inPtr) {
718 return -EINVAL;
719 }
720
721 /* find the length of data */
722 dataEnd = inPtr;
723 while (('\0' != *dataEnd)) {
724 dataEnd++;
725 }
726 *pBufLen = dataEnd - inPtr;
727 if (*pBufLen <= 0)
728 return -EINVAL;
729
730 /*
731 * Allocate the number of bytes based on the number of input characters
732 * whether it is even or odd.
733 * if the number of input characters are even, then we need N/2 byte.
734 * if the number of input characters are odd, then we need do (N+1)/2
735 * to compensate rounding off.
736 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
737 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
738 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530739 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800740 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700741 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742 return -ENOMEM;
743 }
744
745 /* the buffer received from the upper layer is character buffer,
746 * we need to prepare the buffer taking 2 characters in to a U8 hex
747 * decimal number for example 7f0000f0...form a buffer to contain 7f
748 * in 0th location, 00 in 1st and f0 in 3rd location
749 */
750 for (i = 0, j = 0; j < *pBufLen; j += 2) {
751 if (j + 1 == *pBufLen) {
752 tempByte = hex_to_bin(inPtr[j]);
753 } else {
754 tempByte =
755 (hex_to_bin(inPtr[j]) << 4) |
756 (hex_to_bin(inPtr[j + 1]));
757 }
758 (*pBuf)[i++] = tempByte;
759 }
760 *pBufLen = i;
761 return 0;
762}
763
764/**
765 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
766 * @pValue: Pointer to input data (its a NULL terminated string)
767 * @pTargetApBssid: Pointer to target Ap bssid
768 * @pChannel: Pointer to the Target AP channel
769 *
770 * This function parses the reasoc command data passed in the format
771 * REASSOC<space><bssid><space><channel>
772 *
773 * Return: 0 for success non-zero for failure
774 */
775static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
776 uint8_t *pTargetApBssid,
777 uint8_t *pChannel)
778{
779 const uint8_t *inPtr = pValue;
780
781 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
782 return -EINVAL;
783
784 return 0;
785}
786
Naveen Rawat05376ee2016-07-18 16:43:32 -0700787#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800788void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter,
789 const tSirMacAddr bssid, int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700790{
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800791 QDF_STATUS status;
792 hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
793 tCsrRoamProfile *profile = &wext_state->roamProfile;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700794 struct wma_roam_invoke_cmd *fastreassoc;
Rajeev Kumarea95edd2017-01-11 20:49:36 -0800795 struct scheduler_msg msg = {0};
Naveen Rawat05376ee2016-07-18 16:43:32 -0700796
797 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
798 if (NULL == fastreassoc) {
799 hdd_err("qdf_mem_malloc failed for fastreassoc");
800 return;
801 }
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800802 fastreassoc->vdev_id = adapter->sessionId;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700803 fastreassoc->channel = channel;
804 fastreassoc->bssid[0] = bssid[0];
805 fastreassoc->bssid[1] = bssid[1];
806 fastreassoc->bssid[2] = bssid[2];
807 fastreassoc->bssid[3] = bssid[3];
808 fastreassoc->bssid[4] = bssid[4];
809 fastreassoc->bssid[5] = bssid[5];
810
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800811 status = sme_get_beacon_frm(WLAN_HDD_GET_HAL_CTX(adapter), profile,
812 bssid, &fastreassoc->frame_buf,
813 &fastreassoc->frame_len);
814
815 if (QDF_STATUS_SUCCESS != status) {
816 hdd_err("sme_get_beacon_frm failed");
817 fastreassoc->frame_buf = NULL;
818 fastreassoc->frame_len = 0;
819 }
820
Naveen Rawat05376ee2016-07-18 16:43:32 -0700821 msg.type = SIR_HAL_ROAM_INVOKE;
822 msg.reserved = 0;
823 msg.bodyptr = fastreassoc;
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800824 status = scheduler_post_msg(QDF_MODULE_ID_WMA, &msg);
825 if (QDF_STATUS_SUCCESS != status) {
Naveen Rawat05376ee2016-07-18 16:43:32 -0700826 hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA");
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800827 qdf_mem_free(fastreassoc);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700828 }
829}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700830#endif
831
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800832/**
833 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800834 * @adapter: Adapter upon which the command was received
835 * @bssid: BSSID with which to reassociate
836 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700837 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800838 *
839 * This function performs a userspace-directed reassoc operation
840 *
841 * Return: 0 for success non-zero for failure
842 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700843int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800844 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800845{
846 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700847 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800848 int ret = 0;
849
Naveen Rawat05376ee2016-07-18 16:43:32 -0700850 if (hdd_ctx == NULL) {
851 hdd_err("Invalid hdd ctx");
852 return -EINVAL;
853 }
854
Krunal Sonibe766b02016-03-10 13:00:44 -0800855 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800856 hdd_warn("Unsupported in mode %s(%d)",
857 hdd_device_mode_to_string(adapter->device_mode),
858 adapter->device_mode);
859 return -EINVAL;
860 }
861
862 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
863
864 /* if not associated, no need to proceed with reassoc */
865 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700866 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800867 ret = -EINVAL;
868 goto exit;
869 }
870
871 /*
872 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800873 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800874 */
875 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530876 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700877 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800878 channel = pHddStaCtx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800879 }
880
881 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530882 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800883 wlan_hdd_validate_operation_channel(adapter, channel)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700884 hdd_err("Invalid Channel %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800885 ret = -EINVAL;
886 goto exit;
887 }
888
889 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700890 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800891 hdd_wma_send_fastreassoc_cmd(adapter,
Naveen Rawat05376ee2016-07-18 16:43:32 -0700892 bssid, (int)channel);
893 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800894 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800895
896 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700897 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530898 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
900 &handoffInfo);
901 }
902exit:
903 return ret;
904}
905
906/**
907 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
908 * @adapter: Adapter upon which the command was received
909 * @command: ASCII text command that was received
910 *
911 * This function parses the v1 REASSOC command with the format
912 *
913 * REASSOC xx:xx:xx:xx:xx:xx CH
914 *
915 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
916 * BSSID and CH is the ASCII representation of the channel. For
917 * example
918 *
919 * REASSOC 00:0a:0b:11:22:33 48
920 *
921 * Return: 0 for success non-zero for failure
922 */
923static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
924{
925 uint8_t channel = 0;
926 tSirMacAddr bssid;
927 int ret;
928
929 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
930 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700931 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800932 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700933 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934 }
935 return ret;
936}
937
938/**
939 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
940 * @adapter: Adapter upon which the command was received
941 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700942 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800943 *
944 * This function parses the v2 REASSOC command with the format
945 *
946 * REASSOC <android_wifi_reassoc_params>
947 *
948 * Return: 0 for success non-zero for failure
949 */
950static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
951{
952 struct android_wifi_reassoc_params params;
953 tSirMacAddr bssid;
954 int ret;
955
956 /* The params are located after "REASSOC " */
957 memcpy(&params, command + 8, sizeof(params));
958
959 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700960 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800961 ret = -EINVAL;
962 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700963 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964 }
965 return ret;
966}
967
968/**
969 * hdd_parse_reassoc() - parse the REASSOC command
970 * @adapter: Adapter upon which the command was received
971 * @command: Command that was received
972 *
973 * There are two different versions of the REASSOC command. Version 1
974 * of the command contains a parameter list that is ASCII characters
975 * whereas version 2 contains a combination of ASCII and binary
976 * payload. Determine if a version 1 or a version 2 command is being
977 * parsed by examining the parameters, and then dispatch the parser
978 * that is appropriate for the command.
979 *
980 * Return: 0 for success non-zero for failure
981 */
982static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
983{
984 int ret;
985
986 /* both versions start with "REASSOC "
987 * v1 has a bssid and channel # as an ASCII string
988 * REASSOC xx:xx:xx:xx:xx:xx CH
989 * v2 has a C struct
990 * REASSOC <binary c struct>
991 *
992 * The first field in the v2 struct is also the bssid in ASCII.
993 * But in the case of a v2 message the BSSID is NUL-terminated.
994 * Hence we can peek at that offset to see if this is V1 or V2
995 * REASSOC xx:xx:xx:xx:xx:xx*
996 * 1111111111222222
997 * 01234567890123456789012345
998 */
999 if (command[25]) {
1000 ret = hdd_parse_reassoc_v1(adapter, command);
1001 } else {
1002 ret = hdd_parse_reassoc_v2(adapter, command);
1003 }
1004
1005 return ret;
1006}
1007
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001008/**
1009 * hdd_sendactionframe() - send a userspace-supplied action frame
1010 * @adapter: Adapter upon which the command was received
1011 * @bssid: BSSID target of the action frame
1012 * @channel: Channel upon which to send the frame
1013 * @dwell_time: Amount of time to dwell when the frame is sent
1014 * @payload_len:Length of the payload
1015 * @payload: Payload of the frame
1016 *
1017 * This function sends a userspace-supplied action frame
1018 *
1019 * Return: 0 for success non-zero for failure
1020 */
1021static int
1022hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1023 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001024 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001025{
1026 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001027 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 uint8_t *frame;
1029 struct ieee80211_hdr_3addr *hdr;
1030 u64 cookie;
1031 hdd_station_ctx_t *pHddStaCtx;
1032 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001033 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1034 (tpSirMacVendorSpecificFrameHdr) payload;
1035#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1036 struct cfg80211_mgmt_tx_params params;
1037#endif
1038
Krunal Sonibe766b02016-03-10 13:00:44 -08001039 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001040 hdd_warn("Unsupported in mode %s(%d)",
1041 hdd_device_mode_to_string(adapter->device_mode),
1042 adapter->device_mode);
1043 return -EINVAL;
1044 }
1045
1046 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1047 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1048
1049 /* if not associated, no need to send action frame */
1050 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001051 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052 ret = -EINVAL;
1053 goto exit;
1054 }
1055
1056 /*
1057 * if the target bssid is different from currently associated AP,
1058 * then no need to send action frame
1059 */
1060 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301061 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001062 hdd_info("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001063 ret = -EINVAL;
1064 goto exit;
1065 }
1066
1067 chan.center_freq = sme_chn_to_freq(channel);
1068 /* Check if it is specific action frame */
1069 if (pVendorSpecific->category ==
1070 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1071 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301072 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073 /*
1074 * if the channel number is different from operating
1075 * channel then no need to send action frame
1076 */
1077 if (channel != 0) {
1078 if (channel !=
1079 pHddStaCtx->conn_info.operationChannel) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001080 hdd_info("channel(%d) is different from operating channel(%d)",
1081 channel,
1082 pHddStaCtx->conn_info.
1083 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 ret = -EINVAL;
1085 goto exit;
1086 }
1087 /*
1088 * If channel number is specified and same
1089 * as home channel, ensure that action frame
1090 * is sent immediately by cancelling
1091 * roaming scans. Otherwise large dwell times
1092 * may cause long delays in sending action
1093 * frames.
1094 */
1095 sme_abort_roam_scan(hdd_ctx->hHal,
1096 adapter->sessionId);
1097 } else {
1098 /*
1099 * 0 is accepted as current home channel,
1100 * delayed transmission of action frame is ok.
1101 */
1102 chan.center_freq =
1103 sme_chn_to_freq(pHddStaCtx->conn_info.
1104 operationChannel);
1105 }
1106 }
1107 }
1108 if (chan.center_freq == 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001109 hdd_err("Invalid channel number %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001110 ret = -EINVAL;
1111 goto exit;
1112 }
1113
1114 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301115 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001116 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001117 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118 ret = -ENOMEM;
1119 goto exit;
1120 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001121
1122 hdr = (struct ieee80211_hdr_3addr *)frame;
1123 hdr->frame_control =
1124 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301125 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1126 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301127 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301128 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1129 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130
1131#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1132 params.chan = &chan;
1133 params.offchan = 0;
1134 params.wait = dwell_time;
1135 params.buf = frame;
1136 params.len = frame_len;
1137 params.no_cck = 1;
1138 params.dont_wait_for_ack = 1;
1139 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1140#else
1141 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001143 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001144
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145 dwell_time, frame, frame_len, 1, 1, &cookie);
1146#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1147
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301148 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001149exit:
1150 return ret;
1151}
1152
1153/**
1154 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1155 * SENDACTIONFRAME command
1156 * @adapter: Adapter upon which the command was received
1157 * @command: ASCII text command that was received
1158 *
1159 * This function parses the v1 SENDACTIONFRAME command with the format
1160 *
1161 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1162 *
1163 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1164 * BSSID, CH is the ASCII representation of the channel, DW is the
1165 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1166 * payload. For example
1167 *
1168 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1169 *
1170 * Return: 0 for success non-zero for failure
1171 */
1172static int
1173hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1174{
1175 uint8_t channel = 0;
1176 uint8_t dwell_time = 0;
1177 uint8_t payload_len = 0;
1178 uint8_t *payload = NULL;
1179 tSirMacAddr bssid;
1180 int ret;
1181
1182 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1183 &dwell_time, &payload,
1184 &payload_len);
1185 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001186 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001187 } else {
1188 ret = hdd_sendactionframe(adapter, bssid, channel,
1189 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301190 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001191 }
1192
1193 return ret;
1194}
1195
1196/**
1197 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1198 * SENDACTIONFRAME command
1199 * @adapter: Adapter upon which the command was received
1200 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001201 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001202 *
1203 * This function parses the v2 SENDACTIONFRAME command with the format
1204 *
1205 * SENDACTIONFRAME <android_wifi_af_params>
1206 *
1207 * Return: 0 for success non-zero for failure
1208 */
1209static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001210hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1211 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001212{
1213 struct android_wifi_af_params *params;
1214 tSirMacAddr bssid;
1215 int ret;
1216
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001218 total_len -= 16;
1219 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001220
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001221 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1222 (params->len > total_len)) {
1223 hdd_err("Invalid payload length: %d", params->len);
1224 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001225 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001226
1227 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1228 hdd_err("MAC address parsing failed");
1229 return -EINVAL;
1230 }
1231
1232 if (params->channel < 0 ||
1233 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1234 hdd_err("Invalid channel: %d", params->channel);
1235 return -EINVAL;
1236 }
1237
1238 if (params->dwell_time < 0) {
1239 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1240 return -EINVAL;
1241 }
1242
1243 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1244 params->dwell_time, params->len, params->data);
1245
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001246 return ret;
1247}
1248
1249/**
1250 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1251 * @adapter: Adapter upon which the command was received
1252 * @command: Command that was received
1253 *
1254 * There are two different versions of the SENDACTIONFRAME command.
1255 * Version 1 of the command contains a parameter list that is ASCII
1256 * characters whereas version 2 contains a combination of ASCII and
1257 * binary payload. Determine if a version 1 or a version 2 command is
1258 * being parsed by examining the parameters, and then dispatch the
1259 * parser that is appropriate for the version of the command.
1260 *
1261 * Return: 0 for success non-zero for failure
1262 */
1263static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001264hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1265 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001266{
1267 int ret;
1268
1269 /*
1270 * both versions start with "SENDACTIONFRAME "
1271 * v1 has a bssid and other parameters as an ASCII string
1272 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1273 * v2 has a C struct
1274 * SENDACTIONFRAME <binary c struct>
1275 *
1276 * The first field in the v2 struct is also the bssid in ASCII.
1277 * But in the case of a v2 message the BSSID is NUL-terminated.
1278 * Hence we can peek at that offset to see if this is V1 or V2
1279 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1280 * 111111111122222222223333
1281 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001282 * For both the commands, a valid command must have atleast
1283 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001284 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001285 if (total_len < 34) {
1286 hdd_err("Invalid command (total_len=%d)", total_len);
1287 return -EINVAL;
1288 }
1289
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001290 if (command[33]) {
1291 ret = hdd_parse_sendactionframe_v1(adapter, command);
1292 } else {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001293 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001294 }
1295
1296 return ret;
1297}
1298
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001299/**
1300 * hdd_parse_channellist() - HDD Parse channel list
1301 * @pValue: Pointer to input channel list
1302 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001303 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001304 * @pNumChannels: Pointer to number of roam scan channels
1305 *
1306 * This function parses the channel list passed in the format
1307 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1308 * if the Number of channels (N) does not match with the actual number
1309 * of channels passed then take the minimum of N and count of
1310 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1311 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1312 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1313 * removing duplicate channels from the list
1314 *
1315 * Return: 0 for success non-zero for failure
1316 */
1317static int
1318hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1319 uint8_t *pNumChannels)
1320{
1321 const uint8_t *inPtr = pValue;
1322 int tempInt;
1323 int j = 0;
1324 int v = 0;
1325 char buf[32];
1326
1327 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1328 /* no argument after the command */
1329 if (NULL == inPtr) {
1330 return -EINVAL;
1331 }
1332
1333 /* no space after the command */
1334 else if (SPACE_ASCII_VALUE != *inPtr) {
1335 return -EINVAL;
1336 }
1337
1338 /* remove empty spaces */
1339 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1340 inPtr++;
1341
1342 /* no argument followed by spaces */
1343 if ('\0' == *inPtr) {
1344 return -EINVAL;
1345 }
1346
1347 /* get the first argument ie the number of channels */
1348 v = sscanf(inPtr, "%31s ", buf);
1349 if (1 != v)
1350 return -EINVAL;
1351
1352 v = kstrtos32(buf, 10, &tempInt);
1353 if ((v < 0) ||
1354 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1355 return -EINVAL;
1356 }
1357
1358 *pNumChannels = tempInt;
1359
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001360 hdd_info("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001361
1362 for (j = 0; j < (*pNumChannels); j++) {
1363 /*
1364 * inPtr pointing to the beginning of first space after number
1365 * of channels
1366 */
1367 inPtr = strpbrk(inPtr, " ");
1368 /* no channel list after the number of channels argument */
1369 if (NULL == inPtr) {
1370 if (0 != j) {
1371 *pNumChannels = j;
1372 return 0;
1373 } else {
1374 return -EINVAL;
1375 }
1376 }
1377
1378 /* remove empty space */
1379 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1380 inPtr++;
1381
1382 /*
1383 * no channel list after the number of channels
1384 * argument and spaces
1385 */
1386 if ('\0' == *inPtr) {
1387 if (0 != j) {
1388 *pNumChannels = j;
1389 return 0;
1390 } else {
1391 return -EINVAL;
1392 }
1393 }
1394
1395 v = sscanf(inPtr, "%31s ", buf);
1396 if (1 != v)
1397 return -EINVAL;
1398
1399 v = kstrtos32(buf, 10, &tempInt);
1400 if ((v < 0) ||
1401 (tempInt <= 0) ||
1402 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1403 return -EINVAL;
1404 }
1405 pChannelList[j] = tempInt;
1406
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001407 hdd_info("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001408 pChannelList[j]);
1409 }
1410
1411 return 0;
1412}
1413
1414/**
1415 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1416 * SETROAMSCANCHANNELS command
1417 * @adapter: Adapter upon which the command was received
1418 * @command: ASCII text command that was received
1419 *
1420 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1421 *
1422 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1423 *
1424 * Where "N" is the ASCII representation of the number of channels and
1425 * C1 thru Cn is the ASCII representation of the channels. For example
1426 *
1427 * SETROAMSCANCHANNELS 4 36 40 44 48
1428 *
1429 * Return: 0 for success non-zero for failure
1430 */
1431static int
1432hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1433 const char *command)
1434{
1435 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1436 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301437 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1439 int ret;
1440
1441 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1442 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001443 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001444 goto exit;
1445 }
1446
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301447 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001448 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1449 adapter->sessionId, num_chan));
1450
1451 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001452 hdd_err("number of channels (%d) supported exceeded max (%d)",
1453 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001454 ret = -EINVAL;
1455 goto exit;
1456 }
1457
1458 status =
1459 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1460 adapter->sessionId,
1461 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301462 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001463 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 ret = -EINVAL;
1465 goto exit;
1466 }
1467exit:
1468 return ret;
1469}
1470
1471/**
1472 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1473 * SETROAMSCANCHANNELS command
1474 * @adapter: Adapter upon which the command was received
1475 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001476 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001477 *
1478 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1479 *
1480 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1481 *
1482 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1483 * what follows the space is an array of u08 parameters. For example
1484 *
1485 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1486 *
1487 * Return: 0 for success non-zero for failure
1488 */
1489static int
1490hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1491 const char *command)
1492{
1493 const uint8_t *value;
1494 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1495 uint8_t channel;
1496 uint8_t num_chan;
1497 int i;
1498 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301499 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001500 int ret = 0;
1501
1502 /* array of values begins after "SETROAMSCANCHANNELS " */
1503 value = command + 20;
1504
1505 num_chan = *value++;
1506 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001507 hdd_err("number of channels (%d) supported exceeded max (%d)",
1508 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001509 ret = -EINVAL;
1510 goto exit;
1511 }
1512
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301513 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001514 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1515 adapter->sessionId, num_chan));
1516
1517 for (i = 0; i < num_chan; i++) {
1518 channel = *value++;
1519 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001520 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001521 i, channel);
1522 ret = -EINVAL;
1523 goto exit;
1524 }
1525 channel_list[i] = channel;
1526 }
1527 status =
1528 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1529 adapter->sessionId,
1530 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301531 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001532 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001533 ret = -EINVAL;
1534 goto exit;
1535 }
1536exit:
1537 return ret;
1538}
1539
1540/**
1541 * hdd_parse_set_roam_scan_channels() - parse the
1542 * SETROAMSCANCHANNELS command
1543 * @adapter: Adapter upon which the command was received
1544 * @command: Command that was received
1545 *
1546 * There are two different versions of the SETROAMSCANCHANNELS command.
1547 * Version 1 of the command contains a parameter list that is ASCII
1548 * characters whereas version 2 contains a binary payload. Determine
1549 * if a version 1 or a version 2 command is being parsed by examining
1550 * the parameters, and then dispatch the parser that is appropriate for
1551 * the command.
1552 *
1553 * Return: 0 for success non-zero for failure
1554 */
1555static int
1556hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1557{
1558 const char *cursor;
1559 char ch;
1560 bool v1;
1561 int ret;
1562
1563 /* start after "SETROAMSCANCHANNELS " */
1564 cursor = command + 20;
1565
1566 /* assume we have a version 1 command until proven otherwise */
1567 v1 = true;
1568
1569 /* v1 params will only contain ASCII digits and space */
1570 while ((ch = *cursor++) && v1) {
1571 if (!(isdigit(ch) || isspace(ch))) {
1572 v1 = false;
1573 }
1574 }
1575 if (v1) {
1576 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1577 } else {
1578 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1579 }
1580
1581 return ret;
1582}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001583
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001584#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001585/**
1586 * hdd_parse_plm_cmd() - HDD Parse Plm command
1587 * @pValue: Pointer to input data
1588 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1589 *
1590 * This function parses the plm command passed in the format
1591 * CCXPLMREQ<space><enable><space><dialog_token><space>
1592 * <meas_token><space><num_of_bursts><space><burst_int><space>
1593 * <measu duration><space><burst_len><space><desired_tx_pwr>
1594 * <space><multcast_addr><space><number_of_channels>
1595 * <space><channel_numbers>
1596 *
1597 * Return: 0 for success non-zero for failure
1598 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001599static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001600{
1601 uint8_t *cmdPtr = NULL;
1602 int count, content = 0, ret = 0;
1603 char buf[32];
1604
1605 /* move to argument list */
1606 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1607 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301608 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001609
1610 /* no space after the command */
1611 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301612 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613
1614 /* remove empty spaces */
1615 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1616 cmdPtr++;
1617
1618 /* START/STOP PLM req */
1619 ret = sscanf(cmdPtr, "%31s ", buf);
1620 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301621 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622
1623 ret = kstrtos32(buf, 10, &content);
1624 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301625 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626
1627 pPlmRequest->enable = content;
1628 cmdPtr = strpbrk(cmdPtr, " ");
1629
1630 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301631 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001632
1633 /* remove empty spaces */
1634 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1635 cmdPtr++;
1636
1637 /* Dialog token of radio meas req containing meas reqIE */
1638 ret = sscanf(cmdPtr, "%31s ", buf);
1639 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301640 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641
1642 ret = kstrtos32(buf, 10, &content);
1643 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301644 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645
1646 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001647 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001648 cmdPtr = strpbrk(cmdPtr, " ");
1649
1650 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301651 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001652
1653 /* remove empty spaces */
1654 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1655 cmdPtr++;
1656
1657 /* measurement token of meas req IE */
1658 ret = sscanf(cmdPtr, "%31s ", buf);
1659 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301660 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001661
1662 ret = kstrtos32(buf, 10, &content);
1663 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301664 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001665
1666 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001667 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001669 hdd_err("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670 if (pPlmRequest->enable) {
1671
1672 cmdPtr = strpbrk(cmdPtr, " ");
1673
1674 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301675 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676
1677 /* remove empty spaces */
1678 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1679 cmdPtr++;
1680
1681 /* total number of bursts after which STA stops sending */
1682 ret = sscanf(cmdPtr, "%31s ", buf);
1683 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301684 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685
1686 ret = kstrtos32(buf, 10, &content);
1687 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301688 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689
1690 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301691 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692
1693 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001694 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695 cmdPtr = strpbrk(cmdPtr, " ");
1696
1697 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301698 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001699
1700 /* remove empty spaces */
1701 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1702 cmdPtr++;
1703
1704 /* burst interval in seconds */
1705 ret = sscanf(cmdPtr, "%31s ", buf);
1706 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301707 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001708
1709 ret = kstrtos32(buf, 10, &content);
1710 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301711 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001712
1713 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301714 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001715
1716 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001717 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718 cmdPtr = strpbrk(cmdPtr, " ");
1719
1720 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301721 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722
1723 /* remove empty spaces */
1724 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1725 cmdPtr++;
1726
1727 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1728 ret = sscanf(cmdPtr, "%31s ", buf);
1729 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301730 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731
1732 ret = kstrtos32(buf, 10, &content);
1733 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301734 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001735
1736 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301737 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738
1739 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001740 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001741 cmdPtr = strpbrk(cmdPtr, " ");
1742
1743 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301744 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001745
1746 /* remove empty spaces */
1747 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1748 cmdPtr++;
1749
1750 /* burst length of PLM bursts */
1751 ret = sscanf(cmdPtr, "%31s ", buf);
1752 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301753 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001754
1755 ret = kstrtos32(buf, 10, &content);
1756 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301757 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758
1759 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301760 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001761
1762 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001763 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001764 cmdPtr = strpbrk(cmdPtr, " ");
1765
1766 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301767 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001768
1769 /* remove empty spaces */
1770 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1771 cmdPtr++;
1772
1773 /* desired tx power for transmission of PLM bursts */
1774 ret = sscanf(cmdPtr, "%31s ", buf);
1775 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301776 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001777
1778 ret = kstrtos32(buf, 10, &content);
1779 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301780 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001781
1782 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301783 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784
1785 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001786 hdd_debug("desiredTxPwr %d",
1787 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001788
Anurag Chouhan6d760662016-02-20 16:05:43 +05301789 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001790 cmdPtr = strpbrk(cmdPtr, " ");
1791
1792 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301793 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794
1795 /* remove empty spaces */
1796 while ((SPACE_ASCII_VALUE == *cmdPtr)
1797 && ('\0' != *cmdPtr))
1798 cmdPtr++;
1799
1800 ret = sscanf(cmdPtr, "%31s ", buf);
1801 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301802 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001803
1804 ret = kstrtos32(buf, 16, &content);
1805 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301806 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001808 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001809 }
1810
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001811 hdd_debug("MC addr " MAC_ADDRESS_STR,
1812 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001813
1814 cmdPtr = strpbrk(cmdPtr, " ");
1815
1816 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301817 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001818
1819 /* remove empty spaces */
1820 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1821 cmdPtr++;
1822
1823 /* number of channels */
1824 ret = sscanf(cmdPtr, "%31s ", buf);
1825 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301826 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001827
1828 ret = kstrtos32(buf, 10, &content);
1829 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301830 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001831
1832 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301833 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001834
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001835 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001836 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001837 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001838
1839 /* Channel numbers */
1840 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1841 cmdPtr = strpbrk(cmdPtr, " ");
1842
1843 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301844 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001845
1846 /* remove empty spaces */
1847 while ((SPACE_ASCII_VALUE == *cmdPtr)
1848 && ('\0' != *cmdPtr))
1849 cmdPtr++;
1850
1851 ret = sscanf(cmdPtr, "%31s ", buf);
1852 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301853 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854
1855 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001856 if (ret < 0 || content <= 0 ||
1857 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301858 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001859
1860 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001861 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862 }
1863 }
1864 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301865 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001866}
1867#endif
1868
1869#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1870static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1871{
1872 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1873 int rc;
1874
1875 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301876 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878 hdd_ctx->ext_wow_should_suspend = is_success;
1879 complete(&hdd_ctx->ready_to_extwow);
1880}
1881
1882static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1883 tpSirExtWoWParams arg_params)
1884{
1885 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301886 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1888 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1889 int rc;
1890
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301891 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001892
1893 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1894
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301895 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001896 &wlan_hdd_ready_to_extwow,
1897 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301898 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001899 hdd_err("sme_configure_ext_wow returned failure %d",
1900 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001901 return -EPERM;
1902 }
1903
1904 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1905 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1906 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001907 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908 return -EPERM;
1909 }
1910
1911 if (hdd_ctx->ext_wow_should_suspend) {
1912 if (hdd_ctx->config->extWowGotoSuspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001913 hdd_info("Received ready to ExtWoW. Going to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001914
1915 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1916 if (rc < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001917 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1918 rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001919 return rc;
1920 }
Dustin Brown9ef609b2017-03-15 12:19:37 -07001921 qdf_ret_status = wlan_hdd_bus_suspend();
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301922 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001923 hdd_err("wlan_hdd_suspend failed, status = %d",
1924 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001925 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1926 return -EPERM;
1927 }
1928 }
1929 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001930 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001931 return -EPERM;
1932 }
1933
1934 return 0;
1935}
1936
1937static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1938 int value)
1939{
1940 tSirExtWoWParams params;
1941 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1942 int rc;
1943
1944 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301945 if (rc)
1946 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001947
1948 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1949 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001950 hdd_err("Invalid type");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001951 return -EINVAL;
1952 }
1953
1954 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1955 hdd_ctx->is_extwow_app_type1_param_set)
1956 params.type = value;
1957 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1958 hdd_ctx->is_extwow_app_type2_param_set)
1959 params.type = value;
1960 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1961 hdd_ctx->is_extwow_app_type1_param_set &&
1962 hdd_ctx->is_extwow_app_type2_param_set)
1963 params.type = value;
1964 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001965 hdd_err("Set app params before enable it value %d",
1966 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967 return -EINVAL;
1968 }
1969
1970 params.vdev_id = vdev_id;
1971 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1972 (hdd_ctx->config->extWowApp2WakeupPinNumber
1973 << 8);
1974
1975 return hdd_enable_ext_wow(adapter, &params);
1976}
1977
1978static int hdd_set_app_type1_params(tHalHandle hHal,
1979 tpSirAppType1Params arg_params)
1980{
1981 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301982 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301984 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301986 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1987 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001988 hdd_err("sme_configure_app_type1_params returned failure %d",
1989 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001990 return -EPERM;
1991 }
1992
1993 return 0;
1994}
1995
1996static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
1997 char *arg, int len)
1998{
1999 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2000 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2001 char id[20], password[20];
2002 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002003 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004
2005 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302006 if (rc)
2007 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002008
2009 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002010 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 return -EINVAL;
2012 }
2013
2014 memset(&params, 0, sizeof(tSirAppType1Params));
2015 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302016 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017
2018 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302019 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302021 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002022
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002023 hdd_info("%d %pM %.8s %u %.16s %u",
2024 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002025 params.identification_id, params.id_length,
2026 params.password, params.pass_length);
2027
2028 return hdd_set_app_type1_params(hHal, &params);
2029}
2030
2031static int hdd_set_app_type2_params(tHalHandle hHal,
2032 tpSirAppType2Params arg_params)
2033{
2034 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302035 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002036
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302037 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302039 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2040 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002041 hdd_err("sme_configure_app_type2_params returned failure %d",
2042 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043 return -EPERM;
2044 }
2045
2046 return 0;
2047}
2048
2049static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2050 char *arg, int len)
2051{
2052 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2053 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2054 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302055 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002056 tSirAppType2Params params;
2057 int ret;
2058
2059 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302060 if (ret)
2061 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062
2063 memset(&params, 0, sizeof(tSirAppType2Params));
2064
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302065 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 -08002066 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2067 (unsigned int *)&params.ip_device_ip,
2068 (unsigned int *)&params.ip_server_ip,
2069 (unsigned int *)&params.tcp_seq,
2070 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302071 (uint16_t *)&params.tcp_src_port,
2072 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002073 (unsigned int *)&params.keepalive_init,
2074 (unsigned int *)&params.keepalive_min,
2075 (unsigned int *)&params.keepalive_max,
2076 (unsigned int *)&params.keepalive_inc,
2077 (unsigned int *)&params.tcp_tx_timeout_val,
2078 (unsigned int *)&params.tcp_rx_timeout_val);
2079
2080 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002081 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002082 return -EINVAL;
2083 }
2084
2085 if (6 !=
2086 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2087 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2088 &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002089 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002090 return -EINVAL;
2091 }
2092
2093 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2094 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002095 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002096 return -EINVAL;
2097 }
2098
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302099 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302100 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002101
2102 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302103 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002104
2105 params.vdev_id = adapter->sessionId;
2106 params.tcp_src_port = (params.tcp_src_port != 0) ?
2107 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2108 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2109 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2110 params.keepalive_init = (params.keepalive_init != 0) ?
2111 params.keepalive_init : hdd_ctx->config->
2112 extWowApp2KAInitPingInterval;
2113 params.keepalive_min =
2114 (params.keepalive_min != 0) ?
2115 params.keepalive_min :
2116 hdd_ctx->config->extWowApp2KAMinPingInterval;
2117 params.keepalive_max =
2118 (params.keepalive_max != 0) ?
2119 params.keepalive_max :
2120 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2121 params.keepalive_inc =
2122 (params.keepalive_inc != 0) ?
2123 params.keepalive_inc :
2124 hdd_ctx->config->extWowApp2KAIncPingInterval;
2125 params.tcp_tx_timeout_val =
2126 (params.tcp_tx_timeout_val != 0) ?
2127 params.tcp_tx_timeout_val :
2128 hdd_ctx->config->extWowApp2TcpTxTimeout;
2129 params.tcp_rx_timeout_val =
2130 (params.tcp_rx_timeout_val != 0) ?
2131 params.tcp_rx_timeout_val :
2132 hdd_ctx->config->extWowApp2TcpRxTimeout;
2133
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002134 hdd_info("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2135 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002136 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2137 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2138 params.keepalive_init, params.keepalive_min,
2139 params.keepalive_max, params.keepalive_inc,
2140 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2141
2142 return hdd_set_app_type2_params(hHal, &params);
2143}
2144#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2145
2146/**
2147 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2148 * @pValue: Pointer to MAXTXPOWER command
2149 * @pDbm: Pointer to tx power
2150 *
2151 * This function parses the MAXTXPOWER command passed in the format
2152 * MAXTXPOWER<space>X(Tx power in dbm)
2153 *
2154 * For example input commands:
2155 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2156 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2157 *
2158 * Return: 0 for success non-zero for failure
2159 */
2160static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2161{
2162 uint8_t *inPtr = pValue;
2163 int tempInt;
2164 int v = 0;
2165 *pTxPower = 0;
2166
2167 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2168 /* no argument after the command */
2169 if (NULL == inPtr) {
2170 return -EINVAL;
2171 }
2172
2173 /* no space after the command */
2174 else if (SPACE_ASCII_VALUE != *inPtr) {
2175 return -EINVAL;
2176 }
2177
2178 /* remove empty spaces */
2179 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2180 inPtr++;
2181
2182 /* no argument followed by spaces */
2183 if ('\0' == *inPtr) {
2184 return 0;
2185 }
2186
2187 v = kstrtos32(inPtr, 10, &tempInt);
2188
2189 /* Range checking for passed parameter */
2190 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2191 return -EINVAL;
2192 }
2193
2194 *pTxPower = tempInt;
2195
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002196 hdd_info("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002197
2198 return 0;
2199} /* End of hdd_parse_setmaxtxpower_command */
2200
2201static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2202 char *extra, uint8_t n, uint8_t *len)
2203{
Jeff Johnson68755312017-02-10 11:46:55 -08002204 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002205
2206 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002207 hdd_err("argument passed for GETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002208 ret = -EINVAL;
2209 return ret;
2210 }
2211
2212 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2213 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2214 (int)pCfg->nActiveMaxChnTime);
2215 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002216 }
2217 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002218 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2219 (int)pCfg->nActiveMinChnTime);
2220 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002221 }
2222 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002223 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2224 (int)pCfg->nPassiveMaxChnTime);
2225 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002226 }
2227 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002228 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2229 (int)pCfg->nPassiveMinChnTime);
2230 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002231 }
2232 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002233 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2234 (int)pCfg->nActiveMaxChnTime);
2235 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002236 }
Jeff Johnson68755312017-02-10 11:46:55 -08002237 ret = -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002238
2239 return ret;
2240}
2241
2242static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2243{
2244 tHalHandle hHal;
2245 struct hdd_config *pCfg;
2246 uint8_t *value = command;
2247 tSmeConfigParams smeConfig;
2248 int val = 0, temp = 0;
2249
2250 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2251 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2252 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002253 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002254 return -EINVAL;
2255 }
2256
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302257 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002258 sme_get_config_param(hHal, &smeConfig);
2259
2260 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2261 value = value + 24;
2262 temp = kstrtou32(value, 10, &val);
2263 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2264 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002265 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002266 return -EFAULT;
2267 }
2268 pCfg->nActiveMaxChnTime = val;
2269 smeConfig.csrConfig.nActiveMaxChnTime = val;
2270 sme_update_config(hHal, &smeConfig);
2271 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2272 value = value + 24;
2273 temp = kstrtou32(value, 10, &val);
2274 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2275 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002276 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002277 return -EFAULT;
2278 }
2279 pCfg->nActiveMinChnTime = val;
2280 smeConfig.csrConfig.nActiveMinChnTime = val;
2281 sme_update_config(hHal, &smeConfig);
2282 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2283 value = value + 25;
2284 temp = kstrtou32(value, 10, &val);
2285 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2286 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002287 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002288 return -EFAULT;
2289 }
2290 pCfg->nPassiveMaxChnTime = val;
2291 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2292 sme_update_config(hHal, &smeConfig);
2293 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2294 value = value + 25;
2295 temp = kstrtou32(value, 10, &val);
2296 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2297 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002298 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002299 return -EFAULT;
2300 }
2301 pCfg->nPassiveMinChnTime = val;
2302 smeConfig.csrConfig.nPassiveMinChnTime = val;
2303 sme_update_config(hHal, &smeConfig);
2304 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2305 value = value + 13;
2306 temp = kstrtou32(value, 10, &val);
2307 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2308 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002309 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002310 return -EFAULT;
2311 }
2312 pCfg->nActiveMaxChnTime = val;
2313 smeConfig.csrConfig.nActiveMaxChnTime = val;
2314 sme_update_config(hHal, &smeConfig);
2315 } else {
2316 return -EINVAL;
2317 }
2318
2319 return 0;
2320}
2321
Jeff Johnson253c0c22017-01-23 16:59:38 -08002322struct link_status_priv {
2323 uint8_t link_status;
2324};
2325
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002326static void hdd_get_link_status_cb(uint8_t status, void *context)
2327{
Jeff Johnson253c0c22017-01-23 16:59:38 -08002328 struct hdd_request *request;
2329 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002330
Jeff Johnson253c0c22017-01-23 16:59:38 -08002331 request = hdd_request_get(context);
2332 if (!request) {
2333 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002334 return;
2335 }
2336
Jeff Johnson253c0c22017-01-23 16:59:38 -08002337 priv = hdd_request_priv(request);
2338 priv->link_status = status;
2339 hdd_request_complete(request);
2340 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002341}
2342
2343/**
2344 * wlan_hdd_get_link_status() - get link status
2345 * @pAdapter: pointer to the adapter
2346 *
2347 * This function sends a request to query the link status and waits
2348 * on a timer to invoke the callback. if the callback is invoked then
2349 * latest link status shall be returned or otherwise cached value
2350 * will be returned.
2351 *
2352 * Return: On success, link status shall be returned.
2353 * On error or not associated, link status 0 will be returned.
2354 */
2355static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2356{
2357
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002358 hdd_station_ctx_t *pHddStaCtx =
2359 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302360 QDF_STATUS hstatus;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002361 int ret;
2362 void *cookie;
2363 struct hdd_request *request;
2364 struct link_status_priv *priv;
2365 static const struct hdd_request_params params = {
2366 .priv_size = sizeof(*priv),
2367 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2368 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002369
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002370 if (cds_is_driver_recovering()) {
2371 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2372 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373 return 0;
2374 }
2375
Krunal Sonibe766b02016-03-10 13:00:44 -08002376 if ((QDF_STA_MODE != adapter->device_mode) &&
2377 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002378 hdd_warn("Unsupported in mode %s(%d)",
2379 hdd_device_mode_to_string(adapter->device_mode),
2380 adapter->device_mode);
2381 return 0;
2382 }
2383
2384 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2385 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2386 /* If not associated, then expected link status return
2387 * value is 0
2388 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002389 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002390 return 0;
2391 }
2392
Jeff Johnson253c0c22017-01-23 16:59:38 -08002393 request = hdd_request_alloc(&params);
2394 if (!request) {
2395 hdd_err("Request allocation failure");
2396 return 0;
2397 }
2398 cookie = hdd_request_cookie(request);
2399
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002400 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2401 hdd_get_link_status_cb,
Jeff Johnson253c0c22017-01-23 16:59:38 -08002402 cookie, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302403 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002404 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002405 /* return a cached value */
2406 } else {
2407 /* request is sent -- wait for the response */
Jeff Johnson253c0c22017-01-23 16:59:38 -08002408 ret = hdd_request_wait_for_response(request);
2409 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002410 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002411 /* return a cached value */
2412 } else {
2413 /* update the adapter with the fresh results */
2414 priv = hdd_request_priv(request);
2415 adapter->linkStatus = priv->link_status;
2416 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002417 }
2418
Jeff Johnson253c0c22017-01-23 16:59:38 -08002419 /*
2420 * either we never sent a request, we sent a request and
2421 * received a response or we sent a request and timed out.
2422 * regardless we are done with the request.
2423 */
2424 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002425
2426 /* either callback updated adapter stats or it has cached data */
2427 return adapter->linkStatus;
2428}
2429
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002430static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2431{
2432 int payload_len;
2433 struct sk_buff *skb;
2434 struct nlmsghdr *nlh;
2435 uint8_t *data;
2436
2437 payload_len = ETH_ALEN;
2438
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002439 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002440 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002441 return;
2442 }
2443
2444 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2445 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002446 hdd_err("nlmsg_new() failed for msg size[%d]",
2447 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002448 return;
2449 }
2450
2451 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2452
2453 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002454 hdd_err("nlmsg_put() failed for msg size[%d]",
2455 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002456
2457 kfree_skb(skb);
2458 return;
2459 }
2460
2461 data = nlmsg_data(nlh);
2462 memcpy(data, MacAddr, ETH_ALEN);
2463
2464 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002465 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2466 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002467 }
2468
2469 return;
2470}
2471
2472
2473/**
2474 * hdd_ParseuserParams - return a pointer to the next argument
2475 * @pValue: Input argument string
2476 * @ppArg: Output pointer to the next argument
2477 *
2478 * This function parses argument stream and finds the pointer
2479 * to the next argument
2480 *
2481 * Return: 0 if the next argument found; -EINVAL otherwise
2482 */
2483static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2484{
2485 uint8_t *pVal;
2486
2487 pVal = strnchr(pValue, strlen(pValue), ' ');
2488
2489 if (NULL == pVal) {
2490 /* no argument remains */
2491 return -EINVAL;
2492 } else if (SPACE_ASCII_VALUE != *pVal) {
2493 /* no space after the current argument */
2494 return -EINVAL;
2495 }
2496
2497 pVal++;
2498
2499 /* remove empty spaces */
2500 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2501 pVal++;
2502 }
2503
2504 /* no argument followed by spaces */
2505 if ('\0' == *pVal) {
2506 return -EINVAL;
2507 }
2508
2509 *ppArg = pVal;
2510
2511 return 0;
2512}
2513
2514/**
2515 * hdd_parse_ibsstx_fail_event_params - Parse params
2516 * for SETIBSSTXFAILEVENT
2517 * @pValue: Input ibss tx fail event argument
2518 * @tx_fail_count: (Output parameter) Tx fail counter
2519 * @pid: (Output parameter) PID
2520 *
2521 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2522 */
2523static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2524 uint8_t *tx_fail_count,
2525 uint16_t *pid)
2526{
2527 uint8_t *param = NULL;
2528 int ret;
2529
2530 ret = hdd_parse_user_params(pValue, &param);
2531
2532 if (0 == ret && NULL != param) {
2533 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2534 ret = -EINVAL;
2535 goto done;
2536 }
2537 } else {
2538 goto done;
2539 }
2540
2541 if (0 == *tx_fail_count) {
2542 *pid = 0;
2543 goto done;
2544 }
2545
2546 pValue = param;
2547 pValue++;
2548
2549 ret = hdd_parse_user_params(pValue, &param);
2550
2551 if (0 == ret) {
2552 if (1 != sscanf(param, "%hu", pid)) {
2553 ret = -EINVAL;
2554 goto done;
2555 }
2556 } else {
2557 goto done;
2558 }
2559
2560done:
2561 return ret;
2562}
2563
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002564#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002565/**
2566 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2567 * @pValue: Pointer to data
2568 * @pEseBcnReq: Output pointer to store parsed ie information
2569 *
2570 * This function parses the ese beacon request passed in the format
2571 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2572 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2573 * <space>Scan Mode N<space>Meas Duration N
2574 *
2575 * If the Number of bcn req fields (N) does not match with the
2576 * actual number of fields passed then take N.
2577 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2578 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2579 * This function does not take care of removing duplicate channels from the
2580 * list
2581 *
2582 * Return: 0 for success non-zero for failure
2583 */
2584static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2585 tCsrEseBeaconReq *pEseBcnReq)
2586{
2587 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002588 uint8_t input = 0;
2589 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002590 int j = 0, i = 0, v = 0;
2591 char buf[32];
2592
2593 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2594 /* no argument after the command */
2595 if (NULL == inPtr) {
2596 return -EINVAL;
2597 }
2598 /* no space after the command */
2599 else if (SPACE_ASCII_VALUE != *inPtr) {
2600 return -EINVAL;
2601 }
2602
2603 /* remove empty spaces */
2604 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2605 inPtr++;
2606
2607 /* no argument followed by spaces */
2608 if ('\0' == *inPtr)
2609 return -EINVAL;
2610
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002611 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612 v = sscanf(inPtr, "%31s ", buf);
2613 if (1 != v)
2614 return -EINVAL;
2615
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002616 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002617 if (v < 0)
2618 return -EINVAL;
2619
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002620 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2621 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002622
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002623 hdd_info("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002624
2625 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2626 for (i = 0; i < 4; i++) {
2627 /*
2628 * inPtr pointing to the beginning of 1st space
2629 * after number of ie fields
2630 */
2631 inPtr = strpbrk(inPtr, " ");
2632 /* no ie data after the number of ie fields argument */
2633 if (NULL == inPtr)
2634 return -EINVAL;
2635
2636 /* remove empty space */
2637 while ((SPACE_ASCII_VALUE == *inPtr)
2638 && ('\0' != *inPtr))
2639 inPtr++;
2640
2641 /*
2642 * no ie data after the number of ie fields
2643 * argument and spaces
2644 */
2645 if ('\0' == *inPtr)
2646 return -EINVAL;
2647
2648 v = sscanf(inPtr, "%31s ", buf);
2649 if (1 != v)
2650 return -EINVAL;
2651
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002652 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002653 if (v < 0)
2654 return -EINVAL;
2655
2656 switch (i) {
2657 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002658 if (!tempInt) {
2659 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002660 tempInt);
2661 return -EINVAL;
2662 }
2663 pEseBcnReq->bcnReq[j].measurementToken =
2664 tempInt;
2665 break;
2666
2667 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002668 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002669 (tempInt >
2670 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002671 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002672 tempInt);
2673 return -EINVAL;
2674 }
2675 pEseBcnReq->bcnReq[j].channel = tempInt;
2676 break;
2677
2678 case 2: /* Scan mode */
2679 if ((tempInt < eSIR_PASSIVE_SCAN)
2680 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002681 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002682 tempInt);
2683 return -EINVAL;
2684 }
2685 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2686 break;
2687
2688 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002689 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002690 && (pEseBcnReq->bcnReq[j].scanMode !=
2691 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002692 (pEseBcnReq->bcnReq[j].scanMode ==
2693 eSIR_BEACON_TABLE)) {
2694 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002695 tempInt);
2696 return -EINVAL;
2697 }
2698 pEseBcnReq->bcnReq[j].measurementDuration =
2699 tempInt;
2700 break;
2701 }
2702 }
2703 }
2704
2705 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002706 hdd_info("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002707 j,
2708 pEseBcnReq->bcnReq[j].measurementToken,
2709 pEseBcnReq->bcnReq[j].channel,
2710 pEseBcnReq->bcnReq[j].scanMode,
2711 pEseBcnReq->bcnReq[j].measurementDuration);
2712 }
2713
2714 return 0;
2715}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002716
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002717/**
2718 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2719 * @pValue: Pointer to input data
2720 * @pCckmIe: Pointer to output cckm Ie
2721 * @pCckmIeLen: Pointer to output cckm ie length
2722 *
2723 * This function parses the SETCCKM IE command
2724 * SETCCKMIE<space><ie data>
2725 *
2726 * Return: 0 for success non-zero for failure
2727 */
2728static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2729 uint8_t *pCckmIeLen)
2730{
2731 uint8_t *inPtr = pValue;
2732 uint8_t *dataEnd;
2733 int j = 0;
2734 int i = 0;
2735 uint8_t tempByte = 0;
2736 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2737 /* no argument after the command */
2738 if (NULL == inPtr) {
2739 return -EINVAL;
2740 }
2741 /* no space after the command */
2742 else if (SPACE_ASCII_VALUE != *inPtr) {
2743 return -EINVAL;
2744 }
2745 /* remove empty spaces */
2746 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2747 inPtr++;
2748 /* no argument followed by spaces */
2749 if ('\0' == *inPtr) {
2750 return -EINVAL;
2751 }
2752 /* find the length of data */
2753 dataEnd = inPtr;
2754 while (('\0' != *dataEnd)) {
2755 dataEnd++;
2756 ++(*pCckmIeLen);
2757 }
2758 if (*pCckmIeLen <= 0)
2759 return -EINVAL;
2760 /*
2761 * Allocate the number of bytes based on the number of input characters
2762 * whether it is even or odd.
2763 * if the number of input characters are even, then we need N / 2 byte.
2764 * if the number of input characters are odd, then we need do
2765 * (N + 1) / 2 to compensate rounding off.
2766 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2767 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2768 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302769 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002770 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002771 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002772 return -ENOMEM;
2773 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002774 /*
2775 * the buffer received from the upper layer is character buffer,
2776 * we need to prepare the buffer taking 2 characters in to a U8 hex
2777 * decimal number for example 7f0000f0...form a buffer to contain
2778 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2779 */
2780 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2781 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2782 (hex_to_bin(inPtr[j + 1]));
2783 (*pCckmIe)[i++] = tempByte;
2784 }
2785 *pCckmIeLen = i;
2786 return 0;
2787}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002788#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002789
2790int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2791{
2792 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302793 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002794 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2795 struct hdd_config *pConfig = NULL;
2796
2797 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002798 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002799 return -EINVAL;
2800 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002801 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2802 (QDF_SAP_MODE != pAdapter->device_mode) &&
2803 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002804 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2805 hdd_device_mode_to_string(pAdapter->device_mode),
2806 pAdapter->device_mode);
2807 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002808 return -EINVAL;
2809 }
2810 pConfig = pHddCtx->config;
2811 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2812 rateUpdate.dev_mode = pAdapter->device_mode;
2813 rateUpdate.mcastDataRate24GHz = targetRate;
2814 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2815 rateUpdate.mcastDataRate5GHz = targetRate;
2816 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302817 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002818 hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
2819 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2820 hdd_device_mode_to_string(pAdapter->device_mode),
2821 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002822 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302823 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002824 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002825 return -EFAULT;
2826 }
2827 return 0;
2828}
2829
2830static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2831 hdd_context_t *hdd_ctx,
2832 uint8_t *command,
2833 uint8_t command_len,
2834 hdd_priv_data_t *priv_data)
2835{
2836 int ret = 0;
2837
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302838 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002839 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2840 adapter->sessionId,
2841 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2842 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2843 + 3) << 16 | *(hdd_ctx->
2844 p2pDeviceAddress.bytes + 4) << 8 |
2845 *(hdd_ctx->p2pDeviceAddress.bytes +
2846 5))));
2847
2848 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2849 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002850 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002851 ret = -EFAULT;
2852 }
2853
2854 return ret;
2855}
2856
2857/**
2858 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2859 * @adapter: Adapter on which the command was received
2860 * @hdd_ctx: HDD global context
2861 * @command: Entire driver command received from userspace
2862 * @command_len: Length of @command
2863 * @priv_data: Pointer to ioctl private data structure
2864 *
2865 * This is a trivial command hander function which simply forwards the
2866 * command to the actual command processor within the P2P module.
2867 *
2868 * Return: 0 on success, non-zero on failure
2869 */
2870static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2871 hdd_context_t *hdd_ctx,
2872 uint8_t *command,
2873 uint8_t command_len,
2874 hdd_priv_data_t *priv_data)
2875{
2876 return hdd_set_p2p_noa(adapter->dev, command);
2877}
2878
2879/**
2880 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2881 * @adapter: Adapter on which the command was received
2882 * @hdd_ctx: HDD global context
2883 * @command: Entire driver command received from userspace
2884 * @command_len: Length of @command
2885 * @priv_data: Pointer to ioctl private data structure
2886 *
2887 * This is a trivial command hander function which simply forwards the
2888 * command to the actual command processor within the P2P module.
2889 *
2890 * Return: 0 on success, non-zero on failure
2891 */
2892static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2893 hdd_context_t *hdd_ctx,
2894 uint8_t *command,
2895 uint8_t command_len,
2896 hdd_priv_data_t *priv_data)
2897{
2898 return hdd_set_p2p_opps(adapter->dev, command);
2899}
2900
2901static int drv_cmd_set_band(hdd_adapter_t *adapter,
2902 hdd_context_t *hdd_ctx,
2903 uint8_t *command,
2904 uint8_t command_len,
2905 hdd_priv_data_t *priv_data)
2906{
2907 int ret = 0;
2908
2909 uint8_t *ptr = command;
2910
2911 /* Change band request received */
2912
2913 /*
2914 * First 8 bytes will have "SETBAND " and
2915 * 9 byte will have band setting value
2916 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002917 hdd_info("SetBandCommand Info comm %s UL %d, TL %d",
2918 command, priv_data->used_len,
2919 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002920
2921 /* Change band request received */
2922 ret = hdd_set_band_helper(adapter->dev, ptr);
2923
2924 return ret;
2925}
2926
2927static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2928 hdd_context_t *hdd_ctx,
2929 uint8_t *command,
2930 uint8_t command_len,
2931 hdd_priv_data_t *priv_data)
2932{
2933 return hdd_wmmps_helper(adapter, command);
2934}
2935
2936static int drv_cmd_country(hdd_adapter_t *adapter,
2937 hdd_context_t *hdd_ctx,
2938 uint8_t *command,
2939 uint8_t command_len,
2940 hdd_priv_data_t *priv_data)
2941{
2942 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302943 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002944 unsigned long rc;
2945 char *country_code;
2946
2947 country_code = command + 8;
2948
2949 INIT_COMPLETION(adapter->change_country_code);
2950
2951 status = sme_change_country_code(hdd_ctx->hHal,
2952 wlan_hdd_change_country_code_callback,
2953 country_code,
2954 adapter,
2955 hdd_ctx->pcds_context,
2956 eSIR_TRUE,
2957 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302958 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002959 rc = wait_for_completion_timeout(
2960 &adapter->change_country_code,
2961 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
2962 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002963 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002964 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002965 hdd_err("SME Change Country code fail, status %d",
2966 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002967 ret = -EINVAL;
2968 }
2969
2970 return ret;
2971}
2972
2973static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
2974 hdd_context_t *hdd_ctx,
2975 uint8_t *command,
2976 uint8_t command_len,
2977 hdd_priv_data_t *priv_data)
2978{
2979 int ret = 0;
2980 uint8_t *value = command;
2981 int8_t rssi = 0;
2982 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302983 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002984
2985 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2986 value = value + command_len + 1;
2987
2988 /* Convert the value from ascii to integer */
2989 ret = kstrtos8(value, 10, &rssi);
2990 if (ret < 0) {
2991 /*
2992 * If the input value is greater than max value of datatype,
2993 * then also kstrtou8 fails
2994 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002995 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2996 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2997 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002998 ret = -EINVAL;
2999 goto exit;
3000 }
3001
3002 lookUpThreshold = abs(rssi);
3003
3004 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3005 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003006 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003007 lookUpThreshold,
3008 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3009 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3010 ret = -EINVAL;
3011 goto exit;
3012 }
3013
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303014 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003015 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3016 adapter->sessionId, lookUpThreshold));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003017 hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 lookUpThreshold);
3019
3020 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3021 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3022 adapter->sessionId,
3023 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303024 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003025 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003026 ret = -EPERM;
3027 goto exit;
3028 }
3029
3030exit:
3031 return ret;
3032}
3033
3034static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3035 hdd_context_t *hdd_ctx,
3036 uint8_t *command,
3037 uint8_t command_len,
3038 hdd_priv_data_t *priv_data)
3039{
3040 int ret = 0;
3041 uint8_t lookUpThreshold =
3042 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3043 int rssi = (-1) * lookUpThreshold;
3044 char extra[32];
3045 uint8_t len = 0;
3046
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303047 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003048 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3049 adapter->sessionId, lookUpThreshold));
3050
3051 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303052 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003053 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003054 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055 ret = -EFAULT;
3056 }
3057
3058 return ret;
3059}
3060
3061static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3062 hdd_context_t *hdd_ctx,
3063 uint8_t *command,
3064 uint8_t command_len,
3065 hdd_priv_data_t *priv_data)
3066{
3067 int ret = 0;
3068 uint8_t *value = command;
3069 uint8_t roamScanPeriod = 0;
3070 uint16_t neighborEmptyScanRefreshPeriod =
3071 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3072
3073 /* input refresh period is in terms of seconds */
3074
3075 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3076 value = value + command_len + 1;
3077
3078 /* Convert the value from ascii to integer */
3079 ret = kstrtou8(value, 10, &roamScanPeriod);
3080 if (ret < 0) {
3081 /*
3082 * If the input value is greater than max value of datatype,
3083 * then also kstrtou8 fails
3084 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003085 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3086 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3087 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003088 ret = -EINVAL;
3089 goto exit;
3090 }
3091
3092 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3093 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003094 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3095 roamScanPeriod,
3096 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3097 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003098 ret = -EINVAL;
3099 goto exit;
3100 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303101 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003102 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3103 adapter->sessionId, roamScanPeriod));
3104 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3105
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003106 hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003107 roamScanPeriod);
3108
3109 hdd_ctx->config->nEmptyScanRefreshPeriod =
3110 neighborEmptyScanRefreshPeriod;
3111 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3112 adapter->sessionId,
3113 neighborEmptyScanRefreshPeriod);
3114
3115exit:
3116 return ret;
3117}
3118
3119static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3120 hdd_context_t *hdd_ctx,
3121 uint8_t *command,
3122 uint8_t command_len,
3123 hdd_priv_data_t *priv_data)
3124{
3125 int ret = 0;
3126 uint16_t nEmptyScanRefreshPeriod =
3127 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3128 char extra[32];
3129 uint8_t len = 0;
3130
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303131 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003132 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3133 adapter->sessionId,
3134 nEmptyScanRefreshPeriod));
3135 len = scnprintf(extra, sizeof(extra), "%s %d",
3136 "GETROAMSCANPERIOD",
3137 (nEmptyScanRefreshPeriod / 1000));
3138 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303139 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003140 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003141 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003142 ret = -EFAULT;
3143 }
3144
3145 return ret;
3146}
3147
3148static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3149 hdd_context_t *hdd_ctx,
3150 uint8_t *command,
3151 uint8_t command_len,
3152 hdd_priv_data_t *priv_data)
3153{
3154 int ret = 0;
3155 uint8_t *value = command;
3156 uint8_t roamScanRefreshPeriod = 0;
3157 uint16_t neighborScanRefreshPeriod =
3158 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3159
3160 /* input refresh period is in terms of seconds */
3161 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3162 value = value + command_len + 1;
3163
3164 /* Convert the value from ascii to integer */
3165 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3166 if (ret < 0) {
3167 /*
3168 * If the input value is greater than max value of datatype,
3169 * then also kstrtou8 fails
3170 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003171 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3172 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3173 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003174 ret = -EINVAL;
3175 goto exit;
3176 }
3177
3178 if ((roamScanRefreshPeriod <
3179 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3180 || (roamScanRefreshPeriod >
3181 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003182 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3183 roamScanRefreshPeriod,
3184 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3185 / 1000),
3186 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3187 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003188 ret = -EINVAL;
3189 goto exit;
3190 }
3191 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3192
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003193 hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003194 roamScanRefreshPeriod);
3195
3196 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3197 neighborScanRefreshPeriod;
3198 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3199 adapter->sessionId,
3200 neighborScanRefreshPeriod);
3201
3202exit:
3203 return ret;
3204}
3205
3206static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3207 hdd_context_t *hdd_ctx,
3208 uint8_t *command,
3209 uint8_t command_len,
3210 hdd_priv_data_t *priv_data)
3211{
3212 int ret = 0;
3213 uint16_t value =
3214 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3215 char extra[32];
3216 uint8_t len = 0;
3217
3218 len = scnprintf(extra, sizeof(extra), "%s %d",
3219 "GETROAMSCANREFRESHPERIOD",
3220 (value / 1000));
3221 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303222 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003223 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003224 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003225 ret = -EFAULT;
3226 }
3227
3228 return ret;
3229}
3230
3231static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3232 hdd_context_t *hdd_ctx,
3233 uint8_t *command,
3234 uint8_t command_len,
3235 hdd_priv_data_t *priv_data)
3236{
3237 int ret = 0;
3238 uint8_t *value = command;
3239 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3240
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003241 if (!adapter->fast_roaming_allowed) {
3242 hdd_err("Roaming is always disabled on this interface");
3243 goto exit;
3244 }
3245
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003246 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3247 value = value + SIZE_OF_SETROAMMODE + 1;
3248
3249 /* Convert the value from ascii to integer */
3250 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3251 if (ret < 0) {
3252 /*
3253 * If the input value is greater than max value of datatype,
3254 * then also kstrtou8 fails
3255 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003256 hdd_err("kstrtou8 failed range [%d - %d]",
3257 CFG_LFR_FEATURE_ENABLED_MIN,
3258 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003259 ret = -EINVAL;
3260 goto exit;
3261 }
3262 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3263 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003264 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3265 roamMode,
3266 CFG_LFR_FEATURE_ENABLED_MIN,
3267 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003268 ret = -EINVAL;
3269 goto exit;
3270 }
3271
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003272 hdd_debug("Received Command to Set Roam Mode = %d",
3273 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003274 /*
3275 * Note that
3276 * SETROAMMODE 0 is to enable LFR while
3277 * SETROAMMODE 1 is to disable LFR, but
3278 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3279 * enable/disable. So, we have to invert the value
3280 * to call sme_update_is_fast_roam_ini_feature_enabled.
3281 */
3282 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3283 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3284 else
3285 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3286
3287 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3288 if (roamMode) {
3289 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3290 sme_update_roam_scan_offload_enabled(
3291 (tHalHandle)(hdd_ctx->hHal),
3292 hdd_ctx->config->isRoamOffloadScanEnabled);
3293 sme_update_is_fast_roam_ini_feature_enabled(
3294 hdd_ctx->hHal,
3295 adapter->sessionId,
3296 roamMode);
3297 } else {
3298 sme_update_is_fast_roam_ini_feature_enabled(
3299 hdd_ctx->hHal,
3300 adapter->sessionId,
3301 roamMode);
3302 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3303 sme_update_roam_scan_offload_enabled(
3304 (tHalHandle)(hdd_ctx->hHal),
3305 hdd_ctx->config->isRoamOffloadScanEnabled);
3306 }
3307
3308
3309exit:
3310 return ret;
3311}
3312
3313static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3314 hdd_context_t *hdd_ctx,
3315 uint8_t *command,
3316 uint8_t command_len,
3317 hdd_priv_data_t *priv_data)
3318{
3319 int ret = 0;
3320 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3321 char extra[32];
3322 uint8_t len = 0;
3323
3324 /*
3325 * roamMode value shall be inverted because the sementics is different.
3326 */
3327 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3328 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3329 else
3330 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3331
3332 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303333 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003334 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003335 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003336 ret = -EFAULT;
3337 }
3338
3339 return ret;
3340}
3341
3342static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3343 hdd_context_t *hdd_ctx,
3344 uint8_t *command,
3345 uint8_t command_len,
3346 hdd_priv_data_t *priv_data)
3347{
3348 int ret = 0;
3349 uint8_t *value = command;
3350 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3351
3352 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3353 value = value + command_len + 1;
3354
3355 /* Convert the value from ascii to integer */
3356 ret = kstrtou8(value, 10, &roamRssiDiff);
3357 if (ret < 0) {
3358 /*
3359 * If the input value is greater than max value of datatype,
3360 * then also kstrtou8 fails
3361 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003362 hdd_err("kstrtou8 failed range [%d - %d]",
3363 CFG_ROAM_RSSI_DIFF_MIN,
3364 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003365 ret = -EINVAL;
3366 goto exit;
3367 }
3368
3369 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3370 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003371 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3372 roamRssiDiff,
3373 CFG_ROAM_RSSI_DIFF_MIN,
3374 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003375 ret = -EINVAL;
3376 goto exit;
3377 }
3378
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003379 hdd_info("Received Command to Set roam rssi diff = %d",
3380 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003381
3382 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3383 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3384 adapter->sessionId,
3385 roamRssiDiff);
3386
3387exit:
3388 return ret;
3389}
3390
3391static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3392 hdd_context_t *hdd_ctx,
3393 uint8_t *command,
3394 uint8_t command_len,
3395 hdd_priv_data_t *priv_data)
3396{
3397 int ret = 0;
3398 uint8_t roamRssiDiff =
3399 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3400 char extra[32];
3401 uint8_t len = 0;
3402
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303403 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003404 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3405 adapter->sessionId, roamRssiDiff));
3406
3407 len = scnprintf(extra, sizeof(extra), "%s %d",
3408 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303409 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410
3411 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003412 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413 ret = -EFAULT;
3414 }
3415
3416 return ret;
3417}
3418
3419static int drv_cmd_get_band(hdd_adapter_t *adapter,
3420 hdd_context_t *hdd_ctx,
3421 uint8_t *command,
3422 uint8_t command_len,
3423 hdd_priv_data_t *priv_data)
3424{
3425 int ret = 0;
3426 int band = -1;
3427 char extra[32];
3428 uint8_t len = 0;
3429
3430 hdd_get_band_helper(hdd_ctx, &band);
3431
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303432 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433 TRACE_CODE_HDD_GETBAND_IOCTL,
3434 adapter->sessionId, band));
3435
3436 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303437 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003438
3439 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003440 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003441 ret = -EFAULT;
3442 }
3443
3444 return ret;
3445}
3446
3447static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3448 hdd_context_t *hdd_ctx,
3449 uint8_t *command,
3450 uint8_t command_len,
3451 hdd_priv_data_t *priv_data)
3452{
3453 return hdd_parse_set_roam_scan_channels(adapter, command);
3454}
3455
3456static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3457 hdd_context_t *hdd_ctx,
3458 uint8_t *command,
3459 uint8_t command_len,
3460 hdd_priv_data_t *priv_data)
3461{
3462 int ret = 0;
3463 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3464 uint8_t numChannels = 0;
3465 uint8_t j = 0;
3466 char extra[128] = { 0 };
3467 int len;
3468
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303469 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003470 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3471 ChannelList,
3472 &numChannels,
3473 adapter->sessionId)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003474 hdd_alert("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003475 ret = -EFAULT;
3476 goto exit;
3477 }
3478
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303479 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003480 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3481 adapter->sessionId, numChannels));
3482 /*
3483 * output channel list is of the format
3484 * [Number of roam scan channels][Channel1][Channel2]...
3485 * copy the number of channels in the 0th index
3486 */
3487 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3488 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303489 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003490 len += scnprintf(extra + len, sizeof(extra) - len,
3491 " %d", ChannelList[j]);
3492
Anurag Chouhan6d760662016-02-20 16:05:43 +05303493 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003494 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003495 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003496 ret = -EFAULT;
3497 goto exit;
3498 }
3499
3500exit:
3501 return ret;
3502}
3503
3504static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3505 hdd_context_t *hdd_ctx,
3506 uint8_t *command,
3507 uint8_t command_len,
3508 hdd_priv_data_t *priv_data)
3509{
3510 int ret = 0;
3511 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3512 char extra[32];
3513 uint8_t len = 0;
3514
3515 /*
3516 * Check if the features OKC/ESE/11R are supported simultaneously,
3517 * then this operation is not permitted (return FAILURE)
3518 */
3519 if (eseMode &&
3520 hdd_is_okc_mode_enabled(hdd_ctx) &&
3521 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003522 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003523 ret = -EPERM;
3524 goto exit;
3525 }
3526
3527 len = scnprintf(extra, sizeof(extra), "%s %d",
3528 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303529 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003530 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003531 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003532 ret = -EFAULT;
3533 goto exit;
3534 }
3535
3536exit:
3537 return ret;
3538}
3539
3540static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3541 hdd_context_t *hdd_ctx,
3542 uint8_t *command,
3543 uint8_t command_len,
3544 hdd_priv_data_t *priv_data)
3545{
3546 int ret = 0;
3547 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3548 char extra[32];
3549 uint8_t len = 0;
3550
3551 /*
3552 * Check if the features OKC/ESE/11R are supported simultaneously,
3553 * then this operation is not permitted (return FAILURE)
3554 */
3555 if (okcMode &&
3556 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3557 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003558 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003559 ret = -EPERM;
3560 goto exit;
3561 }
3562
3563 len = scnprintf(extra, sizeof(extra), "%s %d",
3564 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303565 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003566
3567 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003568 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003569 ret = -EFAULT;
3570 goto exit;
3571 }
3572
3573exit:
3574 return ret;
3575}
3576
3577static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3578 hdd_context_t *hdd_ctx,
3579 uint8_t *command,
3580 uint8_t command_len,
3581 hdd_priv_data_t *priv_data)
3582{
3583 int ret = 0;
3584 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3585 char extra[32];
3586 uint8_t len = 0;
3587
3588 len = scnprintf(extra, sizeof(extra), "%s %d",
3589 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303590 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003591
3592 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003593 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003594 ret = -EFAULT;
3595 }
3596
3597 return ret;
3598}
3599
3600static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3601 hdd_context_t *hdd_ctx,
3602 uint8_t *command,
3603 uint8_t command_len,
3604 hdd_priv_data_t *priv_data)
3605{
3606 int ret = 0;
3607 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3608 char extra[32];
3609 uint8_t len = 0;
3610
3611 len = scnprintf(extra, sizeof(extra), "%s %d",
3612 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303613 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003614
3615 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003616 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003617 ret = -EFAULT;
3618 }
3619
3620 return ret;
3621}
3622
3623static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3624 hdd_context_t *hdd_ctx,
3625 uint8_t *command,
3626 uint8_t command_len,
3627 hdd_priv_data_t *priv_data)
3628{
3629 int ret = 0;
3630 uint8_t *value = command;
3631 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3632
3633 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3634 value = value + command_len + 1;
3635
3636 /* Convert the value from ascii to integer */
3637 ret = kstrtou8(value, 10, &minTime);
3638 if (ret < 0) {
3639 /*
3640 * If the input value is greater than max value of datatype,
3641 * then also kstrtou8 fails
3642 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003643 hdd_err("kstrtou8 failed range [%d - %d]",
3644 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3645 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003646 ret = -EINVAL;
3647 goto exit;
3648 }
3649
3650 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3651 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003652 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3653 minTime,
3654 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3655 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003656 ret = -EINVAL;
3657 goto exit;
3658 }
3659
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303660 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003661 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3662 adapter->sessionId, minTime));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003663 hdd_info("Received Command to change channel min time = %d",
3664 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003665
3666 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3667 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3668 minTime,
3669 adapter->sessionId);
3670
3671exit:
3672 return ret;
3673}
3674
3675static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3676 hdd_context_t *hdd_ctx,
3677 uint8_t *command,
3678 uint8_t command_len,
3679 hdd_priv_data_t *priv_data)
3680{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003681 return hdd_parse_sendactionframe(adapter, command,
3682 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003683}
3684
3685static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3686 hdd_context_t *hdd_ctx,
3687 uint8_t *command,
3688 uint8_t command_len,
3689 hdd_priv_data_t *priv_data)
3690{
3691 int ret = 0;
3692 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3693 adapter->sessionId);
3694 char extra[32];
3695 uint8_t len = 0;
3696
3697 /* value is interms of msec */
3698 len = scnprintf(extra, sizeof(extra), "%s %d",
3699 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303700 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003701
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303702 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003703 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3704 adapter->sessionId, val));
3705
3706 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003707 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708 ret = -EFAULT;
3709 }
3710
3711 return ret;
3712}
3713
3714static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3715 hdd_context_t *hdd_ctx,
3716 uint8_t *command,
3717 uint8_t command_len,
3718 hdd_priv_data_t *priv_data)
3719{
3720 int ret = 0;
3721 uint8_t *value = command;
3722 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3723
3724 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3725 value = value + command_len + 1;
3726
3727 /* Convert the value from ascii to integer */
3728 ret = kstrtou16(value, 10, &maxTime);
3729 if (ret < 0) {
3730 /*
3731 * If the input value is greater than max value of datatype,
3732 * then also kstrtou8 fails
3733 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003734 hdd_err("kstrtou16 failed range [%d - %d]",
3735 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3736 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003737 ret = -EINVAL;
3738 goto exit;
3739 }
3740
3741 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3742 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003743 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3744 maxTime,
3745 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3746 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003747 ret = -EINVAL;
3748 goto exit;
3749 }
3750
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003751 hdd_info("Received Command to change channel max time = %d",
3752 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003753
3754 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3755 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3756 adapter->sessionId,
3757 maxTime);
3758
3759exit:
3760 return ret;
3761}
3762
3763static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3764 hdd_context_t *hdd_ctx,
3765 uint8_t *command,
3766 uint8_t command_len,
3767 hdd_priv_data_t *priv_data)
3768{
3769 int ret = 0;
3770 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3771 adapter->sessionId);
3772 char extra[32];
3773 uint8_t len = 0;
3774
3775 /* value is interms of msec */
3776 len = scnprintf(extra, sizeof(extra), "%s %d",
3777 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303778 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003779
3780 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003781 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003782 ret = -EFAULT;
3783 }
3784
3785 return ret;
3786}
3787
3788static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3789 hdd_context_t *hdd_ctx,
3790 uint8_t *command,
3791 uint8_t command_len,
3792 hdd_priv_data_t *priv_data)
3793{
3794 int ret = 0;
3795 uint8_t *value = command;
3796 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3797
3798 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3799 value = value + command_len + 1;
3800
3801 /* Convert the value from ascii to integer */
3802 ret = kstrtou16(value, 10, &val);
3803 if (ret < 0) {
3804 /*
3805 * If the input value is greater than max value of datatype,
3806 * then also kstrtou8 fails
3807 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003808 hdd_err("kstrtou16 failed range [%d - %d]",
3809 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3810 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003811 ret = -EINVAL;
3812 goto exit;
3813 }
3814
3815 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3816 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003817 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3818 val,
3819 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3820 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003821 ret = -EINVAL;
3822 goto exit;
3823 }
3824
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003825 hdd_info("Received Command to change scan home time = %d",
3826 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003827
3828 hdd_ctx->config->nNeighborScanPeriod = val;
3829 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3830 adapter->sessionId, val);
3831
3832exit:
3833 return ret;
3834}
3835
3836static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3837 hdd_context_t *hdd_ctx,
3838 uint8_t *command,
3839 uint8_t command_len,
3840 hdd_priv_data_t *priv_data)
3841{
3842 int ret = 0;
3843 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3844 adapter->
3845 sessionId);
3846 char extra[32];
3847 uint8_t len = 0;
3848
3849 /* value is interms of msec */
3850 len = scnprintf(extra, sizeof(extra), "%s %d",
3851 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303852 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003853
3854 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003855 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003856 ret = -EFAULT;
3857 }
3858
3859 return ret;
3860}
3861
3862static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3863 hdd_context_t *hdd_ctx,
3864 uint8_t *command,
3865 uint8_t command_len,
3866 hdd_priv_data_t *priv_data)
3867{
3868 int ret = 0;
3869 uint8_t *value = command;
3870 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3871
3872 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3873 value = value + command_len + 1;
3874
3875 /* Convert the value from ascii to integer */
3876 ret = kstrtou8(value, 10, &val);
3877 if (ret < 0) {
3878 /*
3879 * If the input value is greater than max value of datatype,
3880 * then also kstrtou8 fails
3881 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003882 hdd_err("kstrtou8 failed range [%d - %d]",
3883 CFG_ROAM_INTRA_BAND_MIN,
3884 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003885 ret = -EINVAL;
3886 goto exit;
3887 }
3888
3889 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3890 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003891 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3892 val,
3893 CFG_ROAM_INTRA_BAND_MIN,
3894 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003895 ret = -EINVAL;
3896 goto exit;
3897 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003898 hdd_info("Received Command to change intra band = %d",
3899 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003900
3901 hdd_ctx->config->nRoamIntraBand = val;
3902 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3903
3904exit:
3905 return ret;
3906}
3907
3908static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3909 hdd_context_t *hdd_ctx,
3910 uint8_t *command,
3911 uint8_t command_len,
3912 hdd_priv_data_t *priv_data)
3913{
3914 int ret = 0;
3915 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3916 char extra[32];
3917 uint8_t len = 0;
3918
3919 /* value is interms of msec */
3920 len = scnprintf(extra, sizeof(extra), "%s %d",
3921 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303922 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003924 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003925 ret = -EFAULT;
3926 }
3927
3928 return ret;
3929}
3930
3931static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3932 hdd_context_t *hdd_ctx,
3933 uint8_t *command,
3934 uint8_t command_len,
3935 hdd_priv_data_t *priv_data)
3936{
3937 int ret = 0;
3938 uint8_t *value = command;
3939 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3940
3941 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3942 value = value + command_len + 1;
3943
3944 /* Convert the value from ascii to integer */
3945 ret = kstrtou8(value, 10, &nProbes);
3946 if (ret < 0) {
3947 /*
3948 * If the input value is greater than max value of datatype,
3949 * then also kstrtou8 fails
3950 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003951 hdd_err("kstrtou8 failed range [%d - %d]",
3952 CFG_ROAM_SCAN_N_PROBES_MIN,
3953 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003954 ret = -EINVAL;
3955 goto exit;
3956 }
3957
3958 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3959 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003960 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3961 nProbes,
3962 CFG_ROAM_SCAN_N_PROBES_MIN,
3963 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003964 ret = -EINVAL;
3965 goto exit;
3966 }
3967
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003968 hdd_info("Received Command to Set nProbes = %d",
3969 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003970
3971 hdd_ctx->config->nProbes = nProbes;
3972 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3973 adapter->sessionId, nProbes);
3974
3975exit:
3976 return ret;
3977}
3978
3979static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3980 hdd_context_t *hdd_ctx,
3981 uint8_t *command,
3982 uint8_t command_len,
3983 hdd_priv_data_t *priv_data)
3984{
3985 int ret = 0;
3986 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3987 char extra[32];
3988 uint8_t len = 0;
3989
3990 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303991 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003992 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003993 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003994 ret = -EFAULT;
3995 }
3996
3997 return ret;
3998}
3999
4000static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4001 hdd_context_t *hdd_ctx,
4002 uint8_t *command,
4003 uint8_t command_len,
4004 hdd_priv_data_t *priv_data)
4005{
4006 int ret = 0;
4007 uint8_t *value = command;
4008 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4009
4010 /* input value is in units of msec */
4011
4012 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4013 value = value + command_len + 1;
4014
4015 /* Convert the value from ascii to integer */
4016 ret = kstrtou16(value, 10, &homeAwayTime);
4017 if (ret < 0) {
4018 /*
4019 * If the input value is greater than max value of datatype,
4020 * then also kstrtou8 fails
4021 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004022 hdd_err("kstrtou8 failed range [%d - %d]",
4023 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4024 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004025 ret = -EINVAL;
4026 goto exit;
4027 }
4028
4029 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4030 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004031 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004032 homeAwayTime,
4033 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4034 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4035 ret = -EINVAL;
4036 goto exit;
4037 }
4038
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004039 hdd_info("Received Command to Set scan away time = %d",
4040 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004041
4042 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4043 homeAwayTime) {
4044 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4045 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4046 adapter->sessionId,
4047 homeAwayTime,
4048 true);
4049 }
4050
4051exit:
4052 return ret;
4053}
4054
4055static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4056 hdd_context_t *hdd_ctx,
4057 uint8_t *command,
4058 uint8_t command_len,
4059 hdd_priv_data_t *priv_data)
4060{
4061 int ret = 0;
4062 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4063 char extra[32];
4064 uint8_t len = 0;
4065
4066 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304067 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004068
4069 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004070 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071 ret = -EFAULT;
4072 }
4073
4074 return ret;
4075}
4076
4077static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4078 hdd_context_t *hdd_ctx,
4079 uint8_t *command,
4080 uint8_t command_len,
4081 hdd_priv_data_t *priv_data)
4082{
4083 return hdd_parse_reassoc(adapter, command);
4084}
4085
4086static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4087 hdd_context_t *hdd_ctx,
4088 uint8_t *command,
4089 uint8_t command_len,
4090 hdd_priv_data_t *priv_data)
4091{
4092 int ret = 0;
4093 uint8_t *value = command;
4094 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4095
4096 /* Move pointer to ahead of SETWESMODE<delimiter> */
4097 value = value + command_len + 1;
4098
4099 /* Convert the value from ascii to integer */
4100 ret = kstrtou8(value, 10, &wesMode);
4101 if (ret < 0) {
4102 /*
4103 * If the input value is greater than max value of datatype,
4104 * then also kstrtou8 fails
4105 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004106 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004107 CFG_ENABLE_WES_MODE_NAME_MIN,
4108 CFG_ENABLE_WES_MODE_NAME_MAX);
4109 ret = -EINVAL;
4110 goto exit;
4111 }
4112
4113 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4114 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004115 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004116 wesMode,
4117 CFG_ENABLE_WES_MODE_NAME_MIN,
4118 CFG_ENABLE_WES_MODE_NAME_MAX);
4119 ret = -EINVAL;
4120 goto exit;
4121 }
4122
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004123 hdd_info("Received Command to Set WES Mode rssi diff = %d",
4124 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004125
4126 hdd_ctx->config->isWESModeEnabled = wesMode;
4127 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4128
4129exit:
4130 return ret;
4131}
4132
4133static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4134 hdd_context_t *hdd_ctx,
4135 uint8_t *command,
4136 uint8_t command_len,
4137 hdd_priv_data_t *priv_data)
4138{
4139 int ret = 0;
4140 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4141 char extra[32];
4142 uint8_t len = 0;
4143
4144 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304145 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004147 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004148 ret = -EFAULT;
4149 }
4150
4151 return ret;
4152}
4153
4154static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4155 hdd_context_t *hdd_ctx,
4156 uint8_t *command,
4157 uint8_t command_len,
4158 hdd_priv_data_t *priv_data)
4159{
4160 int ret = 0;
4161 uint8_t *value = command;
4162 uint8_t nOpportunisticThresholdDiff =
4163 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4164
4165 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4166 value = value + command_len + 1;
4167
4168 /* Convert the value from ascii to integer */
4169 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4170 if (ret < 0) {
4171 /*
4172 * If the input value is greater than max value of datatype,
4173 * then also kstrtou8 fails
4174 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004175 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004176 ret = -EINVAL;
4177 goto exit;
4178 }
4179
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004180 hdd_info("Received Command to Set Opportunistic Threshold diff = %d",
4181 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004182
4183 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4184 adapter->sessionId,
4185 nOpportunisticThresholdDiff);
4186
4187exit:
4188 return ret;
4189}
4190
4191static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4192 hdd_context_t *hdd_ctx,
4193 uint8_t *command,
4194 uint8_t command_len,
4195 hdd_priv_data_t *priv_data)
4196{
4197 int ret = 0;
4198 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4199 hdd_ctx->hHal);
4200 char extra[32];
4201 uint8_t len = 0;
4202
4203 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304204 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004205 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004206 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004207 ret = -EFAULT;
4208 }
4209
4210 return ret;
4211}
4212
4213static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4214 hdd_context_t *hdd_ctx,
4215 uint8_t *command,
4216 uint8_t command_len,
4217 hdd_priv_data_t *priv_data)
4218{
4219 int ret = 0;
4220 uint8_t *value = command;
4221 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4222
4223 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4224 value = value + command_len + 1;
4225
4226 /* Convert the value from ascii to integer */
4227 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4228 if (ret < 0) {
4229 /*
4230 * If the input value is greater than max value of datatype,
4231 * then also kstrtou8 fails
4232 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004233 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004234 ret = -EINVAL;
4235 goto exit;
4236 }
4237
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004238 hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d",
4239 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004240
4241 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4242 adapter->sessionId,
4243 nRoamRescanRssiDiff);
4244
4245exit:
4246 return ret;
4247}
4248
4249static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4250 hdd_context_t *hdd_ctx,
4251 uint8_t *command,
4252 uint8_t command_len,
4253 hdd_priv_data_t *priv_data)
4254{
4255 int ret = 0;
4256 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4257 char extra[32];
4258 uint8_t len = 0;
4259
4260 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304261 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004262 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004263 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004264 ret = -EFAULT;
4265 }
4266
4267 return ret;
4268}
4269
4270static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4271 hdd_context_t *hdd_ctx,
4272 uint8_t *command,
4273 uint8_t command_len,
4274 hdd_priv_data_t *priv_data)
4275{
4276 int ret = 0;
4277 uint8_t *value = command;
4278 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4279
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004280 if (!adapter->fast_roaming_allowed) {
4281 hdd_err("Roaming is always disabled on this interface");
4282 goto exit;
4283 }
4284
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004285 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4286 value = value + command_len + 1;
4287
4288 /* Convert the value from ascii to integer */
4289 ret = kstrtou8(value, 10, &lfrMode);
4290 if (ret < 0) {
4291 /*
4292 * If the input value is greater than max value of datatype,
4293 * then also kstrtou8 fails
4294 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004295 hdd_err("kstrtou8 failed range [%d - %d]",
4296 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004297 CFG_LFR_FEATURE_ENABLED_MAX);
4298 ret = -EINVAL;
4299 goto exit;
4300 }
4301
4302 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4303 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004304 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004305 lfrMode,
4306 CFG_LFR_FEATURE_ENABLED_MIN,
4307 CFG_LFR_FEATURE_ENABLED_MAX);
4308 ret = -EINVAL;
4309 goto exit;
4310 }
4311
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004312 hdd_info("Received Command to change lfr mode = %d",
4313 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004314
4315 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4316 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4317 adapter->
4318 sessionId,
4319 lfrMode);
4320
4321exit:
4322 return ret;
4323}
4324
4325static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4326 hdd_context_t *hdd_ctx,
4327 uint8_t *command,
4328 uint8_t command_len,
4329 hdd_priv_data_t *priv_data)
4330{
4331 int ret = 0;
4332 uint8_t *value = command;
4333 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4334
4335 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4336 value = value + command_len + 1;
4337
4338 /* Convert the value from ascii to integer */
4339 ret = kstrtou8(value, 10, &ft);
4340 if (ret < 0) {
4341 /*
4342 * If the input value is greater than max value of datatype,
4343 * then also kstrtou8 fails
4344 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004345 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004346 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4347 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4348 ret = -EINVAL;
4349 goto exit;
4350 }
4351
4352 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4353 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004354 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355 ft,
4356 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4357 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4358 ret = -EINVAL;
4359 goto exit;
4360 }
4361
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004362 hdd_info("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363
4364 hdd_ctx->config->isFastTransitionEnabled = ft;
4365 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4366
4367exit:
4368 return ret;
4369}
4370
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004371static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4372 hdd_context_t *hdd_ctx,
4373 uint8_t *command,
4374 uint8_t command_len,
4375 hdd_priv_data_t *priv_data)
4376{
4377 int ret = 0;
4378 uint8_t *value = command;
4379 uint8_t channel = 0;
4380 tSirMacAddr targetApBssid;
4381 uint32_t roamId = 0;
4382 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004383 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004384 hdd_station_ctx_t *pHddStaCtx;
4385
Krunal Sonibe766b02016-03-10 13:00:44 -08004386 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004387 hdd_warn("Unsupported in mode %s(%d)",
4388 hdd_device_mode_to_string(adapter->device_mode),
4389 adapter->device_mode);
4390 return -EINVAL;
4391 }
4392
4393 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4394
4395 /* if not associated, no need to proceed with reassoc */
4396 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004397 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004398 ret = -EINVAL;
4399 goto exit;
4400 }
4401
4402 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4403 &channel);
4404 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004405 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004406 goto exit;
4407 }
4408
4409 /*
4410 * if the target bssid is same as currently associated AP,
4411 * issue reassoc to same AP
4412 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004413 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004414 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304415 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004416 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304417 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004418 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304419 targetApBssid,
4420 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304421 } else {
4422 sme_get_modify_profile_fields(hdd_ctx->hHal,
4423 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004424 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304425 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4426 NULL, modProfileFields, &roamId, 1);
4427 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004428 return 0;
4429 }
4430
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304431 /* Check channel number is a valid channel number */
4432 if (QDF_STATUS_SUCCESS !=
4433 wlan_hdd_validate_operation_channel(adapter, channel)) {
4434 hdd_err("Invalid Channel [%d]", channel);
4435 return -EINVAL;
4436 }
4437
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004438 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004439 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004440 targetApBssid, (int)channel);
4441 goto exit;
4442 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004444 handoffInfo.channel = channel;
4445 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004446 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004447 sizeof(tSirMacAddr));
4448 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4449 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004450exit:
4451 return ret;
4452}
4453
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004454static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4455 hdd_context_t *hdd_ctx,
4456 uint8_t *command,
4457 uint8_t command_len,
4458 hdd_priv_data_t *priv_data)
4459{
4460 int ret = 0;
4461 uint8_t *value = command;
4462 uint8_t roamScanControl = 0;
4463
4464 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4465 value = value + command_len + 1;
4466
4467 /* Convert the value from ascii to integer */
4468 ret = kstrtou8(value, 10, &roamScanControl);
4469 if (ret < 0) {
4470 /*
4471 * If the input value is greater than max value of datatype,
4472 * then also kstrtou8 fails
4473 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004474 hdd_err("kstrtou8 failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004475 ret = -EINVAL;
4476 goto exit;
4477 }
4478
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004479 hdd_info("Received Command to Set roam scan control = %d",
4480 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004481
4482 if (0 != roamScanControl) {
4483 ret = 0; /* return success but ignore param value "true" */
4484 goto exit;
4485 }
4486
4487 sme_set_roam_scan_control(hdd_ctx->hHal,
4488 adapter->sessionId,
4489 roamScanControl);
4490
4491exit:
4492 return ret;
4493}
4494
4495static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4496 hdd_context_t *hdd_ctx,
4497 uint8_t *command,
4498 uint8_t command_len,
4499 hdd_priv_data_t *priv_data)
4500{
4501 int ret = 0;
4502 uint8_t *value = command;
4503 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4504
4505 /*
4506 * Check if the features OKC/ESE/11R are supported simultaneously,
4507 * then this operation is not permitted (return FAILURE)
4508 */
4509 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4510 hdd_is_okc_mode_enabled(hdd_ctx) &&
4511 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004512 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004513 ret = -EPERM;
4514 goto exit;
4515 }
4516
4517 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4518 value = value + command_len + 1;
4519
4520 /* Convert the value from ascii to integer */
4521 ret = kstrtou8(value, 10, &okcMode);
4522 if (ret < 0) {
4523 /*
4524 * If the input value is greater than max value of datatype,
4525 * then also kstrtou8 fails
4526 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004527 hdd_err("kstrtou8 failed range [%d - %d]",
4528 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004529 CFG_OKC_FEATURE_ENABLED_MAX);
4530 ret = -EINVAL;
4531 goto exit;
4532 }
4533
4534 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4535 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004536 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004537 okcMode,
4538 CFG_OKC_FEATURE_ENABLED_MIN,
4539 CFG_OKC_FEATURE_ENABLED_MAX);
4540 ret = -EINVAL;
4541 goto exit;
4542 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004543 hdd_info("Received Command to change okc mode = %d",
4544 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004545
4546 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4547
4548exit:
4549 return ret;
4550}
4551
4552static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4553 hdd_context_t *hdd_ctx,
4554 uint8_t *command,
4555 uint8_t command_len,
4556 hdd_priv_data_t *priv_data)
4557{
4558 int ret = 0;
4559 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4560 char extra[32];
4561 uint8_t len = 0;
4562
4563 len = scnprintf(extra, sizeof(extra), "%s %d",
4564 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304565 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004566 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004567 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004568 ret = -EFAULT;
4569 }
4570
4571 return ret;
4572}
4573
4574static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4575 hdd_context_t *hdd_ctx,
4576 uint8_t *command,
4577 uint8_t command_len,
4578 hdd_priv_data_t *priv_data)
4579{
4580 int ret = 0;
4581 char *bcMode;
4582
4583 bcMode = command + 11;
4584 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004585 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004586 hdd_ctx->btCoexModeSet = true;
4587 ret = wlan_hdd_scan_abort(adapter);
4588 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004589 hdd_err("Failed to abort existing scan status: %d",
4590 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004591 }
4592 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004593 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594 hdd_ctx->btCoexModeSet = false;
4595 }
4596
4597 return ret;
4598}
4599
4600static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4601 hdd_context_t *hdd_ctx,
4602 uint8_t *command,
4603 uint8_t command_len,
4604 hdd_priv_data_t *priv_data)
4605{
4606 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4607 return 0;
4608}
4609
4610static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4611 hdd_context_t *hdd_ctx,
4612 uint8_t *command,
4613 uint8_t command_len,
4614 hdd_priv_data_t *priv_data)
4615{
4616 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4617 return 0;
4618}
4619
4620static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4621 hdd_context_t *hdd_ctx,
4622 uint8_t *command,
4623 uint8_t command_len,
4624 hdd_priv_data_t *priv_data)
4625{
4626 int ret = 0;
4627 struct hdd_config *pCfg =
4628 (WLAN_HDD_GET_CTX(adapter))->config;
4629 char extra[32];
4630 uint8_t len = 0;
4631
4632 memset(extra, 0, sizeof(extra));
4633 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304634 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004635 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004636 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637 ret = -EFAULT;
4638 goto exit;
4639 }
4640 ret = len;
4641exit:
4642 return ret;
4643}
4644
4645static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4646 hdd_context_t *hdd_ctx,
4647 uint8_t *command,
4648 uint8_t command_len,
4649 hdd_priv_data_t *priv_data)
4650{
4651 return hdd_set_dwell_time(adapter, command);
4652}
4653
4654static int drv_cmd_miracast(hdd_adapter_t *adapter,
4655 hdd_context_t *hdd_ctx,
4656 uint8_t *command,
4657 uint8_t command_len,
4658 hdd_priv_data_t *priv_data)
4659{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304660 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004661 int ret = 0;
4662 tHalHandle hHal;
4663 uint8_t filterType = 0;
4664 hdd_context_t *pHddCtx = NULL;
4665 uint8_t *value;
4666
4667 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304668 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004670
4671 hHal = pHddCtx->hHal;
4672 value = command + 9;
4673
4674 /* Convert the value from ascii to integer */
4675 ret = kstrtou8(value, 10, &filterType);
4676 if (ret < 0) {
4677 /*
4678 * If the input value is greater than max value of datatype,
4679 * then also kstrtou8 fails
4680 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004681 hdd_err("kstrtou8 failed range ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004682 ret = -EINVAL;
4683 goto exit;
4684 }
4685 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4686 || (filterType >
4687 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004688 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004689 ret = -EINVAL;
4690 goto exit;
4691 }
4692 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4693 pHddCtx->miracast_value = filterType;
4694
4695 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304696 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004697 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004698 return -EBUSY;
4699 }
4700
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004701 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4702 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004703
4704exit:
4705 return ret;
4706}
4707
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004708/* Function header is left blank intentionally */
4709static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4710 int32_t *oui_length, int32_t limit)
4711{
4712 uint8_t len;
4713 uint8_t data;
4714
4715 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4716 command++;
4717 limit--;
4718 }
4719
4720 len = 2;
4721
4722 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4723 (limit > 1)) {
4724 sscanf(command, "%02x", (unsigned int *)&data);
4725 ie[len++] = data;
4726 command += 2;
4727 limit -= 2;
4728 }
4729
4730 *oui_length = len - 2;
4731
4732 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4733 command++;
4734 limit--;
4735 }
4736
4737 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4738 (limit > 1)) {
4739 sscanf(command, "%02x", (unsigned int *)&data);
4740 ie[len++] = data;
4741 command += 2;
4742 limit -= 2;
4743 }
4744
4745 ie[0] = IE_EID_VENDOR;
4746 ie[1] = len - 2;
4747
4748 return len;
4749}
4750
4751/**
4752 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4753 * @adapter: Pointer to adapter
4754 * @hdd_ctx: Pointer to HDD context
4755 * @command: Pointer to command string
4756 * @command_len : Command length
4757 * @priv_data : Pointer to priv data
4758 *
4759 * Return:
4760 * int status code
4761 */
4762static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4763 hdd_context_t *hdd_ctx,
4764 uint8_t *command,
4765 uint8_t command_len,
4766 hdd_priv_data_t *priv_data)
4767{
4768 int i = 0;
4769 int status;
4770 int ret = 0;
4771 uint8_t *ibss_ie;
4772 int32_t oui_length = 0;
4773 uint32_t ibss_ie_length;
4774 uint8_t *value = command;
4775 tSirModifyIE ibssModifyIE;
4776 tCsrRoamProfile *pRoamProfile;
4777 hdd_wext_state_t *pWextState;
4778
4779
Krunal Sonibe766b02016-03-10 13:00:44 -08004780 if (QDF_IBSS_MODE != adapter->device_mode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004781 hdd_info("Device_mode %s(%d) not IBSS",
4782 hdd_device_mode_to_string(adapter->device_mode),
4783 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004784 return ret;
4785 }
4786
4787 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4788
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004789 hdd_info("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004790
4791
4792 /* validate argument of command */
4793 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004794 hdd_err("No arguments in command length %zu",
4795 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004796 ret = -EFAULT;
4797 goto exit;
4798 }
4799
4800 /* moving to arguments of commands */
4801 value = value + command_len;
4802 command_len = strlen(value);
4803
4804 /* oui_data can't be less than 3 bytes */
4805 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004806 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4807 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004808 ret = -EFAULT;
4809 goto exit;
4810 }
4811
4812 ibss_ie = qdf_mem_malloc(command_len);
4813 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004814 hdd_err("Could not allocate memory for command length %d",
4815 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004816 ret = -ENOMEM;
4817 goto exit;
4818 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004819
4820 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4821 &oui_length,
4822 command_len);
4823 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004824 hdd_err("Could not parse command %s return length %d",
4825 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004826 ret = -EFAULT;
4827 qdf_mem_free(ibss_ie);
4828 goto exit;
4829 }
4830
4831 pRoamProfile = &pWextState->roamProfile;
4832
4833 qdf_copy_macaddr(&ibssModifyIE.bssid,
4834 pRoamProfile->BSSIDs.bssid);
4835
4836 ibssModifyIE.smeSessionId = adapter->sessionId;
4837 ibssModifyIE.notify = true;
4838 ibssModifyIE.ieID = IE_EID_VENDOR;
4839 ibssModifyIE.ieIDLen = ibss_ie_length;
4840 ibssModifyIE.ieBufferlength = ibss_ie_length;
4841 ibssModifyIE.pIEBuffer = ibss_ie;
4842 ibssModifyIE.oui_length = oui_length;
4843
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004844 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4845 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004846 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004847 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004848
4849 /* Probe Bcn modification */
4850 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4851 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4852
4853 /* Populating probe resp frame */
4854 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4855 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4856
4857 qdf_mem_free(ibss_ie);
4858
4859 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4860 adapter->sessionId);
4861 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004862 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004863 status);
4864 ret = -EINVAL;
4865 goto exit;
4866 }
4867
4868exit:
4869 return ret;
4870}
4871
4872static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4873 hdd_context_t *hdd_ctx,
4874 uint8_t *command,
4875 uint8_t command_len,
4876 hdd_priv_data_t *priv_data)
4877{
4878 int ret = 0;
4879 uint8_t *value = command;
4880 uint8_t ucRmcEnable = 0;
4881 int status;
4882
Krunal Sonibe766b02016-03-10 13:00:44 -08004883 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4884 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004885 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4886 hdd_device_mode_to_string(adapter->device_mode),
4887 adapter->device_mode);
4888 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004889 ret = -EINVAL;
4890 goto exit;
4891 }
4892
4893 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4894 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004895 hdd_err("Invalid SETRMCENABLE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004896 ret = -EINVAL;
4897 goto exit;
4898 }
4899
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004900 hdd_info("ucRmcEnable %d ", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004901
4902 if (true == ucRmcEnable) {
4903 status = sme_enable_rmc((tHalHandle)
4904 (hdd_ctx->hHal),
4905 adapter->sessionId);
4906 } else if (false == ucRmcEnable) {
4907 status = sme_disable_rmc((tHalHandle)
4908 (hdd_ctx->hHal),
4909 adapter->sessionId);
4910 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004911 hdd_err("Invalid SETRMCENABLE command %d",
4912 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004913 ret = -EINVAL;
4914 goto exit;
4915 }
4916
4917 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004918 hdd_err("SETRMC %d failed status %d",
4919 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004920 ret = -EINVAL;
4921 goto exit;
4922 }
4923
4924exit:
4925 return ret;
4926}
4927
4928static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4929 hdd_context_t *hdd_ctx,
4930 uint8_t *command,
4931 uint8_t command_len,
4932 hdd_priv_data_t *priv_data)
4933{
4934 int ret = 0;
4935 uint8_t *value = command;
4936 uint32_t uActionPeriod = 0;
4937 int status;
4938
Krunal Sonibe766b02016-03-10 13:00:44 -08004939 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4940 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004941 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004942 hdd_device_mode_to_string(adapter->device_mode),
4943 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004944 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004945 ret = -EINVAL;
4946 goto exit;
4947 }
4948
4949 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4950 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004951 hdd_err("Invalid SETRMCACTIONPERIOD command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004952 ret = -EINVAL;
4953 goto exit;
4954 }
4955
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004956 hdd_info("uActionPeriod %d ",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004957 uActionPeriod);
4958
4959 if (sme_cfg_set_int(hdd_ctx->hHal,
4960 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4961 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004962 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4963 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004964 ret = -EINVAL;
4965 goto exit;
4966 }
4967
4968 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4969 adapter->sessionId);
4970 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004971 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004972 status);
4973 ret = -EINVAL;
4974 goto exit;
4975 }
4976
4977exit:
4978 return ret;
4979}
4980
4981static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
4982 hdd_context_t *hdd_ctx,
4983 uint8_t *command,
4984 uint8_t command_len,
4985 hdd_priv_data_t *priv_data)
4986{
4987 int ret = 0;
4988 int status = QDF_STATUS_SUCCESS;
4989 hdd_station_ctx_t *pHddStaCtx = NULL;
4990 char *extra = NULL;
4991 int idx = 0;
4992 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004993 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004994 uint32_t numOfBytestoPrint = 0;
4995
Krunal Sonibe766b02016-03-10 13:00:44 -08004996 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004997 hdd_warn("Unsupported in mode %s(%d)",
4998 hdd_device_mode_to_string(adapter->device_mode),
4999 adapter->device_mode);
5000 return -EINVAL;
5001 }
5002
5003 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005004 hdd_info("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005005
5006 /* Handle the command */
5007 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5008 if (QDF_STATUS_SUCCESS == status) {
5009 /*
5010 * The variable extra needed to be allocated on the heap since
5011 * amount of memory required to copy the data for 32 devices
5012 * exceeds the size of 1024 bytes of default stack size. On
5013 * 64 bit devices, the default max stack size of 2048 bytes
5014 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005015 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005016
5017 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005018 hdd_err("memory allocation failed");
5019 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005020 goto exit;
5021 }
5022
5023 /* Copy number of stations */
5024 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005025 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005026 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005027 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5028 idx++) {
5029 int8_t rssi;
5030 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005031
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005032 qdf_mem_copy(mac_addr,
5033 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5034 mac_addr, sizeof(mac_addr));
5035
5036 tx_rate =
5037 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5038 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305039 /*
5040 * Only lower 3 bytes are rate info. Mask of the MSByte
5041 */
5042 tx_rate &= 0x00FFFFFF;
5043
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005044 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5045 rssi;
5046
5047 length += scnprintf((extra + length),
5048 WLAN_MAX_BUF_SIZE - length,
5049 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5050 mac_addr[0], mac_addr[1], mac_addr[2],
5051 mac_addr[3], mac_addr[4], mac_addr[5],
5052 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005053 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005054 * cdf_trace_msg has limitation of 512 bytes for the
5055 * print buffer. Hence printing the data in two chunks.
5056 * The first chunk will have the data for 16 devices
5057 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005058 */
5059 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5060 numOfBytestoPrint = length;
5061 }
5062
5063 /*
5064 * Copy the data back into buffer, if the data to copy is
5065 * more than 512 bytes than we will split the data and do
5066 * it in two shots
5067 */
5068 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005069 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005070 ret = -EFAULT;
5071 goto exit;
5072 }
5073
5074 priv_data->buf[numOfBytestoPrint] = '\0';
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005075 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005076
5077 if (length > numOfBytestoPrint) {
5078 if (copy_to_user
5079 (priv_data->buf + numOfBytestoPrint,
5080 extra + numOfBytestoPrint,
5081 length - numOfBytestoPrint + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005082 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005083 ret = -EFAULT;
5084 goto exit;
5085 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005086 hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005087 }
5088
5089 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005090 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005091 } else {
5092 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005093 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5094 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005095 ret = -EINVAL;
5096 goto exit;
5097 }
5098 ret = 0;
5099
5100exit:
5101 return ret;
5102}
5103
5104/* Peer Info <Peer Addr> command */
5105static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5106 hdd_context_t *hdd_ctx,
5107 uint8_t *command,
5108 uint8_t command_len,
5109 hdd_priv_data_t *priv_data)
5110{
5111 int ret = 0;
5112 uint8_t *value = command;
5113 QDF_STATUS status;
5114 hdd_station_ctx_t *pHddStaCtx = NULL;
5115 char extra[128] = { 0 };
5116 uint32_t length = 0;
5117 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005118 struct qdf_mac_addr peerMacAddr;
5119
Krunal Sonibe766b02016-03-10 13:00:44 -08005120 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005121 hdd_warn("Unsupported in mode %s(%d)",
5122 hdd_device_mode_to_string(adapter->device_mode),
5123 adapter->device_mode);
5124 return -EINVAL;
5125 }
5126
5127 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5128
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005129 hdd_info("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005130
5131 /* if there are no peers, no need to continue with the command */
5132 if (eConnectionState_IbssConnected !=
5133 pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005134 hdd_info("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005135 ret = -EINVAL;
5136 goto exit;
5137 }
5138
5139 /* Parse the incoming command buffer */
5140 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5141 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005142 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005143 ret = -EINVAL;
5144 goto exit;
5145 }
5146
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005147 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005148 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005149
Naveen Rawatc45d1622016-07-05 12:20:09 -07005150 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005151 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005152 ret = -EINVAL;
5153 goto exit;
5154 }
5155
5156 /* Handle the command */
5157 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5158 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005159 uint32_t txRate =
5160 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305161 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5162 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005163
5164 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005165 (int)txRate,
5166 (int)pHddStaCtx->ibss_peer_info.
5167 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005168
5169 /* Copy the data back into buffer */
5170 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005171 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005172 ret = -EFAULT;
5173 goto exit;
5174 }
5175 } else {
5176 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005177 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5178 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005179 ret = -EINVAL;
5180 goto exit;
5181 }
5182
5183 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005184 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005185 ret = 0;
5186
5187exit:
5188 return ret;
5189}
5190
5191static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5192 hdd_context_t *hdd_ctx,
5193 uint8_t *command,
5194 uint8_t command_len,
5195 hdd_priv_data_t *priv_data)
5196{
5197 int ret = 0;
5198 uint8_t *value = command;
5199 uint32_t uRate = 0;
5200 tTxrateinfoflags txFlags = 0;
5201 tSirRateUpdateInd rateUpdateParams = {0};
5202 int status;
5203 struct hdd_config *pConfig = hdd_ctx->config;
5204
Krunal Sonibe766b02016-03-10 13:00:44 -08005205 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5206 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005207 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5208 hdd_device_mode_to_string(adapter->device_mode),
5209 adapter->device_mode);
5210 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005211 ret = -EINVAL;
5212 goto exit;
5213 }
5214
5215 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5216 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005217 hdd_err("Invalid SETRMCTXRATE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005218 ret = -EINVAL;
5219 goto exit;
5220 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005221 hdd_info("uRate %d ", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005222 /* -1 implies ignore this param */
5223 rateUpdateParams.ucastDataRate = -1;
5224
5225 /*
5226 * Fill the user specifieed RMC rate param
5227 * and the derived tx flags.
5228 */
5229 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5230 rateUpdateParams.reliableMcastDataRate = uRate;
5231 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5232 rateUpdateParams.dev_mode = adapter->device_mode;
5233 rateUpdateParams.bcastDataRate = -1;
5234 memcpy(rateUpdateParams.bssid.bytes,
5235 adapter->macAddressCurrent.bytes,
5236 sizeof(rateUpdateParams.bssid));
5237 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5238 &rateUpdateParams);
5239
5240exit:
5241 return ret;
5242}
5243
5244static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5245 hdd_context_t *hdd_ctx,
5246 uint8_t *command,
5247 uint8_t command_len,
5248 hdd_priv_data_t *priv_data)
5249{
5250 int ret = 0;
5251 char *value;
5252 uint8_t tx_fail_count = 0;
5253 uint16_t pid = 0;
5254
5255 value = command;
5256
5257 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5258
5259 if (0 != ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005260 hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005261 goto exit;
5262 }
5263
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005264 hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005265
5266 if (0 == tx_fail_count) {
5267 /* Disable TX Fail Indication */
5268 if (QDF_STATUS_SUCCESS ==
5269 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5270 tx_fail_count,
5271 NULL)) {
5272 cesium_pid = 0;
5273 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005274 hdd_err("failed to disable TX Fail Event ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005275 ret = -EINVAL;
5276 }
5277 } else {
5278 if (QDF_STATUS_SUCCESS ==
5279 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5280 tx_fail_count,
5281 (void *)hdd_tx_fail_ind_callback)) {
5282 cesium_pid = pid;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005283 hdd_info("Registered Cesium pid %u",
5284 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005285 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005286 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005287 ret = -EINVAL;
5288 }
5289 }
5290
5291exit:
5292 return ret;
5293}
5294
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005295#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005296static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5297 hdd_context_t *hdd_ctx,
5298 uint8_t *command,
5299 uint8_t command_len,
5300 hdd_priv_data_t *priv_data)
5301{
5302 int ret = 0;
5303 uint8_t *value = command;
5304 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5305 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305306 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005307
5308 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5309 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005310 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005311 goto exit;
5312 }
5313 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005314 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005315 numChannels,
5316 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5317 ret = -EINVAL;
5318 goto exit;
5319 }
5320 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5321 adapter->sessionId,
5322 ChannelList,
5323 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305324 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005325 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005326 ret = -EINVAL;
5327 goto exit;
5328 }
5329
5330exit:
5331 return ret;
5332}
5333
5334static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5335 hdd_context_t *hdd_ctx,
5336 uint8_t *command,
5337 uint8_t command_len,
5338 hdd_priv_data_t *priv_data)
5339{
5340 int ret = 0;
5341 uint8_t *value = command;
5342 char extra[128] = { 0 };
5343 int len = 0;
5344 uint8_t tid = 0;
5345 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005346 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005347
Krunal Sonibe766b02016-03-10 13:00:44 -08005348 if ((QDF_STA_MODE != adapter->device_mode) &&
5349 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005350 hdd_warn("Unsupported in mode %s(%d)",
5351 hdd_device_mode_to_string(adapter->device_mode),
5352 adapter->device_mode);
5353 return -EINVAL;
5354 }
5355
5356 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5357
5358 /* if not associated, return error */
5359 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005360 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005361 ret = -EINVAL;
5362 goto exit;
5363 }
5364
5365 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5366 value = value + command_len + 1;
5367
5368 /* Convert the value from ascii to integer */
5369 ret = kstrtou8(value, 10, &tid);
5370 if (ret < 0) {
5371 /*
5372 * If the input value is greater than max value of datatype,
5373 * then also kstrtou8 fails
5374 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005375 hdd_err("kstrtou8 failed range [%d - %d]",
5376 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005377 TID_MAX_VALUE);
5378 ret = -EINVAL;
5379 goto exit;
5380 }
5381 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005382 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005383 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5384 ret = -EINVAL;
5385 goto exit;
5386 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005387 hdd_info("Received Command to get tsm stats tid = %d",
5388 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005389 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5390 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005391 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005392 goto exit;
5393 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005394 hdd_info(
5395 "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 -08005396 tsm_metrics.UplinkPktQueueDly,
5397 tsm_metrics.UplinkPktQueueDlyHist[0],
5398 tsm_metrics.UplinkPktQueueDlyHist[1],
5399 tsm_metrics.UplinkPktQueueDlyHist[2],
5400 tsm_metrics.UplinkPktQueueDlyHist[3],
5401 tsm_metrics.UplinkPktTxDly,
5402 tsm_metrics.UplinkPktLoss,
5403 tsm_metrics.UplinkPktCount,
5404 tsm_metrics.RoamingCount,
5405 tsm_metrics.RoamingDly);
5406 /*
5407 * Output TSM stats is of the format
5408 * GETTSMSTATS [PktQueueDly]
5409 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5410 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5411 */
5412 len = scnprintf(extra,
5413 sizeof(extra),
5414 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5415 command,
5416 tsm_metrics.UplinkPktQueueDly,
5417 tsm_metrics.UplinkPktQueueDlyHist[0],
5418 tsm_metrics.UplinkPktQueueDlyHist[1],
5419 tsm_metrics.UplinkPktQueueDlyHist[2],
5420 tsm_metrics.UplinkPktQueueDlyHist[3],
5421 tsm_metrics.UplinkPktTxDly,
5422 tsm_metrics.UplinkPktLoss,
5423 tsm_metrics.UplinkPktCount,
5424 tsm_metrics.RoamingCount,
5425 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305426 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005427 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005428 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005429 ret = -EFAULT;
5430 goto exit;
5431 }
5432
5433exit:
5434 return ret;
5435}
5436
5437static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5438 hdd_context_t *hdd_ctx,
5439 uint8_t *command,
5440 uint8_t command_len,
5441 hdd_priv_data_t *priv_data)
5442{
5443 int ret;
5444 uint8_t *value = command;
5445 uint8_t *cckmIe = NULL;
5446 uint8_t cckmIeLen = 0;
5447
5448 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5449 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005450 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005451 goto exit;
5452 }
5453
5454 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005455 hdd_err("CCKM Ie input length is more than max[%d]",
5456 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005457 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305458 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005459 cckmIe = NULL;
5460 }
5461 ret = -EINVAL;
5462 goto exit;
5463 }
5464
5465 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5466 cckmIe, cckmIeLen);
5467 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305468 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005469 cckmIe = NULL;
5470 }
5471
5472exit:
5473 return ret;
5474}
5475
5476static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5477 hdd_context_t *hdd_ctx,
5478 uint8_t *command,
5479 uint8_t command_len,
5480 hdd_priv_data_t *priv_data)
5481{
5482 int ret;
5483 uint8_t *value = command;
5484 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305485 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005486
Krunal Sonibe766b02016-03-10 13:00:44 -08005487 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005488 hdd_warn("Unsupported in mode %s(%d)",
5489 hdd_device_mode_to_string(adapter->device_mode),
5490 adapter->device_mode);
5491 return -EINVAL;
5492 }
5493
5494 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5495 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005496 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005497 goto exit;
5498 }
5499
5500 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005501 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005502 hdd_indicate_ese_bcn_report_no_results(adapter,
5503 eseBcnReq.bcnReq[0].measurementToken,
5504 0x02, /* BIT(1) set for measurement done */
5505 0); /* no BSS */
5506 goto exit;
5507 }
5508
5509 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5510 adapter->sessionId,
5511 &eseBcnReq);
5512
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305513 if (QDF_STATUS_E_RESOURCES == status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005514 hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress",
5515 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005516 ret = -EBUSY;
5517 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305518 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005519 hdd_err("sme_set_ese_beacon_request failed (%d)",
5520 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005521 ret = -EINVAL;
5522 goto exit;
5523 }
5524
5525exit:
5526 return ret;
5527}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005528
5529/**
5530 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5531 * @adapter: Pointer to the HDD adapter
5532 * @hdd_ctx: Pointer to the HDD context
5533 * @command: Driver command string
5534 * @command_len: Driver command string length
5535 * @priv_data: Private data coming with the driver command. Unused here
5536 *
5537 * This function handles driver command that sets the ESE PLM request
5538 *
5539 * Return: 0 on success; negative errno otherwise
5540 */
5541static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5542 hdd_context_t *hdd_ctx,
5543 uint8_t *command,
5544 uint8_t command_len,
5545 hdd_priv_data_t *priv_data)
5546{
5547 int ret = 0;
5548 uint8_t *value = command;
5549 QDF_STATUS status = QDF_STATUS_SUCCESS;
5550 tpSirPlmReq pPlmRequest = NULL;
5551
5552 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5553 if (NULL == pPlmRequest) {
5554 ret = -ENOMEM;
5555 goto exit;
5556 }
5557
5558 status = hdd_parse_plm_cmd(value, pPlmRequest);
5559 if (QDF_STATUS_SUCCESS != status) {
5560 qdf_mem_free(pPlmRequest);
5561 pPlmRequest = NULL;
5562 ret = -EINVAL;
5563 goto exit;
5564 }
5565 pPlmRequest->sessionId = adapter->sessionId;
5566
5567 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5568 if (QDF_STATUS_SUCCESS != status) {
5569 qdf_mem_free(pPlmRequest);
5570 pPlmRequest = NULL;
5571 ret = -EINVAL;
5572 goto exit;
5573 }
5574
5575exit:
5576 return ret;
5577}
5578
5579/**
5580 * drv_cmd_set_ccx_mode() - Set ESE mode
5581 * @adapter: Pointer to the HDD adapter
5582 * @hdd_ctx: Pointer to the HDD context
5583 * @command: Driver command string
5584 * @command_len: Driver command string length
5585 * @priv_data: Private data coming with the driver command. Unused here
5586 *
5587 * This function handles driver command that sets ESE mode
5588 *
5589 * Return: 0 on success; negative errno otherwise
5590 */
5591static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5592 hdd_context_t *hdd_ctx,
5593 uint8_t *command,
5594 uint8_t command_len,
5595 hdd_priv_data_t *priv_data)
5596{
5597 int ret = 0;
5598 uint8_t *value = command;
5599 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5600
5601 /*
5602 * Check if the features OKC/ESE/11R are supported simultaneously,
5603 * then this operation is not permitted (return FAILURE)
5604 */
5605 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5606 hdd_is_okc_mode_enabled(hdd_ctx) &&
5607 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5608 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5609 ret = -EPERM;
5610 goto exit;
5611 }
5612
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005613 if (!adapter->fast_roaming_allowed) {
5614 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5615 ret = -EPERM;
5616 goto exit;
5617 }
5618
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005619 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5620 value = value + command_len + 1;
5621
5622 /* Convert the value from ascii to integer */
5623 ret = kstrtou8(value, 10, &eseMode);
5624 if (ret < 0) {
5625 /*
5626 * If the input value is greater than max value of datatype,
5627 * then also kstrtou8 fails
5628 */
5629 hdd_err("kstrtou8 failed range [%d - %d]",
5630 CFG_ESE_FEATURE_ENABLED_MIN,
5631 CFG_ESE_FEATURE_ENABLED_MAX);
5632 ret = -EINVAL;
5633 goto exit;
5634 }
5635
5636 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5637 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5638 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5639 eseMode,
5640 CFG_ESE_FEATURE_ENABLED_MIN,
5641 CFG_ESE_FEATURE_ENABLED_MAX);
5642 ret = -EINVAL;
5643 goto exit;
5644 }
5645 hdd_info("Received Command to change ese mode = %d", eseMode);
5646
5647 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5648 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5649 adapter->sessionId,
5650 eseMode);
5651
5652exit:
5653 return ret;
5654}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005655#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005656
5657static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5658 hdd_context_t *hdd_ctx,
5659 uint8_t *command,
5660 uint8_t command_len,
5661 hdd_priv_data_t *priv_data)
5662{
5663 int ret = 0;
5664 uint8_t *value = command;
5665 int targetRate;
5666
5667 /* input value is in units of hundred kbps */
5668
5669 /* Move pointer to ahead of SETMCRATE<delimiter> */
5670 value = value + command_len + 1;
5671
5672 /* Convert the value from ascii to integer, decimal base */
5673 ret = kstrtouint(value, 10, &targetRate);
5674
5675 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5676 return ret;
5677}
5678
5679static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5680 hdd_context_t *hdd_ctx,
5681 uint8_t *command,
5682 uint8_t command_len,
5683 hdd_priv_data_t *priv_data)
5684{
5685 int ret = 0;
5686 int status;
5687 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305688 QDF_STATUS qdf_status;
5689 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005690 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305691 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5692 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005693 hdd_adapter_list_node_t *pAdapterNode = NULL;
5694 hdd_adapter_list_node_t *pNext = NULL;
5695
5696 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5697 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005698 hdd_err("Invalid MAXTXPOWER command ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005699 ret = -EINVAL;
5700 goto exit;
5701 }
5702
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305703 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005704 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305705 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005706 adapter = pAdapterNode->pAdapter;
5707 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305708 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005709 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305710 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005711 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005712
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005713 hdd_info("Device mode %d max tx power %d selfMac: "
5714 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005715 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005716 MAC_ADDR_ARRAY(selfMac.bytes),
5717 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005718
Srinivas Girigowda97215232015-09-24 12:26:28 -07005719 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5720 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305721 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005722 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005723 ret = -EINVAL;
5724 goto exit;
5725 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005726 hdd_info("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305727 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005728 &pNext);
5729 pAdapterNode = pNext;
5730 }
5731
5732exit:
5733 return ret;
5734}
5735
5736static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5737 hdd_context_t *hdd_ctx,
5738 uint8_t *command,
5739 uint8_t command_len,
5740 hdd_priv_data_t *priv_data)
5741{
5742 int ret = 0;
5743 uint8_t *value = command;
5744 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5745
5746 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5747 value = value + command_len + 1;
5748
5749 /* Convert the value from ascii to integer */
5750 ret = kstrtou8(value, 10, &dfsScanMode);
5751 if (ret < 0) {
5752 /*
5753 * If the input value is greater than max value of datatype,
5754 * then also kstrtou8 fails
5755 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005756 hdd_err("kstrtou8 failed range [%d - %d]",
5757 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005758 CFG_ROAMING_DFS_CHANNEL_MAX);
5759 ret = -EINVAL;
5760 goto exit;
5761 }
5762
5763 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5764 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005765 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005766 dfsScanMode,
5767 CFG_ROAMING_DFS_CHANNEL_MIN,
5768 CFG_ROAMING_DFS_CHANNEL_MAX);
5769 ret = -EINVAL;
5770 goto exit;
5771 }
5772
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005773 hdd_info("Received Command to Set DFS Scan Mode = %d",
5774 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005775
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005776 /* When DFS scanning is disabled, the DFS channels need to be
5777 * removed from the operation of device.
5778 */
5779 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5780 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5781 if (ret < 0) {
5782 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005783 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005784 goto exit;
5785 }
5786
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005787 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5788 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5789 dfsScanMode);
5790
5791exit:
5792 return ret;
5793}
5794
5795static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5796 hdd_context_t *hdd_ctx,
5797 uint8_t *command,
5798 uint8_t command_len,
5799 hdd_priv_data_t *priv_data)
5800{
5801 int ret = 0;
5802 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5803 char extra[32];
5804 uint8_t len = 0;
5805
5806 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305807 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005808 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005809 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005810 ret = -EFAULT;
5811 }
5812
5813 return ret;
5814}
5815
5816static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5817 hdd_context_t *hdd_ctx,
5818 uint8_t *command,
5819 uint8_t command_len,
5820 hdd_priv_data_t *priv_data)
5821{
5822 int ret = 0;
5823 int value = wlan_hdd_get_link_status(adapter);
5824 char extra[32];
5825 uint8_t len;
5826
5827 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305828 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005829 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005830 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005831 ret = -EFAULT;
5832 }
5833
5834 return ret;
5835}
5836
5837#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5838static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5839 hdd_context_t *hdd_ctx,
5840 uint8_t *command,
5841 uint8_t command_len,
5842 hdd_priv_data_t *priv_data)
5843{
5844 uint8_t *value = command;
5845 int set_value;
5846
5847 /* Move pointer to ahead of ENABLEEXTWOW */
5848 value = value + command_len;
5849
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305850 if (!(sscanf(value, "%d", &set_value))) {
5851 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5852 ("No input identified"));
5853 return -EINVAL;
5854 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005855
5856 return hdd_enable_ext_wow_parser(adapter,
5857 adapter->sessionId,
5858 set_value);
5859}
5860
5861static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5862 hdd_context_t *hdd_ctx,
5863 uint8_t *command,
5864 uint8_t command_len,
5865 hdd_priv_data_t *priv_data)
5866{
5867 int ret;
5868 uint8_t *value = command;
5869
5870 /* Move pointer to ahead of SETAPP1PARAMS */
5871 value = value + command_len;
5872
5873 ret = hdd_set_app_type1_parser(adapter,
5874 value, strlen(value));
5875 if (ret >= 0)
5876 hdd_ctx->is_extwow_app_type1_param_set = true;
5877
5878 return ret;
5879}
5880
5881static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5882 hdd_context_t *hdd_ctx,
5883 uint8_t *command,
5884 uint8_t command_len,
5885 hdd_priv_data_t *priv_data)
5886{
5887 int ret;
5888 uint8_t *value = command;
5889
5890 /* Move pointer to ahead of SETAPP2PARAMS */
5891 value = value + command_len;
5892
5893 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5894 if (ret >= 0)
5895 hdd_ctx->is_extwow_app_type2_param_set = true;
5896
5897 return ret;
5898}
5899#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5900
5901#ifdef FEATURE_WLAN_TDLS
5902/**
5903 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5904 * @adapter: Pointer to the HDD adapter
5905 * @hdd_ctx: Pointer to the HDD context
5906 * @command: Driver command string
5907 * @command_len: Driver command string length
5908 * @priv_data: Private data coming with the driver command. Unused here
5909 *
5910 * This function handles driver command that sets the secondary tdls off channel
5911 * offset
5912 *
5913 * Return: 0 on success; negative errno otherwise
5914 */
5915static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5916 hdd_context_t *hdd_ctx,
5917 uint8_t *command,
5918 uint8_t command_len,
5919 hdd_priv_data_t *priv_data)
5920{
5921 int ret;
5922 uint8_t *value = command;
5923 int set_value;
5924
5925 /* Move pointer to point the string */
5926 value += command_len;
5927
5928 ret = sscanf(value, "%d", &set_value);
5929 if (ret != 1)
5930 return -EINVAL;
5931
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005932 hdd_info("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005933
5934 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5935
5936 return ret;
5937}
5938
5939/**
5940 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5941 * @adapter: Pointer to the HDD adapter
5942 * @hdd_ctx: Pointer to the HDD context
5943 * @command: Driver command string
5944 * @command_len: Driver command string length
5945 * @priv_data: Private data coming with the driver command. Unused here
5946 *
5947 * This function handles driver command that sets tdls off channel mode
5948 *
5949 * Return: 0 on success; negative errno otherwise
5950 */
5951static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5952 hdd_context_t *hdd_ctx,
5953 uint8_t *command,
5954 uint8_t command_len,
5955 hdd_priv_data_t *priv_data)
5956{
5957 int ret;
5958 uint8_t *value = command;
5959 int set_value;
5960
5961 /* Move pointer to point the string */
5962 value += command_len;
5963
5964 ret = sscanf(value, "%d", &set_value);
5965 if (ret != 1)
5966 return -EINVAL;
5967
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005968 hdd_info("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005969
5970 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5971
5972 return ret;
5973}
5974
5975/**
5976 * drv_cmd_tdls_off_channel() - set tdls off channel number
5977 * @adapter: Pointer to the HDD adapter
5978 * @hdd_ctx: Pointer to the HDD context
5979 * @command: Driver command string
5980 * @command_len: Driver command string length
5981 * @priv_data: Private data coming with the driver command. Unused here
5982 *
5983 * This function handles driver command that sets tdls off channel number
5984 *
5985 * Return: 0 on success; negative errno otherwise
5986 */
5987static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5988 hdd_context_t *hdd_ctx,
5989 uint8_t *command,
5990 uint8_t command_len,
5991 hdd_priv_data_t *priv_data)
5992{
5993 int ret;
5994 uint8_t *value = command;
5995 int set_value;
5996
5997 /* Move pointer to point the string */
5998 value += command_len;
5999
6000 ret = sscanf(value, "%d", &set_value);
6001 if (ret != 1)
6002 return -EINVAL;
6003
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006004 if (CDS_IS_DFS_CH(set_value)) {
6005 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6006 set_value);
6007 return -EINVAL;
6008 }
6009
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006010 hdd_info("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006011
6012 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6013
6014 return ret;
6015}
6016
6017/**
6018 * drv_cmd_tdls_scan() - set tdls scan type
6019 * @adapter: Pointer to the HDD adapter
6020 * @hdd_ctx: Pointer to the HDD context
6021 * @command: Driver command string
6022 * @command_len: Driver command string length
6023 * @priv_data: Private data coming with the driver command. Unused here
6024 *
6025 * This function handles driver command that sets tdls scan type
6026 *
6027 * Return: 0 on success; negative errno otherwise
6028 */
6029static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6030 hdd_context_t *hdd_ctx,
6031 uint8_t *command,
6032 uint8_t command_len,
6033 hdd_priv_data_t *priv_data)
6034{
6035 int ret;
6036 uint8_t *value = command;
6037 int set_value;
6038
6039 /* Move pointer to point the string */
6040 value += command_len;
6041
6042 ret = sscanf(value, "%d", &set_value);
6043 if (ret != 1)
6044 return -EINVAL;
6045
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006046 hdd_info("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006047
6048 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6049
6050 return ret;
6051}
6052#endif
6053
6054static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6055 hdd_context_t *hdd_ctx,
6056 uint8_t *command,
6057 uint8_t command_len,
6058 hdd_priv_data_t *priv_data)
6059{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006060 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006061 int8_t rssi = 0;
6062 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006063
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006064 uint8_t len = 0;
6065
6066 wlan_hdd_get_rssi(adapter, &rssi);
6067
6068 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306069 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006070
6071 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006072 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006073 ret = -EFAULT;
6074 }
6075
6076 return ret;
6077}
6078
6079static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6080 hdd_context_t *hdd_ctx,
6081 uint8_t *command,
6082 uint8_t command_len,
6083 hdd_priv_data_t *priv_data)
6084{
6085 int ret;
6086 uint32_t link_speed = 0;
6087 char extra[32];
6088 uint8_t len = 0;
6089
6090 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6091 if (0 != ret)
6092 return ret;
6093
6094 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306095 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006096 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006097 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006098 ret = -EFAULT;
6099 }
6100
6101 return ret;
6102}
6103
6104#ifdef FEATURE_NAPI
6105/**
6106 * hdd_parse_napi() - helper functions to drv_cmd_napi
6107 * @str : source string to parse
6108 * @cmd : pointer to cmd part after parsing
6109 * @sub : pointer to subcmd part after parsing
6110 * @aux : pointer to optional aux part after parsing
6111 *
6112 * Example:
6113 * NAPI SCALE <n> +-- IN str
6114 * | | +------ OUT aux
6115 * | +------------ OUT subcmd
6116 * +----------------- OUT cmd
6117 *
6118 * Return: ==0: success; !=0: failure
6119 */
6120static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6121{
6122 int rc;
6123 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6124
6125 NAPI_DEBUG("-->\n");
6126
6127 token = strsep(str, " \t");
6128 if (NULL == token) {
6129 hdd_err("cannot parse cmd");
6130 goto parse_end;
6131 }
6132 lcmd = token;
6133
6134 token = strsep(str, " \t");
6135 if (NULL == token) {
6136 hdd_err("cannot parse subcmd");
6137 goto parse_end;
6138 }
6139 lsub = token;
6140
6141 token = strsep(str, " \t");
6142 if (NULL == token)
6143 hdd_warn("cannot parse aux\n");
6144 else
6145 laux = token;
6146
6147parse_end:
6148 if ((NULL == lcmd) || (NULL == lsub))
6149 rc = -EINVAL;
6150 else {
6151 rc = 0;
6152 *cmd = lcmd;
6153 *sub = lsub;
6154 if (NULL != aux)
6155 *aux = laux;
6156 }
6157 NAPI_DEBUG("<--[rc=%d]\n", rc);
6158 return rc;
6159}
6160
6161
6162/**
6163 * hdd_parse_stats() - print NAPI stats into a buffer
6164 * @buf : buffer to write stats into
6165 * @max : "size of buffer"
6166 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6167 * @napid: binary structure to retrieve the stats from
6168 *
6169 * Return: number of bytes written into the buffer
6170 */
6171int hdd_napi_stats(char *buf,
6172 int max,
6173 char *indp,
6174 struct qca_napi_data *napid)
6175{
6176 int n = 0;
6177 int i, j, k; /* NAPI, CPU, bucket indices */
6178 int from, to;
6179 struct qca_napi_info *napii;
6180 struct qca_napi_stat *napis;
6181
6182 NAPI_DEBUG("-->\n");
6183
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006184 if (NULL == napid)
6185 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006186 if (NULL == indp) {
6187 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006188 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006189 } else {
6190 if (0 > kstrtoint(indp, 10, &to)) {
6191 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006192 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006193 } else
6194 from = to;
6195 }
6196
6197 for (i = from; i < to; i++)
6198 if (napid->ce_map & (0x01 << i)) {
6199 napii = &(napid->napis[i]);
6200 for (j = 0; j < NR_CPUS; j++) {
6201 napis = &(napii->stats[j]);
6202 n += scnprintf(buf + n, max - n,
6203 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6204 i, j,
6205 napis->napi_schedules,
6206 napis->napi_polls,
6207 napis->napi_completes,
6208 napis->napi_workdone);
6209
6210 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6211 n += scnprintf(
6212 buf + n, max - n,
6213 " %d",
6214 napis->napi_budget_uses[k]);
6215 }
6216 n += scnprintf(buf+n, max - n, "\n");
6217 }
6218 }
6219
6220 NAPI_DEBUG("<--[n=%d]\n", n);
6221 return n;
6222}
6223
6224/**
6225 * napi_set_scale() - sets the scale attribute in all NAPI entries
6226 * @sc : scale to set
6227 *
6228 * Return: void
6229 */
6230static void napi_set_scale(uint8_t sc)
6231{
6232 uint32_t i;
6233 struct qca_napi_data *napi_data;
6234
6235 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006236 if (likely(NULL != napi_data))
6237 for (i = 0; i < CE_COUNT_MAX; i++)
6238 if (napi_data->ce_map & (0x01 << i))
6239 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006240
6241 return;
6242}
6243/**
6244 * drv_cmd_napi() - processes NAPI commands
6245 * @adapter : net_device
6246 * @hdd_ctx : HDD context
6247 * @command : command string from user command (including "NAPI")
6248 * @command_len: length of command
6249 * @priv_data : ifr_data
6250 *
6251 * Commands supported:
6252 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6253 * enable NAPI functionally, as some other conditions
6254 * may not have been satisfied yet
6255 * NAPI DISABLE : reverse operation of "enable"
6256 * NAPI STATUS : get global status of NAPI instances
6257 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6258 * NAPI SCALE <n> : set the scale factor
6259 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006260 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006261 */
6262static int drv_cmd_napi(hdd_adapter_t *adapter,
6263 hdd_context_t *hdd_ctx,
6264 uint8_t *command,
6265 uint8_t command_len,
6266 hdd_priv_data_t *priv_data)
6267{
6268 int rc = 0;
6269 int n, l;
6270 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6271 char *synopsis = "NAPI ENABLE\n"
6272 "NAPI DISABLE\n"
6273 "NAPI STATUS\n"
6274 "NAPI STATS [<n>] -- if no <n> then all\n"
6275 "NAPI SCALE <n> -- set the scale\n";
6276 char *reply = NULL;
6277
6278 /* make a local copy, as strsep modifies the str in place */
6279 char *str = NULL;
6280
6281 NAPI_DEBUG("-->\n");
6282
6283 /**
6284 * NOTE TO MAINTAINER: from this point to the end of the function,
6285 * please do not return anywhere in the code except the very end
6286 * to avoid memory leakage (goto end_drv_napi instead)
6287 * or make sure that reply+str is freed
6288 */
6289 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6290 if (NULL == reply) {
6291 hdd_err("could not allocate reply buffer");
6292 rc = -ENOMEM;
6293 goto end_drv_napi;
6294 }
6295
6296 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6297 if (NULL == str) {
6298 hdd_err("could not allocate copy of input buffer");
6299 rc = -ENOMEM;
6300 goto end_drv_napi;
6301 }
6302
6303 strlcpy(str, command, strlen(command) + 1);
6304 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6305 cmd, subcmd, aux);
6306
6307
6308 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6309
6310 if (0 != rc) {
6311 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306312 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006313 strlen(msg)+strlen(synopsis));
6314 n = scnprintf(reply, l, msg, synopsis);
6315
6316 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306317 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006318 hdd_err("failed to copy data to user buffer");
6319 hdd_debug("reply: %s", reply);
6320
6321 rc = -EINVAL;
6322 } else {
6323 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6324 cmd, subcmd, aux);
6325 if (!strcmp(subcmd, "ENABLE"))
6326 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6327 else if (!strcmp(subcmd, "DISABLE"))
6328 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6329 else if (!strcmp(subcmd, "STATUS")) {
6330 int n = 0;
6331 uint32_t i;
6332 struct qca_napi_data *napi_data;
6333
6334 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006335 if (unlikely(NULL == napi_data))
6336 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006337 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6338 "NAPI state: 0x%08x map: 0x%08x\n",
6339 napi_data->state,
6340 napi_data->ce_map);
6341
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006342 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006343 if (napi_data->ce_map & (0x01 << i)) {
6344 n += scnprintf(
6345 reply + n,
6346 MAX_USER_COMMAND_SIZE - n,
6347 "#%d: id: %d, scale=%d\n",
6348 i,
6349 napi_data->napis[i].id,
6350 napi_data->napis[i].scale);
6351 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006352 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006353 hdd_info("wlan: STATUS DATA:\n%s", reply);
6354 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306355 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006356 rc = -EINVAL;
6357 } else if (!strcmp(subcmd, "STATS")) {
6358 int n = 0;
6359 struct qca_napi_data *napi_data;
6360
6361 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006362 if (NULL != napi_data) {
6363 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6364 aux, napi_data);
6365 NAPI_DEBUG("STATS: returns %d\n", n);
6366 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006367 if (n > 0) {
6368 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306369 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006370 n)))
6371 rc = -EINVAL;
6372 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6373 } else
6374 rc = -EINVAL;
6375 } else if (!strcmp(subcmd, "SCALE")) {
6376 if (NULL == aux) {
6377 rc = -EINVAL;
6378 hdd_err("wlan: SCALE cmd requires <n>");
6379 } else {
6380 uint8_t sc;
6381 rc = kstrtou8(aux, 10, &sc);
6382 if (rc) {
6383 hdd_err("wlan: bad scale (%s)", aux);
6384 rc = -EINVAL;
6385 } else
6386 napi_set_scale(sc);
6387 }
6388 } /* SCALE */
6389 }
6390end_drv_napi:
6391 if (NULL != str)
6392 kfree(str);
6393 if (NULL != reply)
6394 kfree(reply);
6395
6396 NAPI_DEBUG("<--[rc=%d]\n", rc);
6397 return rc;
6398}
6399#endif /* FEATURE_NAPI */
6400
6401/**
6402 * hdd_set_rx_filter() - set RX filter
6403 * @adapter: Pointer to adapter
6404 * @action: Filter action
6405 * @pattern: Address pattern
6406 *
6407 * Address pattern is most significant byte of address for example
6408 * 0x01 for IPV4 multicast address
6409 * 0x33 for IPV6 multicast address
6410 * 0xFF for broadcast address
6411 *
6412 * Return: 0 for success, non-zero for failure
6413 */
6414static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6415 uint8_t pattern)
6416{
6417 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006418 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006419 tHalHandle handle;
6420 tSirRcvFltMcAddrList *filter;
6421 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6422
6423 ret = wlan_hdd_validate_context(hdd_ctx);
6424 if (0 != ret)
6425 return ret;
6426
6427 handle = hdd_ctx->hHal;
6428
6429 if (NULL == handle) {
6430 hdd_err("HAL Handle is NULL");
6431 return -EINVAL;
6432 }
6433
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306434 if (!hdd_ctx->config->fEnableMCAddrList) {
6435 hdd_notice("mc addr ini is disabled");
6436 return -EINVAL;
6437 }
6438
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006439 /*
6440 * If action is false it means start dropping packets
6441 * Set addr_filter_pattern which will be used when sending
6442 * MC/BC address list to target
6443 */
6444 if (!action)
6445 adapter->addr_filter_pattern = pattern;
6446 else
6447 adapter->addr_filter_pattern = 0;
6448
Krunal Sonibe766b02016-03-10 13:00:44 -08006449 if (((adapter->device_mode == QDF_STA_MODE) ||
6450 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006451 adapter->mc_addr_list.mc_cnt &&
6452 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6453
6454
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306455 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006456 if (NULL == filter) {
6457 hdd_err("Could not allocate Memory");
6458 return -ENOMEM;
6459 }
6460 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006461 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006462 if (!memcmp(adapter->mc_addr_list.addr[i],
6463 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006464 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006465 adapter->mc_addr_list.addr[i],
6466 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006467
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006468 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006469 MAC_ADDRESS_STR,
6470 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006471 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6472 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006473 }
6474 }
Frank Liuf95e8132016-09-29 19:01:30 +08006475 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006476 /* Set rx filter */
6477 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306478 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006479 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006480 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006481 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6482 }
6483
6484 return 0;
6485}
6486
6487/**
6488 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6489 * @command: Pointer to input string driver command
6490 * @adapter: Pointer to adapter
6491 * @action: Action to enable/disable filtering
6492 *
6493 * If action == false
6494 * Start filtering out data packets based on type
6495 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6496 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6497 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6498 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6499 *
6500 * if action == true
6501 * Stop filtering data packets based on type
6502 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6503 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6504 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6505 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6506 *
6507 * Current implementation only supports IPV4 address filtering by
6508 * selectively allowing IPV4 multicast data packest based on
6509 * address list received in .ndo_set_rx_mode
6510 *
6511 * Return: 0 for success, non-zero for failure
6512 */
6513static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6514 hdd_adapter_t *adapter,
6515 bool action)
6516{
6517 int ret = 0;
6518 uint8_t *value;
6519 uint8_t type;
6520
6521 value = command;
6522 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6523 if (!action)
6524 value = command + 16;
6525 else
6526 value = command + 13;
6527 ret = kstrtou8(value, 10, &type);
6528 if (ret < 0) {
6529 hdd_err("kstrtou8 failed invalid input value %d", type);
6530 return -EINVAL;
6531 }
6532
6533 switch (type) {
6534 case 2:
6535 /* Set rx filter for IPV4 multicast data packets */
6536 ret = hdd_set_rx_filter(adapter, action, 0x01);
6537 break;
6538 default:
6539 hdd_info("Unsupported RXFILTER type %d", type);
6540 break;
6541 }
6542
6543 return ret;
6544}
6545
6546/**
6547 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6548 * @adapter: Pointer to network adapter
6549 * @hdd_ctx: Pointer to hdd context
6550 * @command: Pointer to input command
6551 * @command_len: Command length
6552 * @priv_data: Pointer to private data in command
6553 */
6554static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6555 hdd_context_t *hdd_ctx,
6556 uint8_t *command,
6557 uint8_t command_len,
6558 hdd_priv_data_t *priv_data)
6559{
6560 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6561}
6562
6563/**
6564 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6565 * @adapter: Pointer to network adapter
6566 * @hdd_ctx: Pointer to hdd context
6567 * @command: Pointer to input command
6568 * @command_len: Command length
6569 * @priv_data: Pointer to private data in command
6570 */
6571static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6572 hdd_context_t *hdd_ctx,
6573 uint8_t *command,
6574 uint8_t command_len,
6575 hdd_priv_data_t *priv_data)
6576{
6577 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6578}
6579
Archana Ramachandran393f3792015-11-13 17:13:21 -08006580/**
6581 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6582 * command
6583 * @value: Pointer to SETANTENNAMODE command
6584 * @mode: Pointer to antenna mode
6585 * @reason: Pointer to reason for set antenna mode
6586 *
6587 * This function parses the SETANTENNAMODE command passed in the format
6588 * SETANTENNAMODE<space>mode
6589 *
6590 * Return: 0 for success non-zero for failure
6591 */
6592static int hdd_parse_setantennamode_command(const uint8_t *value)
6593{
6594 const uint8_t *in_ptr = value;
6595 int tmp, v;
6596 char arg1[32];
6597
6598 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6599
6600 /* no argument after the command */
6601 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006602 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006603 return -EINVAL;
6604 }
6605
6606 /* no space after the command */
6607 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006608 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006609 return -EINVAL;
6610 }
6611
6612 /* remove empty spaces */
6613 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6614 in_ptr++;
6615
6616 /* no argument followed by spaces */
6617 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006618 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006619 return -EINVAL;
6620 }
6621
6622 /* get the argument i.e. antenna mode */
6623 v = sscanf(in_ptr, "%31s ", arg1);
6624 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006625 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006626 return -EINVAL;
6627 }
6628
6629 v = kstrtos32(arg1, 10, &tmp);
6630 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006631 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006632 return -EINVAL;
6633 }
6634
6635 return tmp;
6636}
6637
6638/**
6639 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6640 * mask is 2x2 mode
6641 * @hdd_ctx: Pointer to hdd contex
6642 *
6643 * Return: true if supported chain mask 2x2 else false
6644 */
6645static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6646{
6647 /*
6648 * Revisit and the update logic to determine the number
6649 * of TX/RX chains supported in the system when
6650 * antenna sharing per band chain mask support is
6651 * brought in
6652 */
6653 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6654}
6655
6656/**
6657 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6658 * chain mask is 1x1
6659 * @hdd_ctx: Pointer to hdd contex
6660 *
6661 * Return: true if supported chain mask 1x1 else false
6662 */
6663static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6664{
6665 /*
6666 * Revisit and update the logic to determine the number
6667 * of TX/RX chains supported in the system when
6668 * antenna sharing per band chain mask support is
6669 * brought in
6670 */
6671 return (!hdd_ctx->config->enable2x2) ? true : false;
6672}
6673
6674/**
6675 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6676 * handler
6677 * @adapter: Pointer to network adapter
6678 * @hdd_ctx: Pointer to hdd context
6679 * @command: Pointer to input command
6680 * @command_len: Command length
6681 * @priv_data: Pointer to private data in command
6682 */
6683static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6684 hdd_context_t *hdd_ctx,
6685 uint8_t *command,
6686 uint8_t command_len,
6687 hdd_priv_data_t *priv_data)
6688{
6689 struct sir_antenna_mode_param params;
6690 QDF_STATUS status;
6691 int ret = 0;
6692 int mode;
6693 uint8_t *value = command;
6694 uint8_t smps_mode;
6695 uint8_t smps_enable;
6696
6697 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6698 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6699 hdd_err("Operation invalid in non sta or concurrent mode");
6700 ret = -EPERM;
6701 goto exit;
6702 }
6703
6704 mode = hdd_parse_setantennamode_command(value);
6705 if (mode < 0) {
6706 hdd_err("Invalid SETANTENNA command");
6707 ret = mode;
6708 goto exit;
6709 }
6710
6711 hdd_info("Processing antenna mode switch to: %d", mode);
6712
6713 if (hdd_ctx->current_antenna_mode == mode) {
6714 hdd_err("System already in the requested mode");
6715 ret = 0;
6716 goto exit;
6717 }
6718
6719 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6720 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6721 hdd_err("System does not support 2x2 mode");
6722 ret = -EPERM;
6723 goto exit;
6724 }
6725
6726 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6727 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6728 hdd_err("System only supports 1x1 mode");
6729 ret = 0;
6730 goto exit;
6731 }
6732
6733 switch (mode) {
6734 case HDD_ANTENNA_MODE_1X1:
6735 params.num_rx_chains = 1;
6736 params.num_tx_chains = 1;
6737 break;
6738 case HDD_ANTENNA_MODE_2X2:
6739 params.num_rx_chains = 2;
6740 params.num_tx_chains = 2;
6741 break;
6742 default:
6743 hdd_err("unsupported antenna mode");
6744 ret = -EINVAL;
6745 goto exit;
6746 }
6747
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006748 /* Check TDLS status and update antenna mode */
6749 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006750 policy_mgr_is_sta_active_connection_exists(
6751 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006752 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6753 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006754 if (0 != ret)
6755 goto exit;
6756 }
6757
Archana Ramachandran393f3792015-11-13 17:13:21 -08006758 params.set_antenna_mode_resp =
6759 (void *)wlan_hdd_soc_set_antenna_mode_cb;
6760 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
6761 params.num_rx_chains,
6762 params.num_tx_chains);
6763
6764
6765 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6766 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6767 if (QDF_STATUS_SUCCESS != status) {
6768 hdd_err("set antenna mode failed status : %d", status);
6769 ret = -EFAULT;
6770 goto exit;
6771 }
6772
6773 ret = wait_for_completion_timeout(
6774 &hdd_ctx->set_antenna_mode_cmpl,
6775 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6776 if (!ret) {
6777 ret = -EFAULT;
6778 hdd_err("send set antenna mode timed out");
6779 goto exit;
6780 }
6781
6782 /* Update SME SMPS config */
6783 if (HDD_ANTENNA_MODE_1X1 == mode) {
6784 smps_enable = true;
6785 smps_mode = HDD_SMPS_MODE_STATIC;
6786 } else {
6787 smps_enable = false;
6788 smps_mode = HDD_SMPS_MODE_DISABLED;
6789 }
6790
6791 hdd_info("Update SME SMPS enable: %d mode: %d",
6792 smps_enable, smps_mode);
6793 status = sme_update_mimo_power_save(
6794 hdd_ctx->hHal, smps_enable, smps_mode, false);
6795 if (QDF_STATUS_SUCCESS != status) {
6796 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6797 smps_enable, smps_mode, status);
6798 ret = -EFAULT;
6799 goto exit;
6800 }
6801
Archana Ramachandran393f3792015-11-13 17:13:21 -08006802 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006803 /* Update the user requested nss in the mac context.
6804 * This will be used in tdls protocol engine to form tdls
6805 * Management frames.
6806 */
6807 sme_update_user_configured_nss(
6808 hdd_ctx->hHal,
6809 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006810
Archana Ramachandran5041b252016-04-25 14:29:25 -07006811 hdd_info("Successfully switched to mode: %d x %d",
6812 hdd_ctx->current_antenna_mode,
6813 hdd_ctx->current_antenna_mode);
6814 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006815exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006816#ifdef FEATURE_WLAN_TDLS
6817 /* Reset tdls NSS flags */
6818 if (hdd_ctx->tdls_nss_switch_in_progress &&
6819 hdd_ctx->tdls_nss_teardown_complete) {
6820 hdd_ctx->tdls_nss_switch_in_progress = false;
6821 hdd_ctx->tdls_nss_teardown_complete = false;
6822 }
6823 hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
6824 hdd_ctx->tdls_nss_switch_in_progress,
6825 hdd_ctx->tdls_nss_teardown_complete);
6826#endif
Archana Ramachandran393f3792015-11-13 17:13:21 -08006827 hdd_info("Set antenna status: %d current mode: %d",
6828 ret, hdd_ctx->current_antenna_mode);
6829 return ret;
6830
6831}
6832
6833/**
6834 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6835 * handler
6836 * @adapter: Pointer to hdd adapter
6837 * @hdd_ctx: Pointer to hdd context
6838 * @command: Pointer to input command
6839 * @command_len: length of the command
6840 * @priv_data: private data coming with the driver command
6841 *
6842 * Return: 0 for success non-zero for failure
6843 */
6844static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6845 hdd_context_t *hdd_ctx,
6846 uint8_t *command,
6847 uint8_t command_len,
6848 hdd_priv_data_t *priv_data)
6849{
6850 uint32_t antenna_mode = 0;
6851 char extra[32];
6852 uint8_t len = 0;
6853
6854 antenna_mode = hdd_ctx->current_antenna_mode;
6855 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6856 antenna_mode);
6857 len = QDF_MIN(priv_data->total_len, len + 1);
6858 if (copy_to_user(priv_data->buf, &extra, len)) {
6859 hdd_err("Failed to copy data to user buffer");
6860 return -EFAULT;
6861 }
6862
6863 hdd_info("Get antenna mode: %d", antenna_mode);
6864
6865 return 0;
6866}
6867
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006868/*
6869 * dummy (no-op) hdd driver command handler
6870 */
6871static int drv_cmd_dummy(hdd_adapter_t *adapter,
6872 hdd_context_t *hdd_ctx,
6873 uint8_t *command,
6874 uint8_t command_len,
6875 hdd_priv_data_t *priv_data)
6876{
6877 hdd_info("%s: Ignoring driver command \"%s\"",
6878 adapter->dev->name, command);
6879 return 0;
6880}
6881
6882/*
6883 * handler for any unsupported wlan hdd driver command
6884 */
6885static int drv_cmd_invalid(hdd_adapter_t *adapter,
6886 hdd_context_t *hdd_ctx,
6887 uint8_t *command,
6888 uint8_t command_len,
6889 hdd_priv_data_t *priv_data)
6890{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306891 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006892 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6893 adapter->sessionId, 0));
6894
6895 hdd_warn("%s: Unsupported driver command \"%s\"",
6896 adapter->dev->name, command);
6897
6898 return -ENOTSUPP;
6899}
6900
6901/**
6902 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6903 * @adapter: HDD adapter
6904 * @hdd_ctx: HDD context
6905 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6906 * @command_len: command len
6907 * @priv_data: private data
6908 *
6909 * Return: status
6910 */
6911static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6912 hdd_context_t *hdd_ctx,
6913 uint8_t *command,
6914 uint8_t command_len,
6915 hdd_priv_data_t *priv_data)
6916{
6917 uint8_t *value;
6918 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306919 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006920 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006921 int ret = 0;
6922
6923 /*
6924 * this command would be called by user-space when it detects WLAN
6925 * ON after airplane mode is set. When APM is set, WLAN turns off.
6926 * But it can be turned back on. Otherwise; when APM is turned back
6927 * off, WLAN would turn back on. So at that point the command is
6928 * expected to come down. 0 means disable, 1 means enable. The
6929 * constraint is removed when parameter 1 is set or different
6930 * country code is set
6931 */
6932
6933 value = command + command_len + 1;
6934
6935 ret = kstrtou8(value, 10, &fcc_constraint);
6936 if ((ret < 0) || (fcc_constraint > 1)) {
6937 /*
6938 * If the input value is greater than max value of datatype,
6939 * then also it is a failure
6940 */
6941 hdd_err("value out of range");
6942 return -EINVAL;
6943 }
Sandeep Puligillad0004212017-02-26 18:34:56 -08006944#ifndef NAPIER_SCAN
6945 /* This code will be removed*/
Amar Singhal83a047a2016-05-19 15:56:11 -07006946 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
Sandeep Puligillad0004212017-02-26 18:34:56 -08006947#else
6948 scan_pending = ucfg_scan_get_pdev_status(hdd_ctx->hdd_pdev);
6949#endif
Amar Singhal83a047a2016-05-19 15:56:11 -07006950 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6951 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306952 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006953 hdd_err("sme disable fn. returned err");
6954 ret = -EPERM;
6955 }
6956
6957 return ret;
6958}
6959
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306960/**
6961 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6962 * command
6963 * @value: Pointer to the command
6964 * @chan_number: Pointer to the channel number
6965 * @chan_bw: Pointer to the channel bandwidth
6966 *
6967 * Parses and provides the channel number and channel width from the input
6968 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6969 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6970 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6971 *
6972 * Return: 0 for success, non-zero for failure
6973 */
6974static int hdd_parse_set_channel_switch_command(uint8_t *value,
6975 uint32_t *chan_number,
6976 uint32_t *chan_bw)
6977{
6978 const uint8_t *in_ptr = value;
6979 int ret;
6980
6981 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6982
6983 /* no argument after the command */
6984 if (NULL == in_ptr) {
6985 hdd_err("No argument after the command");
6986 return -EINVAL;
6987 }
6988
6989 /* no space after the command */
6990 if (SPACE_ASCII_VALUE != *in_ptr) {
6991 hdd_err("No space after the command ");
6992 return -EINVAL;
6993 }
6994
6995 /* remove empty spaces and move the next argument */
6996 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6997 in_ptr++;
6998
6999 /* no argument followed by spaces */
7000 if ('\0' == *in_ptr) {
7001 hdd_err("No argument followed by spaces");
7002 return -EINVAL;
7003 }
7004
7005 /* get the two arguments: channel number and bandwidth */
7006 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7007 if (ret != 2) {
7008 hdd_err("Arguments retrieval from cmd string failed");
7009 return -EINVAL;
7010 }
7011
7012 return 0;
7013}
7014
7015/**
7016 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7017 * @adapter: HDD adapter
7018 * @hdd_ctx: HDD context
7019 * @command: Pointer to the input command CHANNEL_SWITCH
7020 * @command_len: Command len
7021 * @priv_data: Private data
7022 *
7023 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7024 * of SAP/P2P-GO
7025 *
7026 * Return: 0 for success, non-zero for failure
7027 */
7028static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
7029 hdd_context_t *hdd_ctx,
7030 uint8_t *command,
7031 uint8_t command_len,
7032 hdd_priv_data_t *priv_data)
7033{
7034 struct net_device *dev = adapter->dev;
7035 int status;
7036 uint32_t chan_number = 0, chan_bw = 0;
7037 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007038 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307039
Krunal Sonibe766b02016-03-10 13:00:44 -08007040 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7041 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307042 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7043 adapter->device_mode);
7044 return -EINVAL;
7045 }
7046
7047 status = hdd_parse_set_channel_switch_command(value,
7048 &chan_number, &chan_bw);
7049 if (status) {
7050 hdd_err("Invalid CHANNEL_SWITCH command");
7051 return status;
7052 }
7053
7054 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7055 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7056 return -EINVAL;
7057 }
7058
7059 if (chan_bw == 80)
7060 width = CH_WIDTH_80MHZ;
7061 else if (chan_bw == 40)
7062 width = CH_WIDTH_40MHZ;
7063 else
7064 width = CH_WIDTH_20MHZ;
7065
7066 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
7067
7068 status = hdd_softap_set_channel_change(dev, chan_number, width);
7069 if (status) {
7070 hdd_err("Set channel change fail");
7071 return status;
7072 }
7073
7074 return 0;
7075}
7076
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007077/*
7078 * The following table contains all supported WLAN HDD
7079 * IOCTL driver commands and the handler for each of them.
7080 */
7081static const hdd_drv_cmd_t hdd_drv_cmds[] = {
7082 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
7083 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
7084 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
7085 {"SETBAND", drv_cmd_set_band},
7086 {"SETWMMPS", drv_cmd_set_wmmps},
7087 {"COUNTRY", drv_cmd_country},
7088 {"SETSUSPENDMODE", drv_cmd_dummy},
7089 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
7090 {"BTCOEXSCAN", drv_cmd_dummy},
7091 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007092 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
7093 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
7094 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
7095 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
7096 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
7097 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007098 {"SETROAMMODE", drv_cmd_set_roam_mode},
7099 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007100 {"SETROAMDELTA", drv_cmd_set_roam_delta},
7101 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007102 {"GETBAND", drv_cmd_get_band},
7103 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
7104 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
7105 {"GETCCXMODE", drv_cmd_get_ccx_mode},
7106 {"GETOKCMODE", drv_cmd_get_okc_mode},
7107 {"GETFASTROAM", drv_cmd_get_fast_roam},
7108 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
7109 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
7110 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
7111 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
7112 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
7113 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
7114 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
7115 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
7116 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
7117 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
7118 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
7119 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
7120 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
7121 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7122 {"REASSOC", drv_cmd_reassoc},
7123 {"SETWESMODE", drv_cmd_set_wes_mode},
7124 {"GETWESMODE", drv_cmd_get_wes_mode},
7125 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7126 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7127 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7128 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007129 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007130 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7131 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007132 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007133 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007134 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7135 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7136 {"SCAN-ACTIVE", drv_cmd_scan_active},
7137 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7138 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7139 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7140 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007141 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7142 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7143 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7144 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7145 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7146 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7147 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007148#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007149 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7150 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7151 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07007152 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
7153 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
7154 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007155#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007156 {"SETMCRATE", drv_cmd_set_mc_rate},
7157 {"MAXTXPOWER", drv_cmd_max_tx_power},
7158 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7159 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7160 {"GETLINKSTATUS", drv_cmd_get_link_status},
7161#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7162 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7163 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7164 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7165#endif
7166#ifdef FEATURE_WLAN_TDLS
7167 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7168 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7169 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7170 {"TDLSSCAN", drv_cmd_tdls_scan},
7171#endif
7172 {"RSSI", drv_cmd_get_rssi},
7173 {"LINKSPEED", drv_cmd_get_linkspeed},
7174#ifdef FEATURE_NAPI
7175 {"NAPI", drv_cmd_napi},
7176#endif /* FEATURE_NAPI */
7177 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7178 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7179 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307180 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007181 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7182 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007183};
7184
7185/**
7186 * hdd_drv_cmd_process() - chooses and runs the proper
7187 * handler based on the input command
7188 * @adapter: Pointer to the hdd adapter
7189 * @cmd: Pointer to the driver command
7190 * @priv_data: Pointer to the data associated with the command
7191 *
7192 * This function parses the input hdd driver command and runs
7193 * the proper handler
7194 *
7195 * Return: 0 for success non-zero for failure
7196 */
7197static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7198 uint8_t *cmd,
7199 hdd_priv_data_t *priv_data)
7200{
7201 hdd_context_t *hdd_ctx;
7202 int i;
7203 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7204 uint8_t *cmd_i = NULL;
7205 hdd_drv_cmd_handler_t handler = NULL;
7206 int len = 0;
7207
7208 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007209 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007210 return -EINVAL;
7211 }
7212
7213 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7214
7215 for (i = 0; i < cmd_num_total; i++) {
7216
7217 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7218 handler = hdd_drv_cmds[i].handler;
7219 len = strlen(cmd_i);
7220
7221 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007222 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007223 return -EINVAL;
7224 }
7225
7226 if (strncasecmp(cmd, cmd_i, len) == 0)
7227 return handler(adapter, hdd_ctx,
7228 cmd, len, priv_data);
7229 }
7230
7231 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7232}
7233
7234/**
7235 * hdd_driver_command() - top level wlan hdd driver command handler
7236 * @adapter: Pointer to the hdd adapter
7237 * @priv_data: Pointer to the raw command data
7238 *
7239 * This function is the top level wlan hdd driver command handler. It
7240 * handles the command with the help of hdd_drv_cmd_process()
7241 *
7242 * Return: 0 for success non-zero for failure
7243 */
7244static int hdd_driver_command(hdd_adapter_t *adapter,
7245 hdd_priv_data_t *priv_data)
7246{
7247 uint8_t *command = NULL;
7248 int ret = 0;
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05307249 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007250
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307251 ENTER();
7252
Anurag Chouhan6d760662016-02-20 16:05:43 +05307253 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007254 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007255 return -EINVAL;
7256 }
7257
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05307258 ret = wlan_hdd_validate_context(hdd_ctx);
7259 if (ret)
7260 return ret;
7261
7262 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
7263 hdd_err("Driver module is closed; command can not be processed");
7264 return -EINVAL;
7265 }
7266
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007267 /*
7268 * Note that valid pointers are provided by caller
7269 */
7270
7271 /* copy to local struct to avoid numerous changes to legacy code */
7272 if (priv_data->total_len <= 0 ||
7273 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007274 hdd_warn("Invalid priv_data.total_len(%d)!!!",
7275 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007276 ret = -EINVAL;
7277 goto exit;
7278 }
7279
7280 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007281 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007282 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007283 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007284 ret = -ENOMEM;
7285 goto exit;
7286 }
7287
7288 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7289 ret = -EFAULT;
7290 goto exit;
7291 }
7292
7293 /* Make sure the command is NUL-terminated */
7294 command[priv_data->total_len] = '\0';
7295
7296 hdd_info("%s: %s", adapter->dev->name, command);
7297 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7298
7299exit:
7300 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007301 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307302 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007303 return ret;
7304}
7305
7306#ifdef CONFIG_COMPAT
7307static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7308{
7309 struct {
7310 compat_uptr_t buf;
7311 int used_len;
7312 int total_len;
7313 } compat_priv_data;
7314 hdd_priv_data_t priv_data;
7315 int ret = 0;
7316
7317 /*
7318 * Note that adapter and ifr have already been verified by caller,
7319 * and HDD context has also been validated
7320 */
7321 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7322 sizeof(compat_priv_data))) {
7323 ret = -EFAULT;
7324 goto exit;
7325 }
7326 priv_data.buf = compat_ptr(compat_priv_data.buf);
7327 priv_data.used_len = compat_priv_data.used_len;
7328 priv_data.total_len = compat_priv_data.total_len;
7329 ret = hdd_driver_command(adapter, &priv_data);
7330exit:
7331 return ret;
7332}
7333#else /* CONFIG_COMPAT */
7334static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7335{
7336 /* will never be invoked */
7337 return 0;
7338}
7339#endif /* CONFIG_COMPAT */
7340
7341static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7342{
7343 hdd_priv_data_t priv_data;
7344 int ret = 0;
7345
7346 /*
7347 * Note that adapter and ifr have already been verified by caller,
7348 * and HDD context has also been validated
7349 */
7350 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7351 ret = -EFAULT;
7352 else
7353 ret = hdd_driver_command(adapter, &priv_data);
7354
7355 return ret;
7356}
7357
7358/**
7359 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7360 * @dev: device upon which the ioctl was received
7361 * @ifr: ioctl request information
7362 * @cmd: ioctl command
7363 *
7364 * This function does initial processing of wlan device ioctls.
7365 * Currently two flavors of ioctls are supported. The primary ioctl
7366 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7367 * for Android "DRIVER" commands. The other ioctl that is
7368 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7369 * for FTM on some platforms. This function simply verifies that the
7370 * driver is in a sane state, and that the ioctl is one of the
7371 * supported flavors, in which case flavor-specific handlers are
7372 * dispatched.
7373 *
7374 * Return: 0 on success, non-zero on error
7375 */
7376static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7377{
7378 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7379 hdd_context_t *hdd_ctx;
7380 int ret;
7381
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007382 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307383
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007384 if (dev != adapter->dev) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007385 hdd_alert("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007386 ret = -ENODEV;
7387 goto exit;
7388 }
7389
7390 if ((!ifr) || (!ifr->ifr_data)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007391 hdd_err("invalid data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007392 ret = -EINVAL;
7393 goto exit;
7394 }
7395#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307396 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007397 if (SIOCIOCTLTX99 == cmd) {
7398 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7399 goto exit;
7400 }
7401 }
7402#endif
7403
7404 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7405 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307406 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007407 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007408
7409 switch (cmd) {
7410 case (SIOCDEVPRIVATE + 1):
7411 if (is_compat_task())
7412 ret = hdd_driver_compat_ioctl(adapter, ifr);
7413 else
7414 ret = hdd_driver_ioctl(adapter, ifr);
7415 break;
7416 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007417 hdd_err("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007418 ret = -EINVAL;
7419 break;
7420 }
7421exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307422 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007423 return ret;
7424}
7425
7426/**
7427 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7428 * @dev: device upon which the ioctl was received
7429 * @ifr: ioctl request information
7430 * @cmd: ioctl command
7431 *
7432 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7433 * which is where the ioctls are really handled.
7434 *
7435 * Return: 0 on success, non-zero on error
7436 */
7437int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7438{
7439 int ret;
7440
7441 cds_ssr_protect(__func__);
7442 ret = __hdd_ioctl(dev, ifr, cmd);
7443 cds_ssr_unprotect(__func__);
7444 return ret;
7445}