blob: 6e906dafd357ffe97a666710a230aaa6047c0581 [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"
37#include "cds_concurrency.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
942 * followed by binary data
943 *
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
1201 * followed by binary data
1202 *
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
1303 * channel list
1304 * @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
1476 * followed by binary data
1477 *
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) {
1913 pm_message_t state;
1914
1915 state.event = PM_EVENT_SUSPEND;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001916 hdd_info("Received ready to ExtWoW. Going to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001917
1918 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1919 if (rc < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001920 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1921 rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001922 return rc;
1923 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301924 qdf_ret_status = wlan_hdd_bus_suspend(state);
1925 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001926 hdd_err("wlan_hdd_suspend failed, status = %d",
1927 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001928 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1929 return -EPERM;
1930 }
1931 }
1932 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001933 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001934 return -EPERM;
1935 }
1936
1937 return 0;
1938}
1939
1940static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1941 int value)
1942{
1943 tSirExtWoWParams params;
1944 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1945 int rc;
1946
1947 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301948 if (rc)
1949 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950
1951 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1952 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001953 hdd_err("Invalid type");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 return -EINVAL;
1955 }
1956
1957 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1958 hdd_ctx->is_extwow_app_type1_param_set)
1959 params.type = value;
1960 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1961 hdd_ctx->is_extwow_app_type2_param_set)
1962 params.type = value;
1963 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1964 hdd_ctx->is_extwow_app_type1_param_set &&
1965 hdd_ctx->is_extwow_app_type2_param_set)
1966 params.type = value;
1967 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001968 hdd_err("Set app params before enable it value %d",
1969 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 return -EINVAL;
1971 }
1972
1973 params.vdev_id = vdev_id;
1974 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1975 (hdd_ctx->config->extWowApp2WakeupPinNumber
1976 << 8);
1977
1978 return hdd_enable_ext_wow(adapter, &params);
1979}
1980
1981static int hdd_set_app_type1_params(tHalHandle hHal,
1982 tpSirAppType1Params arg_params)
1983{
1984 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301985 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301987 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001988
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301989 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1990 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001991 hdd_err("sme_configure_app_type1_params returned failure %d",
1992 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 return -EPERM;
1994 }
1995
1996 return 0;
1997}
1998
1999static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
2000 char *arg, int len)
2001{
2002 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2003 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2004 char id[20], password[20];
2005 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002006 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002007
2008 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302009 if (rc)
2010 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011
2012 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002013 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002014 return -EINVAL;
2015 }
2016
2017 memset(&params, 0, sizeof(tSirAppType1Params));
2018 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302019 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020
2021 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302022 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002023 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302024 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002025
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002026 hdd_info("%d %pM %.8s %u %.16s %u",
2027 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002028 params.identification_id, params.id_length,
2029 params.password, params.pass_length);
2030
2031 return hdd_set_app_type1_params(hHal, &params);
2032}
2033
2034static int hdd_set_app_type2_params(tHalHandle hHal,
2035 tpSirAppType2Params arg_params)
2036{
2037 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302038 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002039
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302040 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002041
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302042 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2043 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002044 hdd_err("sme_configure_app_type2_params returned failure %d",
2045 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046 return -EPERM;
2047 }
2048
2049 return 0;
2050}
2051
2052static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2053 char *arg, int len)
2054{
2055 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2056 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2057 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302058 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002059 tSirAppType2Params params;
2060 int ret;
2061
2062 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302063 if (ret)
2064 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002065
2066 memset(&params, 0, sizeof(tSirAppType2Params));
2067
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302068 ret = sscanf(arg, "%17s %16s %x %x %x %u %u %hu %hu %u %u %u %u %u %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002069 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2070 (unsigned int *)&params.ip_device_ip,
2071 (unsigned int *)&params.ip_server_ip,
2072 (unsigned int *)&params.tcp_seq,
2073 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302074 (uint16_t *)&params.tcp_src_port,
2075 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 (unsigned int *)&params.keepalive_init,
2077 (unsigned int *)&params.keepalive_min,
2078 (unsigned int *)&params.keepalive_max,
2079 (unsigned int *)&params.keepalive_inc,
2080 (unsigned int *)&params.tcp_tx_timeout_val,
2081 (unsigned int *)&params.tcp_rx_timeout_val);
2082
2083 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002084 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085 return -EINVAL;
2086 }
2087
2088 if (6 !=
2089 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2090 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2091 &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002092 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002093 return -EINVAL;
2094 }
2095
2096 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2097 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002098 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002099 return -EINVAL;
2100 }
2101
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302102 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302103 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002104
2105 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302106 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002107
2108 params.vdev_id = adapter->sessionId;
2109 params.tcp_src_port = (params.tcp_src_port != 0) ?
2110 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2111 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2112 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2113 params.keepalive_init = (params.keepalive_init != 0) ?
2114 params.keepalive_init : hdd_ctx->config->
2115 extWowApp2KAInitPingInterval;
2116 params.keepalive_min =
2117 (params.keepalive_min != 0) ?
2118 params.keepalive_min :
2119 hdd_ctx->config->extWowApp2KAMinPingInterval;
2120 params.keepalive_max =
2121 (params.keepalive_max != 0) ?
2122 params.keepalive_max :
2123 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2124 params.keepalive_inc =
2125 (params.keepalive_inc != 0) ?
2126 params.keepalive_inc :
2127 hdd_ctx->config->extWowApp2KAIncPingInterval;
2128 params.tcp_tx_timeout_val =
2129 (params.tcp_tx_timeout_val != 0) ?
2130 params.tcp_tx_timeout_val :
2131 hdd_ctx->config->extWowApp2TcpTxTimeout;
2132 params.tcp_rx_timeout_val =
2133 (params.tcp_rx_timeout_val != 0) ?
2134 params.tcp_rx_timeout_val :
2135 hdd_ctx->config->extWowApp2TcpRxTimeout;
2136
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002137 hdd_info("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2138 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002139 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2140 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2141 params.keepalive_init, params.keepalive_min,
2142 params.keepalive_max, params.keepalive_inc,
2143 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2144
2145 return hdd_set_app_type2_params(hHal, &params);
2146}
2147#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2148
2149/**
2150 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2151 * @pValue: Pointer to MAXTXPOWER command
2152 * @pDbm: Pointer to tx power
2153 *
2154 * This function parses the MAXTXPOWER command passed in the format
2155 * MAXTXPOWER<space>X(Tx power in dbm)
2156 *
2157 * For example input commands:
2158 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2159 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2160 *
2161 * Return: 0 for success non-zero for failure
2162 */
2163static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2164{
2165 uint8_t *inPtr = pValue;
2166 int tempInt;
2167 int v = 0;
2168 *pTxPower = 0;
2169
2170 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2171 /* no argument after the command */
2172 if (NULL == inPtr) {
2173 return -EINVAL;
2174 }
2175
2176 /* no space after the command */
2177 else if (SPACE_ASCII_VALUE != *inPtr) {
2178 return -EINVAL;
2179 }
2180
2181 /* remove empty spaces */
2182 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2183 inPtr++;
2184
2185 /* no argument followed by spaces */
2186 if ('\0' == *inPtr) {
2187 return 0;
2188 }
2189
2190 v = kstrtos32(inPtr, 10, &tempInt);
2191
2192 /* Range checking for passed parameter */
2193 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2194 return -EINVAL;
2195 }
2196
2197 *pTxPower = tempInt;
2198
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002199 hdd_info("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002200
2201 return 0;
2202} /* End of hdd_parse_setmaxtxpower_command */
2203
2204static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2205 char *extra, uint8_t n, uint8_t *len)
2206{
Jeff Johnson68755312017-02-10 11:46:55 -08002207 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002208
2209 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002210 hdd_err("argument passed for GETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211 ret = -EINVAL;
2212 return ret;
2213 }
2214
2215 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2216 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2217 (int)pCfg->nActiveMaxChnTime);
2218 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002219 }
2220 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002221 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2222 (int)pCfg->nActiveMinChnTime);
2223 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002224 }
2225 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002226 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2227 (int)pCfg->nPassiveMaxChnTime);
2228 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002229 }
2230 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002231 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2232 (int)pCfg->nPassiveMinChnTime);
2233 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002234 }
2235 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002236 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2237 (int)pCfg->nActiveMaxChnTime);
2238 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002239 }
Jeff Johnson68755312017-02-10 11:46:55 -08002240 ret = -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002241
2242 return ret;
2243}
2244
2245static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2246{
2247 tHalHandle hHal;
2248 struct hdd_config *pCfg;
2249 uint8_t *value = command;
2250 tSmeConfigParams smeConfig;
2251 int val = 0, temp = 0;
2252
2253 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2254 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2255 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002256 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002257 return -EINVAL;
2258 }
2259
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302260 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002261 sme_get_config_param(hHal, &smeConfig);
2262
2263 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2264 value = value + 24;
2265 temp = kstrtou32(value, 10, &val);
2266 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2267 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002268 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002269 return -EFAULT;
2270 }
2271 pCfg->nActiveMaxChnTime = val;
2272 smeConfig.csrConfig.nActiveMaxChnTime = val;
2273 sme_update_config(hHal, &smeConfig);
2274 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2275 value = value + 24;
2276 temp = kstrtou32(value, 10, &val);
2277 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2278 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002279 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002280 return -EFAULT;
2281 }
2282 pCfg->nActiveMinChnTime = val;
2283 smeConfig.csrConfig.nActiveMinChnTime = val;
2284 sme_update_config(hHal, &smeConfig);
2285 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2286 value = value + 25;
2287 temp = kstrtou32(value, 10, &val);
2288 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2289 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002290 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002291 return -EFAULT;
2292 }
2293 pCfg->nPassiveMaxChnTime = val;
2294 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2295 sme_update_config(hHal, &smeConfig);
2296 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2297 value = value + 25;
2298 temp = kstrtou32(value, 10, &val);
2299 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2300 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002301 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002302 return -EFAULT;
2303 }
2304 pCfg->nPassiveMinChnTime = val;
2305 smeConfig.csrConfig.nPassiveMinChnTime = val;
2306 sme_update_config(hHal, &smeConfig);
2307 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2308 value = value + 13;
2309 temp = kstrtou32(value, 10, &val);
2310 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2311 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002312 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002313 return -EFAULT;
2314 }
2315 pCfg->nActiveMaxChnTime = val;
2316 smeConfig.csrConfig.nActiveMaxChnTime = val;
2317 sme_update_config(hHal, &smeConfig);
2318 } else {
2319 return -EINVAL;
2320 }
2321
2322 return 0;
2323}
2324
Jeff Johnson253c0c22017-01-23 16:59:38 -08002325struct link_status_priv {
2326 uint8_t link_status;
2327};
2328
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329static void hdd_get_link_status_cb(uint8_t status, void *context)
2330{
Jeff Johnson253c0c22017-01-23 16:59:38 -08002331 struct hdd_request *request;
2332 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002333
Jeff Johnson253c0c22017-01-23 16:59:38 -08002334 request = hdd_request_get(context);
2335 if (!request) {
2336 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002337 return;
2338 }
2339
Jeff Johnson253c0c22017-01-23 16:59:38 -08002340 priv = hdd_request_priv(request);
2341 priv->link_status = status;
2342 hdd_request_complete(request);
2343 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002344}
2345
2346/**
2347 * wlan_hdd_get_link_status() - get link status
2348 * @pAdapter: pointer to the adapter
2349 *
2350 * This function sends a request to query the link status and waits
2351 * on a timer to invoke the callback. if the callback is invoked then
2352 * latest link status shall be returned or otherwise cached value
2353 * will be returned.
2354 *
2355 * Return: On success, link status shall be returned.
2356 * On error or not associated, link status 0 will be returned.
2357 */
2358static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2359{
2360
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002361 hdd_station_ctx_t *pHddStaCtx =
2362 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302363 QDF_STATUS hstatus;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002364 int ret;
2365 void *cookie;
2366 struct hdd_request *request;
2367 struct link_status_priv *priv;
2368 static const struct hdd_request_params params = {
2369 .priv_size = sizeof(*priv),
2370 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2371 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002372
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002373 if (cds_is_driver_recovering()) {
2374 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2375 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002376 return 0;
2377 }
2378
Krunal Sonibe766b02016-03-10 13:00:44 -08002379 if ((QDF_STA_MODE != adapter->device_mode) &&
2380 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002381 hdd_warn("Unsupported in mode %s(%d)",
2382 hdd_device_mode_to_string(adapter->device_mode),
2383 adapter->device_mode);
2384 return 0;
2385 }
2386
2387 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2388 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2389 /* If not associated, then expected link status return
2390 * value is 0
2391 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002392 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002393 return 0;
2394 }
2395
Jeff Johnson253c0c22017-01-23 16:59:38 -08002396 request = hdd_request_alloc(&params);
2397 if (!request) {
2398 hdd_err("Request allocation failure");
2399 return 0;
2400 }
2401 cookie = hdd_request_cookie(request);
2402
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002403 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2404 hdd_get_link_status_cb,
Jeff Johnson253c0c22017-01-23 16:59:38 -08002405 cookie, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302406 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002407 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002408 /* return a cached value */
2409 } else {
2410 /* request is sent -- wait for the response */
Jeff Johnson253c0c22017-01-23 16:59:38 -08002411 ret = hdd_request_wait_for_response(request);
2412 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002413 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002414 /* return a cached value */
2415 } else {
2416 /* update the adapter with the fresh results */
2417 priv = hdd_request_priv(request);
2418 adapter->linkStatus = priv->link_status;
2419 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002420 }
2421
Jeff Johnson253c0c22017-01-23 16:59:38 -08002422 /*
2423 * either we never sent a request, we sent a request and
2424 * received a response or we sent a request and timed out.
2425 * regardless we are done with the request.
2426 */
2427 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002428
2429 /* either callback updated adapter stats or it has cached data */
2430 return adapter->linkStatus;
2431}
2432
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002433static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2434{
2435 int payload_len;
2436 struct sk_buff *skb;
2437 struct nlmsghdr *nlh;
2438 uint8_t *data;
2439
2440 payload_len = ETH_ALEN;
2441
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002442 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002443 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002444 return;
2445 }
2446
2447 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2448 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002449 hdd_err("nlmsg_new() failed for msg size[%d]",
2450 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002451 return;
2452 }
2453
2454 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2455
2456 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002457 hdd_err("nlmsg_put() failed for msg size[%d]",
2458 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002459
2460 kfree_skb(skb);
2461 return;
2462 }
2463
2464 data = nlmsg_data(nlh);
2465 memcpy(data, MacAddr, ETH_ALEN);
2466
2467 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002468 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2469 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002470 }
2471
2472 return;
2473}
2474
2475
2476/**
2477 * hdd_ParseuserParams - return a pointer to the next argument
2478 * @pValue: Input argument string
2479 * @ppArg: Output pointer to the next argument
2480 *
2481 * This function parses argument stream and finds the pointer
2482 * to the next argument
2483 *
2484 * Return: 0 if the next argument found; -EINVAL otherwise
2485 */
2486static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2487{
2488 uint8_t *pVal;
2489
2490 pVal = strnchr(pValue, strlen(pValue), ' ');
2491
2492 if (NULL == pVal) {
2493 /* no argument remains */
2494 return -EINVAL;
2495 } else if (SPACE_ASCII_VALUE != *pVal) {
2496 /* no space after the current argument */
2497 return -EINVAL;
2498 }
2499
2500 pVal++;
2501
2502 /* remove empty spaces */
2503 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2504 pVal++;
2505 }
2506
2507 /* no argument followed by spaces */
2508 if ('\0' == *pVal) {
2509 return -EINVAL;
2510 }
2511
2512 *ppArg = pVal;
2513
2514 return 0;
2515}
2516
2517/**
2518 * hdd_parse_ibsstx_fail_event_params - Parse params
2519 * for SETIBSSTXFAILEVENT
2520 * @pValue: Input ibss tx fail event argument
2521 * @tx_fail_count: (Output parameter) Tx fail counter
2522 * @pid: (Output parameter) PID
2523 *
2524 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2525 */
2526static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2527 uint8_t *tx_fail_count,
2528 uint16_t *pid)
2529{
2530 uint8_t *param = NULL;
2531 int ret;
2532
2533 ret = hdd_parse_user_params(pValue, &param);
2534
2535 if (0 == ret && NULL != param) {
2536 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2537 ret = -EINVAL;
2538 goto done;
2539 }
2540 } else {
2541 goto done;
2542 }
2543
2544 if (0 == *tx_fail_count) {
2545 *pid = 0;
2546 goto done;
2547 }
2548
2549 pValue = param;
2550 pValue++;
2551
2552 ret = hdd_parse_user_params(pValue, &param);
2553
2554 if (0 == ret) {
2555 if (1 != sscanf(param, "%hu", pid)) {
2556 ret = -EINVAL;
2557 goto done;
2558 }
2559 } else {
2560 goto done;
2561 }
2562
2563done:
2564 return ret;
2565}
2566
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002567#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002568/**
2569 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2570 * @pValue: Pointer to data
2571 * @pEseBcnReq: Output pointer to store parsed ie information
2572 *
2573 * This function parses the ese beacon request passed in the format
2574 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2575 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2576 * <space>Scan Mode N<space>Meas Duration N
2577 *
2578 * If the Number of bcn req fields (N) does not match with the
2579 * actual number of fields passed then take N.
2580 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2581 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2582 * This function does not take care of removing duplicate channels from the
2583 * list
2584 *
2585 * Return: 0 for success non-zero for failure
2586 */
2587static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2588 tCsrEseBeaconReq *pEseBcnReq)
2589{
2590 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002591 uint8_t input = 0;
2592 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002593 int j = 0, i = 0, v = 0;
2594 char buf[32];
2595
2596 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2597 /* no argument after the command */
2598 if (NULL == inPtr) {
2599 return -EINVAL;
2600 }
2601 /* no space after the command */
2602 else if (SPACE_ASCII_VALUE != *inPtr) {
2603 return -EINVAL;
2604 }
2605
2606 /* remove empty spaces */
2607 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2608 inPtr++;
2609
2610 /* no argument followed by spaces */
2611 if ('\0' == *inPtr)
2612 return -EINVAL;
2613
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002614 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002615 v = sscanf(inPtr, "%31s ", buf);
2616 if (1 != v)
2617 return -EINVAL;
2618
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002619 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002620 if (v < 0)
2621 return -EINVAL;
2622
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002623 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2624 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002625
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002626 hdd_info("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002627
2628 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2629 for (i = 0; i < 4; i++) {
2630 /*
2631 * inPtr pointing to the beginning of 1st space
2632 * after number of ie fields
2633 */
2634 inPtr = strpbrk(inPtr, " ");
2635 /* no ie data after the number of ie fields argument */
2636 if (NULL == inPtr)
2637 return -EINVAL;
2638
2639 /* remove empty space */
2640 while ((SPACE_ASCII_VALUE == *inPtr)
2641 && ('\0' != *inPtr))
2642 inPtr++;
2643
2644 /*
2645 * no ie data after the number of ie fields
2646 * argument and spaces
2647 */
2648 if ('\0' == *inPtr)
2649 return -EINVAL;
2650
2651 v = sscanf(inPtr, "%31s ", buf);
2652 if (1 != v)
2653 return -EINVAL;
2654
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002655 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002656 if (v < 0)
2657 return -EINVAL;
2658
2659 switch (i) {
2660 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002661 if (!tempInt) {
2662 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002663 tempInt);
2664 return -EINVAL;
2665 }
2666 pEseBcnReq->bcnReq[j].measurementToken =
2667 tempInt;
2668 break;
2669
2670 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002671 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002672 (tempInt >
2673 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002674 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002675 tempInt);
2676 return -EINVAL;
2677 }
2678 pEseBcnReq->bcnReq[j].channel = tempInt;
2679 break;
2680
2681 case 2: /* Scan mode */
2682 if ((tempInt < eSIR_PASSIVE_SCAN)
2683 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002684 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002685 tempInt);
2686 return -EINVAL;
2687 }
2688 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2689 break;
2690
2691 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002692 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002693 && (pEseBcnReq->bcnReq[j].scanMode !=
2694 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002695 (pEseBcnReq->bcnReq[j].scanMode ==
2696 eSIR_BEACON_TABLE)) {
2697 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002698 tempInt);
2699 return -EINVAL;
2700 }
2701 pEseBcnReq->bcnReq[j].measurementDuration =
2702 tempInt;
2703 break;
2704 }
2705 }
2706 }
2707
2708 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002709 hdd_info("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002710 j,
2711 pEseBcnReq->bcnReq[j].measurementToken,
2712 pEseBcnReq->bcnReq[j].channel,
2713 pEseBcnReq->bcnReq[j].scanMode,
2714 pEseBcnReq->bcnReq[j].measurementDuration);
2715 }
2716
2717 return 0;
2718}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002719
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720/**
2721 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2722 * @pValue: Pointer to input data
2723 * @pCckmIe: Pointer to output cckm Ie
2724 * @pCckmIeLen: Pointer to output cckm ie length
2725 *
2726 * This function parses the SETCCKM IE command
2727 * SETCCKMIE<space><ie data>
2728 *
2729 * Return: 0 for success non-zero for failure
2730 */
2731static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2732 uint8_t *pCckmIeLen)
2733{
2734 uint8_t *inPtr = pValue;
2735 uint8_t *dataEnd;
2736 int j = 0;
2737 int i = 0;
2738 uint8_t tempByte = 0;
2739 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2740 /* no argument after the command */
2741 if (NULL == inPtr) {
2742 return -EINVAL;
2743 }
2744 /* no space after the command */
2745 else if (SPACE_ASCII_VALUE != *inPtr) {
2746 return -EINVAL;
2747 }
2748 /* remove empty spaces */
2749 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2750 inPtr++;
2751 /* no argument followed by spaces */
2752 if ('\0' == *inPtr) {
2753 return -EINVAL;
2754 }
2755 /* find the length of data */
2756 dataEnd = inPtr;
2757 while (('\0' != *dataEnd)) {
2758 dataEnd++;
2759 ++(*pCckmIeLen);
2760 }
2761 if (*pCckmIeLen <= 0)
2762 return -EINVAL;
2763 /*
2764 * Allocate the number of bytes based on the number of input characters
2765 * whether it is even or odd.
2766 * if the number of input characters are even, then we need N / 2 byte.
2767 * if the number of input characters are odd, then we need do
2768 * (N + 1) / 2 to compensate rounding off.
2769 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2770 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2771 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302772 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002773 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002774 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002775 return -ENOMEM;
2776 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002777 /*
2778 * the buffer received from the upper layer is character buffer,
2779 * we need to prepare the buffer taking 2 characters in to a U8 hex
2780 * decimal number for example 7f0000f0...form a buffer to contain
2781 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2782 */
2783 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2784 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2785 (hex_to_bin(inPtr[j + 1]));
2786 (*pCckmIe)[i++] = tempByte;
2787 }
2788 *pCckmIeLen = i;
2789 return 0;
2790}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002791#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002792
2793int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2794{
2795 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302796 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002797 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2798 struct hdd_config *pConfig = NULL;
2799
2800 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002801 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002802 return -EINVAL;
2803 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002804 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2805 (QDF_SAP_MODE != pAdapter->device_mode) &&
2806 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002807 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2808 hdd_device_mode_to_string(pAdapter->device_mode),
2809 pAdapter->device_mode);
2810 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002811 return -EINVAL;
2812 }
2813 pConfig = pHddCtx->config;
2814 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2815 rateUpdate.dev_mode = pAdapter->device_mode;
2816 rateUpdate.mcastDataRate24GHz = targetRate;
2817 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2818 rateUpdate.mcastDataRate5GHz = targetRate;
2819 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302820 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002821 hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
2822 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2823 hdd_device_mode_to_string(pAdapter->device_mode),
2824 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002825 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302826 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002827 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002828 return -EFAULT;
2829 }
2830 return 0;
2831}
2832
2833static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2834 hdd_context_t *hdd_ctx,
2835 uint8_t *command,
2836 uint8_t command_len,
2837 hdd_priv_data_t *priv_data)
2838{
2839 int ret = 0;
2840
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302841 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002842 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2843 adapter->sessionId,
2844 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2845 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2846 + 3) << 16 | *(hdd_ctx->
2847 p2pDeviceAddress.bytes + 4) << 8 |
2848 *(hdd_ctx->p2pDeviceAddress.bytes +
2849 5))));
2850
2851 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2852 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002853 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002854 ret = -EFAULT;
2855 }
2856
2857 return ret;
2858}
2859
2860/**
2861 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2862 * @adapter: Adapter on which the command was received
2863 * @hdd_ctx: HDD global context
2864 * @command: Entire driver command received from userspace
2865 * @command_len: Length of @command
2866 * @priv_data: Pointer to ioctl private data structure
2867 *
2868 * This is a trivial command hander function which simply forwards the
2869 * command to the actual command processor within the P2P module.
2870 *
2871 * Return: 0 on success, non-zero on failure
2872 */
2873static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2874 hdd_context_t *hdd_ctx,
2875 uint8_t *command,
2876 uint8_t command_len,
2877 hdd_priv_data_t *priv_data)
2878{
2879 return hdd_set_p2p_noa(adapter->dev, command);
2880}
2881
2882/**
2883 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2884 * @adapter: Adapter on which the command was received
2885 * @hdd_ctx: HDD global context
2886 * @command: Entire driver command received from userspace
2887 * @command_len: Length of @command
2888 * @priv_data: Pointer to ioctl private data structure
2889 *
2890 * This is a trivial command hander function which simply forwards the
2891 * command to the actual command processor within the P2P module.
2892 *
2893 * Return: 0 on success, non-zero on failure
2894 */
2895static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2896 hdd_context_t *hdd_ctx,
2897 uint8_t *command,
2898 uint8_t command_len,
2899 hdd_priv_data_t *priv_data)
2900{
2901 return hdd_set_p2p_opps(adapter->dev, command);
2902}
2903
2904static int drv_cmd_set_band(hdd_adapter_t *adapter,
2905 hdd_context_t *hdd_ctx,
2906 uint8_t *command,
2907 uint8_t command_len,
2908 hdd_priv_data_t *priv_data)
2909{
2910 int ret = 0;
2911
2912 uint8_t *ptr = command;
2913
2914 /* Change band request received */
2915
2916 /*
2917 * First 8 bytes will have "SETBAND " and
2918 * 9 byte will have band setting value
2919 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002920 hdd_info("SetBandCommand Info comm %s UL %d, TL %d",
2921 command, priv_data->used_len,
2922 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002923
2924 /* Change band request received */
2925 ret = hdd_set_band_helper(adapter->dev, ptr);
2926
2927 return ret;
2928}
2929
2930static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2931 hdd_context_t *hdd_ctx,
2932 uint8_t *command,
2933 uint8_t command_len,
2934 hdd_priv_data_t *priv_data)
2935{
2936 return hdd_wmmps_helper(adapter, command);
2937}
2938
2939static int drv_cmd_country(hdd_adapter_t *adapter,
2940 hdd_context_t *hdd_ctx,
2941 uint8_t *command,
2942 uint8_t command_len,
2943 hdd_priv_data_t *priv_data)
2944{
2945 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302946 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002947 unsigned long rc;
2948 char *country_code;
2949
2950 country_code = command + 8;
2951
2952 INIT_COMPLETION(adapter->change_country_code);
2953
2954 status = sme_change_country_code(hdd_ctx->hHal,
2955 wlan_hdd_change_country_code_callback,
2956 country_code,
2957 adapter,
2958 hdd_ctx->pcds_context,
2959 eSIR_TRUE,
2960 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302961 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002962 rc = wait_for_completion_timeout(
2963 &adapter->change_country_code,
2964 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
2965 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002966 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002967 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002968 hdd_err("SME Change Country code fail, status %d",
2969 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002970 ret = -EINVAL;
2971 }
2972
2973 return ret;
2974}
2975
2976static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
2977 hdd_context_t *hdd_ctx,
2978 uint8_t *command,
2979 uint8_t command_len,
2980 hdd_priv_data_t *priv_data)
2981{
2982 int ret = 0;
2983 uint8_t *value = command;
2984 int8_t rssi = 0;
2985 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302986 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002987
2988 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2989 value = value + command_len + 1;
2990
2991 /* Convert the value from ascii to integer */
2992 ret = kstrtos8(value, 10, &rssi);
2993 if (ret < 0) {
2994 /*
2995 * If the input value is greater than max value of datatype,
2996 * then also kstrtou8 fails
2997 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002998 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2999 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3000 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003001 ret = -EINVAL;
3002 goto exit;
3003 }
3004
3005 lookUpThreshold = abs(rssi);
3006
3007 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3008 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003009 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003010 lookUpThreshold,
3011 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3012 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3013 ret = -EINVAL;
3014 goto exit;
3015 }
3016
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303017 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3019 adapter->sessionId, lookUpThreshold));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003020 hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003021 lookUpThreshold);
3022
3023 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3024 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3025 adapter->sessionId,
3026 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303027 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003028 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003029 ret = -EPERM;
3030 goto exit;
3031 }
3032
3033exit:
3034 return ret;
3035}
3036
3037static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3038 hdd_context_t *hdd_ctx,
3039 uint8_t *command,
3040 uint8_t command_len,
3041 hdd_priv_data_t *priv_data)
3042{
3043 int ret = 0;
3044 uint8_t lookUpThreshold =
3045 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3046 int rssi = (-1) * lookUpThreshold;
3047 char extra[32];
3048 uint8_t len = 0;
3049
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303050 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003051 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3052 adapter->sessionId, lookUpThreshold));
3053
3054 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303055 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003056 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003057 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003058 ret = -EFAULT;
3059 }
3060
3061 return ret;
3062}
3063
3064static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3065 hdd_context_t *hdd_ctx,
3066 uint8_t *command,
3067 uint8_t command_len,
3068 hdd_priv_data_t *priv_data)
3069{
3070 int ret = 0;
3071 uint8_t *value = command;
3072 uint8_t roamScanPeriod = 0;
3073 uint16_t neighborEmptyScanRefreshPeriod =
3074 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3075
3076 /* input refresh period is in terms of seconds */
3077
3078 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3079 value = value + command_len + 1;
3080
3081 /* Convert the value from ascii to integer */
3082 ret = kstrtou8(value, 10, &roamScanPeriod);
3083 if (ret < 0) {
3084 /*
3085 * If the input value is greater than max value of datatype,
3086 * then also kstrtou8 fails
3087 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003088 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3089 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3090 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003091 ret = -EINVAL;
3092 goto exit;
3093 }
3094
3095 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3096 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003097 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3098 roamScanPeriod,
3099 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3100 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101 ret = -EINVAL;
3102 goto exit;
3103 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303104 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003105 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3106 adapter->sessionId, roamScanPeriod));
3107 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3108
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003109 hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003110 roamScanPeriod);
3111
3112 hdd_ctx->config->nEmptyScanRefreshPeriod =
3113 neighborEmptyScanRefreshPeriod;
3114 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3115 adapter->sessionId,
3116 neighborEmptyScanRefreshPeriod);
3117
3118exit:
3119 return ret;
3120}
3121
3122static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3123 hdd_context_t *hdd_ctx,
3124 uint8_t *command,
3125 uint8_t command_len,
3126 hdd_priv_data_t *priv_data)
3127{
3128 int ret = 0;
3129 uint16_t nEmptyScanRefreshPeriod =
3130 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3131 char extra[32];
3132 uint8_t len = 0;
3133
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303134 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3136 adapter->sessionId,
3137 nEmptyScanRefreshPeriod));
3138 len = scnprintf(extra, sizeof(extra), "%s %d",
3139 "GETROAMSCANPERIOD",
3140 (nEmptyScanRefreshPeriod / 1000));
3141 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303142 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003143 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003144 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003145 ret = -EFAULT;
3146 }
3147
3148 return ret;
3149}
3150
3151static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3152 hdd_context_t *hdd_ctx,
3153 uint8_t *command,
3154 uint8_t command_len,
3155 hdd_priv_data_t *priv_data)
3156{
3157 int ret = 0;
3158 uint8_t *value = command;
3159 uint8_t roamScanRefreshPeriod = 0;
3160 uint16_t neighborScanRefreshPeriod =
3161 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3162
3163 /* input refresh period is in terms of seconds */
3164 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3165 value = value + command_len + 1;
3166
3167 /* Convert the value from ascii to integer */
3168 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3169 if (ret < 0) {
3170 /*
3171 * If the input value is greater than max value of datatype,
3172 * then also kstrtou8 fails
3173 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003174 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3175 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3176 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003177 ret = -EINVAL;
3178 goto exit;
3179 }
3180
3181 if ((roamScanRefreshPeriod <
3182 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3183 || (roamScanRefreshPeriod >
3184 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003185 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3186 roamScanRefreshPeriod,
3187 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3188 / 1000),
3189 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3190 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003191 ret = -EINVAL;
3192 goto exit;
3193 }
3194 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3195
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003196 hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003197 roamScanRefreshPeriod);
3198
3199 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3200 neighborScanRefreshPeriod;
3201 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3202 adapter->sessionId,
3203 neighborScanRefreshPeriod);
3204
3205exit:
3206 return ret;
3207}
3208
3209static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3210 hdd_context_t *hdd_ctx,
3211 uint8_t *command,
3212 uint8_t command_len,
3213 hdd_priv_data_t *priv_data)
3214{
3215 int ret = 0;
3216 uint16_t value =
3217 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3218 char extra[32];
3219 uint8_t len = 0;
3220
3221 len = scnprintf(extra, sizeof(extra), "%s %d",
3222 "GETROAMSCANREFRESHPERIOD",
3223 (value / 1000));
3224 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303225 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003226 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003227 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003228 ret = -EFAULT;
3229 }
3230
3231 return ret;
3232}
3233
3234static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3235 hdd_context_t *hdd_ctx,
3236 uint8_t *command,
3237 uint8_t command_len,
3238 hdd_priv_data_t *priv_data)
3239{
3240 int ret = 0;
3241 uint8_t *value = command;
3242 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3243
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003244 if (!adapter->fast_roaming_allowed) {
3245 hdd_err("Roaming is always disabled on this interface");
3246 goto exit;
3247 }
3248
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003249 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3250 value = value + SIZE_OF_SETROAMMODE + 1;
3251
3252 /* Convert the value from ascii to integer */
3253 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3254 if (ret < 0) {
3255 /*
3256 * If the input value is greater than max value of datatype,
3257 * then also kstrtou8 fails
3258 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003259 hdd_err("kstrtou8 failed range [%d - %d]",
3260 CFG_LFR_FEATURE_ENABLED_MIN,
3261 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003262 ret = -EINVAL;
3263 goto exit;
3264 }
3265 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3266 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003267 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3268 roamMode,
3269 CFG_LFR_FEATURE_ENABLED_MIN,
3270 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003271 ret = -EINVAL;
3272 goto exit;
3273 }
3274
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003275 hdd_debug("Received Command to Set Roam Mode = %d",
3276 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003277 /*
3278 * Note that
3279 * SETROAMMODE 0 is to enable LFR while
3280 * SETROAMMODE 1 is to disable LFR, but
3281 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3282 * enable/disable. So, we have to invert the value
3283 * to call sme_update_is_fast_roam_ini_feature_enabled.
3284 */
3285 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3286 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3287 else
3288 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3289
3290 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3291 if (roamMode) {
3292 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3293 sme_update_roam_scan_offload_enabled(
3294 (tHalHandle)(hdd_ctx->hHal),
3295 hdd_ctx->config->isRoamOffloadScanEnabled);
3296 sme_update_is_fast_roam_ini_feature_enabled(
3297 hdd_ctx->hHal,
3298 adapter->sessionId,
3299 roamMode);
3300 } else {
3301 sme_update_is_fast_roam_ini_feature_enabled(
3302 hdd_ctx->hHal,
3303 adapter->sessionId,
3304 roamMode);
3305 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3306 sme_update_roam_scan_offload_enabled(
3307 (tHalHandle)(hdd_ctx->hHal),
3308 hdd_ctx->config->isRoamOffloadScanEnabled);
3309 }
3310
3311
3312exit:
3313 return ret;
3314}
3315
3316static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3317 hdd_context_t *hdd_ctx,
3318 uint8_t *command,
3319 uint8_t command_len,
3320 hdd_priv_data_t *priv_data)
3321{
3322 int ret = 0;
3323 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3324 char extra[32];
3325 uint8_t len = 0;
3326
3327 /*
3328 * roamMode value shall be inverted because the sementics is different.
3329 */
3330 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3331 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3332 else
3333 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3334
3335 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303336 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003337 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003338 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003339 ret = -EFAULT;
3340 }
3341
3342 return ret;
3343}
3344
3345static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3346 hdd_context_t *hdd_ctx,
3347 uint8_t *command,
3348 uint8_t command_len,
3349 hdd_priv_data_t *priv_data)
3350{
3351 int ret = 0;
3352 uint8_t *value = command;
3353 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3354
3355 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3356 value = value + command_len + 1;
3357
3358 /* Convert the value from ascii to integer */
3359 ret = kstrtou8(value, 10, &roamRssiDiff);
3360 if (ret < 0) {
3361 /*
3362 * If the input value is greater than max value of datatype,
3363 * then also kstrtou8 fails
3364 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003365 hdd_err("kstrtou8 failed range [%d - %d]",
3366 CFG_ROAM_RSSI_DIFF_MIN,
3367 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003368 ret = -EINVAL;
3369 goto exit;
3370 }
3371
3372 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3373 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003374 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3375 roamRssiDiff,
3376 CFG_ROAM_RSSI_DIFF_MIN,
3377 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003378 ret = -EINVAL;
3379 goto exit;
3380 }
3381
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003382 hdd_info("Received Command to Set roam rssi diff = %d",
3383 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003384
3385 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3386 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3387 adapter->sessionId,
3388 roamRssiDiff);
3389
3390exit:
3391 return ret;
3392}
3393
3394static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3395 hdd_context_t *hdd_ctx,
3396 uint8_t *command,
3397 uint8_t command_len,
3398 hdd_priv_data_t *priv_data)
3399{
3400 int ret = 0;
3401 uint8_t roamRssiDiff =
3402 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3403 char extra[32];
3404 uint8_t len = 0;
3405
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303406 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003407 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3408 adapter->sessionId, roamRssiDiff));
3409
3410 len = scnprintf(extra, sizeof(extra), "%s %d",
3411 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303412 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413
3414 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003415 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003416 ret = -EFAULT;
3417 }
3418
3419 return ret;
3420}
3421
3422static int drv_cmd_get_band(hdd_adapter_t *adapter,
3423 hdd_context_t *hdd_ctx,
3424 uint8_t *command,
3425 uint8_t command_len,
3426 hdd_priv_data_t *priv_data)
3427{
3428 int ret = 0;
3429 int band = -1;
3430 char extra[32];
3431 uint8_t len = 0;
3432
3433 hdd_get_band_helper(hdd_ctx, &band);
3434
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303435 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003436 TRACE_CODE_HDD_GETBAND_IOCTL,
3437 adapter->sessionId, band));
3438
3439 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303440 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003441
3442 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003443 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003444 ret = -EFAULT;
3445 }
3446
3447 return ret;
3448}
3449
3450static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3451 hdd_context_t *hdd_ctx,
3452 uint8_t *command,
3453 uint8_t command_len,
3454 hdd_priv_data_t *priv_data)
3455{
3456 return hdd_parse_set_roam_scan_channels(adapter, command);
3457}
3458
3459static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3460 hdd_context_t *hdd_ctx,
3461 uint8_t *command,
3462 uint8_t command_len,
3463 hdd_priv_data_t *priv_data)
3464{
3465 int ret = 0;
3466 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3467 uint8_t numChannels = 0;
3468 uint8_t j = 0;
3469 char extra[128] = { 0 };
3470 int len;
3471
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303472 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003473 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3474 ChannelList,
3475 &numChannels,
3476 adapter->sessionId)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003477 hdd_alert("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003478 ret = -EFAULT;
3479 goto exit;
3480 }
3481
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303482 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003483 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3484 adapter->sessionId, numChannels));
3485 /*
3486 * output channel list is of the format
3487 * [Number of roam scan channels][Channel1][Channel2]...
3488 * copy the number of channels in the 0th index
3489 */
3490 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3491 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303492 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003493 len += scnprintf(extra + len, sizeof(extra) - len,
3494 " %d", ChannelList[j]);
3495
Anurag Chouhan6d760662016-02-20 16:05:43 +05303496 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003497 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003498 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003499 ret = -EFAULT;
3500 goto exit;
3501 }
3502
3503exit:
3504 return ret;
3505}
3506
3507static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3508 hdd_context_t *hdd_ctx,
3509 uint8_t *command,
3510 uint8_t command_len,
3511 hdd_priv_data_t *priv_data)
3512{
3513 int ret = 0;
3514 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3515 char extra[32];
3516 uint8_t len = 0;
3517
3518 /*
3519 * Check if the features OKC/ESE/11R are supported simultaneously,
3520 * then this operation is not permitted (return FAILURE)
3521 */
3522 if (eseMode &&
3523 hdd_is_okc_mode_enabled(hdd_ctx) &&
3524 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003525 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003526 ret = -EPERM;
3527 goto exit;
3528 }
3529
3530 len = scnprintf(extra, sizeof(extra), "%s %d",
3531 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303532 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003533 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003534 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003535 ret = -EFAULT;
3536 goto exit;
3537 }
3538
3539exit:
3540 return ret;
3541}
3542
3543static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3544 hdd_context_t *hdd_ctx,
3545 uint8_t *command,
3546 uint8_t command_len,
3547 hdd_priv_data_t *priv_data)
3548{
3549 int ret = 0;
3550 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3551 char extra[32];
3552 uint8_t len = 0;
3553
3554 /*
3555 * Check if the features OKC/ESE/11R are supported simultaneously,
3556 * then this operation is not permitted (return FAILURE)
3557 */
3558 if (okcMode &&
3559 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3560 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003561 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003562 ret = -EPERM;
3563 goto exit;
3564 }
3565
3566 len = scnprintf(extra, sizeof(extra), "%s %d",
3567 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303568 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003569
3570 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003571 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003572 ret = -EFAULT;
3573 goto exit;
3574 }
3575
3576exit:
3577 return ret;
3578}
3579
3580static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3581 hdd_context_t *hdd_ctx,
3582 uint8_t *command,
3583 uint8_t command_len,
3584 hdd_priv_data_t *priv_data)
3585{
3586 int ret = 0;
3587 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3588 char extra[32];
3589 uint8_t len = 0;
3590
3591 len = scnprintf(extra, sizeof(extra), "%s %d",
3592 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303593 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003594
3595 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003596 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003597 ret = -EFAULT;
3598 }
3599
3600 return ret;
3601}
3602
3603static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3604 hdd_context_t *hdd_ctx,
3605 uint8_t *command,
3606 uint8_t command_len,
3607 hdd_priv_data_t *priv_data)
3608{
3609 int ret = 0;
3610 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3611 char extra[32];
3612 uint8_t len = 0;
3613
3614 len = scnprintf(extra, sizeof(extra), "%s %d",
3615 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303616 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003617
3618 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003619 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003620 ret = -EFAULT;
3621 }
3622
3623 return ret;
3624}
3625
3626static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3627 hdd_context_t *hdd_ctx,
3628 uint8_t *command,
3629 uint8_t command_len,
3630 hdd_priv_data_t *priv_data)
3631{
3632 int ret = 0;
3633 uint8_t *value = command;
3634 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3635
3636 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3637 value = value + command_len + 1;
3638
3639 /* Convert the value from ascii to integer */
3640 ret = kstrtou8(value, 10, &minTime);
3641 if (ret < 0) {
3642 /*
3643 * If the input value is greater than max value of datatype,
3644 * then also kstrtou8 fails
3645 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003646 hdd_err("kstrtou8 failed range [%d - %d]",
3647 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3648 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003649 ret = -EINVAL;
3650 goto exit;
3651 }
3652
3653 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3654 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003655 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3656 minTime,
3657 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3658 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003659 ret = -EINVAL;
3660 goto exit;
3661 }
3662
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303663 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003664 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3665 adapter->sessionId, minTime));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003666 hdd_info("Received Command to change channel min time = %d",
3667 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003668
3669 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3670 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3671 minTime,
3672 adapter->sessionId);
3673
3674exit:
3675 return ret;
3676}
3677
3678static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3679 hdd_context_t *hdd_ctx,
3680 uint8_t *command,
3681 uint8_t command_len,
3682 hdd_priv_data_t *priv_data)
3683{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003684 return hdd_parse_sendactionframe(adapter, command,
3685 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003686}
3687
3688static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3689 hdd_context_t *hdd_ctx,
3690 uint8_t *command,
3691 uint8_t command_len,
3692 hdd_priv_data_t *priv_data)
3693{
3694 int ret = 0;
3695 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3696 adapter->sessionId);
3697 char extra[32];
3698 uint8_t len = 0;
3699
3700 /* value is interms of msec */
3701 len = scnprintf(extra, sizeof(extra), "%s %d",
3702 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303703 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003704
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303705 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003706 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3707 adapter->sessionId, val));
3708
3709 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003710 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003711 ret = -EFAULT;
3712 }
3713
3714 return ret;
3715}
3716
3717static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3718 hdd_context_t *hdd_ctx,
3719 uint8_t *command,
3720 uint8_t command_len,
3721 hdd_priv_data_t *priv_data)
3722{
3723 int ret = 0;
3724 uint8_t *value = command;
3725 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3726
3727 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3728 value = value + command_len + 1;
3729
3730 /* Convert the value from ascii to integer */
3731 ret = kstrtou16(value, 10, &maxTime);
3732 if (ret < 0) {
3733 /*
3734 * If the input value is greater than max value of datatype,
3735 * then also kstrtou8 fails
3736 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003737 hdd_err("kstrtou16 failed range [%d - %d]",
3738 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3739 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003740 ret = -EINVAL;
3741 goto exit;
3742 }
3743
3744 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3745 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003746 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3747 maxTime,
3748 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3749 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003750 ret = -EINVAL;
3751 goto exit;
3752 }
3753
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003754 hdd_info("Received Command to change channel max time = %d",
3755 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003756
3757 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3758 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3759 adapter->sessionId,
3760 maxTime);
3761
3762exit:
3763 return ret;
3764}
3765
3766static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3767 hdd_context_t *hdd_ctx,
3768 uint8_t *command,
3769 uint8_t command_len,
3770 hdd_priv_data_t *priv_data)
3771{
3772 int ret = 0;
3773 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3774 adapter->sessionId);
3775 char extra[32];
3776 uint8_t len = 0;
3777
3778 /* value is interms of msec */
3779 len = scnprintf(extra, sizeof(extra), "%s %d",
3780 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303781 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003782
3783 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003784 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003785 ret = -EFAULT;
3786 }
3787
3788 return ret;
3789}
3790
3791static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3792 hdd_context_t *hdd_ctx,
3793 uint8_t *command,
3794 uint8_t command_len,
3795 hdd_priv_data_t *priv_data)
3796{
3797 int ret = 0;
3798 uint8_t *value = command;
3799 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3800
3801 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3802 value = value + command_len + 1;
3803
3804 /* Convert the value from ascii to integer */
3805 ret = kstrtou16(value, 10, &val);
3806 if (ret < 0) {
3807 /*
3808 * If the input value is greater than max value of datatype,
3809 * then also kstrtou8 fails
3810 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003811 hdd_err("kstrtou16 failed range [%d - %d]",
3812 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3813 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003814 ret = -EINVAL;
3815 goto exit;
3816 }
3817
3818 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3819 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003820 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3821 val,
3822 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3823 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003824 ret = -EINVAL;
3825 goto exit;
3826 }
3827
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003828 hdd_info("Received Command to change scan home time = %d",
3829 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003830
3831 hdd_ctx->config->nNeighborScanPeriod = val;
3832 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3833 adapter->sessionId, val);
3834
3835exit:
3836 return ret;
3837}
3838
3839static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3840 hdd_context_t *hdd_ctx,
3841 uint8_t *command,
3842 uint8_t command_len,
3843 hdd_priv_data_t *priv_data)
3844{
3845 int ret = 0;
3846 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3847 adapter->
3848 sessionId);
3849 char extra[32];
3850 uint8_t len = 0;
3851
3852 /* value is interms of msec */
3853 len = scnprintf(extra, sizeof(extra), "%s %d",
3854 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303855 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003856
3857 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003858 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003859 ret = -EFAULT;
3860 }
3861
3862 return ret;
3863}
3864
3865static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3866 hdd_context_t *hdd_ctx,
3867 uint8_t *command,
3868 uint8_t command_len,
3869 hdd_priv_data_t *priv_data)
3870{
3871 int ret = 0;
3872 uint8_t *value = command;
3873 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3874
3875 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3876 value = value + command_len + 1;
3877
3878 /* Convert the value from ascii to integer */
3879 ret = kstrtou8(value, 10, &val);
3880 if (ret < 0) {
3881 /*
3882 * If the input value is greater than max value of datatype,
3883 * then also kstrtou8 fails
3884 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003885 hdd_err("kstrtou8 failed range [%d - %d]",
3886 CFG_ROAM_INTRA_BAND_MIN,
3887 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003888 ret = -EINVAL;
3889 goto exit;
3890 }
3891
3892 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3893 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003894 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3895 val,
3896 CFG_ROAM_INTRA_BAND_MIN,
3897 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003898 ret = -EINVAL;
3899 goto exit;
3900 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003901 hdd_info("Received Command to change intra band = %d",
3902 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903
3904 hdd_ctx->config->nRoamIntraBand = val;
3905 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3906
3907exit:
3908 return ret;
3909}
3910
3911static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3912 hdd_context_t *hdd_ctx,
3913 uint8_t *command,
3914 uint8_t command_len,
3915 hdd_priv_data_t *priv_data)
3916{
3917 int ret = 0;
3918 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3919 char extra[32];
3920 uint8_t len = 0;
3921
3922 /* value is interms of msec */
3923 len = scnprintf(extra, sizeof(extra), "%s %d",
3924 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303925 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003926 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003927 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003928 ret = -EFAULT;
3929 }
3930
3931 return ret;
3932}
3933
3934static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3935 hdd_context_t *hdd_ctx,
3936 uint8_t *command,
3937 uint8_t command_len,
3938 hdd_priv_data_t *priv_data)
3939{
3940 int ret = 0;
3941 uint8_t *value = command;
3942 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3943
3944 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3945 value = value + command_len + 1;
3946
3947 /* Convert the value from ascii to integer */
3948 ret = kstrtou8(value, 10, &nProbes);
3949 if (ret < 0) {
3950 /*
3951 * If the input value is greater than max value of datatype,
3952 * then also kstrtou8 fails
3953 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003954 hdd_err("kstrtou8 failed range [%d - %d]",
3955 CFG_ROAM_SCAN_N_PROBES_MIN,
3956 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003957 ret = -EINVAL;
3958 goto exit;
3959 }
3960
3961 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3962 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003963 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3964 nProbes,
3965 CFG_ROAM_SCAN_N_PROBES_MIN,
3966 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967 ret = -EINVAL;
3968 goto exit;
3969 }
3970
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003971 hdd_info("Received Command to Set nProbes = %d",
3972 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003973
3974 hdd_ctx->config->nProbes = nProbes;
3975 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3976 adapter->sessionId, nProbes);
3977
3978exit:
3979 return ret;
3980}
3981
3982static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3983 hdd_context_t *hdd_ctx,
3984 uint8_t *command,
3985 uint8_t command_len,
3986 hdd_priv_data_t *priv_data)
3987{
3988 int ret = 0;
3989 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3990 char extra[32];
3991 uint8_t len = 0;
3992
3993 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303994 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003995 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003996 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003997 ret = -EFAULT;
3998 }
3999
4000 return ret;
4001}
4002
4003static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4004 hdd_context_t *hdd_ctx,
4005 uint8_t *command,
4006 uint8_t command_len,
4007 hdd_priv_data_t *priv_data)
4008{
4009 int ret = 0;
4010 uint8_t *value = command;
4011 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4012
4013 /* input value is in units of msec */
4014
4015 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4016 value = value + command_len + 1;
4017
4018 /* Convert the value from ascii to integer */
4019 ret = kstrtou16(value, 10, &homeAwayTime);
4020 if (ret < 0) {
4021 /*
4022 * If the input value is greater than max value of datatype,
4023 * then also kstrtou8 fails
4024 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004025 hdd_err("kstrtou8 failed range [%d - %d]",
4026 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4027 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028 ret = -EINVAL;
4029 goto exit;
4030 }
4031
4032 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4033 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004034 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004035 homeAwayTime,
4036 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4037 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4038 ret = -EINVAL;
4039 goto exit;
4040 }
4041
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004042 hdd_info("Received Command to Set scan away time = %d",
4043 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004044
4045 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4046 homeAwayTime) {
4047 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4048 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4049 adapter->sessionId,
4050 homeAwayTime,
4051 true);
4052 }
4053
4054exit:
4055 return ret;
4056}
4057
4058static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4059 hdd_context_t *hdd_ctx,
4060 uint8_t *command,
4061 uint8_t command_len,
4062 hdd_priv_data_t *priv_data)
4063{
4064 int ret = 0;
4065 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4066 char extra[32];
4067 uint8_t len = 0;
4068
4069 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304070 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071
4072 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004073 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004074 ret = -EFAULT;
4075 }
4076
4077 return ret;
4078}
4079
4080static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4081 hdd_context_t *hdd_ctx,
4082 uint8_t *command,
4083 uint8_t command_len,
4084 hdd_priv_data_t *priv_data)
4085{
4086 return hdd_parse_reassoc(adapter, command);
4087}
4088
4089static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4090 hdd_context_t *hdd_ctx,
4091 uint8_t *command,
4092 uint8_t command_len,
4093 hdd_priv_data_t *priv_data)
4094{
4095 int ret = 0;
4096 uint8_t *value = command;
4097 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4098
4099 /* Move pointer to ahead of SETWESMODE<delimiter> */
4100 value = value + command_len + 1;
4101
4102 /* Convert the value from ascii to integer */
4103 ret = kstrtou8(value, 10, &wesMode);
4104 if (ret < 0) {
4105 /*
4106 * If the input value is greater than max value of datatype,
4107 * then also kstrtou8 fails
4108 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004109 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004110 CFG_ENABLE_WES_MODE_NAME_MIN,
4111 CFG_ENABLE_WES_MODE_NAME_MAX);
4112 ret = -EINVAL;
4113 goto exit;
4114 }
4115
4116 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4117 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004118 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004119 wesMode,
4120 CFG_ENABLE_WES_MODE_NAME_MIN,
4121 CFG_ENABLE_WES_MODE_NAME_MAX);
4122 ret = -EINVAL;
4123 goto exit;
4124 }
4125
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004126 hdd_info("Received Command to Set WES Mode rssi diff = %d",
4127 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004128
4129 hdd_ctx->config->isWESModeEnabled = wesMode;
4130 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4131
4132exit:
4133 return ret;
4134}
4135
4136static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4137 hdd_context_t *hdd_ctx,
4138 uint8_t *command,
4139 uint8_t command_len,
4140 hdd_priv_data_t *priv_data)
4141{
4142 int ret = 0;
4143 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4144 char extra[32];
4145 uint8_t len = 0;
4146
4147 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304148 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004149 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004150 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004151 ret = -EFAULT;
4152 }
4153
4154 return ret;
4155}
4156
4157static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4158 hdd_context_t *hdd_ctx,
4159 uint8_t *command,
4160 uint8_t command_len,
4161 hdd_priv_data_t *priv_data)
4162{
4163 int ret = 0;
4164 uint8_t *value = command;
4165 uint8_t nOpportunisticThresholdDiff =
4166 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4167
4168 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4169 value = value + command_len + 1;
4170
4171 /* Convert the value from ascii to integer */
4172 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4173 if (ret < 0) {
4174 /*
4175 * If the input value is greater than max value of datatype,
4176 * then also kstrtou8 fails
4177 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004178 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004179 ret = -EINVAL;
4180 goto exit;
4181 }
4182
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004183 hdd_info("Received Command to Set Opportunistic Threshold diff = %d",
4184 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004185
4186 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4187 adapter->sessionId,
4188 nOpportunisticThresholdDiff);
4189
4190exit:
4191 return ret;
4192}
4193
4194static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4195 hdd_context_t *hdd_ctx,
4196 uint8_t *command,
4197 uint8_t command_len,
4198 hdd_priv_data_t *priv_data)
4199{
4200 int ret = 0;
4201 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4202 hdd_ctx->hHal);
4203 char extra[32];
4204 uint8_t len = 0;
4205
4206 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304207 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004208 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004209 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004210 ret = -EFAULT;
4211 }
4212
4213 return ret;
4214}
4215
4216static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4217 hdd_context_t *hdd_ctx,
4218 uint8_t *command,
4219 uint8_t command_len,
4220 hdd_priv_data_t *priv_data)
4221{
4222 int ret = 0;
4223 uint8_t *value = command;
4224 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4225
4226 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4227 value = value + command_len + 1;
4228
4229 /* Convert the value from ascii to integer */
4230 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4231 if (ret < 0) {
4232 /*
4233 * If the input value is greater than max value of datatype,
4234 * then also kstrtou8 fails
4235 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004236 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004237 ret = -EINVAL;
4238 goto exit;
4239 }
4240
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004241 hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d",
4242 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004243
4244 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4245 adapter->sessionId,
4246 nRoamRescanRssiDiff);
4247
4248exit:
4249 return ret;
4250}
4251
4252static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4253 hdd_context_t *hdd_ctx,
4254 uint8_t *command,
4255 uint8_t command_len,
4256 hdd_priv_data_t *priv_data)
4257{
4258 int ret = 0;
4259 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4260 char extra[32];
4261 uint8_t len = 0;
4262
4263 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304264 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004265 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004266 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004267 ret = -EFAULT;
4268 }
4269
4270 return ret;
4271}
4272
4273static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4274 hdd_context_t *hdd_ctx,
4275 uint8_t *command,
4276 uint8_t command_len,
4277 hdd_priv_data_t *priv_data)
4278{
4279 int ret = 0;
4280 uint8_t *value = command;
4281 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4282
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004283 if (!adapter->fast_roaming_allowed) {
4284 hdd_err("Roaming is always disabled on this interface");
4285 goto exit;
4286 }
4287
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004288 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4289 value = value + command_len + 1;
4290
4291 /* Convert the value from ascii to integer */
4292 ret = kstrtou8(value, 10, &lfrMode);
4293 if (ret < 0) {
4294 /*
4295 * If the input value is greater than max value of datatype,
4296 * then also kstrtou8 fails
4297 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004298 hdd_err("kstrtou8 failed range [%d - %d]",
4299 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004300 CFG_LFR_FEATURE_ENABLED_MAX);
4301 ret = -EINVAL;
4302 goto exit;
4303 }
4304
4305 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4306 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004307 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004308 lfrMode,
4309 CFG_LFR_FEATURE_ENABLED_MIN,
4310 CFG_LFR_FEATURE_ENABLED_MAX);
4311 ret = -EINVAL;
4312 goto exit;
4313 }
4314
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004315 hdd_info("Received Command to change lfr mode = %d",
4316 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004317
4318 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4319 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4320 adapter->
4321 sessionId,
4322 lfrMode);
4323
4324exit:
4325 return ret;
4326}
4327
4328static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4329 hdd_context_t *hdd_ctx,
4330 uint8_t *command,
4331 uint8_t command_len,
4332 hdd_priv_data_t *priv_data)
4333{
4334 int ret = 0;
4335 uint8_t *value = command;
4336 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4337
4338 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4339 value = value + command_len + 1;
4340
4341 /* Convert the value from ascii to integer */
4342 ret = kstrtou8(value, 10, &ft);
4343 if (ret < 0) {
4344 /*
4345 * If the input value is greater than max value of datatype,
4346 * then also kstrtou8 fails
4347 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004348 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004349 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4350 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4351 ret = -EINVAL;
4352 goto exit;
4353 }
4354
4355 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4356 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004357 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004358 ft,
4359 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4360 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4361 ret = -EINVAL;
4362 goto exit;
4363 }
4364
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004365 hdd_info("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004366
4367 hdd_ctx->config->isFastTransitionEnabled = ft;
4368 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4369
4370exit:
4371 return ret;
4372}
4373
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004374static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4375 hdd_context_t *hdd_ctx,
4376 uint8_t *command,
4377 uint8_t command_len,
4378 hdd_priv_data_t *priv_data)
4379{
4380 int ret = 0;
4381 uint8_t *value = command;
4382 uint8_t channel = 0;
4383 tSirMacAddr targetApBssid;
4384 uint32_t roamId = 0;
4385 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004387 hdd_station_ctx_t *pHddStaCtx;
4388
Krunal Sonibe766b02016-03-10 13:00:44 -08004389 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004390 hdd_warn("Unsupported in mode %s(%d)",
4391 hdd_device_mode_to_string(adapter->device_mode),
4392 adapter->device_mode);
4393 return -EINVAL;
4394 }
4395
4396 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4397
4398 /* if not associated, no need to proceed with reassoc */
4399 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004400 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004401 ret = -EINVAL;
4402 goto exit;
4403 }
4404
4405 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4406 &channel);
4407 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004408 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004409 goto exit;
4410 }
4411
4412 /*
4413 * if the target bssid is same as currently associated AP,
4414 * issue reassoc to same AP
4415 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004416 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304418 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004419 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304420 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004421 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304422 targetApBssid,
4423 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304424 } else {
4425 sme_get_modify_profile_fields(hdd_ctx->hHal,
4426 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304428 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4429 NULL, modProfileFields, &roamId, 1);
4430 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431 return 0;
4432 }
4433
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304434 /* Check channel number is a valid channel number */
4435 if (QDF_STATUS_SUCCESS !=
4436 wlan_hdd_validate_operation_channel(adapter, channel)) {
4437 hdd_err("Invalid Channel [%d]", channel);
4438 return -EINVAL;
4439 }
4440
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004441 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004442 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443 targetApBssid, (int)channel);
4444 goto exit;
4445 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004446 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004447 handoffInfo.channel = channel;
4448 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004449 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004450 sizeof(tSirMacAddr));
4451 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4452 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004453exit:
4454 return ret;
4455}
4456
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004457static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4458 hdd_context_t *hdd_ctx,
4459 uint8_t *command,
4460 uint8_t command_len,
4461 hdd_priv_data_t *priv_data)
4462{
4463 int ret = 0;
4464 uint8_t *value = command;
4465 uint8_t roamScanControl = 0;
4466
4467 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4468 value = value + command_len + 1;
4469
4470 /* Convert the value from ascii to integer */
4471 ret = kstrtou8(value, 10, &roamScanControl);
4472 if (ret < 0) {
4473 /*
4474 * If the input value is greater than max value of datatype,
4475 * then also kstrtou8 fails
4476 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004477 hdd_err("kstrtou8 failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004478 ret = -EINVAL;
4479 goto exit;
4480 }
4481
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004482 hdd_info("Received Command to Set roam scan control = %d",
4483 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484
4485 if (0 != roamScanControl) {
4486 ret = 0; /* return success but ignore param value "true" */
4487 goto exit;
4488 }
4489
4490 sme_set_roam_scan_control(hdd_ctx->hHal,
4491 adapter->sessionId,
4492 roamScanControl);
4493
4494exit:
4495 return ret;
4496}
4497
4498static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4499 hdd_context_t *hdd_ctx,
4500 uint8_t *command,
4501 uint8_t command_len,
4502 hdd_priv_data_t *priv_data)
4503{
4504 int ret = 0;
4505 uint8_t *value = command;
4506 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4507
4508 /*
4509 * Check if the features OKC/ESE/11R are supported simultaneously,
4510 * then this operation is not permitted (return FAILURE)
4511 */
4512 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4513 hdd_is_okc_mode_enabled(hdd_ctx) &&
4514 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004515 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004516 ret = -EPERM;
4517 goto exit;
4518 }
4519
4520 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4521 value = value + command_len + 1;
4522
4523 /* Convert the value from ascii to integer */
4524 ret = kstrtou8(value, 10, &okcMode);
4525 if (ret < 0) {
4526 /*
4527 * If the input value is greater than max value of datatype,
4528 * then also kstrtou8 fails
4529 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004530 hdd_err("kstrtou8 failed range [%d - %d]",
4531 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004532 CFG_OKC_FEATURE_ENABLED_MAX);
4533 ret = -EINVAL;
4534 goto exit;
4535 }
4536
4537 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4538 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004539 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004540 okcMode,
4541 CFG_OKC_FEATURE_ENABLED_MIN,
4542 CFG_OKC_FEATURE_ENABLED_MAX);
4543 ret = -EINVAL;
4544 goto exit;
4545 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004546 hdd_info("Received Command to change okc mode = %d",
4547 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004548
4549 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4550
4551exit:
4552 return ret;
4553}
4554
4555static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4556 hdd_context_t *hdd_ctx,
4557 uint8_t *command,
4558 uint8_t command_len,
4559 hdd_priv_data_t *priv_data)
4560{
4561 int ret = 0;
4562 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4563 char extra[32];
4564 uint8_t len = 0;
4565
4566 len = scnprintf(extra, sizeof(extra), "%s %d",
4567 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304568 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004569 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004570 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004571 ret = -EFAULT;
4572 }
4573
4574 return ret;
4575}
4576
4577static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4578 hdd_context_t *hdd_ctx,
4579 uint8_t *command,
4580 uint8_t command_len,
4581 hdd_priv_data_t *priv_data)
4582{
4583 int ret = 0;
4584 char *bcMode;
4585
4586 bcMode = command + 11;
4587 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004588 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004589 hdd_ctx->btCoexModeSet = true;
4590 ret = wlan_hdd_scan_abort(adapter);
4591 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004592 hdd_err("Failed to abort existing scan status: %d",
4593 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594 }
4595 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004596 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004597 hdd_ctx->btCoexModeSet = false;
4598 }
4599
4600 return ret;
4601}
4602
4603static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4604 hdd_context_t *hdd_ctx,
4605 uint8_t *command,
4606 uint8_t command_len,
4607 hdd_priv_data_t *priv_data)
4608{
4609 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4610 return 0;
4611}
4612
4613static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4614 hdd_context_t *hdd_ctx,
4615 uint8_t *command,
4616 uint8_t command_len,
4617 hdd_priv_data_t *priv_data)
4618{
4619 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4620 return 0;
4621}
4622
4623static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4624 hdd_context_t *hdd_ctx,
4625 uint8_t *command,
4626 uint8_t command_len,
4627 hdd_priv_data_t *priv_data)
4628{
4629 int ret = 0;
4630 struct hdd_config *pCfg =
4631 (WLAN_HDD_GET_CTX(adapter))->config;
4632 char extra[32];
4633 uint8_t len = 0;
4634
4635 memset(extra, 0, sizeof(extra));
4636 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304637 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004639 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 ret = -EFAULT;
4641 goto exit;
4642 }
4643 ret = len;
4644exit:
4645 return ret;
4646}
4647
4648static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4649 hdd_context_t *hdd_ctx,
4650 uint8_t *command,
4651 uint8_t command_len,
4652 hdd_priv_data_t *priv_data)
4653{
4654 return hdd_set_dwell_time(adapter, command);
4655}
4656
4657static int drv_cmd_miracast(hdd_adapter_t *adapter,
4658 hdd_context_t *hdd_ctx,
4659 uint8_t *command,
4660 uint8_t command_len,
4661 hdd_priv_data_t *priv_data)
4662{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304663 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004664 int ret = 0;
4665 tHalHandle hHal;
4666 uint8_t filterType = 0;
4667 hdd_context_t *pHddCtx = NULL;
4668 uint8_t *value;
4669
4670 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304671 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004672 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004673
4674 hHal = pHddCtx->hHal;
4675 value = command + 9;
4676
4677 /* Convert the value from ascii to integer */
4678 ret = kstrtou8(value, 10, &filterType);
4679 if (ret < 0) {
4680 /*
4681 * If the input value is greater than max value of datatype,
4682 * then also kstrtou8 fails
4683 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004684 hdd_err("kstrtou8 failed range ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004685 ret = -EINVAL;
4686 goto exit;
4687 }
4688 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4689 || (filterType >
4690 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004691 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004692 ret = -EINVAL;
4693 goto exit;
4694 }
4695 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4696 pHddCtx->miracast_value = filterType;
4697
4698 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304699 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004700 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004701 return -EBUSY;
4702 }
4703
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004704 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004705 return cds_set_mas(adapter, filterType);
4706
4707exit:
4708 return ret;
4709}
4710
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004711/* Function header is left blank intentionally */
4712static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4713 int32_t *oui_length, int32_t limit)
4714{
4715 uint8_t len;
4716 uint8_t data;
4717
4718 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4719 command++;
4720 limit--;
4721 }
4722
4723 len = 2;
4724
4725 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4726 (limit > 1)) {
4727 sscanf(command, "%02x", (unsigned int *)&data);
4728 ie[len++] = data;
4729 command += 2;
4730 limit -= 2;
4731 }
4732
4733 *oui_length = len - 2;
4734
4735 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4736 command++;
4737 limit--;
4738 }
4739
4740 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4741 (limit > 1)) {
4742 sscanf(command, "%02x", (unsigned int *)&data);
4743 ie[len++] = data;
4744 command += 2;
4745 limit -= 2;
4746 }
4747
4748 ie[0] = IE_EID_VENDOR;
4749 ie[1] = len - 2;
4750
4751 return len;
4752}
4753
4754/**
4755 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4756 * @adapter: Pointer to adapter
4757 * @hdd_ctx: Pointer to HDD context
4758 * @command: Pointer to command string
4759 * @command_len : Command length
4760 * @priv_data : Pointer to priv data
4761 *
4762 * Return:
4763 * int status code
4764 */
4765static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4766 hdd_context_t *hdd_ctx,
4767 uint8_t *command,
4768 uint8_t command_len,
4769 hdd_priv_data_t *priv_data)
4770{
4771 int i = 0;
4772 int status;
4773 int ret = 0;
4774 uint8_t *ibss_ie;
4775 int32_t oui_length = 0;
4776 uint32_t ibss_ie_length;
4777 uint8_t *value = command;
4778 tSirModifyIE ibssModifyIE;
4779 tCsrRoamProfile *pRoamProfile;
4780 hdd_wext_state_t *pWextState;
4781
4782
Krunal Sonibe766b02016-03-10 13:00:44 -08004783 if (QDF_IBSS_MODE != adapter->device_mode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004784 hdd_info("Device_mode %s(%d) not IBSS",
4785 hdd_device_mode_to_string(adapter->device_mode),
4786 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004787 return ret;
4788 }
4789
4790 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4791
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004792 hdd_info("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004793
4794
4795 /* validate argument of command */
4796 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004797 hdd_err("No arguments in command length %zu",
4798 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004799 ret = -EFAULT;
4800 goto exit;
4801 }
4802
4803 /* moving to arguments of commands */
4804 value = value + command_len;
4805 command_len = strlen(value);
4806
4807 /* oui_data can't be less than 3 bytes */
4808 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004809 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4810 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004811 ret = -EFAULT;
4812 goto exit;
4813 }
4814
4815 ibss_ie = qdf_mem_malloc(command_len);
4816 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004817 hdd_err("Could not allocate memory for command length %d",
4818 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004819 ret = -ENOMEM;
4820 goto exit;
4821 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004822
4823 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4824 &oui_length,
4825 command_len);
4826 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004827 hdd_err("Could not parse command %s return length %d",
4828 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004829 ret = -EFAULT;
4830 qdf_mem_free(ibss_ie);
4831 goto exit;
4832 }
4833
4834 pRoamProfile = &pWextState->roamProfile;
4835
4836 qdf_copy_macaddr(&ibssModifyIE.bssid,
4837 pRoamProfile->BSSIDs.bssid);
4838
4839 ibssModifyIE.smeSessionId = adapter->sessionId;
4840 ibssModifyIE.notify = true;
4841 ibssModifyIE.ieID = IE_EID_VENDOR;
4842 ibssModifyIE.ieIDLen = ibss_ie_length;
4843 ibssModifyIE.ieBufferlength = ibss_ie_length;
4844 ibssModifyIE.pIEBuffer = ibss_ie;
4845 ibssModifyIE.oui_length = oui_length;
4846
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004847 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4848 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004849 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004850 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004851
4852 /* Probe Bcn modification */
4853 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4854 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4855
4856 /* Populating probe resp frame */
4857 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4858 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4859
4860 qdf_mem_free(ibss_ie);
4861
4862 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4863 adapter->sessionId);
4864 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004865 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004866 status);
4867 ret = -EINVAL;
4868 goto exit;
4869 }
4870
4871exit:
4872 return ret;
4873}
4874
4875static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4876 hdd_context_t *hdd_ctx,
4877 uint8_t *command,
4878 uint8_t command_len,
4879 hdd_priv_data_t *priv_data)
4880{
4881 int ret = 0;
4882 uint8_t *value = command;
4883 uint8_t ucRmcEnable = 0;
4884 int status;
4885
Krunal Sonibe766b02016-03-10 13:00:44 -08004886 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4887 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004888 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4889 hdd_device_mode_to_string(adapter->device_mode),
4890 adapter->device_mode);
4891 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004892 ret = -EINVAL;
4893 goto exit;
4894 }
4895
4896 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4897 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004898 hdd_err("Invalid SETRMCENABLE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004899 ret = -EINVAL;
4900 goto exit;
4901 }
4902
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004903 hdd_info("ucRmcEnable %d ", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004904
4905 if (true == ucRmcEnable) {
4906 status = sme_enable_rmc((tHalHandle)
4907 (hdd_ctx->hHal),
4908 adapter->sessionId);
4909 } else if (false == ucRmcEnable) {
4910 status = sme_disable_rmc((tHalHandle)
4911 (hdd_ctx->hHal),
4912 adapter->sessionId);
4913 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004914 hdd_err("Invalid SETRMCENABLE command %d",
4915 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004916 ret = -EINVAL;
4917 goto exit;
4918 }
4919
4920 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004921 hdd_err("SETRMC %d failed status %d",
4922 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004923 ret = -EINVAL;
4924 goto exit;
4925 }
4926
4927exit:
4928 return ret;
4929}
4930
4931static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4932 hdd_context_t *hdd_ctx,
4933 uint8_t *command,
4934 uint8_t command_len,
4935 hdd_priv_data_t *priv_data)
4936{
4937 int ret = 0;
4938 uint8_t *value = command;
4939 uint32_t uActionPeriod = 0;
4940 int status;
4941
Krunal Sonibe766b02016-03-10 13:00:44 -08004942 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4943 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004944 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004945 hdd_device_mode_to_string(adapter->device_mode),
4946 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004947 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004948 ret = -EINVAL;
4949 goto exit;
4950 }
4951
4952 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4953 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004954 hdd_err("Invalid SETRMCACTIONPERIOD command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004955 ret = -EINVAL;
4956 goto exit;
4957 }
4958
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004959 hdd_info("uActionPeriod %d ",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004960 uActionPeriod);
4961
4962 if (sme_cfg_set_int(hdd_ctx->hHal,
4963 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4964 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004965 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4966 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004967 ret = -EINVAL;
4968 goto exit;
4969 }
4970
4971 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4972 adapter->sessionId);
4973 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004974 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004975 status);
4976 ret = -EINVAL;
4977 goto exit;
4978 }
4979
4980exit:
4981 return ret;
4982}
4983
4984static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
4985 hdd_context_t *hdd_ctx,
4986 uint8_t *command,
4987 uint8_t command_len,
4988 hdd_priv_data_t *priv_data)
4989{
4990 int ret = 0;
4991 int status = QDF_STATUS_SUCCESS;
4992 hdd_station_ctx_t *pHddStaCtx = NULL;
4993 char *extra = NULL;
4994 int idx = 0;
4995 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004996 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004997 uint32_t numOfBytestoPrint = 0;
4998
Krunal Sonibe766b02016-03-10 13:00:44 -08004999 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005000 hdd_warn("Unsupported in mode %s(%d)",
5001 hdd_device_mode_to_string(adapter->device_mode),
5002 adapter->device_mode);
5003 return -EINVAL;
5004 }
5005
5006 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005007 hdd_info("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005008
5009 /* Handle the command */
5010 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5011 if (QDF_STATUS_SUCCESS == status) {
5012 /*
5013 * The variable extra needed to be allocated on the heap since
5014 * amount of memory required to copy the data for 32 devices
5015 * exceeds the size of 1024 bytes of default stack size. On
5016 * 64 bit devices, the default max stack size of 2048 bytes
5017 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005018 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005019
5020 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005021 hdd_err("memory allocation failed");
5022 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005023 goto exit;
5024 }
5025
5026 /* Copy number of stations */
5027 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005028 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005029 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005030 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5031 idx++) {
5032 int8_t rssi;
5033 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005034
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005035 qdf_mem_copy(mac_addr,
5036 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5037 mac_addr, sizeof(mac_addr));
5038
5039 tx_rate =
5040 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5041 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305042 /*
5043 * Only lower 3 bytes are rate info. Mask of the MSByte
5044 */
5045 tx_rate &= 0x00FFFFFF;
5046
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005047 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5048 rssi;
5049
5050 length += scnprintf((extra + length),
5051 WLAN_MAX_BUF_SIZE - length,
5052 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5053 mac_addr[0], mac_addr[1], mac_addr[2],
5054 mac_addr[3], mac_addr[4], mac_addr[5],
5055 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005056 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005057 * cdf_trace_msg has limitation of 512 bytes for the
5058 * print buffer. Hence printing the data in two chunks.
5059 * The first chunk will have the data for 16 devices
5060 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005061 */
5062 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5063 numOfBytestoPrint = length;
5064 }
5065
5066 /*
5067 * Copy the data back into buffer, if the data to copy is
5068 * more than 512 bytes than we will split the data and do
5069 * it in two shots
5070 */
5071 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005072 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005073 ret = -EFAULT;
5074 goto exit;
5075 }
5076
5077 priv_data->buf[numOfBytestoPrint] = '\0';
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005078 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005079
5080 if (length > numOfBytestoPrint) {
5081 if (copy_to_user
5082 (priv_data->buf + numOfBytestoPrint,
5083 extra + numOfBytestoPrint,
5084 length - numOfBytestoPrint + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005085 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005086 ret = -EFAULT;
5087 goto exit;
5088 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005089 hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005090 }
5091
5092 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005093 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005094 } else {
5095 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005096 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5097 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005098 ret = -EINVAL;
5099 goto exit;
5100 }
5101 ret = 0;
5102
5103exit:
5104 return ret;
5105}
5106
5107/* Peer Info <Peer Addr> command */
5108static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5109 hdd_context_t *hdd_ctx,
5110 uint8_t *command,
5111 uint8_t command_len,
5112 hdd_priv_data_t *priv_data)
5113{
5114 int ret = 0;
5115 uint8_t *value = command;
5116 QDF_STATUS status;
5117 hdd_station_ctx_t *pHddStaCtx = NULL;
5118 char extra[128] = { 0 };
5119 uint32_t length = 0;
5120 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005121 struct qdf_mac_addr peerMacAddr;
5122
Krunal Sonibe766b02016-03-10 13:00:44 -08005123 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005124 hdd_warn("Unsupported in mode %s(%d)",
5125 hdd_device_mode_to_string(adapter->device_mode),
5126 adapter->device_mode);
5127 return -EINVAL;
5128 }
5129
5130 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5131
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005132 hdd_info("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005133
5134 /* if there are no peers, no need to continue with the command */
5135 if (eConnectionState_IbssConnected !=
5136 pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005137 hdd_info("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005138 ret = -EINVAL;
5139 goto exit;
5140 }
5141
5142 /* Parse the incoming command buffer */
5143 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5144 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005145 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005146 ret = -EINVAL;
5147 goto exit;
5148 }
5149
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005150 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005151 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005152
Naveen Rawatc45d1622016-07-05 12:20:09 -07005153 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005154 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005155 ret = -EINVAL;
5156 goto exit;
5157 }
5158
5159 /* Handle the command */
5160 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5161 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005162 uint32_t txRate =
5163 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305164 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5165 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005166
5167 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005168 (int)txRate,
5169 (int)pHddStaCtx->ibss_peer_info.
5170 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005171
5172 /* Copy the data back into buffer */
5173 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005174 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005175 ret = -EFAULT;
5176 goto exit;
5177 }
5178 } else {
5179 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005180 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5181 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005182 ret = -EINVAL;
5183 goto exit;
5184 }
5185
5186 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005187 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005188 ret = 0;
5189
5190exit:
5191 return ret;
5192}
5193
5194static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5195 hdd_context_t *hdd_ctx,
5196 uint8_t *command,
5197 uint8_t command_len,
5198 hdd_priv_data_t *priv_data)
5199{
5200 int ret = 0;
5201 uint8_t *value = command;
5202 uint32_t uRate = 0;
5203 tTxrateinfoflags txFlags = 0;
5204 tSirRateUpdateInd rateUpdateParams = {0};
5205 int status;
5206 struct hdd_config *pConfig = hdd_ctx->config;
5207
Krunal Sonibe766b02016-03-10 13:00:44 -08005208 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5209 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005210 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5211 hdd_device_mode_to_string(adapter->device_mode),
5212 adapter->device_mode);
5213 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005214 ret = -EINVAL;
5215 goto exit;
5216 }
5217
5218 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5219 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005220 hdd_err("Invalid SETRMCTXRATE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005221 ret = -EINVAL;
5222 goto exit;
5223 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005224 hdd_info("uRate %d ", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005225 /* -1 implies ignore this param */
5226 rateUpdateParams.ucastDataRate = -1;
5227
5228 /*
5229 * Fill the user specifieed RMC rate param
5230 * and the derived tx flags.
5231 */
5232 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5233 rateUpdateParams.reliableMcastDataRate = uRate;
5234 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5235 rateUpdateParams.dev_mode = adapter->device_mode;
5236 rateUpdateParams.bcastDataRate = -1;
5237 memcpy(rateUpdateParams.bssid.bytes,
5238 adapter->macAddressCurrent.bytes,
5239 sizeof(rateUpdateParams.bssid));
5240 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5241 &rateUpdateParams);
5242
5243exit:
5244 return ret;
5245}
5246
5247static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5248 hdd_context_t *hdd_ctx,
5249 uint8_t *command,
5250 uint8_t command_len,
5251 hdd_priv_data_t *priv_data)
5252{
5253 int ret = 0;
5254 char *value;
5255 uint8_t tx_fail_count = 0;
5256 uint16_t pid = 0;
5257
5258 value = command;
5259
5260 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5261
5262 if (0 != ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005263 hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005264 goto exit;
5265 }
5266
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005267 hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005268
5269 if (0 == tx_fail_count) {
5270 /* Disable TX Fail Indication */
5271 if (QDF_STATUS_SUCCESS ==
5272 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5273 tx_fail_count,
5274 NULL)) {
5275 cesium_pid = 0;
5276 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005277 hdd_err("failed to disable TX Fail Event ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005278 ret = -EINVAL;
5279 }
5280 } else {
5281 if (QDF_STATUS_SUCCESS ==
5282 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5283 tx_fail_count,
5284 (void *)hdd_tx_fail_ind_callback)) {
5285 cesium_pid = pid;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005286 hdd_info("Registered Cesium pid %u",
5287 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005288 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005289 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005290 ret = -EINVAL;
5291 }
5292 }
5293
5294exit:
5295 return ret;
5296}
5297
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005298#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005299static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5300 hdd_context_t *hdd_ctx,
5301 uint8_t *command,
5302 uint8_t command_len,
5303 hdd_priv_data_t *priv_data)
5304{
5305 int ret = 0;
5306 uint8_t *value = command;
5307 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5308 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305309 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005310
5311 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5312 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005313 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005314 goto exit;
5315 }
5316 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005317 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005318 numChannels,
5319 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5320 ret = -EINVAL;
5321 goto exit;
5322 }
5323 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5324 adapter->sessionId,
5325 ChannelList,
5326 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305327 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005328 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005329 ret = -EINVAL;
5330 goto exit;
5331 }
5332
5333exit:
5334 return ret;
5335}
5336
5337static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5338 hdd_context_t *hdd_ctx,
5339 uint8_t *command,
5340 uint8_t command_len,
5341 hdd_priv_data_t *priv_data)
5342{
5343 int ret = 0;
5344 uint8_t *value = command;
5345 char extra[128] = { 0 };
5346 int len = 0;
5347 uint8_t tid = 0;
5348 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005349 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005350
Krunal Sonibe766b02016-03-10 13:00:44 -08005351 if ((QDF_STA_MODE != adapter->device_mode) &&
5352 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005353 hdd_warn("Unsupported in mode %s(%d)",
5354 hdd_device_mode_to_string(adapter->device_mode),
5355 adapter->device_mode);
5356 return -EINVAL;
5357 }
5358
5359 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5360
5361 /* if not associated, return error */
5362 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005363 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005364 ret = -EINVAL;
5365 goto exit;
5366 }
5367
5368 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5369 value = value + command_len + 1;
5370
5371 /* Convert the value from ascii to integer */
5372 ret = kstrtou8(value, 10, &tid);
5373 if (ret < 0) {
5374 /*
5375 * If the input value is greater than max value of datatype,
5376 * then also kstrtou8 fails
5377 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005378 hdd_err("kstrtou8 failed range [%d - %d]",
5379 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005380 TID_MAX_VALUE);
5381 ret = -EINVAL;
5382 goto exit;
5383 }
5384 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005385 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005386 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5387 ret = -EINVAL;
5388 goto exit;
5389 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005390 hdd_info("Received Command to get tsm stats tid = %d",
5391 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005392 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5393 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005394 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005395 goto exit;
5396 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005397 hdd_info(
5398 "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 -08005399 tsm_metrics.UplinkPktQueueDly,
5400 tsm_metrics.UplinkPktQueueDlyHist[0],
5401 tsm_metrics.UplinkPktQueueDlyHist[1],
5402 tsm_metrics.UplinkPktQueueDlyHist[2],
5403 tsm_metrics.UplinkPktQueueDlyHist[3],
5404 tsm_metrics.UplinkPktTxDly,
5405 tsm_metrics.UplinkPktLoss,
5406 tsm_metrics.UplinkPktCount,
5407 tsm_metrics.RoamingCount,
5408 tsm_metrics.RoamingDly);
5409 /*
5410 * Output TSM stats is of the format
5411 * GETTSMSTATS [PktQueueDly]
5412 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5413 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5414 */
5415 len = scnprintf(extra,
5416 sizeof(extra),
5417 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5418 command,
5419 tsm_metrics.UplinkPktQueueDly,
5420 tsm_metrics.UplinkPktQueueDlyHist[0],
5421 tsm_metrics.UplinkPktQueueDlyHist[1],
5422 tsm_metrics.UplinkPktQueueDlyHist[2],
5423 tsm_metrics.UplinkPktQueueDlyHist[3],
5424 tsm_metrics.UplinkPktTxDly,
5425 tsm_metrics.UplinkPktLoss,
5426 tsm_metrics.UplinkPktCount,
5427 tsm_metrics.RoamingCount,
5428 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305429 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005430 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005431 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005432 ret = -EFAULT;
5433 goto exit;
5434 }
5435
5436exit:
5437 return ret;
5438}
5439
5440static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5441 hdd_context_t *hdd_ctx,
5442 uint8_t *command,
5443 uint8_t command_len,
5444 hdd_priv_data_t *priv_data)
5445{
5446 int ret;
5447 uint8_t *value = command;
5448 uint8_t *cckmIe = NULL;
5449 uint8_t cckmIeLen = 0;
5450
5451 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5452 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005453 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005454 goto exit;
5455 }
5456
5457 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005458 hdd_err("CCKM Ie input length is more than max[%d]",
5459 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005460 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305461 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005462 cckmIe = NULL;
5463 }
5464 ret = -EINVAL;
5465 goto exit;
5466 }
5467
5468 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5469 cckmIe, cckmIeLen);
5470 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305471 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005472 cckmIe = NULL;
5473 }
5474
5475exit:
5476 return ret;
5477}
5478
5479static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5480 hdd_context_t *hdd_ctx,
5481 uint8_t *command,
5482 uint8_t command_len,
5483 hdd_priv_data_t *priv_data)
5484{
5485 int ret;
5486 uint8_t *value = command;
5487 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305488 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005489
Krunal Sonibe766b02016-03-10 13:00:44 -08005490 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005491 hdd_warn("Unsupported in mode %s(%d)",
5492 hdd_device_mode_to_string(adapter->device_mode),
5493 adapter->device_mode);
5494 return -EINVAL;
5495 }
5496
5497 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5498 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005499 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005500 goto exit;
5501 }
5502
5503 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005504 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005505 hdd_indicate_ese_bcn_report_no_results(adapter,
5506 eseBcnReq.bcnReq[0].measurementToken,
5507 0x02, /* BIT(1) set for measurement done */
5508 0); /* no BSS */
5509 goto exit;
5510 }
5511
5512 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5513 adapter->sessionId,
5514 &eseBcnReq);
5515
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305516 if (QDF_STATUS_E_RESOURCES == status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005517 hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress",
5518 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005519 ret = -EBUSY;
5520 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305521 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005522 hdd_err("sme_set_ese_beacon_request failed (%d)",
5523 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005524 ret = -EINVAL;
5525 goto exit;
5526 }
5527
5528exit:
5529 return ret;
5530}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005531
5532/**
5533 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5534 * @adapter: Pointer to the HDD adapter
5535 * @hdd_ctx: Pointer to the HDD context
5536 * @command: Driver command string
5537 * @command_len: Driver command string length
5538 * @priv_data: Private data coming with the driver command. Unused here
5539 *
5540 * This function handles driver command that sets the ESE PLM request
5541 *
5542 * Return: 0 on success; negative errno otherwise
5543 */
5544static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5545 hdd_context_t *hdd_ctx,
5546 uint8_t *command,
5547 uint8_t command_len,
5548 hdd_priv_data_t *priv_data)
5549{
5550 int ret = 0;
5551 uint8_t *value = command;
5552 QDF_STATUS status = QDF_STATUS_SUCCESS;
5553 tpSirPlmReq pPlmRequest = NULL;
5554
5555 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5556 if (NULL == pPlmRequest) {
5557 ret = -ENOMEM;
5558 goto exit;
5559 }
5560
5561 status = hdd_parse_plm_cmd(value, pPlmRequest);
5562 if (QDF_STATUS_SUCCESS != status) {
5563 qdf_mem_free(pPlmRequest);
5564 pPlmRequest = NULL;
5565 ret = -EINVAL;
5566 goto exit;
5567 }
5568 pPlmRequest->sessionId = adapter->sessionId;
5569
5570 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5571 if (QDF_STATUS_SUCCESS != status) {
5572 qdf_mem_free(pPlmRequest);
5573 pPlmRequest = NULL;
5574 ret = -EINVAL;
5575 goto exit;
5576 }
5577
5578exit:
5579 return ret;
5580}
5581
5582/**
5583 * drv_cmd_set_ccx_mode() - Set ESE mode
5584 * @adapter: Pointer to the HDD adapter
5585 * @hdd_ctx: Pointer to the HDD context
5586 * @command: Driver command string
5587 * @command_len: Driver command string length
5588 * @priv_data: Private data coming with the driver command. Unused here
5589 *
5590 * This function handles driver command that sets ESE mode
5591 *
5592 * Return: 0 on success; negative errno otherwise
5593 */
5594static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5595 hdd_context_t *hdd_ctx,
5596 uint8_t *command,
5597 uint8_t command_len,
5598 hdd_priv_data_t *priv_data)
5599{
5600 int ret = 0;
5601 uint8_t *value = command;
5602 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5603
5604 /*
5605 * Check if the features OKC/ESE/11R are supported simultaneously,
5606 * then this operation is not permitted (return FAILURE)
5607 */
5608 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5609 hdd_is_okc_mode_enabled(hdd_ctx) &&
5610 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5611 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5612 ret = -EPERM;
5613 goto exit;
5614 }
5615
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005616 if (!adapter->fast_roaming_allowed) {
5617 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5618 ret = -EPERM;
5619 goto exit;
5620 }
5621
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005622 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5623 value = value + command_len + 1;
5624
5625 /* Convert the value from ascii to integer */
5626 ret = kstrtou8(value, 10, &eseMode);
5627 if (ret < 0) {
5628 /*
5629 * If the input value is greater than max value of datatype,
5630 * then also kstrtou8 fails
5631 */
5632 hdd_err("kstrtou8 failed range [%d - %d]",
5633 CFG_ESE_FEATURE_ENABLED_MIN,
5634 CFG_ESE_FEATURE_ENABLED_MAX);
5635 ret = -EINVAL;
5636 goto exit;
5637 }
5638
5639 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5640 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5641 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5642 eseMode,
5643 CFG_ESE_FEATURE_ENABLED_MIN,
5644 CFG_ESE_FEATURE_ENABLED_MAX);
5645 ret = -EINVAL;
5646 goto exit;
5647 }
5648 hdd_info("Received Command to change ese mode = %d", eseMode);
5649
5650 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5651 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5652 adapter->sessionId,
5653 eseMode);
5654
5655exit:
5656 return ret;
5657}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005658#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005659
5660static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5661 hdd_context_t *hdd_ctx,
5662 uint8_t *command,
5663 uint8_t command_len,
5664 hdd_priv_data_t *priv_data)
5665{
5666 int ret = 0;
5667 uint8_t *value = command;
5668 int targetRate;
5669
5670 /* input value is in units of hundred kbps */
5671
5672 /* Move pointer to ahead of SETMCRATE<delimiter> */
5673 value = value + command_len + 1;
5674
5675 /* Convert the value from ascii to integer, decimal base */
5676 ret = kstrtouint(value, 10, &targetRate);
5677
5678 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5679 return ret;
5680}
5681
5682static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5683 hdd_context_t *hdd_ctx,
5684 uint8_t *command,
5685 uint8_t command_len,
5686 hdd_priv_data_t *priv_data)
5687{
5688 int ret = 0;
5689 int status;
5690 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305691 QDF_STATUS qdf_status;
5692 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005693 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305694 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5695 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005696 hdd_adapter_list_node_t *pAdapterNode = NULL;
5697 hdd_adapter_list_node_t *pNext = NULL;
5698
5699 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5700 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005701 hdd_err("Invalid MAXTXPOWER command ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005702 ret = -EINVAL;
5703 goto exit;
5704 }
5705
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305706 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005707 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305708 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005709 adapter = pAdapterNode->pAdapter;
5710 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305711 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005712 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305713 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005714 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005715
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005716 hdd_info("Device mode %d max tx power %d selfMac: "
5717 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005718 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005719 MAC_ADDR_ARRAY(selfMac.bytes),
5720 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005721
Srinivas Girigowda97215232015-09-24 12:26:28 -07005722 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5723 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305724 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005725 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005726 ret = -EINVAL;
5727 goto exit;
5728 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005729 hdd_info("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305730 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005731 &pNext);
5732 pAdapterNode = pNext;
5733 }
5734
5735exit:
5736 return ret;
5737}
5738
5739static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5740 hdd_context_t *hdd_ctx,
5741 uint8_t *command,
5742 uint8_t command_len,
5743 hdd_priv_data_t *priv_data)
5744{
5745 int ret = 0;
5746 uint8_t *value = command;
5747 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5748
5749 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5750 value = value + command_len + 1;
5751
5752 /* Convert the value from ascii to integer */
5753 ret = kstrtou8(value, 10, &dfsScanMode);
5754 if (ret < 0) {
5755 /*
5756 * If the input value is greater than max value of datatype,
5757 * then also kstrtou8 fails
5758 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005759 hdd_err("kstrtou8 failed range [%d - %d]",
5760 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005761 CFG_ROAMING_DFS_CHANNEL_MAX);
5762 ret = -EINVAL;
5763 goto exit;
5764 }
5765
5766 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5767 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005768 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005769 dfsScanMode,
5770 CFG_ROAMING_DFS_CHANNEL_MIN,
5771 CFG_ROAMING_DFS_CHANNEL_MAX);
5772 ret = -EINVAL;
5773 goto exit;
5774 }
5775
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005776 hdd_info("Received Command to Set DFS Scan Mode = %d",
5777 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005778
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005779 /* When DFS scanning is disabled, the DFS channels need to be
5780 * removed from the operation of device.
5781 */
5782 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5783 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5784 if (ret < 0) {
5785 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005786 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005787 goto exit;
5788 }
5789
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005790 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5791 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5792 dfsScanMode);
5793
5794exit:
5795 return ret;
5796}
5797
5798static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5799 hdd_context_t *hdd_ctx,
5800 uint8_t *command,
5801 uint8_t command_len,
5802 hdd_priv_data_t *priv_data)
5803{
5804 int ret = 0;
5805 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5806 char extra[32];
5807 uint8_t len = 0;
5808
5809 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305810 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005811 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005812 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005813 ret = -EFAULT;
5814 }
5815
5816 return ret;
5817}
5818
5819static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5820 hdd_context_t *hdd_ctx,
5821 uint8_t *command,
5822 uint8_t command_len,
5823 hdd_priv_data_t *priv_data)
5824{
5825 int ret = 0;
5826 int value = wlan_hdd_get_link_status(adapter);
5827 char extra[32];
5828 uint8_t len;
5829
5830 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305831 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005832 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005833 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005834 ret = -EFAULT;
5835 }
5836
5837 return ret;
5838}
5839
5840#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5841static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5842 hdd_context_t *hdd_ctx,
5843 uint8_t *command,
5844 uint8_t command_len,
5845 hdd_priv_data_t *priv_data)
5846{
5847 uint8_t *value = command;
5848 int set_value;
5849
5850 /* Move pointer to ahead of ENABLEEXTWOW */
5851 value = value + command_len;
5852
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305853 if (!(sscanf(value, "%d", &set_value))) {
5854 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5855 ("No input identified"));
5856 return -EINVAL;
5857 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005858
5859 return hdd_enable_ext_wow_parser(adapter,
5860 adapter->sessionId,
5861 set_value);
5862}
5863
5864static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5865 hdd_context_t *hdd_ctx,
5866 uint8_t *command,
5867 uint8_t command_len,
5868 hdd_priv_data_t *priv_data)
5869{
5870 int ret;
5871 uint8_t *value = command;
5872
5873 /* Move pointer to ahead of SETAPP1PARAMS */
5874 value = value + command_len;
5875
5876 ret = hdd_set_app_type1_parser(adapter,
5877 value, strlen(value));
5878 if (ret >= 0)
5879 hdd_ctx->is_extwow_app_type1_param_set = true;
5880
5881 return ret;
5882}
5883
5884static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5885 hdd_context_t *hdd_ctx,
5886 uint8_t *command,
5887 uint8_t command_len,
5888 hdd_priv_data_t *priv_data)
5889{
5890 int ret;
5891 uint8_t *value = command;
5892
5893 /* Move pointer to ahead of SETAPP2PARAMS */
5894 value = value + command_len;
5895
5896 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5897 if (ret >= 0)
5898 hdd_ctx->is_extwow_app_type2_param_set = true;
5899
5900 return ret;
5901}
5902#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5903
5904#ifdef FEATURE_WLAN_TDLS
5905/**
5906 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5907 * @adapter: Pointer to the HDD adapter
5908 * @hdd_ctx: Pointer to the HDD context
5909 * @command: Driver command string
5910 * @command_len: Driver command string length
5911 * @priv_data: Private data coming with the driver command. Unused here
5912 *
5913 * This function handles driver command that sets the secondary tdls off channel
5914 * offset
5915 *
5916 * Return: 0 on success; negative errno otherwise
5917 */
5918static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5919 hdd_context_t *hdd_ctx,
5920 uint8_t *command,
5921 uint8_t command_len,
5922 hdd_priv_data_t *priv_data)
5923{
5924 int ret;
5925 uint8_t *value = command;
5926 int set_value;
5927
5928 /* Move pointer to point the string */
5929 value += command_len;
5930
5931 ret = sscanf(value, "%d", &set_value);
5932 if (ret != 1)
5933 return -EINVAL;
5934
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005935 hdd_info("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005936
5937 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5938
5939 return ret;
5940}
5941
5942/**
5943 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5944 * @adapter: Pointer to the HDD adapter
5945 * @hdd_ctx: Pointer to the HDD context
5946 * @command: Driver command string
5947 * @command_len: Driver command string length
5948 * @priv_data: Private data coming with the driver command. Unused here
5949 *
5950 * This function handles driver command that sets tdls off channel mode
5951 *
5952 * Return: 0 on success; negative errno otherwise
5953 */
5954static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5955 hdd_context_t *hdd_ctx,
5956 uint8_t *command,
5957 uint8_t command_len,
5958 hdd_priv_data_t *priv_data)
5959{
5960 int ret;
5961 uint8_t *value = command;
5962 int set_value;
5963
5964 /* Move pointer to point the string */
5965 value += command_len;
5966
5967 ret = sscanf(value, "%d", &set_value);
5968 if (ret != 1)
5969 return -EINVAL;
5970
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005971 hdd_info("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005972
5973 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5974
5975 return ret;
5976}
5977
5978/**
5979 * drv_cmd_tdls_off_channel() - set tdls off channel number
5980 * @adapter: Pointer to the HDD adapter
5981 * @hdd_ctx: Pointer to the HDD context
5982 * @command: Driver command string
5983 * @command_len: Driver command string length
5984 * @priv_data: Private data coming with the driver command. Unused here
5985 *
5986 * This function handles driver command that sets tdls off channel number
5987 *
5988 * Return: 0 on success; negative errno otherwise
5989 */
5990static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5991 hdd_context_t *hdd_ctx,
5992 uint8_t *command,
5993 uint8_t command_len,
5994 hdd_priv_data_t *priv_data)
5995{
5996 int ret;
5997 uint8_t *value = command;
5998 int set_value;
5999
6000 /* Move pointer to point the string */
6001 value += command_len;
6002
6003 ret = sscanf(value, "%d", &set_value);
6004 if (ret != 1)
6005 return -EINVAL;
6006
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006007 if (CDS_IS_DFS_CH(set_value)) {
6008 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6009 set_value);
6010 return -EINVAL;
6011 }
6012
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006013 hdd_info("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006014
6015 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6016
6017 return ret;
6018}
6019
6020/**
6021 * drv_cmd_tdls_scan() - set tdls scan type
6022 * @adapter: Pointer to the HDD adapter
6023 * @hdd_ctx: Pointer to the HDD context
6024 * @command: Driver command string
6025 * @command_len: Driver command string length
6026 * @priv_data: Private data coming with the driver command. Unused here
6027 *
6028 * This function handles driver command that sets tdls scan type
6029 *
6030 * Return: 0 on success; negative errno otherwise
6031 */
6032static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6033 hdd_context_t *hdd_ctx,
6034 uint8_t *command,
6035 uint8_t command_len,
6036 hdd_priv_data_t *priv_data)
6037{
6038 int ret;
6039 uint8_t *value = command;
6040 int set_value;
6041
6042 /* Move pointer to point the string */
6043 value += command_len;
6044
6045 ret = sscanf(value, "%d", &set_value);
6046 if (ret != 1)
6047 return -EINVAL;
6048
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006049 hdd_info("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006050
6051 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6052
6053 return ret;
6054}
6055#endif
6056
6057static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6058 hdd_context_t *hdd_ctx,
6059 uint8_t *command,
6060 uint8_t command_len,
6061 hdd_priv_data_t *priv_data)
6062{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006063 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006064 int8_t rssi = 0;
6065 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006066
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006067 uint8_t len = 0;
6068
6069 wlan_hdd_get_rssi(adapter, &rssi);
6070
6071 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306072 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006073
6074 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006075 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006076 ret = -EFAULT;
6077 }
6078
6079 return ret;
6080}
6081
6082static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6083 hdd_context_t *hdd_ctx,
6084 uint8_t *command,
6085 uint8_t command_len,
6086 hdd_priv_data_t *priv_data)
6087{
6088 int ret;
6089 uint32_t link_speed = 0;
6090 char extra[32];
6091 uint8_t len = 0;
6092
6093 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6094 if (0 != ret)
6095 return ret;
6096
6097 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306098 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006099 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006100 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006101 ret = -EFAULT;
6102 }
6103
6104 return ret;
6105}
6106
6107#ifdef FEATURE_NAPI
6108/**
6109 * hdd_parse_napi() - helper functions to drv_cmd_napi
6110 * @str : source string to parse
6111 * @cmd : pointer to cmd part after parsing
6112 * @sub : pointer to subcmd part after parsing
6113 * @aux : pointer to optional aux part after parsing
6114 *
6115 * Example:
6116 * NAPI SCALE <n> +-- IN str
6117 * | | +------ OUT aux
6118 * | +------------ OUT subcmd
6119 * +----------------- OUT cmd
6120 *
6121 * Return: ==0: success; !=0: failure
6122 */
6123static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6124{
6125 int rc;
6126 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6127
6128 NAPI_DEBUG("-->\n");
6129
6130 token = strsep(str, " \t");
6131 if (NULL == token) {
6132 hdd_err("cannot parse cmd");
6133 goto parse_end;
6134 }
6135 lcmd = token;
6136
6137 token = strsep(str, " \t");
6138 if (NULL == token) {
6139 hdd_err("cannot parse subcmd");
6140 goto parse_end;
6141 }
6142 lsub = token;
6143
6144 token = strsep(str, " \t");
6145 if (NULL == token)
6146 hdd_warn("cannot parse aux\n");
6147 else
6148 laux = token;
6149
6150parse_end:
6151 if ((NULL == lcmd) || (NULL == lsub))
6152 rc = -EINVAL;
6153 else {
6154 rc = 0;
6155 *cmd = lcmd;
6156 *sub = lsub;
6157 if (NULL != aux)
6158 *aux = laux;
6159 }
6160 NAPI_DEBUG("<--[rc=%d]\n", rc);
6161 return rc;
6162}
6163
6164
6165/**
6166 * hdd_parse_stats() - print NAPI stats into a buffer
6167 * @buf : buffer to write stats into
6168 * @max : "size of buffer"
6169 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6170 * @napid: binary structure to retrieve the stats from
6171 *
6172 * Return: number of bytes written into the buffer
6173 */
6174int hdd_napi_stats(char *buf,
6175 int max,
6176 char *indp,
6177 struct qca_napi_data *napid)
6178{
6179 int n = 0;
6180 int i, j, k; /* NAPI, CPU, bucket indices */
6181 int from, to;
6182 struct qca_napi_info *napii;
6183 struct qca_napi_stat *napis;
6184
6185 NAPI_DEBUG("-->\n");
6186
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006187 if (NULL == napid)
6188 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006189 if (NULL == indp) {
6190 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006191 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006192 } else {
6193 if (0 > kstrtoint(indp, 10, &to)) {
6194 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006195 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006196 } else
6197 from = to;
6198 }
6199
6200 for (i = from; i < to; i++)
6201 if (napid->ce_map & (0x01 << i)) {
6202 napii = &(napid->napis[i]);
6203 for (j = 0; j < NR_CPUS; j++) {
6204 napis = &(napii->stats[j]);
6205 n += scnprintf(buf + n, max - n,
6206 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6207 i, j,
6208 napis->napi_schedules,
6209 napis->napi_polls,
6210 napis->napi_completes,
6211 napis->napi_workdone);
6212
6213 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6214 n += scnprintf(
6215 buf + n, max - n,
6216 " %d",
6217 napis->napi_budget_uses[k]);
6218 }
6219 n += scnprintf(buf+n, max - n, "\n");
6220 }
6221 }
6222
6223 NAPI_DEBUG("<--[n=%d]\n", n);
6224 return n;
6225}
6226
6227/**
6228 * napi_set_scale() - sets the scale attribute in all NAPI entries
6229 * @sc : scale to set
6230 *
6231 * Return: void
6232 */
6233static void napi_set_scale(uint8_t sc)
6234{
6235 uint32_t i;
6236 struct qca_napi_data *napi_data;
6237
6238 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006239 if (likely(NULL != napi_data))
6240 for (i = 0; i < CE_COUNT_MAX; i++)
6241 if (napi_data->ce_map & (0x01 << i))
6242 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006243
6244 return;
6245}
6246/**
6247 * drv_cmd_napi() - processes NAPI commands
6248 * @adapter : net_device
6249 * @hdd_ctx : HDD context
6250 * @command : command string from user command (including "NAPI")
6251 * @command_len: length of command
6252 * @priv_data : ifr_data
6253 *
6254 * Commands supported:
6255 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6256 * enable NAPI functionally, as some other conditions
6257 * may not have been satisfied yet
6258 * NAPI DISABLE : reverse operation of "enable"
6259 * NAPI STATUS : get global status of NAPI instances
6260 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6261 * NAPI SCALE <n> : set the scale factor
6262 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006263 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006264 */
6265static int drv_cmd_napi(hdd_adapter_t *adapter,
6266 hdd_context_t *hdd_ctx,
6267 uint8_t *command,
6268 uint8_t command_len,
6269 hdd_priv_data_t *priv_data)
6270{
6271 int rc = 0;
6272 int n, l;
6273 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6274 char *synopsis = "NAPI ENABLE\n"
6275 "NAPI DISABLE\n"
6276 "NAPI STATUS\n"
6277 "NAPI STATS [<n>] -- if no <n> then all\n"
6278 "NAPI SCALE <n> -- set the scale\n";
6279 char *reply = NULL;
6280
6281 /* make a local copy, as strsep modifies the str in place */
6282 char *str = NULL;
6283
6284 NAPI_DEBUG("-->\n");
6285
6286 /**
6287 * NOTE TO MAINTAINER: from this point to the end of the function,
6288 * please do not return anywhere in the code except the very end
6289 * to avoid memory leakage (goto end_drv_napi instead)
6290 * or make sure that reply+str is freed
6291 */
6292 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6293 if (NULL == reply) {
6294 hdd_err("could not allocate reply buffer");
6295 rc = -ENOMEM;
6296 goto end_drv_napi;
6297 }
6298
6299 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6300 if (NULL == str) {
6301 hdd_err("could not allocate copy of input buffer");
6302 rc = -ENOMEM;
6303 goto end_drv_napi;
6304 }
6305
6306 strlcpy(str, command, strlen(command) + 1);
6307 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6308 cmd, subcmd, aux);
6309
6310
6311 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6312
6313 if (0 != rc) {
6314 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306315 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006316 strlen(msg)+strlen(synopsis));
6317 n = scnprintf(reply, l, msg, synopsis);
6318
6319 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306320 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006321 hdd_err("failed to copy data to user buffer");
6322 hdd_debug("reply: %s", reply);
6323
6324 rc = -EINVAL;
6325 } else {
6326 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6327 cmd, subcmd, aux);
6328 if (!strcmp(subcmd, "ENABLE"))
6329 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6330 else if (!strcmp(subcmd, "DISABLE"))
6331 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6332 else if (!strcmp(subcmd, "STATUS")) {
6333 int n = 0;
6334 uint32_t i;
6335 struct qca_napi_data *napi_data;
6336
6337 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006338 if (unlikely(NULL == napi_data))
6339 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006340 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6341 "NAPI state: 0x%08x map: 0x%08x\n",
6342 napi_data->state,
6343 napi_data->ce_map);
6344
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006345 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006346 if (napi_data->ce_map & (0x01 << i)) {
6347 n += scnprintf(
6348 reply + n,
6349 MAX_USER_COMMAND_SIZE - n,
6350 "#%d: id: %d, scale=%d\n",
6351 i,
6352 napi_data->napis[i].id,
6353 napi_data->napis[i].scale);
6354 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006355 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006356 hdd_info("wlan: STATUS DATA:\n%s", reply);
6357 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306358 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006359 rc = -EINVAL;
6360 } else if (!strcmp(subcmd, "STATS")) {
6361 int n = 0;
6362 struct qca_napi_data *napi_data;
6363
6364 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006365 if (NULL != napi_data) {
6366 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6367 aux, napi_data);
6368 NAPI_DEBUG("STATS: returns %d\n", n);
6369 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006370 if (n > 0) {
6371 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306372 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006373 n)))
6374 rc = -EINVAL;
6375 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6376 } else
6377 rc = -EINVAL;
6378 } else if (!strcmp(subcmd, "SCALE")) {
6379 if (NULL == aux) {
6380 rc = -EINVAL;
6381 hdd_err("wlan: SCALE cmd requires <n>");
6382 } else {
6383 uint8_t sc;
6384 rc = kstrtou8(aux, 10, &sc);
6385 if (rc) {
6386 hdd_err("wlan: bad scale (%s)", aux);
6387 rc = -EINVAL;
6388 } else
6389 napi_set_scale(sc);
6390 }
6391 } /* SCALE */
6392 }
6393end_drv_napi:
6394 if (NULL != str)
6395 kfree(str);
6396 if (NULL != reply)
6397 kfree(reply);
6398
6399 NAPI_DEBUG("<--[rc=%d]\n", rc);
6400 return rc;
6401}
6402#endif /* FEATURE_NAPI */
6403
6404/**
6405 * hdd_set_rx_filter() - set RX filter
6406 * @adapter: Pointer to adapter
6407 * @action: Filter action
6408 * @pattern: Address pattern
6409 *
6410 * Address pattern is most significant byte of address for example
6411 * 0x01 for IPV4 multicast address
6412 * 0x33 for IPV6 multicast address
6413 * 0xFF for broadcast address
6414 *
6415 * Return: 0 for success, non-zero for failure
6416 */
6417static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6418 uint8_t pattern)
6419{
6420 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006421 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006422 tHalHandle handle;
6423 tSirRcvFltMcAddrList *filter;
6424 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6425
6426 ret = wlan_hdd_validate_context(hdd_ctx);
6427 if (0 != ret)
6428 return ret;
6429
6430 handle = hdd_ctx->hHal;
6431
6432 if (NULL == handle) {
6433 hdd_err("HAL Handle is NULL");
6434 return -EINVAL;
6435 }
6436
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306437 if (!hdd_ctx->config->fEnableMCAddrList) {
6438 hdd_notice("mc addr ini is disabled");
6439 return -EINVAL;
6440 }
6441
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006442 /*
6443 * If action is false it means start dropping packets
6444 * Set addr_filter_pattern which will be used when sending
6445 * MC/BC address list to target
6446 */
6447 if (!action)
6448 adapter->addr_filter_pattern = pattern;
6449 else
6450 adapter->addr_filter_pattern = 0;
6451
Krunal Sonibe766b02016-03-10 13:00:44 -08006452 if (((adapter->device_mode == QDF_STA_MODE) ||
6453 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006454 adapter->mc_addr_list.mc_cnt &&
6455 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6456
6457
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306458 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006459 if (NULL == filter) {
6460 hdd_err("Could not allocate Memory");
6461 return -ENOMEM;
6462 }
6463 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006464 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006465 if (!memcmp(adapter->mc_addr_list.addr[i],
6466 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006467 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006468 adapter->mc_addr_list.addr[i],
6469 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006470
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006471 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006472 MAC_ADDRESS_STR,
6473 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006474 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6475 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006476 }
6477 }
Frank Liuf95e8132016-09-29 19:01:30 +08006478 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006479 /* Set rx filter */
6480 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306481 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006482 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006483 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006484 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6485 }
6486
6487 return 0;
6488}
6489
6490/**
6491 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6492 * @command: Pointer to input string driver command
6493 * @adapter: Pointer to adapter
6494 * @action: Action to enable/disable filtering
6495 *
6496 * If action == false
6497 * Start filtering out data packets based on type
6498 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6499 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6500 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6501 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6502 *
6503 * if action == true
6504 * Stop filtering data packets based on type
6505 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6506 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6507 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6508 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6509 *
6510 * Current implementation only supports IPV4 address filtering by
6511 * selectively allowing IPV4 multicast data packest based on
6512 * address list received in .ndo_set_rx_mode
6513 *
6514 * Return: 0 for success, non-zero for failure
6515 */
6516static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6517 hdd_adapter_t *adapter,
6518 bool action)
6519{
6520 int ret = 0;
6521 uint8_t *value;
6522 uint8_t type;
6523
6524 value = command;
6525 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6526 if (!action)
6527 value = command + 16;
6528 else
6529 value = command + 13;
6530 ret = kstrtou8(value, 10, &type);
6531 if (ret < 0) {
6532 hdd_err("kstrtou8 failed invalid input value %d", type);
6533 return -EINVAL;
6534 }
6535
6536 switch (type) {
6537 case 2:
6538 /* Set rx filter for IPV4 multicast data packets */
6539 ret = hdd_set_rx_filter(adapter, action, 0x01);
6540 break;
6541 default:
6542 hdd_info("Unsupported RXFILTER type %d", type);
6543 break;
6544 }
6545
6546 return ret;
6547}
6548
6549/**
6550 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6551 * @adapter: Pointer to network adapter
6552 * @hdd_ctx: Pointer to hdd context
6553 * @command: Pointer to input command
6554 * @command_len: Command length
6555 * @priv_data: Pointer to private data in command
6556 */
6557static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6558 hdd_context_t *hdd_ctx,
6559 uint8_t *command,
6560 uint8_t command_len,
6561 hdd_priv_data_t *priv_data)
6562{
6563 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6564}
6565
6566/**
6567 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6568 * @adapter: Pointer to network adapter
6569 * @hdd_ctx: Pointer to hdd context
6570 * @command: Pointer to input command
6571 * @command_len: Command length
6572 * @priv_data: Pointer to private data in command
6573 */
6574static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6575 hdd_context_t *hdd_ctx,
6576 uint8_t *command,
6577 uint8_t command_len,
6578 hdd_priv_data_t *priv_data)
6579{
6580 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6581}
6582
Archana Ramachandran393f3792015-11-13 17:13:21 -08006583/**
6584 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6585 * command
6586 * @value: Pointer to SETANTENNAMODE command
6587 * @mode: Pointer to antenna mode
6588 * @reason: Pointer to reason for set antenna mode
6589 *
6590 * This function parses the SETANTENNAMODE command passed in the format
6591 * SETANTENNAMODE<space>mode
6592 *
6593 * Return: 0 for success non-zero for failure
6594 */
6595static int hdd_parse_setantennamode_command(const uint8_t *value)
6596{
6597 const uint8_t *in_ptr = value;
6598 int tmp, v;
6599 char arg1[32];
6600
6601 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6602
6603 /* no argument after the command */
6604 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006605 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006606 return -EINVAL;
6607 }
6608
6609 /* no space after the command */
6610 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006611 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006612 return -EINVAL;
6613 }
6614
6615 /* remove empty spaces */
6616 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6617 in_ptr++;
6618
6619 /* no argument followed by spaces */
6620 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006621 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006622 return -EINVAL;
6623 }
6624
6625 /* get the argument i.e. antenna mode */
6626 v = sscanf(in_ptr, "%31s ", arg1);
6627 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006628 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006629 return -EINVAL;
6630 }
6631
6632 v = kstrtos32(arg1, 10, &tmp);
6633 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006634 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006635 return -EINVAL;
6636 }
6637
6638 return tmp;
6639}
6640
6641/**
6642 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6643 * mask is 2x2 mode
6644 * @hdd_ctx: Pointer to hdd contex
6645 *
6646 * Return: true if supported chain mask 2x2 else false
6647 */
6648static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6649{
6650 /*
6651 * Revisit and the update logic to determine the number
6652 * of TX/RX chains supported in the system when
6653 * antenna sharing per band chain mask support is
6654 * brought in
6655 */
6656 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6657}
6658
6659/**
6660 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6661 * chain mask is 1x1
6662 * @hdd_ctx: Pointer to hdd contex
6663 *
6664 * Return: true if supported chain mask 1x1 else false
6665 */
6666static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6667{
6668 /*
6669 * Revisit and update the logic to determine the number
6670 * of TX/RX chains supported in the system when
6671 * antenna sharing per band chain mask support is
6672 * brought in
6673 */
6674 return (!hdd_ctx->config->enable2x2) ? true : false;
6675}
6676
6677/**
6678 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6679 * handler
6680 * @adapter: Pointer to network adapter
6681 * @hdd_ctx: Pointer to hdd context
6682 * @command: Pointer to input command
6683 * @command_len: Command length
6684 * @priv_data: Pointer to private data in command
6685 */
6686static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6687 hdd_context_t *hdd_ctx,
6688 uint8_t *command,
6689 uint8_t command_len,
6690 hdd_priv_data_t *priv_data)
6691{
6692 struct sir_antenna_mode_param params;
6693 QDF_STATUS status;
6694 int ret = 0;
6695 int mode;
6696 uint8_t *value = command;
6697 uint8_t smps_mode;
6698 uint8_t smps_enable;
6699
6700 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6701 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6702 hdd_err("Operation invalid in non sta or concurrent mode");
6703 ret = -EPERM;
6704 goto exit;
6705 }
6706
6707 mode = hdd_parse_setantennamode_command(value);
6708 if (mode < 0) {
6709 hdd_err("Invalid SETANTENNA command");
6710 ret = mode;
6711 goto exit;
6712 }
6713
6714 hdd_info("Processing antenna mode switch to: %d", mode);
6715
6716 if (hdd_ctx->current_antenna_mode == mode) {
6717 hdd_err("System already in the requested mode");
6718 ret = 0;
6719 goto exit;
6720 }
6721
6722 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6723 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6724 hdd_err("System does not support 2x2 mode");
6725 ret = -EPERM;
6726 goto exit;
6727 }
6728
6729 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6730 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6731 hdd_err("System only supports 1x1 mode");
6732 ret = 0;
6733 goto exit;
6734 }
6735
6736 switch (mode) {
6737 case HDD_ANTENNA_MODE_1X1:
6738 params.num_rx_chains = 1;
6739 params.num_tx_chains = 1;
6740 break;
6741 case HDD_ANTENNA_MODE_2X2:
6742 params.num_rx_chains = 2;
6743 params.num_tx_chains = 2;
6744 break;
6745 default:
6746 hdd_err("unsupported antenna mode");
6747 ret = -EINVAL;
6748 goto exit;
6749 }
6750
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006751 /* Check TDLS status and update antenna mode */
6752 if ((QDF_STA_MODE == adapter->device_mode) &&
Kabilan Kannan32eb5022016-10-04 12:24:50 -07006753 cds_is_sta_active_connection_exists()) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006754 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6755 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006756 if (0 != ret)
6757 goto exit;
6758 }
6759
Archana Ramachandran393f3792015-11-13 17:13:21 -08006760 params.set_antenna_mode_resp =
6761 (void *)wlan_hdd_soc_set_antenna_mode_cb;
6762 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
6763 params.num_rx_chains,
6764 params.num_tx_chains);
6765
6766
6767 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6768 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6769 if (QDF_STATUS_SUCCESS != status) {
6770 hdd_err("set antenna mode failed status : %d", status);
6771 ret = -EFAULT;
6772 goto exit;
6773 }
6774
6775 ret = wait_for_completion_timeout(
6776 &hdd_ctx->set_antenna_mode_cmpl,
6777 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6778 if (!ret) {
6779 ret = -EFAULT;
6780 hdd_err("send set antenna mode timed out");
6781 goto exit;
6782 }
6783
6784 /* Update SME SMPS config */
6785 if (HDD_ANTENNA_MODE_1X1 == mode) {
6786 smps_enable = true;
6787 smps_mode = HDD_SMPS_MODE_STATIC;
6788 } else {
6789 smps_enable = false;
6790 smps_mode = HDD_SMPS_MODE_DISABLED;
6791 }
6792
6793 hdd_info("Update SME SMPS enable: %d mode: %d",
6794 smps_enable, smps_mode);
6795 status = sme_update_mimo_power_save(
6796 hdd_ctx->hHal, smps_enable, smps_mode, false);
6797 if (QDF_STATUS_SUCCESS != status) {
6798 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6799 smps_enable, smps_mode, status);
6800 ret = -EFAULT;
6801 goto exit;
6802 }
6803
Archana Ramachandran393f3792015-11-13 17:13:21 -08006804 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006805 /* Update the user requested nss in the mac context.
6806 * This will be used in tdls protocol engine to form tdls
6807 * Management frames.
6808 */
6809 sme_update_user_configured_nss(
6810 hdd_ctx->hHal,
6811 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006812
Archana Ramachandran5041b252016-04-25 14:29:25 -07006813 hdd_info("Successfully switched to mode: %d x %d",
6814 hdd_ctx->current_antenna_mode,
6815 hdd_ctx->current_antenna_mode);
6816 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006817exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006818#ifdef FEATURE_WLAN_TDLS
6819 /* Reset tdls NSS flags */
6820 if (hdd_ctx->tdls_nss_switch_in_progress &&
6821 hdd_ctx->tdls_nss_teardown_complete) {
6822 hdd_ctx->tdls_nss_switch_in_progress = false;
6823 hdd_ctx->tdls_nss_teardown_complete = false;
6824 }
6825 hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
6826 hdd_ctx->tdls_nss_switch_in_progress,
6827 hdd_ctx->tdls_nss_teardown_complete);
6828#endif
Archana Ramachandran393f3792015-11-13 17:13:21 -08006829 hdd_info("Set antenna status: %d current mode: %d",
6830 ret, hdd_ctx->current_antenna_mode);
6831 return ret;
6832
6833}
6834
6835/**
6836 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6837 * handler
6838 * @adapter: Pointer to hdd adapter
6839 * @hdd_ctx: Pointer to hdd context
6840 * @command: Pointer to input command
6841 * @command_len: length of the command
6842 * @priv_data: private data coming with the driver command
6843 *
6844 * Return: 0 for success non-zero for failure
6845 */
6846static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6847 hdd_context_t *hdd_ctx,
6848 uint8_t *command,
6849 uint8_t command_len,
6850 hdd_priv_data_t *priv_data)
6851{
6852 uint32_t antenna_mode = 0;
6853 char extra[32];
6854 uint8_t len = 0;
6855
6856 antenna_mode = hdd_ctx->current_antenna_mode;
6857 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6858 antenna_mode);
6859 len = QDF_MIN(priv_data->total_len, len + 1);
6860 if (copy_to_user(priv_data->buf, &extra, len)) {
6861 hdd_err("Failed to copy data to user buffer");
6862 return -EFAULT;
6863 }
6864
6865 hdd_info("Get antenna mode: %d", antenna_mode);
6866
6867 return 0;
6868}
6869
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006870/*
6871 * dummy (no-op) hdd driver command handler
6872 */
6873static int drv_cmd_dummy(hdd_adapter_t *adapter,
6874 hdd_context_t *hdd_ctx,
6875 uint8_t *command,
6876 uint8_t command_len,
6877 hdd_priv_data_t *priv_data)
6878{
6879 hdd_info("%s: Ignoring driver command \"%s\"",
6880 adapter->dev->name, command);
6881 return 0;
6882}
6883
6884/*
6885 * handler for any unsupported wlan hdd driver command
6886 */
6887static int drv_cmd_invalid(hdd_adapter_t *adapter,
6888 hdd_context_t *hdd_ctx,
6889 uint8_t *command,
6890 uint8_t command_len,
6891 hdd_priv_data_t *priv_data)
6892{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306893 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006894 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6895 adapter->sessionId, 0));
6896
6897 hdd_warn("%s: Unsupported driver command \"%s\"",
6898 adapter->dev->name, command);
6899
6900 return -ENOTSUPP;
6901}
6902
6903/**
6904 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6905 * @adapter: HDD adapter
6906 * @hdd_ctx: HDD context
6907 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6908 * @command_len: command len
6909 * @priv_data: private data
6910 *
6911 * Return: status
6912 */
6913static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6914 hdd_context_t *hdd_ctx,
6915 uint8_t *command,
6916 uint8_t command_len,
6917 hdd_priv_data_t *priv_data)
6918{
6919 uint8_t *value;
6920 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306921 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006922 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006923 int ret = 0;
6924
6925 /*
6926 * this command would be called by user-space when it detects WLAN
6927 * ON after airplane mode is set. When APM is set, WLAN turns off.
6928 * But it can be turned back on. Otherwise; when APM is turned back
6929 * off, WLAN would turn back on. So at that point the command is
6930 * expected to come down. 0 means disable, 1 means enable. The
6931 * constraint is removed when parameter 1 is set or different
6932 * country code is set
6933 */
6934
6935 value = command + command_len + 1;
6936
6937 ret = kstrtou8(value, 10, &fcc_constraint);
6938 if ((ret < 0) || (fcc_constraint > 1)) {
6939 /*
6940 * If the input value is greater than max value of datatype,
6941 * then also it is a failure
6942 */
6943 hdd_err("value out of range");
6944 return -EINVAL;
6945 }
Sandeep Puligillad0004212017-02-26 18:34:56 -08006946#ifndef NAPIER_SCAN
6947 /* This code will be removed*/
Amar Singhal83a047a2016-05-19 15:56:11 -07006948 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
Sandeep Puligillad0004212017-02-26 18:34:56 -08006949#else
6950 scan_pending = ucfg_scan_get_pdev_status(hdd_ctx->hdd_pdev);
6951#endif
Amar Singhal83a047a2016-05-19 15:56:11 -07006952 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6953 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306954 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006955 hdd_err("sme disable fn. returned err");
6956 ret = -EPERM;
6957 }
6958
6959 return ret;
6960}
6961
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306962/**
6963 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6964 * command
6965 * @value: Pointer to the command
6966 * @chan_number: Pointer to the channel number
6967 * @chan_bw: Pointer to the channel bandwidth
6968 *
6969 * Parses and provides the channel number and channel width from the input
6970 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6971 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6972 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6973 *
6974 * Return: 0 for success, non-zero for failure
6975 */
6976static int hdd_parse_set_channel_switch_command(uint8_t *value,
6977 uint32_t *chan_number,
6978 uint32_t *chan_bw)
6979{
6980 const uint8_t *in_ptr = value;
6981 int ret;
6982
6983 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6984
6985 /* no argument after the command */
6986 if (NULL == in_ptr) {
6987 hdd_err("No argument after the command");
6988 return -EINVAL;
6989 }
6990
6991 /* no space after the command */
6992 if (SPACE_ASCII_VALUE != *in_ptr) {
6993 hdd_err("No space after the command ");
6994 return -EINVAL;
6995 }
6996
6997 /* remove empty spaces and move the next argument */
6998 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6999 in_ptr++;
7000
7001 /* no argument followed by spaces */
7002 if ('\0' == *in_ptr) {
7003 hdd_err("No argument followed by spaces");
7004 return -EINVAL;
7005 }
7006
7007 /* get the two arguments: channel number and bandwidth */
7008 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7009 if (ret != 2) {
7010 hdd_err("Arguments retrieval from cmd string failed");
7011 return -EINVAL;
7012 }
7013
7014 return 0;
7015}
7016
7017/**
7018 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7019 * @adapter: HDD adapter
7020 * @hdd_ctx: HDD context
7021 * @command: Pointer to the input command CHANNEL_SWITCH
7022 * @command_len: Command len
7023 * @priv_data: Private data
7024 *
7025 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7026 * of SAP/P2P-GO
7027 *
7028 * Return: 0 for success, non-zero for failure
7029 */
7030static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
7031 hdd_context_t *hdd_ctx,
7032 uint8_t *command,
7033 uint8_t command_len,
7034 hdd_priv_data_t *priv_data)
7035{
7036 struct net_device *dev = adapter->dev;
7037 int status;
7038 uint32_t chan_number = 0, chan_bw = 0;
7039 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007040 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307041
Krunal Sonibe766b02016-03-10 13:00:44 -08007042 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7043 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307044 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7045 adapter->device_mode);
7046 return -EINVAL;
7047 }
7048
7049 status = hdd_parse_set_channel_switch_command(value,
7050 &chan_number, &chan_bw);
7051 if (status) {
7052 hdd_err("Invalid CHANNEL_SWITCH command");
7053 return status;
7054 }
7055
7056 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7057 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7058 return -EINVAL;
7059 }
7060
7061 if (chan_bw == 80)
7062 width = CH_WIDTH_80MHZ;
7063 else if (chan_bw == 40)
7064 width = CH_WIDTH_40MHZ;
7065 else
7066 width = CH_WIDTH_20MHZ;
7067
7068 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
7069
7070 status = hdd_softap_set_channel_change(dev, chan_number, width);
7071 if (status) {
7072 hdd_err("Set channel change fail");
7073 return status;
7074 }
7075
7076 return 0;
7077}
7078
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007079/*
7080 * The following table contains all supported WLAN HDD
7081 * IOCTL driver commands and the handler for each of them.
7082 */
7083static const hdd_drv_cmd_t hdd_drv_cmds[] = {
7084 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
7085 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
7086 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
7087 {"SETBAND", drv_cmd_set_band},
7088 {"SETWMMPS", drv_cmd_set_wmmps},
7089 {"COUNTRY", drv_cmd_country},
7090 {"SETSUSPENDMODE", drv_cmd_dummy},
7091 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
7092 {"BTCOEXSCAN", drv_cmd_dummy},
7093 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007094 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
7095 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
7096 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
7097 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
7098 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
7099 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007100 {"SETROAMMODE", drv_cmd_set_roam_mode},
7101 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007102 {"SETROAMDELTA", drv_cmd_set_roam_delta},
7103 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007104 {"GETBAND", drv_cmd_get_band},
7105 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
7106 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
7107 {"GETCCXMODE", drv_cmd_get_ccx_mode},
7108 {"GETOKCMODE", drv_cmd_get_okc_mode},
7109 {"GETFASTROAM", drv_cmd_get_fast_roam},
7110 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
7111 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
7112 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
7113 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
7114 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
7115 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
7116 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
7117 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
7118 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
7119 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
7120 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
7121 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
7122 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
7123 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7124 {"REASSOC", drv_cmd_reassoc},
7125 {"SETWESMODE", drv_cmd_set_wes_mode},
7126 {"GETWESMODE", drv_cmd_get_wes_mode},
7127 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7128 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7129 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7130 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007131 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007132 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7133 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007134 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007135 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007136 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7137 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7138 {"SCAN-ACTIVE", drv_cmd_scan_active},
7139 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7140 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7141 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7142 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007143 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7144 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7145 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7146 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7147 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7148 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7149 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007150#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007151 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7152 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7153 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07007154 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
7155 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
7156 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007157#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007158 {"SETMCRATE", drv_cmd_set_mc_rate},
7159 {"MAXTXPOWER", drv_cmd_max_tx_power},
7160 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7161 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7162 {"GETLINKSTATUS", drv_cmd_get_link_status},
7163#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7164 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7165 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7166 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7167#endif
7168#ifdef FEATURE_WLAN_TDLS
7169 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7170 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7171 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7172 {"TDLSSCAN", drv_cmd_tdls_scan},
7173#endif
7174 {"RSSI", drv_cmd_get_rssi},
7175 {"LINKSPEED", drv_cmd_get_linkspeed},
7176#ifdef FEATURE_NAPI
7177 {"NAPI", drv_cmd_napi},
7178#endif /* FEATURE_NAPI */
7179 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7180 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7181 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307182 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007183 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7184 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007185};
7186
7187/**
7188 * hdd_drv_cmd_process() - chooses and runs the proper
7189 * handler based on the input command
7190 * @adapter: Pointer to the hdd adapter
7191 * @cmd: Pointer to the driver command
7192 * @priv_data: Pointer to the data associated with the command
7193 *
7194 * This function parses the input hdd driver command and runs
7195 * the proper handler
7196 *
7197 * Return: 0 for success non-zero for failure
7198 */
7199static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7200 uint8_t *cmd,
7201 hdd_priv_data_t *priv_data)
7202{
7203 hdd_context_t *hdd_ctx;
7204 int i;
7205 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7206 uint8_t *cmd_i = NULL;
7207 hdd_drv_cmd_handler_t handler = NULL;
7208 int len = 0;
7209
7210 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007211 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007212 return -EINVAL;
7213 }
7214
7215 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7216
7217 for (i = 0; i < cmd_num_total; i++) {
7218
7219 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7220 handler = hdd_drv_cmds[i].handler;
7221 len = strlen(cmd_i);
7222
7223 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007224 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007225 return -EINVAL;
7226 }
7227
7228 if (strncasecmp(cmd, cmd_i, len) == 0)
7229 return handler(adapter, hdd_ctx,
7230 cmd, len, priv_data);
7231 }
7232
7233 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7234}
7235
7236/**
7237 * hdd_driver_command() - top level wlan hdd driver command handler
7238 * @adapter: Pointer to the hdd adapter
7239 * @priv_data: Pointer to the raw command data
7240 *
7241 * This function is the top level wlan hdd driver command handler. It
7242 * handles the command with the help of hdd_drv_cmd_process()
7243 *
7244 * Return: 0 for success non-zero for failure
7245 */
7246static int hdd_driver_command(hdd_adapter_t *adapter,
7247 hdd_priv_data_t *priv_data)
7248{
7249 uint8_t *command = NULL;
7250 int ret = 0;
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05307251 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007252
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307253 ENTER();
7254
Anurag Chouhan6d760662016-02-20 16:05:43 +05307255 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007256 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007257 return -EINVAL;
7258 }
7259
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05307260 ret = wlan_hdd_validate_context(hdd_ctx);
7261 if (ret)
7262 return ret;
7263
7264 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
7265 hdd_err("Driver module is closed; command can not be processed");
7266 return -EINVAL;
7267 }
7268
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007269 /*
7270 * Note that valid pointers are provided by caller
7271 */
7272
7273 /* copy to local struct to avoid numerous changes to legacy code */
7274 if (priv_data->total_len <= 0 ||
7275 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007276 hdd_warn("Invalid priv_data.total_len(%d)!!!",
7277 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007278 ret = -EINVAL;
7279 goto exit;
7280 }
7281
7282 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007283 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007284 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007285 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007286 ret = -ENOMEM;
7287 goto exit;
7288 }
7289
7290 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7291 ret = -EFAULT;
7292 goto exit;
7293 }
7294
7295 /* Make sure the command is NUL-terminated */
7296 command[priv_data->total_len] = '\0';
7297
7298 hdd_info("%s: %s", adapter->dev->name, command);
7299 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7300
7301exit:
7302 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007303 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307304 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007305 return ret;
7306}
7307
7308#ifdef CONFIG_COMPAT
7309static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7310{
7311 struct {
7312 compat_uptr_t buf;
7313 int used_len;
7314 int total_len;
7315 } compat_priv_data;
7316 hdd_priv_data_t priv_data;
7317 int ret = 0;
7318
7319 /*
7320 * Note that adapter and ifr have already been verified by caller,
7321 * and HDD context has also been validated
7322 */
7323 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7324 sizeof(compat_priv_data))) {
7325 ret = -EFAULT;
7326 goto exit;
7327 }
7328 priv_data.buf = compat_ptr(compat_priv_data.buf);
7329 priv_data.used_len = compat_priv_data.used_len;
7330 priv_data.total_len = compat_priv_data.total_len;
7331 ret = hdd_driver_command(adapter, &priv_data);
7332exit:
7333 return ret;
7334}
7335#else /* CONFIG_COMPAT */
7336static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7337{
7338 /* will never be invoked */
7339 return 0;
7340}
7341#endif /* CONFIG_COMPAT */
7342
7343static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7344{
7345 hdd_priv_data_t priv_data;
7346 int ret = 0;
7347
7348 /*
7349 * Note that adapter and ifr have already been verified by caller,
7350 * and HDD context has also been validated
7351 */
7352 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7353 ret = -EFAULT;
7354 else
7355 ret = hdd_driver_command(adapter, &priv_data);
7356
7357 return ret;
7358}
7359
7360/**
7361 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7362 * @dev: device upon which the ioctl was received
7363 * @ifr: ioctl request information
7364 * @cmd: ioctl command
7365 *
7366 * This function does initial processing of wlan device ioctls.
7367 * Currently two flavors of ioctls are supported. The primary ioctl
7368 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7369 * for Android "DRIVER" commands. The other ioctl that is
7370 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7371 * for FTM on some platforms. This function simply verifies that the
7372 * driver is in a sane state, and that the ioctl is one of the
7373 * supported flavors, in which case flavor-specific handlers are
7374 * dispatched.
7375 *
7376 * Return: 0 on success, non-zero on error
7377 */
7378static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7379{
7380 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7381 hdd_context_t *hdd_ctx;
7382 int ret;
7383
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007384 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307385
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007386 if (dev != adapter->dev) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007387 hdd_alert("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007388 ret = -ENODEV;
7389 goto exit;
7390 }
7391
7392 if ((!ifr) || (!ifr->ifr_data)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007393 hdd_err("invalid data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007394 ret = -EINVAL;
7395 goto exit;
7396 }
7397#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307398 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007399 if (SIOCIOCTLTX99 == cmd) {
7400 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7401 goto exit;
7402 }
7403 }
7404#endif
7405
7406 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7407 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307408 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007409 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007410
7411 switch (cmd) {
7412 case (SIOCDEVPRIVATE + 1):
7413 if (is_compat_task())
7414 ret = hdd_driver_compat_ioctl(adapter, ifr);
7415 else
7416 ret = hdd_driver_ioctl(adapter, ifr);
7417 break;
7418 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007419 hdd_err("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007420 ret = -EINVAL;
7421 break;
7422 }
7423exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307424 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007425 return ret;
7426}
7427
7428/**
7429 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7430 * @dev: device upon which the ioctl was received
7431 * @ifr: ioctl request information
7432 * @cmd: ioctl command
7433 *
7434 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7435 * which is where the ioctls are really handled.
7436 *
7437 * Return: 0 on success, non-zero on error
7438 */
7439int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7440{
7441 int ret;
7442
7443 cds_ssr_protect(__func__);
7444 ret = __hdd_ioctl(dev, ifr, cmd);
7445 cds_ssr_unprotect(__func__);
7446 return ret;
7447}