blob: b50fb936bd7dd4b6598febed91431b3508e5294f [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Abhishek Singh1f217ec2017-12-22 11:48:27 +05302 * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080019/* Include Files */
20
21#include <wlan_hdd_includes.h>
22#include <wlan_hdd_wowl.h>
Jeff Johnson5fe539b2018-03-23 13:53:30 -070023#include <wlan_hdd_stats.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080024#include "wlan_hdd_trace.h"
25#include "wlan_hdd_ioctl.h"
26#include "wlan_hdd_power.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070027#include "wlan_hdd_regulatory.h"
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -070028#include "wlan_osif_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080029#include "wlan_hdd_driver_ops.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080030#include "wlan_policy_mgr_api.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053031#include "wlan_hdd_hostapd.h"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080032#include "scheduler_api.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070033#include "wlan_reg_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080034#include "wlan_hdd_p2p.h"
35#include <linux/ctype.h>
36#include "wma.h"
37#include "wlan_hdd_napi.h"
38
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080039#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080040#include <sme_api.h>
41#include <sir_api.h>
42#endif
43#include "hif.h"
44
45#if defined(LINUX_QCMBR)
46#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
47#endif
48
49/*
50 * Size of Driver command strings from upper layer
51 */
52#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
53#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
54
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080055/*
56 * Ibss prop IE from command will be of size:
57 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
58 * OUI_DATA should be at least 3 bytes long
59 */
60#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080061
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080062#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080063#define TID_MIN_VALUE 0
64#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080065#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080066
67/*
68 * Maximum buffer size used for returning the data back to user space
69 */
70#define WLAN_MAX_BUF_SIZE 1024
71#define WLAN_PRIV_DATA_MAX_LEN 8192
72
73/*
74 * Driver miracast parameters 0-Disabled
75 * 1-Source, 2-Sink
76 */
77#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
78#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
79
80/*
81 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
82 * we will split the printing.
83 */
84#define NUM_OF_STA_DATA_TO_PRINT 16
85
Dundi Raviteja53de6c32018-05-16 16:56:30 +053086#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
87/**
88 * struct enable_ext_wow_priv - Private data structure for ext wow
89 * @ext_wow_should_suspend: Suspend status of ext wow
90 */
91struct enable_ext_wow_priv {
92 bool ext_wow_should_suspend;
93};
94#endif
95
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080096/*
97 * Android DRIVER command structures
98 */
99struct android_wifi_reassoc_params {
100 unsigned char bssid[18];
101 int channel;
102};
103
104#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
105struct android_wifi_af_params {
106 unsigned char bssid[18];
107 int channel;
108 int dwell_time;
109 int len;
110 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
111};
112
113/*
114 * Define HDD driver command handling entry, each contains a command
115 * string and the handler.
116 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700117typedef int (*hdd_drv_cmd_handler_t)(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -0700118 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800119 uint8_t *cmd,
120 uint8_t cmd_name_len,
Jeff Johnson353cd292017-08-17 06:47:26 -0700121 struct hdd_priv_data *priv_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800122
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530123/**
124 * struct hdd_drv_cmd - Structure to store ioctl command handling info
125 * @cmd: Name of the command
126 * @handler: Command handler to be invoked
127 * @args: Set to true if command expects input parameters
128 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700129struct hdd_drv_cmd {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800130 const char *cmd;
131 hdd_drv_cmd_handler_t handler;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530132 bool args;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700133};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800134
135#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
136#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
137#define WLAN_HDD_MAX_TCP_PORT 65535
138#endif
139
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800140static uint16_t cesium_pid;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800141
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530142/**
143 * drv_cmd_validate() - Validates for space in hdd driver command
144 * @command: pointer to input data (its a NULL terminated string)
145 * @len: length of command name
146 *
147 * This function checks for space after command name and if no space
148 * is found returns error.
149 *
150 * Return: 0 for success non-zero for failure
151 */
152static int drv_cmd_validate(uint8_t *command, int len)
153{
154 if (command[len] != ' ')
155 return -EINVAL;
156
157 return 0;
158}
159
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800160#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800161struct tsm_priv {
162 tAniTrafStrmMetrics tsm_metrics;
163};
164
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
166 const uint32_t staId, void *context)
167{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700168 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800169 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800170
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700171 request = osif_request_get(context);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800172 if (!request) {
173 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174 return;
175 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700176 priv = osif_request_priv(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800177 priv->tsm_metrics = tsm_metrics;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700178 osif_request_complete(request);
179 osif_request_put(request);
Dustin Browne74003f2018-03-14 12:51:58 -0700180 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800181
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800182}
183
Jeff Johnsone44b7012017-09-10 15:25:47 -0700184static int hdd_get_tsm_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185 const uint8_t tid,
186 tAniTrafStrmMetrics *tsm_metrics)
187{
Jeff Johnson621cf972017-08-28 11:58:44 -0700188 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700189 struct hdd_station_ctx *hdd_sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800190 QDF_STATUS status;
191 int ret;
192 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700193 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800194 struct tsm_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700195 static const struct osif_request_params params = {
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800196 .priv_size = sizeof(*priv),
197 .timeout_ms = WLAN_WAIT_TIME_STATS,
198 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800199
200 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700201 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800202 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800203 }
204
205 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
206 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
207
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700208 request = osif_request_alloc(&params);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800209 if (!request) {
210 hdd_err("Request allocation failure");
211 return -ENOMEM;
212 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700213 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800214
Jeff Johnsond549efa2018-06-13 20:27:47 -0700215 status = sme_get_tsm_stats(hdd_ctx->mac_handle, hdd_get_tsm_stats_cb,
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800216 hdd_sta_ctx->conn_info.staId[0],
217 hdd_sta_ctx->conn_info.bssId,
Jeff Johnson30f84552017-09-13 14:55:25 -0700218 cookie, tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800219 if (QDF_STATUS_SUCCESS != status) {
220 hdd_err("Unable to retrieve tsm statistics");
221 ret = qdf_status_to_os_return(status);
222 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 }
224
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700225 ret = osif_request_wait_for_response(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800226 if (ret) {
227 hdd_err("SME timed out while retrieving tsm statistics");
228 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800229 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800230
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700231 priv = osif_request_priv(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800232 *tsm_metrics = priv->tsm_metrics;
233
234 cleanup:
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700235 osif_request_put(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800236
237 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800238}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800239#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800240
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800241/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700242 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
243 * @UserData: Adapter private data
244 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800245 *
246 * This is an asynchronous callback function from SME when the peer info
247 * is received
248 *
249 * Return: 0 for success non-zero for failure
250 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700251void
252hdd_get_ibss_peer_info_cb(void *pUserData,
253 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800254{
Jeff Johnsone44b7012017-09-10 15:25:47 -0700255 struct hdd_adapter *adapter = (struct hdd_adapter *) pUserData;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700256 struct hdd_station_ctx *pStaCtx;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800257 uint8_t i;
258
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800259 if ((NULL == adapter) ||
260 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800261 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800262 return;
263 }
264
265 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
266 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700267 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530268 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
269 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700270 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530271 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800272 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530273 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
274 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
275
276 for (i = 0; i < pPeerInfo->numPeers; i++)
277 pStaCtx->ibss_peer_info.peerInfoParams[i] =
278 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800279 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800280 hdd_debug("peerInfo %s: status %u, numPeers %u",
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530281 pPeerInfo ? "valid" : "null",
282 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
283 pPeerInfo ? pPeerInfo->numPeers : 0);
284 pStaCtx->ibss_peer_info.numPeers = 0;
285 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800286 }
287
288 complete(&adapter->ibss_peer_info_comp);
289}
290
291/**
292 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
293 * @adapter: Adapter context
294 *
295 * Request function to get IBSS peer info from lower layers
296 *
297 * Return: 0 for success non-zero for failure
298 */
299static
Jeff Johnsone44b7012017-09-10 15:25:47 -0700300QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(struct hdd_adapter *adapter)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800301{
Jeff Johnsond549efa2018-06-13 20:27:47 -0700302 QDF_STATUS status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800303 unsigned long rc;
304
305 INIT_COMPLETION(adapter->ibss_peer_info_comp);
306
Jeff Johnsond549efa2018-06-13 20:27:47 -0700307 status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle,
308 adapter,
309 hdd_get_ibss_peer_info_cb,
310 true, 0xFF);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800311
Jeff Johnsond549efa2018-06-13 20:27:47 -0700312 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800313 rc = wait_for_completion_timeout
314 (&adapter->ibss_peer_info_comp,
315 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
316
317 /* status will be 0 if timed out */
318 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700319 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Jeff Johnsond549efa2018-06-13 20:27:47 -0700320 status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800321 }
322 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700323 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800324 }
325
Jeff Johnsond549efa2018-06-13 20:27:47 -0700326 return status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800327}
328
329/**
330 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
331 * @adapter: Adapter context
332 * @staIdx: Sta index for which the peer info is requested
333 *
334 * Request function to get IBSS peer info from lower layers
335 *
336 * Return: 0 for success non-zero for failure
337 */
338static QDF_STATUS
Jeff Johnsone44b7012017-09-10 15:25:47 -0700339hdd_cfg80211_get_ibss_peer_info(struct hdd_adapter *adapter, uint8_t staIdx)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800340{
341 unsigned long rc;
Jeff Johnsond549efa2018-06-13 20:27:47 -0700342 QDF_STATUS status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800343
344 INIT_COMPLETION(adapter->ibss_peer_info_comp);
345
Jeff Johnsond549efa2018-06-13 20:27:47 -0700346 status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle,
347 adapter,
348 hdd_get_ibss_peer_info_cb,
349 false, staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800350
Jeff Johnsond549efa2018-06-13 20:27:47 -0700351 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800352 rc = wait_for_completion_timeout(
353 &adapter->ibss_peer_info_comp,
354 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
355
356 /* status = 0 on timeout */
357 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700358 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Jeff Johnsond549efa2018-06-13 20:27:47 -0700359 status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800360 }
361 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700362 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800363 }
364
Jeff Johnsond549efa2018-06-13 20:27:47 -0700365 return status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800366}
367
368/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700369static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800370hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
371{
372 uint8_t *inPtr = pValue;
Min Liu5359ab12018-03-29 14:30:24 +0800373 size_t in_ptr_len = strlen(pValue);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700374
Min Liu5359ab12018-03-29 14:30:24 +0800375 inPtr = strnchr(pValue, in_ptr_len, SPACE_ASCII_VALUE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800376
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700377 if (NULL == inPtr)
378 return QDF_STATUS_E_FAILURE;
379 else if (SPACE_ASCII_VALUE != *inPtr)
380 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800381
382 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
383 inPtr++;
384
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700385 if ('\0' == *inPtr)
386 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800387
Min Liu5359ab12018-03-29 14:30:24 +0800388 in_ptr_len -= (inPtr - pValue);
389 if (in_ptr_len < 17)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700390 return QDF_STATUS_E_FAILURE;
Min Liu5359ab12018-03-29 14:30:24 +0800391
392 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
393 inPtr[11] != ':' || inPtr[14] != ':')
394 return QDF_STATUS_E_FAILURE;
395
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800396 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
397 (unsigned int *)&pPeerMacAddr->bytes[0],
398 (unsigned int *)&pPeerMacAddr->bytes[1],
399 (unsigned int *)&pPeerMacAddr->bytes[2],
400 (unsigned int *)&pPeerMacAddr->bytes[3],
401 (unsigned int *)&pPeerMacAddr->bytes[4],
402 (unsigned int *)&pPeerMacAddr->bytes[5]);
403
404 return QDF_STATUS_SUCCESS;
405}
406
Jeff Johnsond549efa2018-06-13 20:27:47 -0700407static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *ui_band)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800408{
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800409 enum band_info band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700410
Jeff Johnsond549efa2018-06-13 20:27:47 -0700411 sme_get_freq_band(hdd_ctx->mac_handle, &band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800412 switch (band) {
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800413 case BAND_ALL:
Jeff Johnsond549efa2018-06-13 20:27:47 -0700414 *ui_band = WLAN_HDD_UI_BAND_AUTO;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800415 break;
416
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800417 case BAND_2G:
Jeff Johnsond549efa2018-06-13 20:27:47 -0700418 *ui_band = WLAN_HDD_UI_BAND_2_4_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800419 break;
420
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800421 case BAND_5G:
Jeff Johnsond549efa2018-06-13 20:27:47 -0700422 *ui_band = WLAN_HDD_UI_BAND_5_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423 break;
424
425 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700426 hdd_warn("Invalid Band %d", band);
Jeff Johnsond549efa2018-06-13 20:27:47 -0700427 *ui_band = -1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800428 break;
429 }
430}
431
432/**
433 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
434 * @data: input data
435 * @target_ap_bssid: pointer to bssid (output parameter)
436 * @channel: pointer to channel (output parameter)
437 *
438 * Return: 0 if parsing is successful; -EINVAL otherwise
439 */
440static int _hdd_parse_bssid_and_chan(const uint8_t **data,
441 uint8_t *bssid,
442 uint8_t *channel)
443{
444 const uint8_t *in_ptr;
445 int v = 0;
446 int temp_int;
447 uint8_t temp_buf[32];
448
449 /* 12 hexa decimal digits, 5 ':' and '\0' */
450 uint8_t mac_addr[18];
451
452 if (!data || !*data)
453 return -EINVAL;
454
455 in_ptr = *data;
456
457 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
458 /* no argument after the command */
459 if (NULL == in_ptr)
460 goto error;
461 /* no space after the command */
462 else if (SPACE_ASCII_VALUE != *in_ptr)
463 goto error;
464
465 /* remove empty spaces */
466 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
467 in_ptr++;
468
469 /* no argument followed by spaces */
470 if ('\0' == *in_ptr)
471 goto error;
472
473 v = sscanf(in_ptr, "%17s", mac_addr);
474 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700475 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
476 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477 goto error;
478 }
479
480 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
481 hex_to_bin(mac_addr[1]);
482 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
483 hex_to_bin(mac_addr[4]);
484 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
485 hex_to_bin(mac_addr[7]);
486 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
487 hex_to_bin(mac_addr[10]);
488 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
489 hex_to_bin(mac_addr[13]);
490 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
491 hex_to_bin(mac_addr[16]);
492
493 /* point to the next argument */
494 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
495 /* no argument after the command */
496 if (NULL == in_ptr)
497 goto error;
498
499 /* remove empty spaces */
500 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
501 in_ptr++;
502
503 /* no argument followed by spaces */
504 if ('\0' == *in_ptr)
505 goto error;
506
507 /* get the next argument ie the channel number */
508 v = sscanf(in_ptr, "%31s ", temp_buf);
509 if (1 != v)
510 goto error;
511
512 v = kstrtos32(temp_buf, 10, &temp_int);
513 if ((v < 0) || (temp_int < 0) ||
514 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
515 return -EINVAL;
516
517 *channel = temp_int;
518 *data = in_ptr;
519 return 0;
520error:
521 *data = in_ptr;
522 return -EINVAL;
523}
524
525/**
526 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
527 * @pValue: Pointer to input data
528 * @pTargetApBssid: Pointer to target Ap bssid
529 * @pChannel: Pointer to the Target AP channel
530 * @pDwellTime: Pointer to the time to stay off-channel
531 * after transmitting action frame
532 * @pBuf: Pointer to data
533 * @pBufLen: Pointer to data length
534 *
535 * This function parses the send action frame data passed in the format
536 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
537 *
538 * Return: 0 for success non-zero for failure
539 */
540static int
541hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
542 uint8_t *pTargetApBssid,
543 uint8_t *pChannel, uint8_t *pDwellTime,
544 uint8_t **pBuf, uint8_t *pBufLen)
545{
546 const uint8_t *inPtr = pValue;
547 const uint8_t *dataEnd;
548 int tempInt;
549 int j = 0;
550 int i = 0;
551 int v = 0;
552 uint8_t tempBuf[32];
553 uint8_t tempByte = 0;
554
555 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
556 return -EINVAL;
557
558 /* point to the next argument */
559 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
560 /* no argument after the command */
561 if (NULL == inPtr)
562 return -EINVAL;
563 /* removing empty spaces */
564 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
565 inPtr++;
566
567 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700568 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800569 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800570
571 /* getting the next argument ie the dwell time */
572 v = sscanf(inPtr, "%31s ", tempBuf);
573 if (1 != v)
574 return -EINVAL;
575
576 v = kstrtos32(tempBuf, 10, &tempInt);
577 if (v < 0 || tempInt < 0)
578 return -EINVAL;
579
580 *pDwellTime = tempInt;
581
582 /* point to the next argument */
583 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
584 /* no argument after the command */
585 if (NULL == inPtr)
586 return -EINVAL;
587 /* removing empty spaces */
588 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
589 inPtr++;
590
591 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700592 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800593 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800594
595 /* find the length of data */
596 dataEnd = inPtr;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700597 while (('\0' != *dataEnd))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800598 dataEnd++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700599
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800600 *pBufLen = dataEnd - inPtr;
601 if (*pBufLen <= 0)
602 return -EINVAL;
603
604 /*
605 * Allocate the number of bytes based on the number of input characters
606 * whether it is even or odd.
607 * if the number of input characters are even, then we need N/2 byte.
608 * if the number of input characters are odd, then we need do (N+1)/2
609 * to compensate rounding off.
610 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
611 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
612 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530613 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800614 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700615 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800616 return -ENOMEM;
617 }
618
619 /* the buffer received from the upper layer is character buffer,
620 * we need to prepare the buffer taking 2 characters in to a U8 hex
621 * decimal number for example 7f0000f0...form a buffer to contain 7f
622 * in 0th location, 00 in 1st and f0 in 3rd location
623 */
624 for (i = 0, j = 0; j < *pBufLen; j += 2) {
625 if (j + 1 == *pBufLen) {
626 tempByte = hex_to_bin(inPtr[j]);
627 } else {
628 tempByte =
629 (hex_to_bin(inPtr[j]) << 4) |
630 (hex_to_bin(inPtr[j + 1]));
631 }
632 (*pBuf)[i++] = tempByte;
633 }
634 *pBufLen = i;
635 return 0;
636}
637
638/**
639 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
640 * @pValue: Pointer to input data (its a NULL terminated string)
641 * @pTargetApBssid: Pointer to target Ap bssid
642 * @pChannel: Pointer to the Target AP channel
643 *
644 * This function parses the reasoc command data passed in the format
645 * REASSOC<space><bssid><space><channel>
646 *
647 * Return: 0 for success non-zero for failure
648 */
649static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
650 uint8_t *pTargetApBssid,
651 uint8_t *pChannel)
652{
653 const uint8_t *inPtr = pValue;
654
655 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
656 return -EINVAL;
657
658 return 0;
659}
660
Naveen Rawat05376ee2016-07-18 16:43:32 -0700661#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Abhinav Kumareab25932018-07-13 11:48:43 +0530662QDF_STATUS hdd_wma_send_fastreassoc_cmd(struct hdd_adapter *adapter,
663 const tSirMacAddr bssid,
664 int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700665{
Krunal Soni332f4af2017-06-01 14:36:17 -0700666 struct hdd_station_ctx *hdd_sta_ctx =
667 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnson8313b9d2018-03-14 15:09:28 -0700668 struct csr_roam_profile *roam_profile;
Krunal Soni332f4af2017-06-01 14:36:17 -0700669 tSirMacAddr connected_bssid;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700670
Jeff Johnson8313b9d2018-03-14 15:09:28 -0700671 roam_profile = hdd_roam_profile(adapter);
Krunal Soni332f4af2017-06-01 14:36:17 -0700672 qdf_mem_copy(connected_bssid, hdd_sta_ctx->conn_info.bssId.bytes,
673 ETH_ALEN);
Abhinav Kumareab25932018-07-13 11:48:43 +0530674 return sme_fast_reassoc(adapter->hdd_ctx->mac_handle,
675 roam_profile, bssid, channel,
676 adapter->session_id, connected_bssid);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700677}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700678#endif
679
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800680/**
681 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800682 * @adapter: Adapter upon which the command was received
683 * @bssid: BSSID with which to reassociate
684 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700685 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800686 *
687 * This function performs a userspace-directed reassoc operation
688 *
689 * Return: 0 for success non-zero for failure
690 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700691int hdd_reassoc(struct hdd_adapter *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800692 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800693{
Jeff Johnsond377dce2017-10-04 10:32:42 -0700694 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -0700695 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800696 int ret = 0;
Abhinav Kumareab25932018-07-13 11:48:43 +0530697 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800698
Naveen Rawat05376ee2016-07-18 16:43:32 -0700699 if (hdd_ctx == NULL) {
700 hdd_err("Invalid hdd ctx");
701 return -EINVAL;
702 }
703
Krunal Sonibe766b02016-03-10 13:00:44 -0800704 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800705 hdd_warn("Unsupported in mode %s(%d)",
706 hdd_device_mode_to_string(adapter->device_mode),
707 adapter->device_mode);
708 return -EINVAL;
709 }
710
Jeff Johnsond377dce2017-10-04 10:32:42 -0700711 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800712
713 /* if not associated, no need to proceed with reassoc */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700714 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800715 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800716 ret = -EINVAL;
717 goto exit;
718 }
719
720 /*
721 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800722 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800723 */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700724 if (!memcmp(bssid, sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530725 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800726 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Jeff Johnsond377dce2017-10-04 10:32:42 -0700727 channel = sta_ctx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800728 }
729
730 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530731 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800733 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800734 ret = -EINVAL;
735 goto exit;
736 }
737
738 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700739 if (roaming_offload_enabled(hdd_ctx)) {
Abhinav Kumareab25932018-07-13 11:48:43 +0530740 status = hdd_wma_send_fastreassoc_cmd(adapter,
741 bssid, (int)channel);
742 if (status != QDF_STATUS_SUCCESS) {
743 hdd_err("Failed to send fast reassoc cmd");
744 ret = -EINVAL;
745 }
Naveen Rawat05376ee2016-07-18 16:43:32 -0700746 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -0700747 tCsrHandoffRequest handoff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800748
Jeff Johnsond549efa2018-06-13 20:27:47 -0700749 handoff.channel = channel;
750 handoff.src = src;
751 qdf_mem_copy(handoff.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
752 sme_handoff_request(hdd_ctx->mac_handle, adapter->session_id,
753 &handoff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800754 }
755exit:
756 return ret;
757}
758
759/**
760 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
761 * @adapter: Adapter upon which the command was received
762 * @command: ASCII text command that was received
763 *
764 * This function parses the v1 REASSOC command with the format
765 *
766 * REASSOC xx:xx:xx:xx:xx:xx CH
767 *
768 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
769 * BSSID and CH is the ASCII representation of the channel. For
770 * example
771 *
772 * REASSOC 00:0a:0b:11:22:33 48
773 *
774 * Return: 0 for success non-zero for failure
775 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700776static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800777{
778 uint8_t channel = 0;
779 tSirMacAddr bssid;
780 int ret;
781
782 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700783 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700784 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700785 else
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700786 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700787
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800788 return ret;
789}
790
791/**
792 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
793 * @adapter: Adapter upon which the command was received
794 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700795 * followed by binary data
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530796 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800797 *
798 * This function parses the v2 REASSOC command with the format
799 *
800 * REASSOC <android_wifi_reassoc_params>
801 *
802 * Return: 0 for success non-zero for failure
803 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700804static int hdd_parse_reassoc_v2(struct hdd_adapter *adapter,
805 const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530806 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800807{
808 struct android_wifi_reassoc_params params;
809 tSirMacAddr bssid;
810 int ret;
811
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530812 if (total_len < sizeof(params) + 8) {
813 hdd_err("Invalid command length");
814 return -EINVAL;
815 }
816
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800817 /* The params are located after "REASSOC " */
818 memcpy(&params, command + 8, sizeof(params));
819
820 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700821 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800822 ret = -EINVAL;
823 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700824 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800825 }
826 return ret;
827}
828
829/**
830 * hdd_parse_reassoc() - parse the REASSOC command
831 * @adapter: Adapter upon which the command was received
832 * @command: Command that was received
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530833 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834 *
835 * There are two different versions of the REASSOC command. Version 1
836 * of the command contains a parameter list that is ASCII characters
837 * whereas version 2 contains a combination of ASCII and binary
838 * payload. Determine if a version 1 or a version 2 command is being
839 * parsed by examining the parameters, and then dispatch the parser
840 * that is appropriate for the command.
841 *
842 * Return: 0 for success non-zero for failure
843 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700844static int hdd_parse_reassoc(struct hdd_adapter *adapter, const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530845 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800846{
847 int ret;
848
849 /* both versions start with "REASSOC "
850 * v1 has a bssid and channel # as an ASCII string
851 * REASSOC xx:xx:xx:xx:xx:xx CH
852 * v2 has a C struct
853 * REASSOC <binary c struct>
854 *
855 * The first field in the v2 struct is also the bssid in ASCII.
856 * But in the case of a v2 message the BSSID is NUL-terminated.
857 * Hence we can peek at that offset to see if this is V1 or V2
858 * REASSOC xx:xx:xx:xx:xx:xx*
859 * 1111111111222222
860 * 01234567890123456789012345
861 */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530862
863 if (total_len < 26) {
864 hdd_err("Invalid command, total_len = %d", total_len);
865 return -EINVAL;
866 }
867
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700868 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800869 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700870 else
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530871 ret = hdd_parse_reassoc_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800872
873 return ret;
874}
875
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800876/**
877 * hdd_sendactionframe() - send a userspace-supplied action frame
878 * @adapter: Adapter upon which the command was received
879 * @bssid: BSSID target of the action frame
880 * @channel: Channel upon which to send the frame
881 * @dwell_time: Amount of time to dwell when the frame is sent
882 * @payload_len:Length of the payload
883 * @payload: Payload of the frame
884 *
885 * This function sends a userspace-supplied action frame
886 *
887 * Return: 0 for success non-zero for failure
888 */
889static int
Jeff Johnsone44b7012017-09-10 15:25:47 -0700890hdd_sendactionframe(struct hdd_adapter *adapter, const uint8_t *bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800891 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700892 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800893{
894 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700895 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896 uint8_t *frame;
897 struct ieee80211_hdr_3addr *hdr;
898 u64 cookie;
Jeff Johnsond377dce2017-10-04 10:32:42 -0700899 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -0700900 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800901 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
902 (tpSirMacVendorSpecificFrameHdr) payload;
903#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
904 struct cfg80211_mgmt_tx_params params;
905#endif
906
Krunal Sonibe766b02016-03-10 13:00:44 -0800907 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800908 hdd_warn("Unsupported in mode %s(%d)",
909 hdd_device_mode_to_string(adapter->device_mode),
910 adapter->device_mode);
911 return -EINVAL;
912 }
913
Jeff Johnsond377dce2017-10-04 10:32:42 -0700914 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800915 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
916
917 /* if not associated, no need to send action frame */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700918 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800919 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800920 ret = -EINVAL;
921 goto exit;
922 }
923
924 /*
925 * if the target bssid is different from currently associated AP,
926 * then no need to send action frame
927 */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700928 if (memcmp(bssid, sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530929 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800930 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931 ret = -EINVAL;
932 goto exit;
933 }
934
935 chan.center_freq = sme_chn_to_freq(channel);
936 /* Check if it is specific action frame */
937 if (pVendorSpecific->category ==
938 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
939 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700940
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530941 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800942 /*
943 * if the channel number is different from operating
944 * channel then no need to send action frame
945 */
946 if (channel != 0) {
947 if (channel !=
Jeff Johnsond377dce2017-10-04 10:32:42 -0700948 sta_ctx->conn_info.operationChannel) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800949 hdd_warn("channel(%d) is different from operating channel(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700950 channel,
Jeff Johnsond377dce2017-10-04 10:32:42 -0700951 sta_ctx->conn_info.
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700952 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800953 ret = -EINVAL;
954 goto exit;
955 }
956 /*
957 * If channel number is specified and same
958 * as home channel, ensure that action frame
959 * is sent immediately by cancelling
960 * roaming scans. Otherwise large dwell times
961 * may cause long delays in sending action
962 * frames.
963 */
Jeff Johnsond549efa2018-06-13 20:27:47 -0700964 sme_abort_roam_scan(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -0700965 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800966 } else {
967 /*
968 * 0 is accepted as current home channel,
969 * delayed transmission of action frame is ok.
970 */
971 chan.center_freq =
Jeff Johnsond377dce2017-10-04 10:32:42 -0700972 sme_chn_to_freq(sta_ctx->conn_info.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973 operationChannel);
974 }
975 }
976 }
977 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800978 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800979 ret = -EINVAL;
980 goto exit;
981 }
982
983 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530984 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800985 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700986 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800987 ret = -ENOMEM;
988 goto exit;
989 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990
991 hdr = (struct ieee80211_hdr_3addr *)frame;
992 hdr->frame_control =
993 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530994 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson1e851a12017-10-28 14:36:12 -0700995 qdf_mem_copy(hdr->addr2, adapter->mac_addr.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530996 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530997 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
998 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800999
1000#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1001 params.chan = &chan;
1002 params.offchan = 0;
1003 params.wait = dwell_time;
1004 params.buf = frame;
1005 params.len = frame_len;
1006 params.no_cck = 1;
1007 params.dont_wait_for_ack = 1;
1008 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1009#else
1010 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001012 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001013
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014 dwell_time, frame, frame_len, 1, 1, &cookie);
1015#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1016
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301017 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001018exit:
1019 return ret;
1020}
1021
1022/**
1023 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1024 * SENDACTIONFRAME command
1025 * @adapter: Adapter upon which the command was received
1026 * @command: ASCII text command that was received
1027 *
1028 * This function parses the v1 SENDACTIONFRAME command with the format
1029 *
1030 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1031 *
1032 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1033 * BSSID, CH is the ASCII representation of the channel, DW is the
1034 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1035 * payload. For example
1036 *
1037 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1038 *
1039 * Return: 0 for success non-zero for failure
1040 */
1041static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001042hdd_parse_sendactionframe_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043{
1044 uint8_t channel = 0;
1045 uint8_t dwell_time = 0;
1046 uint8_t payload_len = 0;
1047 uint8_t *payload = NULL;
1048 tSirMacAddr bssid;
1049 int ret;
1050
1051 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1052 &dwell_time, &payload,
1053 &payload_len);
1054 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001055 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001056 } else {
1057 ret = hdd_sendactionframe(adapter, bssid, channel,
1058 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301059 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001060 }
1061
1062 return ret;
1063}
1064
1065/**
1066 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1067 * SENDACTIONFRAME command
1068 * @adapter: Adapter upon which the command was received
1069 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001070 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001071 *
1072 * This function parses the v2 SENDACTIONFRAME command with the format
1073 *
1074 * SENDACTIONFRAME <android_wifi_af_params>
1075 *
1076 * Return: 0 for success non-zero for failure
1077 */
1078static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001079hdd_parse_sendactionframe_v2(struct hdd_adapter *adapter,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001080 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001081{
1082 struct android_wifi_af_params *params;
1083 tSirMacAddr bssid;
1084 int ret;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301085 int len_wo_payload = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001086
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001087 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001088 total_len -= 16;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301089 len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE;
1090 if (total_len <= len_wo_payload) {
1091 hdd_err("Invalid command len");
1092 return -EINVAL;
1093 }
1094
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001095 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001097 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301098 (params->len > (total_len - len_wo_payload))) {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001099 hdd_err("Invalid payload length: %d", params->len);
1100 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001101 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001102
1103 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1104 hdd_err("MAC address parsing failed");
1105 return -EINVAL;
1106 }
1107
1108 if (params->channel < 0 ||
1109 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1110 hdd_err("Invalid channel: %d", params->channel);
1111 return -EINVAL;
1112 }
1113
1114 if (params->dwell_time < 0) {
1115 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1116 return -EINVAL;
1117 }
1118
1119 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1120 params->dwell_time, params->len, params->data);
1121
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001122 return ret;
1123}
1124
1125/**
1126 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1127 * @adapter: Adapter upon which the command was received
1128 * @command: Command that was received
1129 *
1130 * There are two different versions of the SENDACTIONFRAME command.
1131 * Version 1 of the command contains a parameter list that is ASCII
1132 * characters whereas version 2 contains a combination of ASCII and
1133 * binary payload. Determine if a version 1 or a version 2 command is
1134 * being parsed by examining the parameters, and then dispatch the
1135 * parser that is appropriate for the version of the command.
1136 *
1137 * Return: 0 for success non-zero for failure
1138 */
1139static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001140hdd_parse_sendactionframe(struct hdd_adapter *adapter, const char *command,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001141 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142{
1143 int ret;
1144
1145 /*
1146 * both versions start with "SENDACTIONFRAME "
1147 * v1 has a bssid and other parameters as an ASCII string
1148 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1149 * v2 has a C struct
1150 * SENDACTIONFRAME <binary c struct>
1151 *
1152 * The first field in the v2 struct is also the bssid in ASCII.
1153 * But in the case of a v2 message the BSSID is NUL-terminated.
1154 * Hence we can peek at that offset to see if this is V1 or V2
1155 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1156 * 111111111122222222223333
1157 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001158 * For both the commands, a valid command must have atleast
1159 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001160 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001161 if (total_len < 34) {
1162 hdd_err("Invalid command (total_len=%d)", total_len);
1163 return -EINVAL;
1164 }
1165
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001166 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001167 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001168 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001169 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170
1171 return ret;
1172}
1173
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001174/**
1175 * hdd_parse_channellist() - HDD Parse channel list
1176 * @pValue: Pointer to input channel list
1177 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001178 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001179 * @pNumChannels: Pointer to number of roam scan channels
1180 *
1181 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001182 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1183 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001184 * if the Number of channels (N) does not match with the actual number
1185 * of channels passed then take the minimum of N and count of
1186 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1187 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1188 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1189 * removing duplicate channels from the list
1190 *
1191 * Return: 0 for success non-zero for failure
1192 */
1193static int
1194hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1195 uint8_t *pNumChannels)
1196{
1197 const uint8_t *inPtr = pValue;
1198 int tempInt;
1199 int j = 0;
1200 int v = 0;
1201 char buf[32];
1202
1203 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1204 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001205 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001206 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001207 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001208 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001209
1210 /* remove empty spaces */
1211 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1212 inPtr++;
1213
1214 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001215 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001216 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217
1218 /* get the first argument ie the number of channels */
1219 v = sscanf(inPtr, "%31s ", buf);
1220 if (1 != v)
1221 return -EINVAL;
1222
1223 v = kstrtos32(buf, 10, &tempInt);
1224 if ((v < 0) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001225 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001226 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001227
1228 *pNumChannels = tempInt;
1229
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001230 hdd_debug("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001231
1232 for (j = 0; j < (*pNumChannels); j++) {
1233 /*
1234 * inPtr pointing to the beginning of first space after number
1235 * of channels
1236 */
1237 inPtr = strpbrk(inPtr, " ");
1238 /* no channel list after the number of channels argument */
1239 if (NULL == inPtr) {
1240 if (0 != j) {
1241 *pNumChannels = j;
1242 return 0;
1243 } else {
1244 return -EINVAL;
1245 }
1246 }
1247
1248 /* remove empty space */
1249 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1250 inPtr++;
1251
1252 /*
1253 * no channel list after the number of channels
1254 * argument and spaces
1255 */
1256 if ('\0' == *inPtr) {
1257 if (0 != j) {
1258 *pNumChannels = j;
1259 return 0;
1260 } else {
1261 return -EINVAL;
1262 }
1263 }
1264
1265 v = sscanf(inPtr, "%31s ", buf);
1266 if (1 != v)
1267 return -EINVAL;
1268
1269 v = kstrtos32(buf, 10, &tempInt);
1270 if ((v < 0) ||
1271 (tempInt <= 0) ||
1272 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1273 return -EINVAL;
1274 }
1275 pChannelList[j] = tempInt;
1276
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001277 hdd_debug("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001278 pChannelList[j]);
1279 }
1280
1281 return 0;
1282}
1283
1284/**
1285 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1286 * SETROAMSCANCHANNELS command
1287 * @adapter: Adapter upon which the command was received
1288 * @command: ASCII text command that was received
1289 *
1290 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1291 *
1292 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1293 *
1294 * Where "N" is the ASCII representation of the number of channels and
1295 * C1 thru Cn is the ASCII representation of the channels. For example
1296 *
1297 * SETROAMSCANCHANNELS 4 36 40 44 48
1298 *
1299 * Return: 0 for success non-zero for failure
1300 */
1301static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001302hdd_parse_set_roam_scan_channels_v1(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001303 const char *command)
1304{
1305 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1306 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301307 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001308 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001309 int ret;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001310 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001311
1312 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1313 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001314 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001315 goto exit;
1316 }
1317
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301318 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001319 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001320 adapter->session_id, num_chan));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001321
1322 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001323 hdd_err("number of channels (%d) supported exceeded max (%d)",
1324 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001325 ret = -EINVAL;
1326 goto exit;
1327 }
1328
Jeff Johnsond549efa2018-06-13 20:27:47 -07001329 mac_handle = hdd_ctx->mac_handle;
1330 if (!sme_validate_channel_list(mac_handle, channel_list, num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301331 hdd_err("List contains invalid channel(s)");
1332 ret = -EINVAL;
1333 goto exit;
1334 }
1335
Jeff Johnsond549efa2018-06-13 20:27:47 -07001336 status = sme_change_roam_scan_channel_list(mac_handle,
1337 adapter->session_id,
1338 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301339 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001340 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001341 ret = -EINVAL;
1342 goto exit;
1343 }
1344exit:
1345 return ret;
1346}
1347
1348/**
1349 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1350 * SETROAMSCANCHANNELS command
1351 * @adapter: Adapter upon which the command was received
1352 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001353 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354 *
1355 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1356 *
1357 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1358 *
1359 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1360 * what follows the space is an array of u08 parameters. For example
1361 *
1362 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1363 *
1364 * Return: 0 for success non-zero for failure
1365 */
1366static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001367hdd_parse_set_roam_scan_channels_v2(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001368 const char *command)
1369{
1370 const uint8_t *value;
1371 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1372 uint8_t channel;
1373 uint8_t num_chan;
1374 int i;
Jeff Johnson621cf972017-08-28 11:58:44 -07001375 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301376 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001378 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001379
1380 /* array of values begins after "SETROAMSCANCHANNELS " */
1381 value = command + 20;
1382
1383 num_chan = *value++;
1384 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001385 hdd_err("number of channels (%d) supported exceeded max (%d)",
1386 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001387 ret = -EINVAL;
1388 goto exit;
1389 }
1390
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301391 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001392 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001393 adapter->session_id, num_chan));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001394
1395 for (i = 0; i < num_chan; i++) {
1396 channel = *value++;
Nachiket Kukadecaa2e842018-05-09 17:56:12 +05301397 if (!channel) {
1398 hdd_err("Channels end at index %d, expected %d",
1399 i, num_chan);
1400 ret = -EINVAL;
1401 goto exit;
1402 }
1403
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001404 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001405 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001406 i, channel);
1407 ret = -EINVAL;
1408 goto exit;
1409 }
1410 channel_list[i] = channel;
1411 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301412
Jeff Johnsond549efa2018-06-13 20:27:47 -07001413 mac_handle = hdd_ctx->mac_handle;
1414 if (!sme_validate_channel_list(mac_handle, channel_list, num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301415 hdd_err("List contains invalid channel(s)");
1416 ret = -EINVAL;
1417 goto exit;
1418 }
1419
Jeff Johnsond549efa2018-06-13 20:27:47 -07001420 status = sme_change_roam_scan_channel_list(mac_handle,
1421 adapter->session_id,
1422 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301423 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001424 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001425 ret = -EINVAL;
1426 goto exit;
1427 }
1428exit:
1429 return ret;
1430}
1431
1432/**
1433 * hdd_parse_set_roam_scan_channels() - parse the
1434 * SETROAMSCANCHANNELS command
1435 * @adapter: Adapter upon which the command was received
1436 * @command: Command that was received
1437 *
1438 * There are two different versions of the SETROAMSCANCHANNELS command.
1439 * Version 1 of the command contains a parameter list that is ASCII
1440 * characters whereas version 2 contains a binary payload. Determine
1441 * if a version 1 or a version 2 command is being parsed by examining
1442 * the parameters, and then dispatch the parser that is appropriate for
1443 * the command.
1444 *
1445 * Return: 0 for success non-zero for failure
1446 */
1447static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001448hdd_parse_set_roam_scan_channels(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449{
1450 const char *cursor;
1451 char ch;
1452 bool v1;
1453 int ret;
1454
1455 /* start after "SETROAMSCANCHANNELS " */
1456 cursor = command + 20;
1457
1458 /* assume we have a version 1 command until proven otherwise */
1459 v1 = true;
1460
1461 /* v1 params will only contain ASCII digits and space */
1462 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001463 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001465 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001466
1467 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001469 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001470 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001471
1472 return ret;
1473}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001474
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001475#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001476/**
1477 * hdd_parse_plm_cmd() - HDD Parse Plm command
1478 * @pValue: Pointer to input data
1479 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1480 *
1481 * This function parses the plm command passed in the format
1482 * CCXPLMREQ<space><enable><space><dialog_token><space>
1483 * <meas_token><space><num_of_bursts><space><burst_int><space>
1484 * <measu duration><space><burst_len><space><desired_tx_pwr>
1485 * <space><multcast_addr><space><number_of_channels>
1486 * <space><channel_numbers>
1487 *
1488 * Return: 0 for success non-zero for failure
1489 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001490static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001491{
1492 uint8_t *cmdPtr = NULL;
1493 int count, content = 0, ret = 0;
1494 char buf[32];
1495
1496 /* move to argument list */
1497 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1498 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301499 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001500
1501 /* no space after the command */
1502 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301503 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001504
1505 /* remove empty spaces */
1506 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1507 cmdPtr++;
1508
1509 /* START/STOP PLM req */
1510 ret = sscanf(cmdPtr, "%31s ", buf);
1511 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301512 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513
1514 ret = kstrtos32(buf, 10, &content);
1515 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301516 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001517
1518 pPlmRequest->enable = content;
1519 cmdPtr = strpbrk(cmdPtr, " ");
1520
1521 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301522 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523
1524 /* remove empty spaces */
1525 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1526 cmdPtr++;
1527
1528 /* Dialog token of radio meas req containing meas reqIE */
1529 ret = sscanf(cmdPtr, "%31s ", buf);
1530 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301531 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001532
1533 ret = kstrtos32(buf, 10, &content);
1534 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301535 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001536
1537 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001538 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001539 cmdPtr = strpbrk(cmdPtr, " ");
1540
1541 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301542 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001543
1544 /* remove empty spaces */
1545 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1546 cmdPtr++;
1547
1548 /* measurement token of meas req IE */
1549 ret = sscanf(cmdPtr, "%31s ", buf);
1550 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301551 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001552
1553 ret = kstrtos32(buf, 10, &content);
1554 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301555 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001556
1557 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001558 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001559
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001560 hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001561 if (pPlmRequest->enable) {
1562
1563 cmdPtr = strpbrk(cmdPtr, " ");
1564
1565 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301566 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001567
1568 /* remove empty spaces */
1569 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1570 cmdPtr++;
1571
1572 /* total number of bursts after which STA stops sending */
1573 ret = sscanf(cmdPtr, "%31s ", buf);
1574 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301575 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001576
1577 ret = kstrtos32(buf, 10, &content);
1578 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301579 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580
1581 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301582 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001583
1584 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001585 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586 cmdPtr = strpbrk(cmdPtr, " ");
1587
1588 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301589 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001590
1591 /* remove empty spaces */
1592 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1593 cmdPtr++;
1594
1595 /* burst interval in seconds */
1596 ret = sscanf(cmdPtr, "%31s ", buf);
1597 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301598 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001599
1600 ret = kstrtos32(buf, 10, &content);
1601 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301602 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603
1604 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301605 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001606
1607 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001608 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001609 cmdPtr = strpbrk(cmdPtr, " ");
1610
1611 if (NULL == 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 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
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 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301628 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629
1630 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001631 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001632 cmdPtr = strpbrk(cmdPtr, " ");
1633
1634 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301635 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001636
1637 /* remove empty spaces */
1638 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1639 cmdPtr++;
1640
1641 /* burst length of PLM bursts */
1642 ret = sscanf(cmdPtr, "%31s ", buf);
1643 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301644 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645
1646 ret = kstrtos32(buf, 10, &content);
1647 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301648 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001649
1650 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301651 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001652
1653 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001654 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001655 cmdPtr = strpbrk(cmdPtr, " ");
1656
1657 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301658 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001659
1660 /* remove empty spaces */
1661 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1662 cmdPtr++;
1663
1664 /* desired tx power for transmission of PLM bursts */
1665 ret = sscanf(cmdPtr, "%31s ", buf);
1666 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301667 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668
1669 ret = kstrtos32(buf, 10, &content);
1670 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301671 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672
1673 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301674 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001675
1676 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001677 hdd_debug("desiredTxPwr %d",
1678 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001679
Anurag Chouhan6d760662016-02-20 16:05:43 +05301680 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001681 cmdPtr = strpbrk(cmdPtr, " ");
1682
1683 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301684 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685
1686 /* remove empty spaces */
1687 while ((SPACE_ASCII_VALUE == *cmdPtr)
1688 && ('\0' != *cmdPtr))
1689 cmdPtr++;
1690
1691 ret = sscanf(cmdPtr, "%31s ", buf);
1692 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301693 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694
1695 ret = kstrtos32(buf, 16, &content);
1696 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301697 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001699 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700 }
1701
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001702 hdd_debug("MC addr " MAC_ADDRESS_STR,
1703 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001704
1705 cmdPtr = strpbrk(cmdPtr, " ");
1706
1707 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301708 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709
1710 /* remove empty spaces */
1711 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1712 cmdPtr++;
1713
1714 /* number of channels */
1715 ret = sscanf(cmdPtr, "%31s ", buf);
1716 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301717 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718
1719 ret = kstrtos32(buf, 10, &content);
1720 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301721 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722
1723 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301724 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001726 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001727 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001728 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729
1730 /* Channel numbers */
1731 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1732 cmdPtr = strpbrk(cmdPtr, " ");
1733
1734 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301735 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736
1737 /* remove empty spaces */
1738 while ((SPACE_ASCII_VALUE == *cmdPtr)
1739 && ('\0' != *cmdPtr))
1740 cmdPtr++;
1741
1742 ret = sscanf(cmdPtr, "%31s ", buf);
1743 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301744 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001745
1746 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001747 if (ret < 0 || content <= 0 ||
1748 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301749 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001750
1751 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001752 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753 }
1754 }
1755 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301756 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757}
1758#endif
1759
1760#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301761/**
1762 * wlan_hdd_ready_to_extwow() - Callback function for enable ext wow
1763 * @cookie: callback context
1764 * @is_success: suspend status of ext wow
1765 *
1766 * Return: none
1767 */
1768static void wlan_hdd_ready_to_extwow(void *cookie, bool is_success)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769{
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301770 struct osif_request *request = NULL;
1771 struct enable_ext_wow_priv *priv = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001772
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301773 request = osif_request_get(cookie);
1774 if (!request) {
1775 hdd_err("Obselete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001776 return;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301777 }
1778 priv = osif_request_priv(request);
1779 priv->ext_wow_should_suspend = is_success;
1780
1781 osif_request_complete(request);
1782 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783}
1784
Jeff Johnsone44b7012017-09-10 15:25:47 -07001785static int hdd_enable_ext_wow(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786 tpSirExtWoWParams arg_params)
1787{
1788 tSirExtWoWParams params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001789 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001790 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001791 int rc;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301792 struct enable_ext_wow_priv *priv = NULL;
1793 struct osif_request *request = NULL;
1794 void *cookie = NULL;
1795 struct osif_request_params hdd_params = {
1796 .priv_size = sizeof(*priv),
1797 .timeout_ms = WLAN_WAIT_TIME_READY_TO_EXTWOW,
1798 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001799
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301800 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001801
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301802 request = osif_request_alloc(&hdd_params);
1803 if (!request) {
1804 hdd_err("Request Allocation Failure");
1805 return -ENOMEM;
1806 }
1807 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808
Jeff Johnsond549efa2018-06-13 20:27:47 -07001809 status = sme_configure_ext_wow(hdd_ctx->mac_handle, &params,
1810 &wlan_hdd_ready_to_extwow,
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301811 cookie);
Jeff Johnsond549efa2018-06-13 20:27:47 -07001812 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001813 hdd_err("sme_configure_ext_wow returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07001814 status);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301815 rc = -EPERM;
1816 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817 }
1818
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301819 rc = osif_request_wait_for_response(request);
1820 if (rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001821 hdd_err("Failed to get ready to extwow");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301822 rc = -EPERM;
1823 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001824 }
1825
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301826 priv = osif_request_priv(request);
1827 if (!priv->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001828 hdd_err("Received ready to ExtWoW failure");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301829 rc = -EPERM;
1830 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001831 }
1832
Jeff Johnson17d62672017-03-27 08:00:11 -07001833 if (hdd_ctx->config->extWowGotoSuspend) {
1834 hdd_info("Received ready to ExtWoW. Going to suspend");
1835
1836 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1837 if (rc < 0) {
1838 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1839 rc);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301840 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07001841 }
1842 rc = wlan_hdd_bus_suspend();
1843 if (rc) {
1844 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1845 rc);
1846 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301847 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07001848 }
1849 }
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301850exit:
1851 osif_request_put(request);
1852 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001853}
1854
Jeff Johnsone44b7012017-09-10 15:25:47 -07001855static int hdd_enable_ext_wow_parser(struct hdd_adapter *adapter, int vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001856 int value)
1857{
1858 tSirExtWoWParams params;
Jeff Johnson621cf972017-08-28 11:58:44 -07001859 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860 int rc;
1861
1862 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301863 if (rc)
1864 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001865
1866 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1867 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001868 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001869 return -EINVAL;
1870 }
1871
1872 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1873 hdd_ctx->is_extwow_app_type1_param_set)
1874 params.type = value;
1875 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1876 hdd_ctx->is_extwow_app_type2_param_set)
1877 params.type = value;
1878 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1879 hdd_ctx->is_extwow_app_type1_param_set &&
1880 hdd_ctx->is_extwow_app_type2_param_set)
1881 params.type = value;
1882 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001883 hdd_err("Set app params before enable it value %d",
1884 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885 return -EINVAL;
1886 }
1887
1888 params.vdev_id = vdev_id;
1889 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1890 (hdd_ctx->config->extWowApp2WakeupPinNumber
1891 << 8);
1892
1893 return hdd_enable_ext_wow(adapter, &params);
1894}
1895
Jeff Johnsond549efa2018-06-13 20:27:47 -07001896static int hdd_set_app_type1_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001897 tpSirAppType1Params arg_params)
1898{
1899 tSirAppType1Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001900 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001901
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301902 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903
Jeff Johnsond549efa2018-06-13 20:27:47 -07001904 status = sme_configure_app_type1_params(mac_handle, &params);
1905 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001906 hdd_err("sme_configure_app_type1_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07001907 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908 return -EPERM;
1909 }
1910
1911 return 0;
1912}
1913
Jeff Johnsone44b7012017-09-10 15:25:47 -07001914static int hdd_set_app_type1_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915 char *arg, int len)
1916{
Jeff Johnson621cf972017-08-28 11:58:44 -07001917 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918 char id[20], password[20];
1919 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001920 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001921
1922 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301923 if (rc)
1924 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001925
1926 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001927 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001928 return -EINVAL;
1929 }
1930
1931 memset(&params, 0, sizeof(tSirAppType1Params));
Jeff Johnson1b780e42017-10-31 14:11:45 -07001932 params.vdev_id = adapter->session_id;
Jeff Johnson1e851a12017-10-28 14:36:12 -07001933 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001934
1935 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301936 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301938 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001939
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001940 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001941 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001942 params.identification_id, params.id_length,
1943 params.password, params.pass_length);
1944
Jeff Johnsond549efa2018-06-13 20:27:47 -07001945 return hdd_set_app_type1_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946}
1947
Jeff Johnsond549efa2018-06-13 20:27:47 -07001948static int hdd_set_app_type2_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001949 tpSirAppType2Params arg_params)
1950{
1951 tSirAppType2Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001952 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301954 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001955
Jeff Johnsond549efa2018-06-13 20:27:47 -07001956 status = sme_configure_app_type2_params(mac_handle, &params);
1957 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001958 hdd_err("sme_configure_app_type2_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07001959 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001960 return -EPERM;
1961 }
1962
1963 return 0;
1964}
1965
Jeff Johnsone44b7012017-09-10 15:25:47 -07001966static int hdd_set_app_type2_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967 char *arg, int len)
1968{
Jeff Johnson621cf972017-08-28 11:58:44 -07001969 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05301971 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972 tSirAppType2Params params;
1973 int ret;
1974
1975 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301976 if (ret)
1977 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001978
1979 memset(&params, 0, sizeof(tSirAppType2Params));
1980
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05301981 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 -08001982 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
1983 (unsigned int *)&params.ip_device_ip,
1984 (unsigned int *)&params.ip_server_ip,
1985 (unsigned int *)&params.tcp_seq,
1986 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05301987 (uint16_t *)&params.tcp_src_port,
1988 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001989 (unsigned int *)&params.keepalive_init,
1990 (unsigned int *)&params.keepalive_min,
1991 (unsigned int *)&params.keepalive_max,
1992 (unsigned int *)&params.keepalive_inc,
1993 (unsigned int *)&params.tcp_tx_timeout_val,
1994 (unsigned int *)&params.tcp_rx_timeout_val);
1995
1996 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001997 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998 return -EINVAL;
1999 }
2000
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002001 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
2002 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2003 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002004 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002005 return -EINVAL;
2006 }
2007
2008 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2009 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002010 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 return -EINVAL;
2012 }
2013
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302014 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302015 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002016
2017 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302018 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002019
Jeff Johnson1b780e42017-10-31 14:11:45 -07002020 params.vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021 params.tcp_src_port = (params.tcp_src_port != 0) ?
2022 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2023 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2024 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2025 params.keepalive_init = (params.keepalive_init != 0) ?
2026 params.keepalive_init : hdd_ctx->config->
2027 extWowApp2KAInitPingInterval;
2028 params.keepalive_min =
2029 (params.keepalive_min != 0) ?
2030 params.keepalive_min :
2031 hdd_ctx->config->extWowApp2KAMinPingInterval;
2032 params.keepalive_max =
2033 (params.keepalive_max != 0) ?
2034 params.keepalive_max :
2035 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2036 params.keepalive_inc =
2037 (params.keepalive_inc != 0) ?
2038 params.keepalive_inc :
2039 hdd_ctx->config->extWowApp2KAIncPingInterval;
2040 params.tcp_tx_timeout_val =
2041 (params.tcp_tx_timeout_val != 0) ?
2042 params.tcp_tx_timeout_val :
2043 hdd_ctx->config->extWowApp2TcpTxTimeout;
2044 params.tcp_rx_timeout_val =
2045 (params.tcp_rx_timeout_val != 0) ?
2046 params.tcp_rx_timeout_val :
2047 hdd_ctx->config->extWowApp2TcpRxTimeout;
2048
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002049 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002050 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2052 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2053 params.keepalive_init, params.keepalive_min,
2054 params.keepalive_max, params.keepalive_inc,
2055 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2056
Jeff Johnsond549efa2018-06-13 20:27:47 -07002057 return hdd_set_app_type2_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002058}
2059#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2060
2061/**
2062 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2063 * @pValue: Pointer to MAXTXPOWER command
2064 * @pDbm: Pointer to tx power
2065 *
2066 * This function parses the MAXTXPOWER command passed in the format
2067 * MAXTXPOWER<space>X(Tx power in dbm)
2068 *
2069 * For example input commands:
2070 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2071 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2072 *
2073 * Return: 0 for success non-zero for failure
2074 */
2075static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2076{
2077 uint8_t *inPtr = pValue;
2078 int tempInt;
2079 int v = 0;
2080 *pTxPower = 0;
2081
2082 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2083 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002084 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002086 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002088
2089 /* remove empty spaces */
2090 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2091 inPtr++;
2092
2093 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002094 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002095 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002096
2097 v = kstrtos32(inPtr, 10, &tempInt);
2098
2099 /* Range checking for passed parameter */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002100 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002101 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002102
2103 *pTxPower = tempInt;
2104
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002105 hdd_debug("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002106
2107 return 0;
2108} /* End of hdd_parse_setmaxtxpower_command */
2109
2110static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2111 char *extra, uint8_t n, uint8_t *len)
2112{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002113 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002114 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002115 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002116 }
2117
2118 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2119 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2120 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002121 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002122 }
Jeff Johnson68755312017-02-10 11:46:55 -08002123 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002124 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2125 (int)pCfg->nPassiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002126 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002127 }
Jeff Johnson68755312017-02-10 11:46:55 -08002128 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Srinivas Girigowdab9086af2017-10-14 14:41:13 -07002129 *len = scnprintf(extra, n, "GETDWELLTIME %u\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002130 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002131 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002132 }
2133
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002134 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002135}
2136
Jeff Johnsone44b7012017-09-10 15:25:47 -07002137static int hdd_set_dwell_time(struct hdd_adapter *adapter, uint8_t *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002138{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002139 mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002140 struct hdd_config *pCfg;
2141 uint8_t *value = command;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302142 tSmeConfigParams *sme_config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002143 int val = 0, temp = 0;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302144 int retval = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145
2146 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
Jeff Johnsonbacb4802018-08-20 09:31:17 -07002147 if (!pCfg || !mac_handle) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002148 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002149 return -EINVAL;
2150 }
2151
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302152 sme_config = qdf_mem_malloc(sizeof(*sme_config));
2153 if (!sme_config) {
2154 hdd_err("failed to allocate memory for sme_config");
2155 return -ENOMEM;
2156 }
2157 qdf_mem_zero(sme_config, sizeof(*sme_config));
Jeff Johnsond549efa2018-06-13 20:27:47 -07002158 sme_get_config_param(mac_handle, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002159
2160 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302161 if (drv_cmd_validate(command, 23))
2162 return -EINVAL;
2163
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002164 value = value + 24;
2165 temp = kstrtou32(value, 10, &val);
2166 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2167 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002168 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302169 retval = -EFAULT;
2170 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002171 }
2172 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302173 sme_config->csrConfig.nActiveMaxChnTime = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002174 sme_update_config(mac_handle, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002175 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302176 if (drv_cmd_validate(command, 24))
2177 return -EINVAL;
2178
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002179 value = value + 25;
2180 temp = kstrtou32(value, 10, &val);
2181 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2182 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002183 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302184 retval = -EFAULT;
2185 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002186 }
2187 pCfg->nPassiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302188 sme_config->csrConfig.nPassiveMaxChnTime = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002189 sme_update_config(mac_handle, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002190 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302191 if (drv_cmd_validate(command, 12))
2192 return -EINVAL;
2193
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 value = value + 13;
2195 temp = kstrtou32(value, 10, &val);
2196 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2197 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002198 hdd_err("argument passed for SETDWELLTIME is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302199 retval = -EFAULT;
2200 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002201 }
2202 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302203 sme_config->csrConfig.nActiveMaxChnTime = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002204 sme_update_config(mac_handle, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002205 } else {
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302206 retval = -EINVAL;
2207 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002208 }
2209
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302210free:
2211 qdf_mem_free(sme_config);
2212 return retval;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002213}
2214
Jeff Johnson253c0c22017-01-23 16:59:38 -08002215struct link_status_priv {
2216 uint8_t link_status;
2217};
2218
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302219#ifdef WLAN_AP_STA_CONCURRENCY
2220/**
2221 * hdd_conc_set_dwell_time() - Set Concurrent dwell time parameters
2222 * @adapter: Adapter upon which the command was received
2223 * @command: ASCII text command that is received
2224 *
2225 * Driver commands:
2226 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MAX <value>
2227 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MIN <value>
2228 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MAX <value>
2229 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MIN <value>
2230 *
2231 * Return: 0 for success non-zero for failure
2232 */
2233static int hdd_conc_set_dwell_time(hdd_context_t *hdd_ctx, uint8_t *command)
2234{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002235 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302236 struct hdd_config *p_cfg;
2237 u8 *value = command;
2238 tSmeConfigParams *sme_config;
2239 int val = 0, temp = 0;
2240 int retval = 0;
2241
2242 p_cfg = hdd_ctx->config;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002243 if (!p_cfg || !mac_handle) {
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302244 hdd_err("Argument passed for CONCSETDWELLTIME is incorrect");
2245 return -EINVAL;
2246 }
2247
2248 sme_config = qdf_mem_malloc(sizeof(*sme_config));
2249 if (!sme_config) {
2250 hdd_err("Failed to allocate memory for sme_config");
2251 return -ENOMEM;
2252 }
2253
2254 qdf_mem_zero(sme_config, sizeof(*sme_config));
Jeff Johnsond549efa2018-06-13 20:27:47 -07002255 sme_get_config_param(mac_handle, sme_config);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302256
2257 if (strncmp(command, "CONCSETDWELLTIME ACTIVE MAX", 27) == 0) {
2258 if (drv_cmd_validate(command, 27)) {
2259 hdd_err("Invalid driver command");
2260 retval = -EINVAL;
2261 goto sme_config_free;
2262 }
2263
2264 value = value + 28;
2265 temp = kstrtou32(value, 10, &val);
2266 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MIN ||
2267 val > CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MAX) {
2268 hdd_err("Argument passed for CONCSETDWELLTIME ACTIVE MAX is incorrect");
2269 retval = -EFAULT;
2270 goto sme_config_free;
2271 }
2272
2273 p_cfg->nActiveMaxChnTimeConc = val;
2274 sme_config->csrConfig.nActiveMaxChnTimeConc = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002275 sme_update_config(mac_handle, sme_config);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302276 } else if (strncmp(command, "CONCSETDWELLTIME ACTIVE MIN", 27) == 0) {
2277 if (drv_cmd_validate(command, 27)) {
2278 hdd_err("Invalid driver command");
2279 retval = -EINVAL;
2280 goto sme_config_free;
2281 }
2282
2283 value = value + 28;
2284 temp = kstrtou32(value, 10, &val);
2285 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MIN ||
2286 val > CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MAX) {
2287 hdd_err("argument passed for CONCSETDWELLTIME ACTIVE MIN is incorrect");
2288 retval = -EFAULT;
2289 goto sme_config_free;
2290 }
2291
2292 p_cfg->nActiveMinChnTimeConc = val;
2293 sme_config->csrConfig.nActiveMinChnTimeConc = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002294 sme_update_config(mac_handle, sme_config);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302295 } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MAX", 28) == 0) {
2296 if (drv_cmd_validate(command, 28)) {
2297 hdd_err("Invalid driver command");
2298 retval = -EINVAL;
2299 goto sme_config_free;
2300 }
2301
2302 value = value + 29;
2303 temp = kstrtou32(value, 10, &val);
2304 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MIN ||
2305 val > CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MAX) {
2306 hdd_err("Argument passed for CONCSETDWELLTIME PASSIVE MAX is incorrect");
2307 retval = -EFAULT;
2308 goto sme_config_free;
2309 }
2310
2311 p_cfg->nPassiveMaxChnTimeConc = val;
2312 sme_config->csrConfig.nPassiveMaxChnTimeConc = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002313 sme_update_config(mac_handle, sme_config);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302314 } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MIN", 28) == 0) {
2315 if (drv_cmd_validate(command, 28)) {
2316 hdd_err("Invalid driver command");
2317 retval = -EINVAL;
2318 goto sme_config_free;
2319 }
2320
2321 value = value + 29;
2322 temp = kstrtou32(value, 10, &val);
2323 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MIN ||
2324 val > CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MAX) {
2325 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
2326 retval = -EFAULT;
2327 goto sme_config_free;
2328 }
2329
2330 p_cfg->nPassiveMinChnTimeConc = val;
2331 sme_config->csrConfig.nPassiveMinChnTimeConc = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002332 sme_update_config(mac_handle, sme_config);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302333 } else {
2334 retval = -EINVAL;
2335 }
2336
2337sme_config_free:
2338 qdf_mem_free(sme_config);
2339 return retval;
2340}
2341#endif
2342
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002343static void hdd_get_link_status_cb(uint8_t status, void *context)
2344{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002345 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002346 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002347
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002348 request = osif_request_get(context);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002349 if (!request) {
2350 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002351 return;
2352 }
2353
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002354 priv = osif_request_priv(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002355 priv->link_status = status;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002356 osif_request_complete(request);
2357 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002358}
2359
2360/**
2361 * wlan_hdd_get_link_status() - get link status
Jeff Johnson25c77342017-10-02 13:28:03 -07002362 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002363 *
2364 * This function sends a request to query the link status and waits
2365 * on a timer to invoke the callback. if the callback is invoked then
2366 * latest link status shall be returned or otherwise cached value
2367 * will be returned.
2368 *
2369 * Return: On success, link status shall be returned.
2370 * On error or not associated, link status 0 will be returned.
2371 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002372static int wlan_hdd_get_link_status(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002374 struct hdd_station_ctx *sta_ctx;
2375 QDF_STATUS status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002376 int ret;
2377 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002378 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002379 struct link_status_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002380 static const struct osif_request_params params = {
Jeff Johnson253c0c22017-01-23 16:59:38 -08002381 .priv_size = sizeof(*priv),
2382 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2383 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002384
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05302385 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002386 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2387 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002388 return 0;
2389 }
2390
Krunal Sonibe766b02016-03-10 13:00:44 -08002391 if ((QDF_STA_MODE != adapter->device_mode) &&
2392 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002393 hdd_warn("Unsupported in mode %s(%d)",
2394 hdd_device_mode_to_string(adapter->device_mode),
2395 adapter->device_mode);
2396 return 0;
2397 }
2398
Jeff Johnsond377dce2017-10-04 10:32:42 -07002399 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2400 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002401 /* If not associated, then expected link status return
2402 * value is 0
2403 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002404 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002405 return 0;
2406 }
2407
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002408 request = osif_request_alloc(&params);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002409 if (!request) {
2410 hdd_err("Request allocation failure");
2411 return 0;
2412 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002413 cookie = osif_request_cookie(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002414
Jeff Johnsond549efa2018-06-13 20:27:47 -07002415 status = sme_get_link_status(adapter->hdd_ctx->mac_handle,
2416 hdd_get_link_status_cb,
2417 cookie, adapter->session_id);
2418 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002419 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002420 /* return a cached value */
2421 } else {
2422 /* request is sent -- wait for the response */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002423 ret = osif_request_wait_for_response(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002424 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002425 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002426 /* return a cached value */
2427 } else {
2428 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002429 priv = osif_request_priv(request);
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07002430 adapter->link_status = priv->link_status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002431 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 }
2433
Jeff Johnson253c0c22017-01-23 16:59:38 -08002434 /*
2435 * either we never sent a request, we sent a request and
2436 * received a response or we sent a request and timed out.
2437 * regardless we are done with the request.
2438 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002439 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002440
2441 /* either callback updated adapter stats or it has cached data */
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07002442 return adapter->link_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002443}
2444
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002445static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2446{
2447 int payload_len;
2448 struct sk_buff *skb;
2449 struct nlmsghdr *nlh;
2450 uint8_t *data;
2451
2452 payload_len = ETH_ALEN;
2453
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002454 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002455 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002456 return;
2457 }
2458
2459 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2460 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002461 hdd_err("nlmsg_new() failed for msg size[%d]",
2462 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002463 return;
2464 }
2465
2466 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2467
2468 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002469 hdd_err("nlmsg_put() failed for msg size[%d]",
2470 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002471
2472 kfree_skb(skb);
2473 return;
2474 }
2475
2476 data = nlmsg_data(nlh);
2477 memcpy(data, MacAddr, ETH_ALEN);
2478
2479 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002480 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2481 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002482 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002483}
2484
2485
2486/**
2487 * hdd_ParseuserParams - return a pointer to the next argument
2488 * @pValue: Input argument string
2489 * @ppArg: Output pointer to the next argument
2490 *
2491 * This function parses argument stream and finds the pointer
2492 * to the next argument
2493 *
2494 * Return: 0 if the next argument found; -EINVAL otherwise
2495 */
2496static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2497{
2498 uint8_t *pVal;
2499
2500 pVal = strnchr(pValue, strlen(pValue), ' ');
2501
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002502 if (NULL == pVal) /* no argument remains */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002503 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002504 else if (SPACE_ASCII_VALUE != *pVal)/* no space after the current arg */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002505 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002506
2507 pVal++;
2508
2509 /* remove empty spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002510 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002511 pVal++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002512
2513 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002514 if ('\0' == *pVal)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002515 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002516
2517 *ppArg = pVal;
2518
2519 return 0;
2520}
2521
2522/**
2523 * hdd_parse_ibsstx_fail_event_params - Parse params
2524 * for SETIBSSTXFAILEVENT
2525 * @pValue: Input ibss tx fail event argument
2526 * @tx_fail_count: (Output parameter) Tx fail counter
2527 * @pid: (Output parameter) PID
2528 *
2529 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2530 */
2531static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2532 uint8_t *tx_fail_count,
2533 uint16_t *pid)
2534{
2535 uint8_t *param = NULL;
2536 int ret;
2537
2538 ret = hdd_parse_user_params(pValue, &param);
2539
2540 if (0 == ret && NULL != param) {
2541 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2542 ret = -EINVAL;
2543 goto done;
2544 }
2545 } else {
2546 goto done;
2547 }
2548
2549 if (0 == *tx_fail_count) {
2550 *pid = 0;
2551 goto done;
2552 }
2553
2554 pValue = param;
2555 pValue++;
2556
2557 ret = hdd_parse_user_params(pValue, &param);
2558
2559 if (0 == ret) {
2560 if (1 != sscanf(param, "%hu", pid)) {
2561 ret = -EINVAL;
2562 goto done;
2563 }
2564 } else {
2565 goto done;
2566 }
2567
2568done:
2569 return ret;
2570}
2571
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002572#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002573/**
2574 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2575 * @pValue: Pointer to data
2576 * @pEseBcnReq: Output pointer to store parsed ie information
2577 *
2578 * This function parses the ese beacon request passed in the format
2579 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2580 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2581 * <space>Scan Mode N<space>Meas Duration N
2582 *
2583 * If the Number of bcn req fields (N) does not match with the
2584 * actual number of fields passed then take N.
2585 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2586 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2587 * This function does not take care of removing duplicate channels from the
2588 * list
2589 *
2590 * Return: 0 for success non-zero for failure
2591 */
2592static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2593 tCsrEseBeaconReq *pEseBcnReq)
2594{
2595 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002596 uint8_t input = 0;
2597 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002598 int j = 0, i = 0, v = 0;
2599 char buf[32];
2600
2601 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002602 if (NULL == inPtr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002603 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002604 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002605 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002606
2607 /* remove empty spaces */
2608 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2609 inPtr++;
2610
2611 /* no argument followed by spaces */
2612 if ('\0' == *inPtr)
2613 return -EINVAL;
2614
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002615 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002616 v = sscanf(inPtr, "%31s ", buf);
2617 if (1 != v)
2618 return -EINVAL;
2619
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002620 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002621 if (v < 0)
2622 return -EINVAL;
2623
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002624 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2625 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002626
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002627 hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002628
2629 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2630 for (i = 0; i < 4; i++) {
2631 /*
2632 * inPtr pointing to the beginning of 1st space
2633 * after number of ie fields
2634 */
2635 inPtr = strpbrk(inPtr, " ");
2636 /* no ie data after the number of ie fields argument */
2637 if (NULL == inPtr)
2638 return -EINVAL;
2639
2640 /* remove empty space */
2641 while ((SPACE_ASCII_VALUE == *inPtr)
2642 && ('\0' != *inPtr))
2643 inPtr++;
2644
2645 /*
2646 * no ie data after the number of ie fields
2647 * argument and spaces
2648 */
2649 if ('\0' == *inPtr)
2650 return -EINVAL;
2651
2652 v = sscanf(inPtr, "%31s ", buf);
2653 if (1 != v)
2654 return -EINVAL;
2655
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002656 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002657 if (v < 0)
2658 return -EINVAL;
2659
2660 switch (i) {
2661 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002662 if (!tempInt) {
2663 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002664 tempInt);
2665 return -EINVAL;
2666 }
2667 pEseBcnReq->bcnReq[j].measurementToken =
2668 tempInt;
2669 break;
2670
2671 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002672 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002673 (tempInt >
2674 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002675 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002676 tempInt);
2677 return -EINVAL;
2678 }
2679 pEseBcnReq->bcnReq[j].channel = tempInt;
2680 break;
2681
2682 case 2: /* Scan mode */
2683 if ((tempInt < eSIR_PASSIVE_SCAN)
2684 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002685 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002686 tempInt);
2687 return -EINVAL;
2688 }
2689 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2690 break;
2691
2692 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002693 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002694 && (pEseBcnReq->bcnReq[j].scanMode !=
2695 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002696 (pEseBcnReq->bcnReq[j].scanMode ==
2697 eSIR_BEACON_TABLE)) {
2698 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002699 tempInt);
2700 return -EINVAL;
2701 }
2702 pEseBcnReq->bcnReq[j].measurementDuration =
2703 tempInt;
2704 break;
2705 }
2706 }
2707 }
2708
2709 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002710 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002711 j,
2712 pEseBcnReq->bcnReq[j].measurementToken,
2713 pEseBcnReq->bcnReq[j].channel,
2714 pEseBcnReq->bcnReq[j].scanMode,
2715 pEseBcnReq->bcnReq[j].measurementDuration);
2716 }
2717
2718 return 0;
2719}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002721/**
2722 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2723 * @pValue: Pointer to input data
2724 * @pCckmIe: Pointer to output cckm Ie
2725 * @pCckmIeLen: Pointer to output cckm ie length
2726 *
2727 * This function parses the SETCCKM IE command
2728 * SETCCKMIE<space><ie data>
2729 *
2730 * Return: 0 for success non-zero for failure
2731 */
2732static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2733 uint8_t *pCckmIeLen)
2734{
2735 uint8_t *inPtr = pValue;
2736 uint8_t *dataEnd;
2737 int j = 0;
2738 int i = 0;
2739 uint8_t tempByte = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002740
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002741 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2742 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002743 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002744 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002745 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002746 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002747
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002748 /* remove empty spaces */
2749 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2750 inPtr++;
2751 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002752 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002753 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002754
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002755 /* 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
Jeff Johnson25c77342017-10-02 13:28:03 -07002793int wlan_hdd_set_mc_rate(struct hdd_adapter *adapter, int targetRate)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002794{
2795 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302796 QDF_STATUS status;
Jeff Johnson25c77342017-10-02 13:28:03 -07002797 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsond549efa2018-06-13 20:27:47 -07002798 struct hdd_config *pConfig;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002799
Jeff Johnson6da2db12017-09-03 09:18:52 -07002800 if (hdd_ctx == 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 }
Jeff Johnson25c77342017-10-02 13:28:03 -07002804 if ((QDF_IBSS_MODE != adapter->device_mode) &&
2805 (QDF_SAP_MODE != adapter->device_mode) &&
2806 (QDF_STA_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002807 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
Jeff Johnson25c77342017-10-02 13:28:03 -07002808 hdd_device_mode_to_string(adapter->device_mode),
2809 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002810 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002811 return -EINVAL;
2812 }
Jeff Johnson6da2db12017-09-03 09:18:52 -07002813 pConfig = hdd_ctx->config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002814 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
Jeff Johnson25c77342017-10-02 13:28:03 -07002815 rateUpdate.dev_mode = adapter->device_mode;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002816 rateUpdate.mcastDataRate24GHz = targetRate;
2817 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2818 rateUpdate.mcastDataRate5GHz = targetRate;
2819 rateUpdate.bcastDataRate = -1;
Jeff Johnson1e851a12017-10-28 14:36:12 -07002820 qdf_copy_macaddr(&rateUpdate.bssid, &adapter->mac_addr);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002821 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002822 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
Jeff Johnson25c77342017-10-02 13:28:03 -07002823 hdd_device_mode_to_string(adapter->device_mode),
2824 adapter->device_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07002825 status = sme_send_rate_update_ind(hdd_ctx->mac_handle, &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
Jeff Johnsone44b7012017-09-10 15:25:47 -07002833static int drv_cmd_p2p_dev_addr(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002834 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002835 uint8_t *command,
2836 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002837 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002838{
Dustin Brownee220712018-04-19 16:24:23 -07002839 struct qdf_mac_addr *addr = &hdd_ctx->p2p_device_address;
2840 size_t user_size = qdf_min(sizeof(addr->bytes),
2841 (size_t)priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002842
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302843 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002844 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002845 adapter->session_id,
Dustin Brownee220712018-04-19 16:24:23 -07002846 (unsigned int)(*(addr->bytes + 2) << 24 |
2847 *(addr->bytes + 3) << 16 |
2848 *(addr->bytes + 4) << 8 |
2849 *(addr->bytes + 5))));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002850
Dustin Brownee220712018-04-19 16:24:23 -07002851 if (copy_to_user(priv_data->buf, addr->bytes, user_size)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002852 hdd_err("failed to copy data to user buffer");
Dustin Brownee220712018-04-19 16:24:23 -07002853 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002854 }
2855
Dustin Brownee220712018-04-19 16:24:23 -07002856 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002857}
2858
2859/**
2860 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2861 * @adapter: Adapter on which the command was received
2862 * @hdd_ctx: HDD global context
2863 * @command: Entire driver command received from userspace
2864 * @command_len: Length of @command
2865 * @priv_data: Pointer to ioctl private data structure
2866 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07002867 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002868 * command to the actual command processor within the P2P module.
2869 *
2870 * Return: 0 on success, non-zero on failure
2871 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002872static int drv_cmd_p2p_set_noa(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002873 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002874 uint8_t *command,
2875 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002876 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002877{
2878 return hdd_set_p2p_noa(adapter->dev, command);
2879}
2880
2881/**
2882 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2883 * @adapter: Adapter on which the command was received
2884 * @hdd_ctx: HDD global context
2885 * @command: Entire driver command received from userspace
2886 * @command_len: Length of @command
2887 * @priv_data: Pointer to ioctl private data structure
2888 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07002889 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002890 * command to the actual command processor within the P2P module.
2891 *
2892 * Return: 0 on success, non-zero on failure
2893 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002894static int drv_cmd_p2p_set_ps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002895 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002896 uint8_t *command,
2897 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002898 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002899{
2900 return hdd_set_p2p_opps(adapter->dev, command);
2901}
2902
Jeff Johnsone44b7012017-09-10 15:25:47 -07002903static int drv_cmd_set_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002904 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002905 uint8_t *command,
2906 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002907 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002908{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002909 int err;
2910 uint8_t band;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002911
2912 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002913 * Parse the band value passed from userspace. The first 8 bytes
2914 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002915 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002916 err = kstrtou8(command + command_len + 1, 10, &band);
2917 if (err) {
2918 hdd_err("error %d parsing userspace band parameter", err);
2919 return err;
2920 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002921
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002922 return hdd_reg_set_band(adapter->dev, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002923}
2924
Jeff Johnsone44b7012017-09-10 15:25:47 -07002925static int drv_cmd_set_wmmps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002926 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002927 uint8_t *command,
2928 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002929 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002930{
2931 return hdd_wmmps_helper(adapter, command);
2932}
2933
Jeff Johnsone44b7012017-09-10 15:25:47 -07002934static inline int drv_cmd_country(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002935 struct hdd_context *hdd_ctx,
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002936 uint8_t *command,
2937 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002938 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002939{
Sourav Mohapatraa30c4572018-05-22 11:18:39 +05302940 char *country_code;
2941
2942 country_code = strnchr(command, strlen(command), ' ');
2943 /* no argument after the command */
2944 if (!country_code)
2945 return -EINVAL;
2946
2947 /* no space after the command */
2948 if (*country_code != SPACE_ASCII_VALUE)
2949 return -EINVAL;
2950
2951 country_code++;
2952
2953 /* removing empty spaces */
2954 while ((*country_code == SPACE_ASCII_VALUE) &&
2955 (*country_code != '\0'))
2956 country_code++;
2957
2958 /* no or less than 2 arguments followed by spaces */
2959 if (*country_code == '\0' || *(country_code + 1) == '\0')
2960 return -EINVAL;
2961
2962 return hdd_reg_set_country(hdd_ctx, country_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002963}
2964
Jeff Johnsone44b7012017-09-10 15:25:47 -07002965static int drv_cmd_set_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002966 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002967 uint8_t *command,
2968 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002969 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002970{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002971 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002972 uint8_t *value = command;
2973 int8_t rssi = 0;
2974 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302975 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002976
2977 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2978 value = value + command_len + 1;
2979
2980 /* Convert the value from ascii to integer */
2981 ret = kstrtos8(value, 10, &rssi);
2982 if (ret < 0) {
2983 /*
2984 * If the input value is greater than max value of datatype,
2985 * then also kstrtou8 fails
2986 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002987 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2988 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2989 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002990 ret = -EINVAL;
2991 goto exit;
2992 }
2993
2994 lookUpThreshold = abs(rssi);
2995
Jeff Johnsond549efa2018-06-13 20:27:47 -07002996 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN) ||
2997 (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002998 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002999 lookUpThreshold,
3000 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3001 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3002 ret = -EINVAL;
3003 goto exit;
3004 }
3005
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303006 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003007 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003008 adapter->session_id, lookUpThreshold));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003009 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003010 lookUpThreshold);
3011
3012 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003013 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003014 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003015 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303016 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003017 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 ret = -EPERM;
3019 goto exit;
3020 }
3021
3022exit:
3023 return ret;
3024}
3025
Jeff Johnsone44b7012017-09-10 15:25:47 -07003026static int drv_cmd_get_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003027 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003028 uint8_t *command,
3029 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003030 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003031{
3032 int ret = 0;
3033 uint8_t lookUpThreshold =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003034 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003035 int rssi = (-1) * lookUpThreshold;
3036 char extra[32];
3037 uint8_t len = 0;
3038
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303039 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003040 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003041 adapter->session_id, lookUpThreshold));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003042
3043 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303044 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003045 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003046 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003047 ret = -EFAULT;
3048 }
3049
3050 return ret;
3051}
3052
Jeff Johnsone44b7012017-09-10 15:25:47 -07003053static int drv_cmd_set_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003054 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055 uint8_t *command,
3056 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003057 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003058{
3059 int ret = 0;
3060 uint8_t *value = command;
3061 uint8_t roamScanPeriod = 0;
3062 uint16_t neighborEmptyScanRefreshPeriod =
3063 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3064
3065 /* input refresh period is in terms of seconds */
3066
3067 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3068 value = value + command_len + 1;
3069
3070 /* Convert the value from ascii to integer */
3071 ret = kstrtou8(value, 10, &roamScanPeriod);
3072 if (ret < 0) {
3073 /*
3074 * If the input value is greater than max value of datatype,
3075 * then also kstrtou8 fails
3076 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003077 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3078 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3079 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003080 ret = -EINVAL;
3081 goto exit;
3082 }
3083
3084 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3085 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003086 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3087 roamScanPeriod,
3088 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3089 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003090 ret = -EINVAL;
3091 goto exit;
3092 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303093 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003094 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003095 adapter->session_id, roamScanPeriod));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003096 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3097
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003098 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003099 roamScanPeriod);
3100
3101 hdd_ctx->config->nEmptyScanRefreshPeriod =
3102 neighborEmptyScanRefreshPeriod;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003103 sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003104 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003105 neighborEmptyScanRefreshPeriod);
3106
3107exit:
3108 return ret;
3109}
3110
Jeff Johnsone44b7012017-09-10 15:25:47 -07003111static int drv_cmd_get_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003112 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003113 uint8_t *command,
3114 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003115 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003116{
3117 int ret = 0;
3118 uint16_t nEmptyScanRefreshPeriod =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003119 sme_get_empty_scan_refresh_period(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003120 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003121 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003122
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303123 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003124 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003125 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003126 nEmptyScanRefreshPeriod));
3127 len = scnprintf(extra, sizeof(extra), "%s %d",
3128 "GETROAMSCANPERIOD",
3129 (nEmptyScanRefreshPeriod / 1000));
3130 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303131 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003132 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003133 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003134 ret = -EFAULT;
3135 }
3136
3137 return ret;
3138}
3139
Jeff Johnsone44b7012017-09-10 15:25:47 -07003140static int drv_cmd_set_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003141 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003142 uint8_t *command,
3143 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003144 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003145{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003146 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003147 uint8_t *value = command;
3148 uint8_t roamScanRefreshPeriod = 0;
3149 uint16_t neighborScanRefreshPeriod =
3150 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3151
3152 /* input refresh period is in terms of seconds */
3153 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3154 value = value + command_len + 1;
3155
3156 /* Convert the value from ascii to integer */
3157 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3158 if (ret < 0) {
3159 /*
3160 * If the input value is greater than max value of datatype,
3161 * then also kstrtou8 fails
3162 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003163 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3164 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3165 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003166 ret = -EINVAL;
3167 goto exit;
3168 }
3169
3170 if ((roamScanRefreshPeriod <
Jeff Johnsond549efa2018-06-13 20:27:47 -07003171 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000)) ||
3172 (roamScanRefreshPeriod >
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003173 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003174 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3175 roamScanRefreshPeriod,
3176 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3177 / 1000),
3178 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3179 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003180 ret = -EINVAL;
3181 goto exit;
3182 }
3183 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3184
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003185 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003186 roamScanRefreshPeriod);
3187
3188 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3189 neighborScanRefreshPeriod;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003190 sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003191 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003192 neighborScanRefreshPeriod);
3193
3194exit:
3195 return ret;
3196}
3197
Jeff Johnsone44b7012017-09-10 15:25:47 -07003198static int drv_cmd_get_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003199 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003200 uint8_t *command,
3201 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003202 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003203{
3204 int ret = 0;
3205 uint16_t value =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003206 sme_get_neighbor_scan_refresh_period(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003207 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003208 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003209
3210 len = scnprintf(extra, sizeof(extra), "%s %d",
3211 "GETROAMSCANREFRESHPERIOD",
3212 (value / 1000));
3213 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303214 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003215 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003216 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003217 ret = -EFAULT;
3218 }
3219
3220 return ret;
3221}
3222
Jeff Johnsone44b7012017-09-10 15:25:47 -07003223static int drv_cmd_set_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003224 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003225 uint8_t *command,
3226 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003227 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003228{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003229 mac_handle_t mac_handle;
3230 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003231 uint8_t *value = command;
3232 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3233
3234 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3235 value = value + SIZE_OF_SETROAMMODE + 1;
3236
3237 /* Convert the value from ascii to integer */
Rajeev Kumar Sirasanagandla248697d2017-08-30 12:27:45 +05303238 ret = kstrtou8(value, 10, &roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003239 if (ret < 0) {
3240 /*
3241 * If the input value is greater than max value of datatype,
3242 * then also kstrtou8 fails
3243 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003244 hdd_err("kstrtou8 failed range [%d - %d]",
3245 CFG_LFR_FEATURE_ENABLED_MIN,
3246 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003247 ret = -EINVAL;
3248 goto exit;
3249 }
3250 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3251 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003252 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3253 roamMode,
3254 CFG_LFR_FEATURE_ENABLED_MIN,
3255 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003256 ret = -EINVAL;
3257 goto exit;
3258 }
3259
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003260 hdd_debug("Received Command to Set Roam Mode = %d",
3261 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003262 /*
3263 * Note that
3264 * SETROAMMODE 0 is to enable LFR while
3265 * SETROAMMODE 1 is to disable LFR, but
3266 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3267 * enable/disable. So, we have to invert the value
3268 * to call sme_update_is_fast_roam_ini_feature_enabled.
3269 */
3270 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3271 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3272 else
3273 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3274
3275 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003276 mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003277 if (roamMode) {
3278 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003279 sme_update_roam_scan_offload_enabled(mac_handle, roamMode);
3280 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
3281 adapter->session_id,
3282 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003283 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07003284 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
3285 adapter->session_id,
3286 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003287 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003288 sme_update_roam_scan_offload_enabled(mac_handle, roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003289 }
3290
3291
3292exit:
3293 return ret;
3294}
3295
Jeff Johnsone44b7012017-09-10 15:25:47 -07003296static int drv_cmd_get_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003297 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003298 uint8_t *command,
3299 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003300 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003301{
3302 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003303 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003304 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003305 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003306
3307 /*
3308 * roamMode value shall be inverted because the sementics is different.
3309 */
3310 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3311 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3312 else
3313 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3314
3315 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303316 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003317 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003318 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003319 ret = -EFAULT;
3320 }
3321
3322 return ret;
3323}
3324
Jeff Johnsone44b7012017-09-10 15:25:47 -07003325static int drv_cmd_set_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003326 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003327 uint8_t *command,
3328 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003329 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003330{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003331 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003332 uint8_t *value = command;
3333 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3334
3335 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3336 value = value + command_len + 1;
3337
3338 /* Convert the value from ascii to integer */
3339 ret = kstrtou8(value, 10, &roamRssiDiff);
3340 if (ret < 0) {
3341 /*
3342 * If the input value is greater than max value of datatype,
3343 * then also kstrtou8 fails
3344 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003345 hdd_err("kstrtou8 failed range [%d - %d]",
3346 CFG_ROAM_RSSI_DIFF_MIN,
3347 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003348 ret = -EINVAL;
3349 goto exit;
3350 }
3351
3352 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3353 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003354 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3355 roamRssiDiff,
3356 CFG_ROAM_RSSI_DIFF_MIN,
3357 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003358 ret = -EINVAL;
3359 goto exit;
3360 }
3361
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003362 hdd_debug("Received Command to Set roam rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003363 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364
3365 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003366 sme_update_roam_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003367 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003368 roamRssiDiff);
3369
3370exit:
3371 return ret;
3372}
3373
Jeff Johnsone44b7012017-09-10 15:25:47 -07003374static int drv_cmd_get_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003375 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003376 uint8_t *command,
3377 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003378 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003379{
3380 int ret = 0;
3381 uint8_t roamRssiDiff =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003382 sme_get_roam_rssi_diff(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003383 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003384 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003385
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303386 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003387 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003388 adapter->session_id, roamRssiDiff));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003389
3390 len = scnprintf(extra, sizeof(extra), "%s %d",
3391 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303392 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003393
3394 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003395 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003396 ret = -EFAULT;
3397 }
3398
3399 return ret;
3400}
3401
Jeff Johnsone44b7012017-09-10 15:25:47 -07003402static int drv_cmd_get_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003403 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003404 uint8_t *command,
3405 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003406 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003407{
3408 int ret = 0;
3409 int band = -1;
3410 char extra[32];
3411 uint8_t len = 0;
3412
3413 hdd_get_band_helper(hdd_ctx, &band);
3414
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303415 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003416 TRACE_CODE_HDD_GETBAND_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003417 adapter->session_id, band));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418
3419 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303420 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421
3422 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003423 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003424 ret = -EFAULT;
3425 }
3426
3427 return ret;
3428}
3429
Jeff Johnsone44b7012017-09-10 15:25:47 -07003430static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003431 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003432 uint8_t *command,
3433 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003434 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003435{
3436 return hdd_parse_set_roam_scan_channels(adapter, command);
3437}
3438
Jeff Johnsone44b7012017-09-10 15:25:47 -07003439static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003440 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003441 uint8_t *command,
3442 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003443 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003444{
3445 int ret = 0;
3446 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3447 uint8_t numChannels = 0;
3448 uint8_t j = 0;
3449 char extra[128] = { 0 };
3450 int len;
3451
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303452 if (QDF_STATUS_SUCCESS !=
Jeff Johnsond549efa2018-06-13 20:27:47 -07003453 sme_get_roam_scan_channel_list(hdd_ctx->mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003454 ChannelList,
3455 &numChannels,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003456 adapter->session_id)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003457 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003458 ret = -EFAULT;
3459 goto exit;
3460 }
3461
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303462 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003463 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003464 adapter->session_id, numChannels));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003465 /*
3466 * output channel list is of the format
3467 * [Number of roam scan channels][Channel1][Channel2]...
3468 * copy the number of channels in the 0th index
3469 */
3470 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3471 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303472 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003473 len += scnprintf(extra + len, sizeof(extra) - len,
3474 " %d", ChannelList[j]);
3475
Anurag Chouhan6d760662016-02-20 16:05:43 +05303476 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003477 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003478 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479 ret = -EFAULT;
3480 goto exit;
3481 }
3482
3483exit:
3484 return ret;
3485}
3486
Jeff Johnsone44b7012017-09-10 15:25:47 -07003487static int drv_cmd_get_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003488 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003489 uint8_t *command,
3490 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003491 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003492{
3493 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003494 mac_handle_t mac_handle = hdd_ctx->mac_handle;
3495 bool eseMode = sme_get_is_ese_feature_enabled(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003496 char extra[32];
3497 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003498 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003499
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003500 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003501 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003502 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003503 * then this operation is not permitted (return FAILURE)
3504 */
3505 if (eseMode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003506 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07003507 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003508 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003509 ret = -EPERM;
3510 goto exit;
3511 }
3512
3513 len = scnprintf(extra, sizeof(extra), "%s %d",
3514 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303515 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003516 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003517 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003518 ret = -EFAULT;
3519 goto exit;
3520 }
3521
3522exit:
3523 return ret;
3524}
3525
Jeff Johnsone44b7012017-09-10 15:25:47 -07003526static int drv_cmd_get_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003527 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003528 uint8_t *command,
3529 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003530 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003531{
3532 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003533 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003534 char extra[32];
3535 uint8_t len = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003536 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003537
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003538 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003539 /*
3540 * Check if the features OKC/ESE/11R are supported simultaneously,
3541 * then this operation is not permitted (return FAILURE)
3542 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003543 if (pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07003544 sme_get_is_ese_feature_enabled(mac_handle) &&
3545 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003546 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003547 ret = -EPERM;
3548 goto exit;
3549 }
3550
3551 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003552 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303553 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003554
3555 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003556 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003557 ret = -EFAULT;
3558 goto exit;
3559 }
3560
3561exit:
3562 return ret;
3563}
3564
Jeff Johnsone44b7012017-09-10 15:25:47 -07003565static int drv_cmd_get_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003566 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003567 uint8_t *command,
3568 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003569 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003570{
3571 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003572 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003573 char extra[32];
3574 uint8_t len = 0;
3575
3576 len = scnprintf(extra, sizeof(extra), "%s %d",
3577 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303578 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003579
3580 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003581 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003582 ret = -EFAULT;
3583 }
3584
3585 return ret;
3586}
3587
Jeff Johnsone44b7012017-09-10 15:25:47 -07003588static int drv_cmd_get_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003589 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590 uint8_t *command,
3591 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003592 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003593{
3594 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003595 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003596 char extra[32];
3597 uint8_t len = 0;
3598
3599 len = scnprintf(extra, sizeof(extra), "%s %d",
3600 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303601 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003602
3603 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003604 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003605 ret = -EFAULT;
3606 }
3607
3608 return ret;
3609}
3610
Jeff Johnsone44b7012017-09-10 15:25:47 -07003611static int drv_cmd_set_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003612 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 uint8_t *command,
3614 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003615 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003616{
3617 int ret = 0;
3618 uint8_t *value = command;
3619 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3620
3621 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3622 value = value + command_len + 1;
3623
3624 /* Convert the value from ascii to integer */
3625 ret = kstrtou8(value, 10, &minTime);
3626 if (ret < 0) {
3627 /*
3628 * If the input value is greater than max value of datatype,
3629 * then also kstrtou8 fails
3630 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003631 hdd_err("kstrtou8 failed range [%d - %d]",
3632 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3633 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003634 ret = -EINVAL;
3635 goto exit;
3636 }
3637
3638 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3639 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003640 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3641 minTime,
3642 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3643 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003644 ret = -EINVAL;
3645 goto exit;
3646 }
3647
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303648 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003649 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003650 adapter->session_id, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003651 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003652 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003653
3654 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003655 sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003656 minTime,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003657 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658
3659exit:
3660 return ret;
3661}
3662
Jeff Johnsone44b7012017-09-10 15:25:47 -07003663static int drv_cmd_send_action_frame(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003664 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003665 uint8_t *command,
3666 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003667 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003668{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003669 return hdd_parse_sendactionframe(adapter, command,
3670 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003671}
3672
Jeff Johnsone44b7012017-09-10 15:25:47 -07003673static int drv_cmd_get_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003674 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003675 uint8_t *command,
3676 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003677 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003678{
3679 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003680 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
3681 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003682 char extra[32];
3683 uint8_t len = 0;
3684
3685 /* value is interms of msec */
3686 len = scnprintf(extra, sizeof(extra), "%s %d",
3687 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303688 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003689
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303690 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003691 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003692 adapter->session_id, val));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003693
3694 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003695 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003696 ret = -EFAULT;
3697 }
3698
3699 return ret;
3700}
3701
Jeff Johnsone44b7012017-09-10 15:25:47 -07003702static int drv_cmd_set_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003703 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003704 uint8_t *command,
3705 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003706 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707{
3708 int ret = 0;
3709 uint8_t *value = command;
3710 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3711
3712 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3713 value = value + command_len + 1;
3714
3715 /* Convert the value from ascii to integer */
3716 ret = kstrtou16(value, 10, &maxTime);
3717 if (ret < 0) {
3718 /*
3719 * If the input value is greater than max value of datatype,
3720 * then also kstrtou8 fails
3721 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003722 hdd_err("kstrtou16 failed range [%d - %d]",
3723 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3724 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003725 ret = -EINVAL;
3726 goto exit;
3727 }
3728
3729 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3730 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003731 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3732 maxTime,
3733 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3734 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003735 ret = -EINVAL;
3736 goto exit;
3737 }
3738
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003739 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003740 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003741
3742 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003743 sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003744 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745 maxTime);
3746
3747exit:
3748 return ret;
3749}
3750
Jeff Johnsone44b7012017-09-10 15:25:47 -07003751static int drv_cmd_get_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003752 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003753 uint8_t *command,
3754 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003755 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003756{
3757 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003758 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
3759 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003760 char extra[32];
3761 uint8_t len = 0;
3762
3763 /* value is interms of msec */
3764 len = scnprintf(extra, sizeof(extra), "%s %d",
3765 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303766 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003767
3768 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003769 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003770 ret = -EFAULT;
3771 }
3772
3773 return ret;
3774}
3775
Jeff Johnsone44b7012017-09-10 15:25:47 -07003776static int drv_cmd_set_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003777 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003778 uint8_t *command,
3779 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003780 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003781{
3782 int ret = 0;
3783 uint8_t *value = command;
3784 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3785
3786 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3787 value = value + command_len + 1;
3788
3789 /* Convert the value from ascii to integer */
3790 ret = kstrtou16(value, 10, &val);
3791 if (ret < 0) {
3792 /*
3793 * If the input value is greater than max value of datatype,
3794 * then also kstrtou8 fails
3795 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003796 hdd_err("kstrtou16 failed range [%d - %d]",
3797 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3798 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003799 ret = -EINVAL;
3800 goto exit;
3801 }
3802
3803 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3804 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003805 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3806 val,
3807 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3808 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003809 ret = -EINVAL;
3810 goto exit;
3811 }
3812
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003813 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003814 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003815
3816 hdd_ctx->config->nNeighborScanPeriod = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003817 sme_set_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003818 adapter->session_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003819
3820exit:
3821 return ret;
3822}
3823
Jeff Johnsone44b7012017-09-10 15:25:47 -07003824static int drv_cmd_get_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003825 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826 uint8_t *command,
3827 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003828 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003829{
3830 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003831 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003832 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003833 char extra[32];
3834 uint8_t len = 0;
3835
3836 /* value is interms of msec */
3837 len = scnprintf(extra, sizeof(extra), "%s %d",
3838 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303839 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003840
3841 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003842 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003843 ret = -EFAULT;
3844 }
3845
3846 return ret;
3847}
3848
Jeff Johnsone44b7012017-09-10 15:25:47 -07003849static int drv_cmd_set_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003850 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003851 uint8_t *command,
3852 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003853 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003854{
3855 int ret = 0;
3856 uint8_t *value = command;
3857 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3858
3859 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3860 value = value + command_len + 1;
3861
3862 /* Convert the value from ascii to integer */
3863 ret = kstrtou8(value, 10, &val);
3864 if (ret < 0) {
3865 /*
3866 * If the input value is greater than max value of datatype,
3867 * then also kstrtou8 fails
3868 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003869 hdd_err("kstrtou8 failed range [%d - %d]",
3870 CFG_ROAM_INTRA_BAND_MIN,
3871 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003872 ret = -EINVAL;
3873 goto exit;
3874 }
3875
3876 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3877 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003878 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3879 val,
3880 CFG_ROAM_INTRA_BAND_MIN,
3881 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003882 ret = -EINVAL;
3883 goto exit;
3884 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003885 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003886 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003887
3888 hdd_ctx->config->nRoamIntraBand = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003889 sme_set_roam_intra_band(hdd_ctx->mac_handle, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003890
3891exit:
3892 return ret;
3893}
3894
Jeff Johnsone44b7012017-09-10 15:25:47 -07003895static int drv_cmd_get_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003896 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897 uint8_t *command,
3898 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003899 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003900{
3901 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003902 uint16_t val = sme_get_roam_intra_band(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903 char extra[32];
3904 uint8_t len = 0;
3905
3906 /* value is interms of msec */
3907 len = scnprintf(extra, sizeof(extra), "%s %d",
3908 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303909 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003910 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003911 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003912 ret = -EFAULT;
3913 }
3914
3915 return ret;
3916}
3917
Jeff Johnsone44b7012017-09-10 15:25:47 -07003918static int drv_cmd_set_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003919 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003920 uint8_t *command,
3921 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003922 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923{
3924 int ret = 0;
3925 uint8_t *value = command;
3926 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3927
3928 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3929 value = value + command_len + 1;
3930
3931 /* Convert the value from ascii to integer */
3932 ret = kstrtou8(value, 10, &nProbes);
3933 if (ret < 0) {
3934 /*
3935 * If the input value is greater than max value of datatype,
3936 * then also kstrtou8 fails
3937 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003938 hdd_err("kstrtou8 failed range [%d - %d]",
3939 CFG_ROAM_SCAN_N_PROBES_MIN,
3940 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003941 ret = -EINVAL;
3942 goto exit;
3943 }
3944
3945 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3946 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003947 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3948 nProbes,
3949 CFG_ROAM_SCAN_N_PROBES_MIN,
3950 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003951 ret = -EINVAL;
3952 goto exit;
3953 }
3954
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003955 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003956 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003957
3958 hdd_ctx->config->nProbes = nProbes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003959 sme_update_roam_scan_n_probes(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003960 adapter->session_id, nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003961
3962exit:
3963 return ret;
3964}
3965
Jeff Johnsone44b7012017-09-10 15:25:47 -07003966static int drv_cmd_get_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003967 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003968 uint8_t *command,
3969 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003970 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003971{
3972 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003973 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003974 char extra[32];
3975 uint8_t len = 0;
3976
3977 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303978 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003979 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003980 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003981 ret = -EFAULT;
3982 }
3983
3984 return ret;
3985}
3986
Jeff Johnsone44b7012017-09-10 15:25:47 -07003987static int drv_cmd_set_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003988 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003989 uint8_t *command,
3990 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003991 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003992{
3993 int ret = 0;
3994 uint8_t *value = command;
3995 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3996
3997 /* input value is in units of msec */
3998
3999 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4000 value = value + command_len + 1;
4001
4002 /* Convert the value from ascii to integer */
4003 ret = kstrtou16(value, 10, &homeAwayTime);
4004 if (ret < 0) {
4005 /*
4006 * If the input value is greater than max value of datatype,
4007 * then also kstrtou8 fails
4008 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004009 hdd_err("kstrtou8 failed range [%d - %d]",
4010 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4011 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012 ret = -EINVAL;
4013 goto exit;
4014 }
4015
4016 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4017 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004018 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004019 homeAwayTime,
4020 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4021 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4022 ret = -EINVAL;
4023 goto exit;
4024 }
4025
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004026 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004027 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028
4029 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4030 homeAwayTime) {
4031 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004032 sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004033 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004034 homeAwayTime,
4035 true);
4036 }
4037
4038exit:
4039 return ret;
4040}
4041
Jeff Johnsone44b7012017-09-10 15:25:47 -07004042static int drv_cmd_get_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004043 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004044 uint8_t *command,
4045 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004046 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004047{
4048 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004049 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004050 char extra[32];
4051 uint8_t len = 0;
4052
4053 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304054 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004055
4056 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004057 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004058 ret = -EFAULT;
4059 }
4060
4061 return ret;
4062}
4063
Jeff Johnsone44b7012017-09-10 15:25:47 -07004064static int drv_cmd_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004065 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004066 uint8_t *command,
4067 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004068 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004069{
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05304070 return hdd_parse_reassoc(adapter, command, priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071}
4072
Jeff Johnsone44b7012017-09-10 15:25:47 -07004073static int drv_cmd_set_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004074 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004075 uint8_t *command,
4076 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004077 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004078{
4079 int ret = 0;
4080 uint8_t *value = command;
4081 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4082
4083 /* Move pointer to ahead of SETWESMODE<delimiter> */
4084 value = value + command_len + 1;
4085
4086 /* Convert the value from ascii to integer */
4087 ret = kstrtou8(value, 10, &wesMode);
4088 if (ret < 0) {
4089 /*
4090 * If the input value is greater than max value of datatype,
4091 * then also kstrtou8 fails
4092 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004093 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004094 CFG_ENABLE_WES_MODE_NAME_MIN,
4095 CFG_ENABLE_WES_MODE_NAME_MAX);
4096 ret = -EINVAL;
4097 goto exit;
4098 }
4099
4100 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4101 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004102 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004103 wesMode,
4104 CFG_ENABLE_WES_MODE_NAME_MIN,
4105 CFG_ENABLE_WES_MODE_NAME_MAX);
4106 ret = -EINVAL;
4107 goto exit;
4108 }
4109
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004110 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004111 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004112
4113 hdd_ctx->config->isWESModeEnabled = wesMode;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004114 sme_update_wes_mode(hdd_ctx->mac_handle, wesMode, adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115
4116exit:
4117 return ret;
4118}
4119
Jeff Johnsone44b7012017-09-10 15:25:47 -07004120static int drv_cmd_get_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004121 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004122 uint8_t *command,
4123 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004124 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004125{
4126 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004127 bool wesMode = sme_get_wes_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004128 char extra[32];
4129 uint8_t len = 0;
4130
4131 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304132 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004133 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004134 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004135 ret = -EFAULT;
4136 }
4137
4138 return ret;
4139}
4140
Jeff Johnsone44b7012017-09-10 15:25:47 -07004141static int drv_cmd_set_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004142 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004143 uint8_t *command,
4144 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004145 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146{
4147 int ret = 0;
4148 uint8_t *value = command;
4149 uint8_t nOpportunisticThresholdDiff =
4150 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4151
4152 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4153 value = value + command_len + 1;
4154
4155 /* Convert the value from ascii to integer */
4156 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4157 if (ret < 0) {
4158 /*
4159 * If the input value is greater than max value of datatype,
4160 * then also kstrtou8 fails
4161 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004162 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004163 ret = -EINVAL;
4164 goto exit;
4165 }
4166
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004167 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004168 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004169
Jeff Johnsond549efa2018-06-13 20:27:47 -07004170 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004171 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004172 nOpportunisticThresholdDiff);
4173
4174exit:
4175 return ret;
4176}
4177
Jeff Johnsone44b7012017-09-10 15:25:47 -07004178static int drv_cmd_get_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004179 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004180 uint8_t *command,
4181 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004182 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004183{
4184 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004185 mac_handle_t mac_handle = hdd_ctx->mac_handle;
4186 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004187 char extra[32];
4188 uint8_t len = 0;
4189
4190 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304191 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004192 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004193 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004194 ret = -EFAULT;
4195 }
4196
4197 return ret;
4198}
4199
Jeff Johnsone44b7012017-09-10 15:25:47 -07004200static int drv_cmd_set_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004201 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004202 uint8_t *command,
4203 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004204 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004205{
4206 int ret = 0;
4207 uint8_t *value = command;
4208 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4209
4210 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4211 value = value + command_len + 1;
4212
4213 /* Convert the value from ascii to integer */
4214 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4215 if (ret < 0) {
4216 /*
4217 * If the input value is greater than max value of datatype,
4218 * then also kstrtou8 fails
4219 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004220 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004221 ret = -EINVAL;
4222 goto exit;
4223 }
4224
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004225 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004226 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004227
Jeff Johnsond549efa2018-06-13 20:27:47 -07004228 sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004229 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004230 nRoamRescanRssiDiff);
4231
4232exit:
4233 return ret;
4234}
4235
Jeff Johnsone44b7012017-09-10 15:25:47 -07004236static int drv_cmd_get_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004237 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004238 uint8_t *command,
4239 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004240 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004241{
4242 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004243 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004244 char extra[32];
4245 uint8_t len = 0;
4246
4247 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304248 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004249 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004250 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251 ret = -EFAULT;
4252 }
4253
4254 return ret;
4255}
4256
Jeff Johnsone44b7012017-09-10 15:25:47 -07004257static int drv_cmd_set_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004258 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004259 uint8_t *command,
4260 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004261 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004262{
4263 int ret = 0;
4264 uint8_t *value = command;
4265 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4266
4267 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4268 value = value + command_len + 1;
4269
4270 /* Convert the value from ascii to integer */
4271 ret = kstrtou8(value, 10, &lfrMode);
4272 if (ret < 0) {
4273 /*
4274 * If the input value is greater than max value of datatype,
4275 * then also kstrtou8 fails
4276 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004277 hdd_err("kstrtou8 failed range [%d - %d]",
4278 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004279 CFG_LFR_FEATURE_ENABLED_MAX);
4280 ret = -EINVAL;
4281 goto exit;
4282 }
4283
4284 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4285 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004286 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004287 lfrMode,
4288 CFG_LFR_FEATURE_ENABLED_MIN,
4289 CFG_LFR_FEATURE_ENABLED_MAX);
4290 ret = -EINVAL;
4291 goto exit;
4292 }
4293
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004294 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004295 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004296
4297 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004298 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004299 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004300 lfrMode);
4301
4302exit:
4303 return ret;
4304}
4305
Jeff Johnsone44b7012017-09-10 15:25:47 -07004306static int drv_cmd_set_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004307 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004308 uint8_t *command,
4309 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004310 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004311{
4312 int ret = 0;
4313 uint8_t *value = command;
4314 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4315
4316 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4317 value = value + command_len + 1;
4318
4319 /* Convert the value from ascii to integer */
4320 ret = kstrtou8(value, 10, &ft);
4321 if (ret < 0) {
4322 /*
4323 * If the input value is greater than max value of datatype,
4324 * then also kstrtou8 fails
4325 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004326 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004327 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4328 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4329 ret = -EINVAL;
4330 goto exit;
4331 }
4332
4333 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4334 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004335 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 ft,
4337 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4338 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4339 ret = -EINVAL;
4340 goto exit;
4341 }
4342
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004343 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344
4345 hdd_ctx->config->isFastTransitionEnabled = ft;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004346 sme_update_fast_transition_enabled(hdd_ctx->mac_handle, ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004347
4348exit:
4349 return ret;
4350}
4351
Jeff Johnsone44b7012017-09-10 15:25:47 -07004352static int drv_cmd_fast_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004353 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004354 uint8_t *command,
4355 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004356 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004357{
4358 int ret = 0;
4359 uint8_t *value = command;
4360 uint8_t channel = 0;
4361 tSirMacAddr targetApBssid;
Krunal Sonibfd05492017-10-03 15:48:37 -07004362 uint32_t roamId = INVALID_ROAM_ID;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004364 tCsrHandoffRequest handoffInfo;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004365 struct hdd_station_ctx *sta_ctx;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004366 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004367
Krunal Sonibe766b02016-03-10 13:00:44 -08004368 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004369 hdd_warn("Unsupported in mode %s(%d)",
4370 hdd_device_mode_to_string(adapter->device_mode),
4371 adapter->device_mode);
4372 return -EINVAL;
4373 }
4374
Jeff Johnsond377dce2017-10-04 10:32:42 -07004375 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004376
4377 /* if not associated, no need to proceed with reassoc */
Jeff Johnsond377dce2017-10-04 10:32:42 -07004378 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004379 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004380 ret = -EINVAL;
4381 goto exit;
4382 }
4383
4384 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4385 &channel);
4386 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004387 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004388 goto exit;
4389 }
4390
Jeff Johnsond549efa2018-06-13 20:27:47 -07004391 mac_handle = hdd_ctx->mac_handle;
4392
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004393 /*
4394 * if the target bssid is same as currently associated AP,
4395 * issue reassoc to same AP
4396 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004397 if (!qdf_mem_cmp(targetApBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004398 sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304399 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004400 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304401 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004402 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304403 targetApBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004404 sta_ctx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304405 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07004406 sme_get_modify_profile_fields(mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004407 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004408 &modProfileFields);
Jeff Johnsond549efa2018-06-13 20:27:47 -07004409 sme_roam_reassoc(mac_handle, adapter->session_id,
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304410 NULL, modProfileFields, &roamId, 1);
4411 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004412 return 0;
4413 }
4414
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304415 /* Check channel number is a valid channel number */
Selvaraj, Sridhar64b0a9c2017-05-11 16:50:15 +05304416 if (channel && (QDF_STATUS_SUCCESS !=
4417 wlan_hdd_validate_operation_channel(adapter, channel))) {
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304418 hdd_err("Invalid Channel [%d]", channel);
4419 return -EINVAL;
4420 }
4421
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004422 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004423 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004424 targetApBssid, (int)channel);
4425 goto exit;
4426 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004428 handoffInfo.channel = channel;
4429 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004430 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431 sizeof(tSirMacAddr));
Jeff Johnsond549efa2018-06-13 20:27:47 -07004432 sme_handoff_request(mac_handle, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004433 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004434exit:
4435 return ret;
4436}
4437
Jeff Johnsone44b7012017-09-10 15:25:47 -07004438static int drv_cmd_set_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004439 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004440 uint8_t *command,
4441 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004442 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443{
4444 int ret = 0;
4445 uint8_t *value = command;
4446 uint8_t roamScanControl = 0;
4447
4448 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4449 value = value + command_len + 1;
4450
4451 /* Convert the value from ascii to integer */
4452 ret = kstrtou8(value, 10, &roamScanControl);
4453 if (ret < 0) {
4454 /*
4455 * If the input value is greater than max value of datatype,
4456 * then also kstrtou8 fails
4457 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004458 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004459 ret = -EINVAL;
4460 goto exit;
4461 }
4462
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004463 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004464 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004465
4466 if (0 != roamScanControl) {
4467 ret = 0; /* return success but ignore param value "true" */
4468 goto exit;
4469 }
4470
Jeff Johnsond549efa2018-06-13 20:27:47 -07004471 sme_set_roam_scan_control(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004472 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004473 roamScanControl);
4474
4475exit:
4476 return ret;
4477}
4478
Jeff Johnsone44b7012017-09-10 15:25:47 -07004479static int drv_cmd_set_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004480 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004481 uint8_t *command,
4482 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004483 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484{
4485 int ret = 0;
4486 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004487 uint32_t okc_mode;
4488 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004489 mac_handle_t mac_handle;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004490
4491 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004492
4493 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004494 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004495 * then this operation is not permitted (return FAILURE)
4496 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07004497 mac_handle = hdd_ctx->mac_handle;
4498 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004499 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07004500 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004501 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502 ret = -EPERM;
4503 goto exit;
4504 }
4505
4506 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4507 value = value + command_len + 1;
4508
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004509 /* get the current configured value */
4510 okc_mode = hdd_ctx->config->pmkid_modes & CFG_PMKID_MODES_OKC;
4511
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004513 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004514 if (ret < 0) {
4515 /*
4516 * If the input value is greater than max value of datatype,
4517 * then also kstrtou8 fails
4518 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004519 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004520 ret = -EINVAL;
4521 goto exit;
4522 }
4523
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004524 if ((okc_mode < 0) ||
4525 (okc_mode > 1)) {
4526 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4527 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004528 ret = -EINVAL;
4529 goto exit;
4530 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004531 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004532 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004533
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004534 if (okc_mode)
4535 hdd_ctx->config->pmkid_modes |= CFG_PMKID_MODES_OKC;
4536 else
4537 hdd_ctx->config->pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004538
4539exit:
4540 return ret;
4541}
4542
Jeff Johnsone44b7012017-09-10 15:25:47 -07004543static int drv_cmd_get_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004544 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004545 uint8_t *command,
4546 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004547 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004548{
4549 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004550 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004551 char extra[32];
4552 uint8_t len = 0;
4553
4554 len = scnprintf(extra, sizeof(extra), "%s %d",
4555 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304556 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004557 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004558 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004559 ret = -EFAULT;
4560 }
4561
4562 return ret;
4563}
4564
Jeff Johnsone44b7012017-09-10 15:25:47 -07004565static int drv_cmd_bt_coex_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004566 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004567 uint8_t *command,
4568 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004569 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004570{
4571 int ret = 0;
4572 char *bcMode;
4573
4574 bcMode = command + 11;
4575 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004576 hdd_debug("BTCOEXMODE %d", *bcMode);
Jeff Johnson59b19312017-11-02 21:14:33 -07004577 hdd_ctx->bt_coex_mode_set = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004578 ret = wlan_hdd_scan_abort(adapter);
4579 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004580 hdd_err("Failed to abort existing scan status: %d",
4581 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004582 }
4583 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004584 hdd_debug("BTCOEXMODE %d", *bcMode);
Jeff Johnson59b19312017-11-02 21:14:33 -07004585 hdd_ctx->bt_coex_mode_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004586 }
4587
4588 return ret;
4589}
4590
Jeff Johnsone44b7012017-09-10 15:25:47 -07004591static int drv_cmd_scan_active(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004592 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004593 uint8_t *command,
4594 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004595 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004596{
4597 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4598 return 0;
4599}
4600
Jeff Johnsone44b7012017-09-10 15:25:47 -07004601static int drv_cmd_scan_passive(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004602 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004603 uint8_t *command,
4604 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004605 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004606{
4607 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4608 return 0;
4609}
4610
Jeff Johnsone44b7012017-09-10 15:25:47 -07004611static int drv_cmd_get_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004612 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 uint8_t *command,
4614 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004615 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004616{
4617 int ret = 0;
4618 struct hdd_config *pCfg =
4619 (WLAN_HDD_GET_CTX(adapter))->config;
4620 char extra[32];
4621 uint8_t len = 0;
4622
4623 memset(extra, 0, sizeof(extra));
4624 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304625 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004626 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004627 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004628 ret = -EFAULT;
4629 goto exit;
4630 }
4631 ret = len;
4632exit:
4633 return ret;
4634}
4635
Jeff Johnsone44b7012017-09-10 15:25:47 -07004636static int drv_cmd_set_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004637 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 uint8_t *command,
4639 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004640 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004641{
4642 return hdd_set_dwell_time(adapter, command);
4643}
4644
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05304645#ifdef WLAN_AP_STA_CONCURRENCY
4646static int drv_cmd_conc_set_dwell_time(hdd_adapter_t *adapter,
4647 hdd_context_t *hdd_ctx,
4648 u8 *command,
4649 u8 command_len,
4650 hdd_priv_data_t *priv_data)
4651{
4652 return hdd_conc_set_dwell_time(hdd_ctx, command);
4653}
4654#endif
4655
Jeff Johnsone44b7012017-09-10 15:25:47 -07004656static int drv_cmd_miracast(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004657 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658 uint8_t *command,
4659 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004660 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004661{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304662 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004663 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004664 uint8_t filterType = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004665 uint8_t *value;
4666
Jeff Johnson6da2db12017-09-03 09:18:52 -07004667 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004668 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004670 value = command + 9;
4671
4672 /* Convert the value from ascii to integer */
4673 ret = kstrtou8(value, 10, &filterType);
4674 if (ret < 0) {
4675 /*
4676 * If the input value is greater than max value of datatype,
4677 * then also kstrtou8 fails
4678 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004679 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004680 ret = -EINVAL;
4681 goto exit;
4682 }
4683 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4684 || (filterType >
4685 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004686 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004687 ret = -EINVAL;
4688 goto exit;
4689 }
4690 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
Jeff Johnson6da2db12017-09-03 09:18:52 -07004691 hdd_ctx->miracast_value = filterType;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004692
Jeff Johnsond549efa2018-06-13 20:27:47 -07004693 ret_status = sme_set_miracast(hdd_ctx->mac_handle, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304694 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004695 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004696 return -EBUSY;
4697 }
Abhishek Singhc87bb042018-01-30 17:10:42 +05304698 ret_status = ucfg_scan_set_miracast(hdd_ctx->hdd_psoc,
4699 filterType ? true : false);
4700 if (QDF_IS_STATUS_ERROR(ret_status)) {
4701 hdd_err("Failed to set miracastn scan");
4702 return -EBUSY;
4703 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004704
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004705 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4706 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707
4708exit:
4709 return ret;
4710}
4711
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004712/* Function header is left blank intentionally */
4713static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4714 int32_t *oui_length, int32_t limit)
4715{
4716 uint8_t len;
4717 uint8_t data;
4718
4719 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4720 command++;
4721 limit--;
4722 }
4723
4724 len = 2;
4725
4726 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4727 (limit > 1)) {
4728 sscanf(command, "%02x", (unsigned int *)&data);
4729 ie[len++] = data;
4730 command += 2;
4731 limit -= 2;
4732 }
4733
4734 *oui_length = len - 2;
4735
4736 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4737 command++;
4738 limit--;
4739 }
4740
4741 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4742 (limit > 1)) {
4743 sscanf(command, "%02x", (unsigned int *)&data);
4744 ie[len++] = data;
4745 command += 2;
4746 limit -= 2;
4747 }
4748
4749 ie[0] = IE_EID_VENDOR;
4750 ie[1] = len - 2;
4751
4752 return len;
4753}
4754
4755/**
4756 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4757 * @adapter: Pointer to adapter
4758 * @hdd_ctx: Pointer to HDD context
4759 * @command: Pointer to command string
4760 * @command_len : Command length
4761 * @priv_data : Pointer to priv data
4762 *
4763 * Return:
4764 * int status code
4765 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07004766static int drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004767 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004768 uint8_t *command,
4769 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004770 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004771{
4772 int i = 0;
4773 int status;
4774 int ret = 0;
4775 uint8_t *ibss_ie;
4776 int32_t oui_length = 0;
4777 uint32_t ibss_ie_length;
4778 uint8_t *value = command;
4779 tSirModifyIE ibssModifyIE;
Jeff Johnson61b5e982018-03-15 11:33:31 -07004780 struct csr_roam_profile *roam_profile;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004781 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004782
Krunal Sonibe766b02016-03-10 13:00:44 -08004783 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004784 hdd_debug("Device_mode %s(%d) not IBSS",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004785 hdd_device_mode_to_string(adapter->device_mode),
4786 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004787 return ret;
4788 }
4789
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004790 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004791
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004792 /* validate argument of command */
4793 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004794 hdd_err("No arguments in command length %zu",
4795 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004796 ret = -EFAULT;
4797 goto exit;
4798 }
4799
4800 /* moving to arguments of commands */
4801 value = value + command_len;
4802 command_len = strlen(value);
4803
4804 /* oui_data can't be less than 3 bytes */
4805 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004806 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4807 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004808 ret = -EFAULT;
4809 goto exit;
4810 }
4811
4812 ibss_ie = qdf_mem_malloc(command_len);
4813 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004814 hdd_err("Could not allocate memory for command length %d",
4815 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004816 ret = -ENOMEM;
4817 goto exit;
4818 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004819
4820 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4821 &oui_length,
4822 command_len);
4823 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004824 hdd_err("Could not parse command %s return length %d",
4825 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004826 ret = -EFAULT;
4827 qdf_mem_free(ibss_ie);
4828 goto exit;
4829 }
4830
Jeff Johnson8313b9d2018-03-14 15:09:28 -07004831 roam_profile = hdd_roam_profile(adapter);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004832
4833 qdf_copy_macaddr(&ibssModifyIE.bssid,
Jeff Johnson5b34fce2017-10-13 13:24:51 -07004834 roam_profile->BSSIDs.bssid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004835
Jeff Johnson1b780e42017-10-31 14:11:45 -07004836 ibssModifyIE.smeSessionId = adapter->session_id;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004837 ibssModifyIE.notify = true;
4838 ibssModifyIE.ieID = IE_EID_VENDOR;
4839 ibssModifyIE.ieIDLen = ibss_ie_length;
4840 ibssModifyIE.ieBufferlength = ibss_ie_length;
4841 ibssModifyIE.pIEBuffer = ibss_ie;
4842 ibssModifyIE.oui_length = oui_length;
4843
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004844 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4845 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004846 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004847 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004848
4849 /* Probe Bcn modification */
Jeff Johnsond549efa2018-06-13 20:27:47 -07004850 mac_handle = hdd_ctx->mac_handle;
4851 sme_modify_add_ie(mac_handle, &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004852
4853 /* Populating probe resp frame */
Jeff Johnsond549efa2018-06-13 20:27:47 -07004854 sme_modify_add_ie(mac_handle, &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004855
4856 qdf_mem_free(ibss_ie);
4857
Jeff Johnsond549efa2018-06-13 20:27:47 -07004858 status = sme_send_cesium_enable_ind(mac_handle,
4859 adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004860 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004861 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004862 status);
4863 ret = -EINVAL;
4864 goto exit;
4865 }
4866
4867exit:
4868 return ret;
4869}
4870
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304871#ifdef FEATURE_WLAN_RMC
4872/* Function header is left blank intentionally */
4873static int hdd_parse_setrmcenable_command(uint8_t *pValue,
4874 uint8_t *pRmcEnable)
4875{
4876 uint8_t *inPtr = pValue;
4877 int tempInt;
4878 int v = 0;
4879 char buf[32];
4880 *pRmcEnable = 0;
4881
4882 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
4883
4884 if (NULL == inPtr)
4885 return 0;
4886 else if (SPACE_ASCII_VALUE != *inPtr)
4887 return 0;
4888
4889 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
4890 inPtr++;
4891
4892 if ('\0' == *inPtr)
4893 return 0;
4894
4895 v = sscanf(inPtr, "%31s ", buf);
4896 if (1 != v)
4897 return -EINVAL;
4898
4899 v = kstrtos32(buf, 10, &tempInt);
4900 if (v < 0)
4901 return -EINVAL;
4902
4903 *pRmcEnable = tempInt;
4904
4905 hdd_debug("ucRmcEnable: %d", *pRmcEnable);
4906
4907 return 0;
4908}
4909
4910/* Function header is left blank intentionally */
4911static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
4912 uint32_t *pActionPeriod)
4913{
4914 uint8_t *inPtr = pValue;
4915 int tempInt;
4916 int v = 0;
4917 char buf[32];
4918 *pActionPeriod = 0;
4919
4920 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
4921
4922 if (NULL == inPtr)
4923 return -EINVAL;
4924 else if (SPACE_ASCII_VALUE != *inPtr)
4925 return -EINVAL;
4926
4927 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
4928 inPtr++;
4929
4930 if ('\0' == *inPtr)
4931 return 0;
4932
4933 v = sscanf(inPtr, "%31s ", buf);
4934 if (1 != v)
4935 return -EINVAL;
4936
4937 v = kstrtos32(buf, 10, &tempInt);
4938 if (v < 0)
4939 return -EINVAL;
4940
4941 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
4942 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX))
4943 return -EINVAL;
4944
4945 *pActionPeriod = tempInt;
4946
4947 hdd_debug("uActionPeriod: %d", *pActionPeriod);
4948
4949 return 0;
4950}
4951
4952/* Function header is left blank intentionally */
4953static int hdd_parse_setrmcrate_command(uint8_t *pValue,
4954 uint32_t *pRate,
4955 enum tx_rate_info *pTxFlags)
4956{
4957 uint8_t *inPtr = pValue;
4958 int tempInt;
4959 int v = 0;
4960 char buf[32];
4961 *pRate = 0;
4962 *pTxFlags = 0;
4963
4964 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
4965
4966 if (NULL == inPtr)
4967 return -EINVAL;
4968 else if (SPACE_ASCII_VALUE != *inPtr)
4969 return -EINVAL;
4970
4971 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
4972 inPtr++;
4973
4974 if ('\0' == *inPtr)
4975 return 0;
4976
4977 v = sscanf(inPtr, "%31s ", buf);
4978 if (1 != v)
4979 return -EINVAL;
4980
4981 v = kstrtos32(buf, 10, &tempInt);
4982 if (v < 0)
4983 return -EINVAL;
4984
4985 switch (tempInt) {
4986 default:
4987 hdd_warn("Unsupported rate: %d", tempInt);
4988 return -EINVAL;
4989 case 0:
4990 case 6:
4991 case 9:
4992 case 12:
4993 case 18:
4994 case 24:
4995 case 36:
4996 case 48:
4997 case 54:
4998 *pTxFlags = TX_RATE_LEGACY;
4999 *pRate = tempInt * 10;
5000 break;
5001 case 65:
5002 *pTxFlags = TX_RATE_HT20;
5003 *pRate = tempInt * 10;
5004 break;
5005 case 72:
5006 *pTxFlags = TX_RATE_HT20 | TX_RATE_SGI;
5007 *pRate = 722;
5008 break;
5009 }
5010
5011 hdd_debug("Rate: %d", *pRate);
5012
5013 return 0;
5014}
5015
Jeff Johnsone44b7012017-09-10 15:25:47 -07005016static int drv_cmd_set_rmc_enable(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005017 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005018 uint8_t *command,
5019 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005020 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005021{
5022 int ret = 0;
5023 uint8_t *value = command;
5024 uint8_t ucRmcEnable = 0;
5025 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005026 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005027
Krunal Sonibe766b02016-03-10 13:00:44 -08005028 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5029 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005030 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
5031 hdd_device_mode_to_string(adapter->device_mode),
5032 adapter->device_mode);
5033 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005034 ret = -EINVAL;
5035 goto exit;
5036 }
5037
5038 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
5039 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005040 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005041 ret = -EINVAL;
5042 goto exit;
5043 }
5044
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005045 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005046 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005047
5048 if (true == ucRmcEnable) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07005049 status = sme_enable_rmc(mac_handle, adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005050 } else if (false == ucRmcEnable) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07005051 status = sme_disable_rmc(mac_handle, adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005052 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07005053 hdd_err("Invalid SETRMCENABLE command %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005054 ret = -EINVAL;
5055 goto exit;
5056 }
5057
5058 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07005059 hdd_err("SETRMC %d failed status %d", ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005060 ret = -EINVAL;
5061 goto exit;
5062 }
5063
5064exit:
5065 return ret;
5066}
5067
Jeff Johnsone44b7012017-09-10 15:25:47 -07005068static int drv_cmd_set_rmc_action_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005069 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005070 uint8_t *command,
5071 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005072 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005073{
5074 int ret = 0;
5075 uint8_t *value = command;
5076 uint32_t uActionPeriod = 0;
5077 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005078 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005079
Krunal Sonibe766b02016-03-10 13:00:44 -08005080 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5081 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005082 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005083 hdd_device_mode_to_string(adapter->device_mode),
5084 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005085 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005086 ret = -EINVAL;
5087 goto exit;
5088 }
5089
5090 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
5091 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005092 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005093 ret = -EINVAL;
5094 goto exit;
5095 }
5096
Jeff Johnsond549efa2018-06-13 20:27:47 -07005097 hdd_debug("uActionPeriod %d", uActionPeriod);
5098 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005099
Jeff Johnsond549efa2018-06-13 20:27:47 -07005100 if (sme_cfg_set_int(mac_handle,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005101 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
5102 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005103 hdd_err("Could not set SETRMCACTIONPERIOD %d",
5104 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005105 ret = -EINVAL;
5106 goto exit;
5107 }
5108
Jeff Johnsond549efa2018-06-13 20:27:47 -07005109 status = sme_send_rmc_action_period(mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005110 adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005111 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005112 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005113 status);
5114 ret = -EINVAL;
5115 goto exit;
5116 }
5117
5118exit:
5119 return ret;
5120}
5121
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305122static int drv_cmd_set_rmc_tx_rate(struct hdd_adapter *adapter,
5123 struct hdd_context *hdd_ctx,
5124 uint8_t *command,
5125 uint8_t command_len,
5126 struct hdd_priv_data *priv_data)
5127{
5128 int ret = 0;
5129 uint8_t *value = command;
5130 uint32_t uRate = 0;
5131 enum tx_rate_info txFlags = 0;
5132 tSirRateUpdateInd rateUpdateParams = {0};
5133 int status;
5134 struct hdd_config *pConfig = hdd_ctx->config;
5135
5136 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5137 (QDF_SAP_MODE != adapter->device_mode)) {
5138 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5139 hdd_device_mode_to_string(adapter->device_mode),
5140 adapter->device_mode);
5141 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
5142 ret = -EINVAL;
5143 goto exit;
5144 }
5145
5146 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5147 if (status) {
5148 hdd_err("Invalid SETRMCTXRATE command");
5149 ret = -EINVAL;
5150 goto exit;
5151 }
5152 hdd_debug("uRate %d", uRate);
5153 /* -1 implies ignore this param */
5154 rateUpdateParams.ucastDataRate = -1;
5155
5156 /*
5157 * Fill the user specifieed RMC rate param
5158 * and the derived tx flags.
5159 */
5160 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5161 rateUpdateParams.reliableMcastDataRate = uRate;
5162 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5163 rateUpdateParams.dev_mode = adapter->device_mode;
5164 rateUpdateParams.bcastDataRate = -1;
5165 memcpy(rateUpdateParams.bssid.bytes,
5166 adapter->mac_addr.bytes,
5167 sizeof(rateUpdateParams.bssid));
5168 status = sme_send_rate_update_ind(hdd_ctx->mac_handle,
5169 &rateUpdateParams);
5170
5171exit:
5172 return ret;
5173}
5174#endif /* FEATURE_WLAN_RMC */
5175
Jeff Johnsone44b7012017-09-10 15:25:47 -07005176static int drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005177 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005178 uint8_t *command,
5179 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005180 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005181{
5182 int ret = 0;
5183 int status = QDF_STATUS_SUCCESS;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005184 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005185 char *extra = NULL;
5186 int idx = 0;
5187 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005188 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005189 uint32_t numOfBytestoPrint = 0;
5190
Krunal Sonibe766b02016-03-10 13:00:44 -08005191 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005192 hdd_warn("Unsupported in mode %s(%d)",
5193 hdd_device_mode_to_string(adapter->device_mode),
5194 adapter->device_mode);
5195 return -EINVAL;
5196 }
5197
Jeff Johnsond377dce2017-10-04 10:32:42 -07005198 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005199 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005200
5201 /* Handle the command */
5202 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5203 if (QDF_STATUS_SUCCESS == status) {
Dustin Brownc8e96f12018-04-19 09:27:42 -07005204 size_t user_size = qdf_min(WLAN_MAX_BUF_SIZE,
5205 priv_data->total_len);
5206
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005207 /*
5208 * The variable extra needed to be allocated on the heap since
5209 * amount of memory required to copy the data for 32 devices
5210 * exceeds the size of 1024 bytes of default stack size. On
5211 * 64 bit devices, the default max stack size of 2048 bytes
5212 */
Dustin Brownc8e96f12018-04-19 09:27:42 -07005213 extra = qdf_mem_malloc(user_size);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005214
5215 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005216 hdd_err("memory allocation failed");
5217 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005218 goto exit;
5219 }
5220
5221 /* Copy number of stations */
Dustin Brownc8e96f12018-04-19 09:27:42 -07005222 length = scnprintf(extra, user_size, "%d ",
Jeff Johnsond377dce2017-10-04 10:32:42 -07005223 sta_ctx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005224 numOfBytestoPrint = length;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005225 for (idx = 0; idx < sta_ctx->ibss_peer_info.numPeers;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005226 idx++) {
5227 int8_t rssi;
5228 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005229
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005230 qdf_mem_copy(mac_addr,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005231 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005232 mac_addr, sizeof(mac_addr));
5233
5234 tx_rate =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005235 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005236 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305237 /*
5238 * Only lower 3 bytes are rate info. Mask of the MSByte
5239 */
5240 tx_rate &= 0x00FFFFFF;
5241
Jeff Johnsond377dce2017-10-04 10:32:42 -07005242 rssi = sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005243 rssi;
5244
Dustin Brownc8e96f12018-04-19 09:27:42 -07005245 length += scnprintf(extra + length,
5246 user_size - length,
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005247 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5248 mac_addr[0], mac_addr[1], mac_addr[2],
5249 mac_addr[3], mac_addr[4], mac_addr[5],
5250 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005251 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005252 * cdf_trace_msg has limitation of 512 bytes for the
5253 * print buffer. Hence printing the data in two chunks.
5254 * The first chunk will have the data for 16 devices
5255 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005256 */
5257 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5258 numOfBytestoPrint = length;
5259 }
5260
5261 /*
5262 * Copy the data back into buffer, if the data to copy is
5263 * more than 512 bytes than we will split the data and do
5264 * it in two shots
5265 */
5266 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005267 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005268 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305269 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005270 }
5271
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005272 /* This overwrites the last space, which we already copied */
5273 extra[numOfBytestoPrint - 1] = '\0';
5274 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005275
5276 if (length > numOfBytestoPrint) {
5277 if (copy_to_user
5278 (priv_data->buf + numOfBytestoPrint,
5279 extra + numOfBytestoPrint,
5280 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005281 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005282 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305283 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005284 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005285 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005286 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005287 } else {
5288 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005289 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5290 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005291 ret = -EINVAL;
5292 goto exit;
5293 }
5294 ret = 0;
5295
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305296mem_free:
5297 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005298exit:
5299 return ret;
5300}
5301
5302/* Peer Info <Peer Addr> command */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005303static int drv_cmd_get_ibss_peer_info(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005304 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005305 uint8_t *command,
5306 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005307 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005308{
5309 int ret = 0;
5310 uint8_t *value = command;
5311 QDF_STATUS status;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005312 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005313 char extra[128] = { 0 };
5314 uint32_t length = 0;
5315 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005316 struct qdf_mac_addr peerMacAddr;
5317
Krunal Sonibe766b02016-03-10 13:00:44 -08005318 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005319 hdd_warn("Unsupported in mode %s(%d)",
5320 hdd_device_mode_to_string(adapter->device_mode),
5321 adapter->device_mode);
5322 return -EINVAL;
5323 }
5324
Jeff Johnsond377dce2017-10-04 10:32:42 -07005325 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005326
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005327 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005328
5329 /* if there are no peers, no need to continue with the command */
5330 if (eConnectionState_IbssConnected !=
Jeff Johnsond377dce2017-10-04 10:32:42 -07005331 sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005332 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005333 ret = -EINVAL;
5334 goto exit;
5335 }
5336
5337 /* Parse the incoming command buffer */
5338 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5339 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005340 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005341 ret = -EINVAL;
5342 goto exit;
5343 }
5344
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005345 /* Get station index for the peer mac address and sanitize it */
Jeff Johnsond377dce2017-10-04 10:32:42 -07005346 hdd_get_peer_sta_id(sta_ctx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005347
Naveen Rawatc45d1622016-07-05 12:20:09 -07005348 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005349 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005350 ret = -EINVAL;
5351 goto exit;
5352 }
5353
5354 /* Handle the command */
5355 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5356 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005357 uint32_t txRate =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005358 sta_ctx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305359 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5360 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005361
5362 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005363 (int)txRate,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005364 (int)sta_ctx->ibss_peer_info.
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005365 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005366
5367 /* Copy the data back into buffer */
5368 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005369 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005370 ret = -EFAULT;
5371 goto exit;
5372 }
5373 } else {
5374 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005375 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5376 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005377 ret = -EINVAL;
5378 goto exit;
5379 }
5380
5381 /* Success ! */
Rajeev Kumar Sirasanagandla92ec9d92018-04-24 21:33:06 +05305382 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005383 ret = 0;
5384
5385exit:
5386 return ret;
5387}
5388
Jeff Johnsone44b7012017-09-10 15:25:47 -07005389static int drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005390 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005391 uint8_t *command,
5392 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005393 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005394{
5395 int ret = 0;
5396 char *value;
5397 uint8_t tx_fail_count = 0;
5398 uint16_t pid = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005399 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005400
5401 value = command;
5402
5403 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5404
5405 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005406 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005407 goto exit;
5408 }
5409
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005410 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005411 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005412
5413 if (0 == tx_fail_count) {
5414 /* Disable TX Fail Indication */
5415 if (QDF_STATUS_SUCCESS ==
Jeff Johnsond549efa2018-06-13 20:27:47 -07005416 sme_tx_fail_monitor_start_stop_ind(mac_handle,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005417 tx_fail_count,
5418 NULL)) {
5419 cesium_pid = 0;
5420 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005421 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005422 ret = -EINVAL;
5423 }
5424 } else {
5425 if (QDF_STATUS_SUCCESS ==
Jeff Johnsond549efa2018-06-13 20:27:47 -07005426 sme_tx_fail_monitor_start_stop_ind(mac_handle,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005427 tx_fail_count,
5428 (void *)hdd_tx_fail_ind_callback)) {
5429 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005430 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005431 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005432 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005433 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005434 ret = -EINVAL;
5435 }
5436 }
5437
5438exit:
5439 return ret;
5440}
5441
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005442#ifdef FEATURE_WLAN_ESE
Jeff Johnsone44b7012017-09-10 15:25:47 -07005443static int drv_cmd_set_ccx_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005444 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005445 uint8_t *command,
5446 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005447 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005448{
5449 int ret = 0;
5450 uint8_t *value = command;
5451 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5452 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305453 QDF_STATUS status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005454 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005455
5456 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5457 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005458 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005459 goto exit;
5460 }
5461 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005462 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005463 numChannels,
5464 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5465 ret = -EINVAL;
5466 goto exit;
5467 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305468
Jeff Johnsond549efa2018-06-13 20:27:47 -07005469 mac_handle = hdd_ctx->mac_handle;
5470 if (!sme_validate_channel_list(mac_handle, ChannelList, numChannels)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305471 hdd_err("List contains invalid channel(s)");
5472 ret = -EINVAL;
5473 goto exit;
5474 }
5475
Jeff Johnsond549efa2018-06-13 20:27:47 -07005476 status = sme_set_ese_roam_scan_channel_list(mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005477 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005478 ChannelList,
5479 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305480 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005481 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005482 ret = -EINVAL;
5483 goto exit;
5484 }
5485
5486exit:
5487 return ret;
5488}
5489
Jeff Johnsone44b7012017-09-10 15:25:47 -07005490static int drv_cmd_get_tsm_stats(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005491 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005492 uint8_t *command,
5493 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005494 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005495{
5496 int ret = 0;
5497 uint8_t *value = command;
5498 char extra[128] = { 0 };
5499 int len = 0;
5500 uint8_t tid = 0;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005501 struct hdd_station_ctx *sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005502 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005503
Krunal Sonibe766b02016-03-10 13:00:44 -08005504 if ((QDF_STA_MODE != adapter->device_mode) &&
5505 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005506 hdd_warn("Unsupported in mode %s(%d)",
5507 hdd_device_mode_to_string(adapter->device_mode),
5508 adapter->device_mode);
5509 return -EINVAL;
5510 }
5511
Jeff Johnsond377dce2017-10-04 10:32:42 -07005512 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005513
5514 /* if not associated, return error */
Jeff Johnsond377dce2017-10-04 10:32:42 -07005515 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005516 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005517 ret = -EINVAL;
5518 goto exit;
5519 }
5520
5521 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5522 value = value + command_len + 1;
5523
5524 /* Convert the value from ascii to integer */
5525 ret = kstrtou8(value, 10, &tid);
5526 if (ret < 0) {
5527 /*
5528 * If the input value is greater than max value of datatype,
5529 * then also kstrtou8 fails
5530 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005531 hdd_err("kstrtou8 failed range [%d - %d]",
5532 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005533 TID_MAX_VALUE);
5534 ret = -EINVAL;
5535 goto exit;
5536 }
5537 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005538 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005539 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5540 ret = -EINVAL;
5541 goto exit;
5542 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005543 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005544 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005545 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5546 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005547 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005548 goto exit;
5549 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005550 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005551 "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 -08005552 tsm_metrics.UplinkPktQueueDly,
5553 tsm_metrics.UplinkPktQueueDlyHist[0],
5554 tsm_metrics.UplinkPktQueueDlyHist[1],
5555 tsm_metrics.UplinkPktQueueDlyHist[2],
5556 tsm_metrics.UplinkPktQueueDlyHist[3],
5557 tsm_metrics.UplinkPktTxDly,
5558 tsm_metrics.UplinkPktLoss,
5559 tsm_metrics.UplinkPktCount,
5560 tsm_metrics.RoamingCount,
5561 tsm_metrics.RoamingDly);
5562 /*
5563 * Output TSM stats is of the format
5564 * GETTSMSTATS [PktQueueDly]
5565 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5566 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5567 */
5568 len = scnprintf(extra,
5569 sizeof(extra),
5570 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5571 command,
5572 tsm_metrics.UplinkPktQueueDly,
5573 tsm_metrics.UplinkPktQueueDlyHist[0],
5574 tsm_metrics.UplinkPktQueueDlyHist[1],
5575 tsm_metrics.UplinkPktQueueDlyHist[2],
5576 tsm_metrics.UplinkPktQueueDlyHist[3],
5577 tsm_metrics.UplinkPktTxDly,
5578 tsm_metrics.UplinkPktLoss,
5579 tsm_metrics.UplinkPktCount,
5580 tsm_metrics.RoamingCount,
5581 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305582 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005583 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005584 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005585 ret = -EFAULT;
5586 goto exit;
5587 }
5588
5589exit:
5590 return ret;
5591}
5592
Jeff Johnsone44b7012017-09-10 15:25:47 -07005593static int drv_cmd_set_cckm_ie(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005594 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005595 uint8_t *command,
5596 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005597 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005598{
5599 int ret;
5600 uint8_t *value = command;
5601 uint8_t *cckmIe = NULL;
5602 uint8_t cckmIeLen = 0;
5603
5604 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5605 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005606 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005607 goto exit;
5608 }
5609
5610 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005611 hdd_err("CCKM Ie input length is more than max[%d]",
5612 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005613 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305614 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005615 cckmIe = NULL;
5616 }
5617 ret = -EINVAL;
5618 goto exit;
5619 }
5620
Jeff Johnsond549efa2018-06-13 20:27:47 -07005621 sme_set_cckm_ie(hdd_ctx->mac_handle, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005622 cckmIe, cckmIeLen);
5623 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305624 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005625 cckmIe = NULL;
5626 }
5627
5628exit:
5629 return ret;
5630}
5631
Jeff Johnsone44b7012017-09-10 15:25:47 -07005632static int drv_cmd_ccx_beacon_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005633 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005634 uint8_t *command,
5635 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005636 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005637{
5638 int ret;
5639 uint8_t *value = command;
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305640 tCsrEseBeaconReq eseBcnReq = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305641 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005642
Krunal Sonibe766b02016-03-10 13:00:44 -08005643 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005644 hdd_warn("Unsupported in mode %s(%d)",
5645 hdd_device_mode_to_string(adapter->device_mode),
5646 adapter->device_mode);
5647 return -EINVAL;
5648 }
5649
5650 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5651 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005652 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005653 goto exit;
5654 }
5655
5656 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005657 hdd_debug("Not associated");
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305658
5659 if (!eseBcnReq.numBcnReqIe)
5660 return -EINVAL;
5661
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005662 hdd_indicate_ese_bcn_report_no_results(adapter,
5663 eseBcnReq.bcnReq[0].measurementToken,
5664 0x02, /* BIT(1) set for measurement done */
5665 0); /* no BSS */
5666 goto exit;
5667 }
5668
Jeff Johnsond549efa2018-06-13 20:27:47 -07005669 status = sme_set_ese_beacon_request(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005670 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005671 &eseBcnReq);
5672
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305673 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005674 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005675 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005676 ret = -EBUSY;
5677 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305678 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005679 hdd_err("sme_set_ese_beacon_request failed (%d)",
5680 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005681 ret = -EINVAL;
5682 goto exit;
5683 }
5684
5685exit:
5686 return ret;
5687}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005688
5689/**
5690 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5691 * @adapter: Pointer to the HDD adapter
5692 * @hdd_ctx: Pointer to the HDD context
5693 * @command: Driver command string
5694 * @command_len: Driver command string length
5695 * @priv_data: Private data coming with the driver command. Unused here
5696 *
5697 * This function handles driver command that sets the ESE PLM request
5698 *
5699 * Return: 0 on success; negative errno otherwise
5700 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005701static int drv_cmd_ccx_plm_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005702 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005703 uint8_t *command,
5704 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005705 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005706{
5707 int ret = 0;
5708 uint8_t *value = command;
5709 QDF_STATUS status = QDF_STATUS_SUCCESS;
5710 tpSirPlmReq pPlmRequest = NULL;
5711
5712 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5713 if (NULL == pPlmRequest) {
5714 ret = -ENOMEM;
5715 goto exit;
5716 }
5717
5718 status = hdd_parse_plm_cmd(value, pPlmRequest);
5719 if (QDF_STATUS_SUCCESS != status) {
5720 qdf_mem_free(pPlmRequest);
5721 pPlmRequest = NULL;
5722 ret = -EINVAL;
5723 goto exit;
5724 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07005725 pPlmRequest->sessionId = adapter->session_id;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005726
Jeff Johnsond549efa2018-06-13 20:27:47 -07005727 status = sme_set_plm_request(hdd_ctx->mac_handle, pPlmRequest);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005728 if (QDF_STATUS_SUCCESS != status) {
5729 qdf_mem_free(pPlmRequest);
5730 pPlmRequest = NULL;
5731 ret = -EINVAL;
5732 goto exit;
5733 }
5734
5735exit:
5736 return ret;
5737}
5738
5739/**
5740 * drv_cmd_set_ccx_mode() - Set ESE mode
5741 * @adapter: Pointer to the HDD adapter
5742 * @hdd_ctx: Pointer to the HDD context
5743 * @command: Driver command string
5744 * @command_len: Driver command string length
5745 * @priv_data: Private data coming with the driver command. Unused here
5746 *
5747 * This function handles driver command that sets ESE mode
5748 *
5749 * Return: 0 on success; negative errno otherwise
5750 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005751static int drv_cmd_set_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005752 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005753 uint8_t *command,
5754 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005755 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005756{
5757 int ret = 0;
5758 uint8_t *value = command;
5759 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005760 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005761 mac_handle_t mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005762
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005763 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005764 mac_handle = hdd_ctx->mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005765 /*
5766 * Check if the features OKC/ESE/11R are supported simultaneously,
5767 * then this operation is not permitted (return FAILURE)
5768 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005769 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005770 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07005771 sme_get_is_ft_feature_enabled(mac_handle)) {
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005772 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5773 ret = -EPERM;
5774 goto exit;
5775 }
5776
5777 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5778 value = value + command_len + 1;
5779
5780 /* Convert the value from ascii to integer */
5781 ret = kstrtou8(value, 10, &eseMode);
5782 if (ret < 0) {
5783 /*
5784 * If the input value is greater than max value of datatype,
5785 * then also kstrtou8 fails
5786 */
5787 hdd_err("kstrtou8 failed range [%d - %d]",
5788 CFG_ESE_FEATURE_ENABLED_MIN,
5789 CFG_ESE_FEATURE_ENABLED_MAX);
5790 ret = -EINVAL;
5791 goto exit;
5792 }
5793
5794 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5795 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5796 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5797 eseMode,
5798 CFG_ESE_FEATURE_ENABLED_MIN,
5799 CFG_ESE_FEATURE_ENABLED_MAX);
5800 ret = -EINVAL;
5801 goto exit;
5802 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005803 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005804
5805 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005806 sme_update_is_ese_feature_enabled(mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005807 adapter->session_id,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005808 eseMode);
5809
5810exit:
5811 return ret;
5812}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005813#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005814
Jeff Johnsone44b7012017-09-10 15:25:47 -07005815static int drv_cmd_set_mc_rate(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005816 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005817 uint8_t *command,
5818 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005819 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005820{
5821 int ret = 0;
5822 uint8_t *value = command;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005823 int target_rate = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005824
5825 /* input value is in units of hundred kbps */
5826
5827 /* Move pointer to ahead of SETMCRATE<delimiter> */
5828 value = value + command_len + 1;
5829
5830 /* Convert the value from ascii to integer, decimal base */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005831 ret = kstrtouint(value, 10, &target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005832
Jeff Johnsond549efa2018-06-13 20:27:47 -07005833 ret = wlan_hdd_set_mc_rate(adapter, target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005834 return ret;
5835}
5836
Jeff Johnsone44b7012017-09-10 15:25:47 -07005837static int drv_cmd_max_tx_power(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005838 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005839 uint8_t *command,
5840 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005841 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005842{
Jeff Johnsond549efa2018-06-13 20:27:47 -07005843 int ret;
5844 int tx_power;
5845 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005846 uint8_t *value = command;
Dustin Brownce5b3d32018-01-17 15:07:38 -08005847 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005848 struct qdf_mac_addr selfmac = QDF_MAC_ADDR_BCAST_INIT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005849
Jeff Johnsond549efa2018-06-13 20:27:47 -07005850 ret = hdd_parse_setmaxtxpower_command(value, &tx_power);
5851 if (ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005852 hdd_err("Invalid MAXTXPOWER command");
Jeff Johnsond549efa2018-06-13 20:27:47 -07005853 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005854 }
5855
Dustin Brown920397d2017-12-13 16:27:50 -08005856 hdd_for_each_adapter(hdd_ctx, adapter) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005857 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305858 qdf_copy_macaddr(&bssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005859 &adapter->mac_addr);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005860 qdf_copy_macaddr(&selfmac,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005861 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005862
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005863 hdd_debug("Device mode %d max tx power %d selfMac: "
Jeff Johnsond549efa2018-06-13 20:27:47 -07005864 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR,
5865 adapter->device_mode, tx_power,
5866 MAC_ADDR_ARRAY(selfmac.bytes),
5867 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005868
Jeff Johnsond549efa2018-06-13 20:27:47 -07005869 status = sme_set_max_tx_power(hdd_ctx->mac_handle,
5870 bssid, selfmac, tx_power);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305871 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005872 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005873 ret = -EINVAL;
5874 goto exit;
5875 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005876 hdd_debug("Set max tx power success");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005877 }
5878
5879exit:
5880 return ret;
5881}
5882
Jeff Johnsone44b7012017-09-10 15:25:47 -07005883static int drv_cmd_set_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005884 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005885 uint8_t *command,
5886 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005887 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005888{
5889 int ret = 0;
5890 uint8_t *value = command;
5891 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5892
5893 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5894 value = value + command_len + 1;
5895
5896 /* Convert the value from ascii to integer */
5897 ret = kstrtou8(value, 10, &dfsScanMode);
5898 if (ret < 0) {
5899 /*
5900 * If the input value is greater than max value of datatype,
5901 * then also kstrtou8 fails
5902 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005903 hdd_err("kstrtou8 failed range [%d - %d]",
5904 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005905 CFG_ROAMING_DFS_CHANNEL_MAX);
5906 ret = -EINVAL;
5907 goto exit;
5908 }
5909
5910 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5911 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005912 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005913 dfsScanMode,
5914 CFG_ROAMING_DFS_CHANNEL_MIN,
5915 CFG_ROAMING_DFS_CHANNEL_MAX);
5916 ret = -EINVAL;
5917 goto exit;
5918 }
5919
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005920 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005921 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005922
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005923 /* When DFS scanning is disabled, the DFS channels need to be
5924 * removed from the operation of device.
5925 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005926 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5927 dfsScanMode != CFG_ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005928 if (ret < 0) {
5929 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005930 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005931 goto exit;
5932 }
5933
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005934 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005935 sme_update_dfs_scan_mode(hdd_ctx->mac_handle, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005936 dfsScanMode);
5937
5938exit:
5939 return ret;
5940}
5941
Jeff Johnsone44b7012017-09-10 15:25:47 -07005942static int drv_cmd_get_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005943 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005944 uint8_t *command,
5945 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005946 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005947{
5948 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005949 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005950 char extra[32];
5951 uint8_t len = 0;
5952
5953 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305954 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005955 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005956 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005957 ret = -EFAULT;
5958 }
5959
5960 return ret;
5961}
5962
Jeff Johnsone44b7012017-09-10 15:25:47 -07005963static int drv_cmd_get_link_status(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005964 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005965 uint8_t *command,
5966 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005967 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005968{
5969 int ret = 0;
5970 int value = wlan_hdd_get_link_status(adapter);
5971 char extra[32];
5972 uint8_t len;
5973
5974 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305975 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005976 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005977 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005978 ret = -EFAULT;
5979 }
5980
5981 return ret;
5982}
5983
5984#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Jeff Johnsone44b7012017-09-10 15:25:47 -07005985static int drv_cmd_enable_ext_wow(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005986 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005987 uint8_t *command,
5988 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005989 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005990{
5991 uint8_t *value = command;
5992 int set_value;
5993
5994 /* Move pointer to ahead of ENABLEEXTWOW */
5995 value = value + command_len;
5996
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305997 if (!(sscanf(value, "%d", &set_value))) {
Dustin Browna2868622018-03-20 11:38:14 -07005998 hdd_info("No input identified");
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305999 return -EINVAL;
6000 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006001
6002 return hdd_enable_ext_wow_parser(adapter,
Jeff Johnson1b780e42017-10-31 14:11:45 -07006003 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006004 set_value);
6005}
6006
Jeff Johnsone44b7012017-09-10 15:25:47 -07006007static int drv_cmd_set_app1_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006008 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006009 uint8_t *command,
6010 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006011 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006012{
6013 int ret;
6014 uint8_t *value = command;
6015
6016 /* Move pointer to ahead of SETAPP1PARAMS */
6017 value = value + command_len;
6018
6019 ret = hdd_set_app_type1_parser(adapter,
6020 value, strlen(value));
6021 if (ret >= 0)
6022 hdd_ctx->is_extwow_app_type1_param_set = true;
6023
6024 return ret;
6025}
6026
Jeff Johnsone44b7012017-09-10 15:25:47 -07006027static int drv_cmd_set_app2_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006028 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006029 uint8_t *command,
6030 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006031 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006032{
6033 int ret;
6034 uint8_t *value = command;
6035
6036 /* Move pointer to ahead of SETAPP2PARAMS */
6037 value = value + command_len;
6038
6039 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
6040 if (ret >= 0)
6041 hdd_ctx->is_extwow_app_type2_param_set = true;
6042
6043 return ret;
6044}
6045#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
6046
6047#ifdef FEATURE_WLAN_TDLS
6048/**
6049 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
6050 * @adapter: Pointer to the HDD adapter
6051 * @hdd_ctx: Pointer to the HDD context
6052 * @command: Driver command string
6053 * @command_len: Driver command string length
6054 * @priv_data: Private data coming with the driver command. Unused here
6055 *
6056 * This function handles driver command that sets the secondary tdls off channel
6057 * offset
6058 *
6059 * Return: 0 on success; negative errno otherwise
6060 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006061static int drv_cmd_tdls_secondary_channel_offset(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006062 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006063 uint8_t *command,
6064 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006065 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006066{
6067 int ret;
6068 uint8_t *value = command;
6069 int set_value;
6070
6071 /* Move pointer to point the string */
6072 value += command_len;
6073
6074 ret = sscanf(value, "%d", &set_value);
6075 if (ret != 1)
6076 return -EINVAL;
6077
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006078 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006079
6080 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
6081
6082 return ret;
6083}
6084
6085/**
6086 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
6087 * @adapter: Pointer to the HDD adapter
6088 * @hdd_ctx: Pointer to the HDD context
6089 * @command: Driver command string
6090 * @command_len: Driver command string length
6091 * @priv_data: Private data coming with the driver command. Unused here
6092 *
6093 * This function handles driver command that sets tdls off channel mode
6094 *
6095 * Return: 0 on success; negative errno otherwise
6096 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006097static int drv_cmd_tdls_off_channel_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006098 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006099 uint8_t *command,
6100 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006101 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006102{
6103 int ret;
6104 uint8_t *value = command;
6105 int set_value;
6106
6107 /* Move pointer to point the string */
6108 value += command_len;
6109
6110 ret = sscanf(value, "%d", &set_value);
6111 if (ret != 1)
6112 return -EINVAL;
6113
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006114 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006115
6116 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
6117
6118 return ret;
6119}
6120
6121/**
6122 * drv_cmd_tdls_off_channel() - set tdls off channel number
6123 * @adapter: Pointer to the HDD adapter
6124 * @hdd_ctx: Pointer to the HDD context
6125 * @command: Driver command string
6126 * @command_len: Driver command string length
6127 * @priv_data: Private data coming with the driver command. Unused here
6128 *
6129 * This function handles driver command that sets tdls off channel number
6130 *
6131 * Return: 0 on success; negative errno otherwise
6132 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006133static int drv_cmd_tdls_off_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006134 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006135 uint8_t *command,
6136 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006137 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006138{
6139 int ret;
6140 uint8_t *value = command;
6141 int set_value;
6142
6143 /* Move pointer to point the string */
6144 value += command_len;
6145
6146 ret = sscanf(value, "%d", &set_value);
6147 if (ret != 1)
6148 return -EINVAL;
6149
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -07006150 if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, set_value)) {
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006151 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6152 set_value);
6153 return -EINVAL;
6154 }
6155
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006156 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006157
6158 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6159
6160 return ret;
6161}
6162
6163/**
6164 * drv_cmd_tdls_scan() - set tdls scan type
6165 * @adapter: Pointer to the HDD adapter
6166 * @hdd_ctx: Pointer to the HDD context
6167 * @command: Driver command string
6168 * @command_len: Driver command string length
6169 * @priv_data: Private data coming with the driver command. Unused here
6170 *
6171 * This function handles driver command that sets tdls scan type
6172 *
6173 * Return: 0 on success; negative errno otherwise
6174 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006175static int drv_cmd_tdls_scan(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006176 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006177 uint8_t *command,
6178 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006179 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006180{
6181 int ret;
6182 uint8_t *value = command;
6183 int set_value;
6184
6185 /* Move pointer to point the string */
6186 value += command_len;
6187
6188 ret = sscanf(value, "%d", &set_value);
6189 if (ret != 1)
6190 return -EINVAL;
6191
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006192 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006193
6194 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6195
6196 return ret;
6197}
6198#endif
6199
Jeff Johnsone44b7012017-09-10 15:25:47 -07006200static int drv_cmd_get_rssi(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006201 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006202 uint8_t *command,
6203 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006204 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006205{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006206 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006207 int8_t rssi = 0;
6208 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006209
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006210 uint8_t len = 0;
6211
6212 wlan_hdd_get_rssi(adapter, &rssi);
6213
6214 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306215 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006216
6217 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006218 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006219 ret = -EFAULT;
6220 }
6221
6222 return ret;
6223}
6224
Jeff Johnsone44b7012017-09-10 15:25:47 -07006225static int drv_cmd_get_linkspeed(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006226 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006227 uint8_t *command,
6228 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006229 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006230{
6231 int ret;
6232 uint32_t link_speed = 0;
6233 char extra[32];
6234 uint8_t len = 0;
6235
6236 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6237 if (0 != ret)
6238 return ret;
6239
6240 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306241 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006242 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006243 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006244 ret = -EFAULT;
6245 }
6246
6247 return ret;
6248}
6249
Qiwei Cai4505fc62018-05-17 18:35:19 +08006250#ifdef WLAN_FEATURE_PACKET_FILTERING
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006251/**
6252 * hdd_set_rx_filter() - set RX filter
6253 * @adapter: Pointer to adapter
6254 * @action: Filter action
6255 * @pattern: Address pattern
6256 *
6257 * Address pattern is most significant byte of address for example
6258 * 0x01 for IPV4 multicast address
6259 * 0x33 for IPV6 multicast address
6260 * 0xFF for broadcast address
6261 *
6262 * Return: 0 for success, non-zero for failure
6263 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006264static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006265 uint8_t pattern)
6266{
6267 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006268 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006269 tSirRcvFltMcAddrList *filter;
Jeff Johnson621cf972017-08-28 11:58:44 -07006270 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006271 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006272
6273 ret = wlan_hdd_validate_context(hdd_ctx);
6274 if (0 != ret)
6275 return ret;
6276
Jeff Johnsond549efa2018-06-13 20:27:47 -07006277 mac_handle = hdd_ctx->mac_handle;
6278 if (!mac_handle) {
6279 hdd_err("MAC Handle is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006280 return -EINVAL;
6281 }
6282
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306283 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006284 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306285 return -EINVAL;
6286 }
6287
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006288 /*
6289 * If action is false it means start dropping packets
6290 * Set addr_filter_pattern which will be used when sending
6291 * MC/BC address list to target
6292 */
6293 if (!action)
6294 adapter->addr_filter_pattern = pattern;
6295 else
6296 adapter->addr_filter_pattern = 0;
6297
Krunal Sonibe766b02016-03-10 13:00:44 -08006298 if (((adapter->device_mode == QDF_STA_MODE) ||
6299 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006300 adapter->mc_addr_list.mc_cnt &&
6301 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6302
6303
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306304 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006305 if (NULL == filter) {
6306 hdd_err("Could not allocate Memory");
6307 return -ENOMEM;
6308 }
6309 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006310 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006311 if (!memcmp(adapter->mc_addr_list.addr[i],
6312 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006313 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006314 adapter->mc_addr_list.addr[i],
6315 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006316
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006317 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006318 MAC_ADDRESS_STR,
6319 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006320 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6321 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006322 }
SaidiReddy Yenuga0b2c9f42017-02-03 12:26:38 +05306323 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
6324 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006325 }
Frank Liuf95e8132016-09-29 19:01:30 +08006326 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006327 /* Set rx filter */
Jeff Johnsond549efa2018-06-13 20:27:47 -07006328 sme_8023_multicast_list(mac_handle, adapter->session_id,
6329 filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306330 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006331 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006332 hdd_debug("mode %d mc_cnt %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07006333 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006334 }
6335
6336 return 0;
6337}
6338
6339/**
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006340 * hdd_driver_rxfilter_command_handler() - RXFILTER driver command handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006341 * @command: Pointer to input string driver command
6342 * @adapter: Pointer to adapter
6343 * @action: Action to enable/disable filtering
6344 *
6345 * If action == false
6346 * Start filtering out data packets based on type
6347 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6348 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6349 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6350 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6351 *
6352 * if action == true
6353 * Stop filtering data packets based on type
6354 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6355 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6356 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6357 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6358 *
6359 * Current implementation only supports IPV4 address filtering by
6360 * selectively allowing IPV4 multicast data packest based on
6361 * address list received in .ndo_set_rx_mode
6362 *
6363 * Return: 0 for success, non-zero for failure
6364 */
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006365static int hdd_driver_rxfilter_command_handler(uint8_t *command,
Jeff Johnsone44b7012017-09-10 15:25:47 -07006366 struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006367 bool action)
6368{
6369 int ret = 0;
6370 uint8_t *value;
6371 uint8_t type;
6372
6373 value = command;
6374 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6375 if (!action)
6376 value = command + 16;
6377 else
6378 value = command + 13;
6379 ret = kstrtou8(value, 10, &type);
6380 if (ret < 0) {
Dustin Brown933cd2a2018-04-18 11:28:15 -07006381 hdd_err("kstrtou8 failed invalid input value");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006382 return -EINVAL;
6383 }
6384
6385 switch (type) {
6386 case 2:
6387 /* Set rx filter for IPV4 multicast data packets */
6388 ret = hdd_set_rx_filter(adapter, action, 0x01);
6389 break;
6390 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006391 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006392 break;
6393 }
6394
6395 return ret;
6396}
6397
6398/**
6399 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6400 * @adapter: Pointer to network adapter
6401 * @hdd_ctx: Pointer to hdd context
6402 * @command: Pointer to input command
6403 * @command_len: Command length
6404 * @priv_data: Pointer to private data in command
6405 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006406static int drv_cmd_rx_filter_remove(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006407 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006408 uint8_t *command,
6409 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006410 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006411{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006412 return hdd_driver_rxfilter_command_handler(command, adapter, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006413}
6414
6415/**
6416 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6417 * @adapter: Pointer to network adapter
6418 * @hdd_ctx: Pointer to hdd context
6419 * @command: Pointer to input command
6420 * @command_len: Command length
6421 * @priv_data: Pointer to private data in command
6422 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006423static int drv_cmd_rx_filter_add(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006424 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006425 uint8_t *command,
6426 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006427 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006428{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006429 return hdd_driver_rxfilter_command_handler(command, adapter, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006430}
Qiwei Cai4505fc62018-05-17 18:35:19 +08006431#endif /* WLAN_FEATURE_PACKET_FILTERING */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006432
Archana Ramachandran393f3792015-11-13 17:13:21 -08006433/**
6434 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6435 * command
6436 * @value: Pointer to SETANTENNAMODE command
6437 * @mode: Pointer to antenna mode
6438 * @reason: Pointer to reason for set antenna mode
6439 *
6440 * This function parses the SETANTENNAMODE command passed in the format
6441 * SETANTENNAMODE<space>mode
6442 *
6443 * Return: 0 for success non-zero for failure
6444 */
6445static int hdd_parse_setantennamode_command(const uint8_t *value)
6446{
6447 const uint8_t *in_ptr = value;
6448 int tmp, v;
6449 char arg1[32];
6450
6451 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6452
6453 /* no argument after the command */
6454 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006455 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006456 return -EINVAL;
6457 }
6458
6459 /* no space after the command */
6460 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006461 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006462 return -EINVAL;
6463 }
6464
6465 /* remove empty spaces */
6466 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6467 in_ptr++;
6468
6469 /* no argument followed by spaces */
6470 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006471 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006472 return -EINVAL;
6473 }
6474
6475 /* get the argument i.e. antenna mode */
6476 v = sscanf(in_ptr, "%31s ", arg1);
6477 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006478 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006479 return -EINVAL;
6480 }
6481
6482 v = kstrtos32(arg1, 10, &tmp);
6483 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006484 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006485 return -EINVAL;
6486 }
6487
6488 return tmp;
6489}
6490
6491/**
6492 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6493 * mask is 2x2 mode
6494 * @hdd_ctx: Pointer to hdd contex
6495 *
6496 * Return: true if supported chain mask 2x2 else false
6497 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006498static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006499{
6500 /*
6501 * Revisit and the update logic to determine the number
6502 * of TX/RX chains supported in the system when
6503 * antenna sharing per band chain mask support is
6504 * brought in
6505 */
6506 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6507}
6508
6509/**
6510 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6511 * chain mask is 1x1
6512 * @hdd_ctx: Pointer to hdd contex
6513 *
6514 * Return: true if supported chain mask 1x1 else false
6515 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006516static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006517{
6518 /*
6519 * Revisit and update the logic to determine the number
6520 * of TX/RX chains supported in the system when
6521 * antenna sharing per band chain mask support is
6522 * brought in
6523 */
6524 return (!hdd_ctx->config->enable2x2) ? true : false;
6525}
6526
Jeff Johnson621cf972017-08-28 11:58:44 -07006527QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
Nitesh Shahe50711f2017-04-26 16:30:45 +05306528{
6529 QDF_STATUS status;
6530 uint8_t smps_mode;
6531 uint8_t smps_enable;
Jeff Johnsond549efa2018-06-13 20:27:47 -07006532 mac_handle_t mac_handle;
Nitesh Shahe50711f2017-04-26 16:30:45 +05306533
6534 /* Update SME SMPS config */
6535 if (HDD_ANTENNA_MODE_1X1 == mode) {
6536 smps_enable = true;
6537 smps_mode = HDD_SMPS_MODE_STATIC;
6538 } else {
6539 smps_enable = false;
6540 smps_mode = HDD_SMPS_MODE_DISABLED;
6541 }
6542
6543 hdd_debug("Update SME SMPS enable: %d mode: %d",
6544 smps_enable, smps_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006545 mac_handle = hdd_ctx->mac_handle;
6546 status = sme_update_mimo_power_save(mac_handle, smps_enable,
6547 smps_mode, false);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306548 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07006549 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
Nitesh Shahe50711f2017-04-26 16:30:45 +05306550 smps_enable, smps_mode, status);
6551 return QDF_STATUS_E_FAILURE;
6552 }
6553
6554 hdd_ctx->current_antenna_mode = mode;
6555 /*
6556 * Update the user requested nss in the mac context.
6557 * This will be used in tdls protocol engine to form tdls
6558 * Management frames.
6559 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07006560 sme_update_user_configured_nss(mac_handle,
6561 hdd_ctx->current_antenna_mode);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306562
6563 hdd_debug("Successfully switched to mode: %d x %d",
6564 hdd_ctx->current_antenna_mode,
6565 hdd_ctx->current_antenna_mode);
6566
6567 return QDF_STATUS_SUCCESS;
6568}
6569
Dundi Raviteja4016e932018-08-02 12:16:25 +05306570/**
6571 * wlan_hdd_soc_set_antenna_mode_cb() - Callback for set antenna mode
6572 * @status: Status of set antenna mode
6573 * @context: callback context
6574 *
6575 * Callback on setting antenna mode
6576 *
6577 * Return: None
6578 */
6579static void
6580wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status,
6581 void *context)
6582{
6583 struct osif_request *request = NULL;
6584
6585 hdd_debug("Status: %d", status);
6586
6587 request = osif_request_get(context);
6588 if (!request) {
6589 hdd_err("obselete request");
6590 return;
6591 }
6592
6593 /* Signal the completion of set dual mac config */
6594 osif_request_complete(request);
6595 osif_request_put(request);
6596}
6597
Abhishek Singh1571ca72018-04-17 15:14:21 +05306598int hdd_set_antenna_mode(struct hdd_adapter *adapter,
6599 struct hdd_context *hdd_ctx, int mode)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006600{
Abhishek Singh1571ca72018-04-17 15:14:21 +05306601
Archana Ramachandran393f3792015-11-13 17:13:21 -08006602 struct sir_antenna_mode_param params;
6603 QDF_STATUS status;
6604 int ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306605 struct osif_request *request = NULL;
6606 static const struct osif_request_params request_params = {
6607 .priv_size = 0,
6608 .timeout_ms = WLAN_WAIT_TIME_ANTENNA_MODE_REQ,
6609 };
Archana Ramachandran393f3792015-11-13 17:13:21 -08006610
6611 if (hdd_ctx->current_antenna_mode == mode) {
6612 hdd_err("System already in the requested mode");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006613 goto exit;
6614 }
6615
6616 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6617 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6618 hdd_err("System does not support 2x2 mode");
6619 ret = -EPERM;
6620 goto exit;
6621 }
6622
6623 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6624 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6625 hdd_err("System only supports 1x1 mode");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006626 goto exit;
6627 }
6628
6629 switch (mode) {
6630 case HDD_ANTENNA_MODE_1X1:
6631 params.num_rx_chains = 1;
6632 params.num_tx_chains = 1;
6633 break;
6634 case HDD_ANTENNA_MODE_2X2:
6635 params.num_rx_chains = 2;
6636 params.num_tx_chains = 2;
6637 break;
6638 default:
6639 hdd_err("unsupported antenna mode");
6640 ret = -EINVAL;
6641 goto exit;
6642 }
6643
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006644 /* Check TDLS status and update antenna mode */
6645 if ((QDF_STA_MODE == adapter->device_mode) &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07006646 policy_mgr_is_sta_active_connection_exists(hdd_ctx->hdd_psoc)) {
6647 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter, mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006648 if (0 != ret)
6649 goto exit;
6650 }
6651
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306652 request = osif_request_alloc(&request_params);
6653 if (!request) {
6654 hdd_err("Request Allocation Failure");
6655 ret = -ENOMEM;
6656 goto exit;
6657 }
6658
6659 params.set_antenna_mode_ctx = osif_request_cookie(request);
6660 params.set_antenna_mode_resp = (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006661 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006662 params.num_rx_chains,
6663 params.num_tx_chains);
6664
Jeff Johnsond549efa2018-06-13 20:27:47 -07006665 status = sme_soc_set_antenna_mode(hdd_ctx->mac_handle, &params);
Abhishek Singh1571ca72018-04-17 15:14:21 +05306666 if (QDF_IS_STATUS_ERROR(status)) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006667 hdd_err("set antenna mode failed status : %d", status);
6668 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306669 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006670 }
6671
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306672 ret = osif_request_wait_for_response(request);
6673 if (ret) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006674 hdd_err("send set antenna mode timed out");
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306675 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006676 }
6677
Nitesh Shahe50711f2017-04-26 16:30:45 +05306678 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006679 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006680 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306681 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006682 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006683 ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306684request_put:
6685 osif_request_put(request);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006686exit:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006687 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006688 ret, hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006689
Abhishek Singh1571ca72018-04-17 15:14:21 +05306690 return ret;
6691}
6692/**
6693 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6694 * handler
6695 * @adapter: Pointer to network adapter
6696 * @hdd_ctx: Pointer to hdd context
6697 * @command: Pointer to input command
6698 * @command_len: Command length
6699 * @priv_data: Pointer to private data in command
6700 */
6701static int drv_cmd_set_antenna_mode(struct hdd_adapter *adapter,
6702 struct hdd_context *hdd_ctx,
6703 uint8_t *command,
6704 uint8_t command_len,
6705 struct hdd_priv_data *priv_data)
6706{
6707 int mode;
6708 uint8_t *value = command;
6709
6710 mode = hdd_parse_setantennamode_command(value);
6711 if (mode < 0) {
6712 hdd_err("Invalid SETANTENNA command");
6713 return mode;
6714 }
6715
6716 hdd_debug("Processing antenna mode switch to: %d", mode);
6717
6718 return hdd_set_antenna_mode(adapter, hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006719}
6720
6721/**
6722 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6723 * handler
6724 * @adapter: Pointer to hdd adapter
6725 * @hdd_ctx: Pointer to hdd context
6726 * @command: Pointer to input command
6727 * @command_len: length of the command
6728 * @priv_data: private data coming with the driver command
6729 *
6730 * Return: 0 for success non-zero for failure
6731 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006732static inline int drv_cmd_get_antenna_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006733 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006734 uint8_t *command,
6735 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006736 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006737{
6738 uint32_t antenna_mode = 0;
6739 char extra[32];
6740 uint8_t len = 0;
6741
6742 antenna_mode = hdd_ctx->current_antenna_mode;
6743 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6744 antenna_mode);
6745 len = QDF_MIN(priv_data->total_len, len + 1);
6746 if (copy_to_user(priv_data->buf, &extra, len)) {
6747 hdd_err("Failed to copy data to user buffer");
6748 return -EFAULT;
6749 }
6750
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006751 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006752
6753 return 0;
6754}
6755
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006756/*
6757 * dummy (no-op) hdd driver command handler
6758 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006759static int drv_cmd_dummy(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006760 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006761 uint8_t *command,
6762 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006763 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006764{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006765 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006766 adapter->dev->name, command);
6767 return 0;
6768}
6769
6770/*
6771 * handler for any unsupported wlan hdd driver command
6772 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006773static int drv_cmd_invalid(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006774 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006775 uint8_t *command,
6776 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006777 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006778{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306779 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006780 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07006781 adapter->session_id, 0));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006782
6783 hdd_warn("%s: Unsupported driver command \"%s\"",
6784 adapter->dev->name, command);
6785
6786 return -ENOTSUPP;
6787}
6788
6789/**
6790 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6791 * @adapter: HDD adapter
6792 * @hdd_ctx: HDD context
6793 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6794 * @command_len: command len
6795 * @priv_data: private data
6796 *
6797 * Return: status
6798 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006799static int drv_cmd_set_fcc_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006800 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006801 uint8_t *command,
6802 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006803 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006804{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306805 QDF_STATUS status;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006806 uint8_t fcc_constraint;
6807 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006808
6809 /*
6810 * this command would be called by user-space when it detects WLAN
6811 * ON after airplane mode is set. When APM is set, WLAN turns off.
6812 * But it can be turned back on. Otherwise; when APM is turned back
6813 * off, WLAN would turn back on. So at that point the command is
6814 * expected to come down. 0 means disable, 1 means enable. The
6815 * constraint is removed when parameter 1 is set or different
6816 * country code is set
6817 */
6818
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006819 err = kstrtou8(command + command_len + 1, 10, &fcc_constraint);
6820 if (err) {
6821 hdd_err("error %d parsing userspace fcc parameter", err);
6822 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006823 }
6824
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006825 status = ucfg_reg_set_fcc_constraint(hdd_ctx->hdd_pdev,
6826 fcc_constraint);
6827
6828 if (QDF_IS_STATUS_ERROR(status))
6829 hdd_err("Failed to %s tx power for channels 12/13",
6830 fcc_constraint ? "reduce" : "restore");
6831
6832 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006833}
6834
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306835/**
6836 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6837 * command
6838 * @value: Pointer to the command
6839 * @chan_number: Pointer to the channel number
6840 * @chan_bw: Pointer to the channel bandwidth
6841 *
6842 * Parses and provides the channel number and channel width from the input
6843 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6844 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6845 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6846 *
6847 * Return: 0 for success, non-zero for failure
6848 */
6849static int hdd_parse_set_channel_switch_command(uint8_t *value,
6850 uint32_t *chan_number,
6851 uint32_t *chan_bw)
6852{
6853 const uint8_t *in_ptr = value;
6854 int ret;
6855
6856 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6857
6858 /* no argument after the command */
6859 if (NULL == in_ptr) {
6860 hdd_err("No argument after the command");
6861 return -EINVAL;
6862 }
6863
6864 /* no space after the command */
6865 if (SPACE_ASCII_VALUE != *in_ptr) {
6866 hdd_err("No space after the command ");
6867 return -EINVAL;
6868 }
6869
6870 /* remove empty spaces and move the next argument */
6871 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6872 in_ptr++;
6873
6874 /* no argument followed by spaces */
6875 if ('\0' == *in_ptr) {
6876 hdd_err("No argument followed by spaces");
6877 return -EINVAL;
6878 }
6879
6880 /* get the two arguments: channel number and bandwidth */
6881 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6882 if (ret != 2) {
6883 hdd_err("Arguments retrieval from cmd string failed");
6884 return -EINVAL;
6885 }
6886
6887 return 0;
6888}
6889
6890/**
6891 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6892 * @adapter: HDD adapter
6893 * @hdd_ctx: HDD context
6894 * @command: Pointer to the input command CHANNEL_SWITCH
6895 * @command_len: Command len
6896 * @priv_data: Private data
6897 *
6898 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6899 * of SAP/P2P-GO
6900 *
6901 * Return: 0 for success, non-zero for failure
6902 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006903static int drv_cmd_set_channel_switch(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006904 struct hdd_context *hdd_ctx,
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306905 uint8_t *command,
6906 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006907 struct hdd_priv_data *priv_data)
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306908{
6909 struct net_device *dev = adapter->dev;
6910 int status;
6911 uint32_t chan_number = 0, chan_bw = 0;
6912 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006913 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306914
Krunal Sonibe766b02016-03-10 13:00:44 -08006915 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6916 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306917 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6918 adapter->device_mode);
6919 return -EINVAL;
6920 }
6921
6922 status = hdd_parse_set_channel_switch_command(value,
6923 &chan_number, &chan_bw);
6924 if (status) {
6925 hdd_err("Invalid CHANNEL_SWITCH command");
6926 return status;
6927 }
6928
6929 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6930 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6931 return -EINVAL;
6932 }
6933
6934 if (chan_bw == 80)
6935 width = CH_WIDTH_80MHZ;
6936 else if (chan_bw == 40)
6937 width = CH_WIDTH_40MHZ;
6938 else
6939 width = CH_WIDTH_20MHZ;
6940
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006941 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306942
Wu Gao9daee1a2018-05-22 14:49:59 +08006943 status = hdd_softap_set_channel_change(dev, chan_number, width, true);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306944 if (status) {
6945 hdd_err("Set channel change fail");
6946 return status;
6947 }
6948
6949 return 0;
6950}
6951
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05306952#ifdef DISABLE_CHANNEL_LIST
6953void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
6954{
6955 hdd_enter();
6956
6957 if (!hdd_ctx->original_channels)
6958 return;
6959
6960 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
6961 hdd_ctx->original_channels->num_channels = 0;
6962 if (hdd_ctx->original_channels->channel_info) {
6963 qdf_mem_free(hdd_ctx->original_channels->channel_info);
6964 hdd_ctx->original_channels->channel_info = NULL;
6965 }
6966 qdf_mem_free(hdd_ctx->original_channels);
6967 hdd_ctx->original_channels = NULL;
6968 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
6969
6970 hdd_exit();
6971}
6972
6973/**
6974 * hdd_alloc_chan_cache() - Allocate the memory to cache the channel
6975 * info for the channels received in command SET_DISABLE_CHANNEL_LIST
6976 * @hdd_ctx: Pointer to HDD context
6977 * @num_chan: Number of channels for which memory needs to
6978 * be allocated
6979 *
6980 * Return: 0 on success and error code on failure
6981 */
6982static int hdd_alloc_chan_cache(struct hdd_context *hdd_ctx, int num_chan)
6983{
6984 hdd_ctx->original_channels =
6985 qdf_mem_malloc(sizeof(struct hdd_cache_channels));
6986 if (!hdd_ctx->original_channels) {
6987 hdd_err("QDF_MALLOC_ERR");
6988 return -ENOMEM;
6989 }
6990 hdd_ctx->original_channels->num_channels = num_chan;
6991 hdd_ctx->original_channels->channel_info =
6992 qdf_mem_malloc(num_chan *
6993 sizeof(struct hdd_cache_channel_info));
6994 if (!hdd_ctx->original_channels->channel_info) {
6995 hdd_err("QDF_MALLOC_ERR");
6996 hdd_ctx->original_channels->num_channels = 0;
6997 qdf_mem_free(hdd_ctx->original_channels);
6998 hdd_ctx->original_channels = NULL;
6999 return -ENOMEM;
7000 }
7001 return 0;
7002}
7003
7004/**
7005 * hdd_parse_disable_chan_cmd() - Parse the channel list received
7006 * in command.
7007 * @adapter: pointer to hdd adapter
7008 * @ptr: Pointer to the command string
7009 *
7010 * This function parses the channel list received in the command.
7011 * command should be a string having format
7012 * SET_DISABLE_CHANNEL_LIST <num of channels>
7013 * <channels separated by spaces>.
7014 * If the command comes multiple times than this function will compare
7015 * the channels received in the command with the channles cached in the
7016 * first command, if the channel list matches with the cached channles,
7017 * it returns success otherwise returns failure.
7018 *
7019 * Return: 0 on success, Error code on failure
7020 */
7021
7022static int hdd_parse_disable_chan_cmd(struct hdd_adapter *adapter, uint8_t *ptr)
7023{
7024 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7025 uint8_t *param;
7026 int j, i, temp_int, ret = 0, num_channels;
7027 uint32_t parsed_channels[MAX_CHANNEL];
7028 bool is_command_repeated = false;
7029
7030 if (NULL == hdd_ctx) {
7031 hdd_err("HDD Context is NULL");
7032 return -EINVAL;
7033 }
7034
7035 param = strnchr(ptr, strlen(ptr), ' ');
7036 /*no argument after the command*/
7037 if (NULL == param)
7038 return -EINVAL;
7039
7040 /*no space after the command*/
7041 else if (SPACE_ASCII_VALUE != *param)
7042 return -EINVAL;
7043
7044 param++;
7045
7046 /*removing empty spaces*/
7047 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7048 param++;
7049
7050 /*no argument followed by spaces*/
7051 if ('\0' == *param)
7052 return -EINVAL;
7053
7054 /*getting the first argument ie the number of channels*/
7055 if (sscanf(param, "%d ", &temp_int) != 1) {
7056 hdd_err("Cannot get number of channels from input");
7057 return -EINVAL;
7058 }
7059
7060 if (temp_int < 0 || temp_int > MAX_CHANNEL) {
7061 hdd_err("Invalid Number of channel received");
7062 return -EINVAL;
7063 }
7064
7065 hdd_debug("Number of channel to disable are: %d", temp_int);
7066
7067 if (!temp_int) {
7068 if (!wlan_hdd_restore_channels(hdd_ctx, false)) {
7069 /*
7070 * Free the cache channels only when the command is
7071 * received with num channels as 0
7072 */
7073 wlan_hdd_free_cache_channels(hdd_ctx);
7074 }
7075 return 0;
7076 }
7077
7078 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7079
7080 if (!hdd_ctx->original_channels) {
7081 if (hdd_alloc_chan_cache(hdd_ctx, temp_int)) {
7082 ret = -ENOMEM;
7083 goto mem_alloc_failed;
7084 }
7085 } else if (hdd_ctx->original_channels->num_channels != temp_int) {
7086 hdd_err("Invalid Number of channels");
7087 ret = -EINVAL;
7088 is_command_repeated = true;
7089 goto parse_failed;
7090 } else {
7091 is_command_repeated = true;
7092 }
7093 num_channels = temp_int;
7094 for (j = 0; j < num_channels; j++) {
7095 /*
7096 * param pointing to the beginning of first space
7097 * after number of channels
7098 */
7099 param = strpbrk(param, " ");
7100 /*no channel list after the number of channels argument*/
7101 if (NULL == param) {
7102 hdd_err("Invalid No of channel provided in the list");
7103 ret = -EINVAL;
7104 goto parse_failed;
7105 }
7106
7107 param++;
7108
7109 /*removing empty space*/
7110 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7111 param++;
7112
7113 if ('\0' == *param) {
7114 hdd_err("No channel is provided in the list");
7115 ret = -EINVAL;
7116 goto parse_failed;
7117 }
7118
7119 if (sscanf(param, "%d ", &temp_int) != 1) {
7120 hdd_err("Cannot read channel number");
7121 ret = -EINVAL;
7122 goto parse_failed;
7123 }
7124
7125 if (!IS_CHANNEL_VALID(temp_int)) {
7126 hdd_err("Invalid channel number received");
7127 ret = -EINVAL;
7128 goto parse_failed;
7129 }
7130
7131 hdd_debug("channel[%d] = %d", j, temp_int);
7132 parsed_channels[j] = temp_int;
7133 }
7134
7135 /*extra arguments check*/
7136 param = strpbrk(param, " ");
7137 if (NULL != param) {
7138 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7139 param++;
7140
7141 if ('\0' != *param) {
7142 hdd_err("Invalid argument received");
7143 ret = -EINVAL;
7144 goto parse_failed;
7145 }
7146 }
7147
7148 /*
7149 * If command is received first time, cache the channels to
7150 * be disabled else compare the channels received in the
7151 * command with the cached channels, if channel list matches
7152 * return success otherewise return failure.
7153 */
7154 if (!is_command_repeated) {
7155 for (j = 0; j < num_channels; j++)
7156 hdd_ctx->original_channels->
7157 channel_info[j].channel_num =
7158 parsed_channels[j];
Dustin Brown3f0d7102018-08-02 12:01:52 -07007159
7160 /* Cache the channel list in regulatory also */
7161 ucfg_reg_cache_channel_state(hdd_ctx->hdd_pdev, parsed_channels,
7162 num_channels);
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307163 } else {
7164 for (i = 0; i < num_channels; i++) {
7165 for (j = 0; j < num_channels; j++)
7166 if (hdd_ctx->original_channels->
7167 channel_info[i].channel_num ==
7168 parsed_channels[j])
7169 break;
7170 if (j == num_channels) {
7171 ret = -EINVAL;
7172 goto parse_failed;
7173 }
7174 }
7175 ret = 0;
7176 }
7177mem_alloc_failed:
7178
7179 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7180 hdd_exit();
7181
7182 return ret;
7183
7184parse_failed:
7185 if (!is_command_repeated)
7186 wlan_hdd_free_cache_channels(hdd_ctx);
7187 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7188 hdd_exit();
7189
7190 return ret;
7191}
7192
7193static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7194 struct hdd_context *hdd_ctx,
7195 uint8_t *command,
7196 uint8_t command_len,
7197 struct hdd_priv_data *priv_data)
7198{
7199 return hdd_parse_disable_chan_cmd(adapter, command);
7200}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307201
7202/**
7203 * hdd_get_disable_ch_list() - get disable channel list
7204 * @hdd_ctx: hdd context
7205 * @buf: buffer to hold disable channel list
7206 * @buf_len: buffer length
7207 *
7208 * Return: length of data copied to buf
7209 */
7210static int hdd_get_disable_ch_list(struct hdd_context *hdd_ctx, uint8_t *buf,
7211 uint32_t buf_len)
7212{
7213 struct hdd_cache_channel_info *ch_list;
7214 unsigned char i, num_ch;
7215 int len = 0;
7216
7217 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7218 if (hdd_ctx->original_channels &&
7219 hdd_ctx->original_channels->num_channels &&
7220 hdd_ctx->original_channels->channel_info) {
7221 num_ch = hdd_ctx->original_channels->num_channels;
7222
7223 len = scnprintf(buf, buf_len, "%s %hhu",
7224 "GET_DISABLE_CHANNEL_LIST", num_ch);
7225 ch_list = hdd_ctx->original_channels->channel_info;
7226 for (i = 0; (i < num_ch) && (len < buf_len - 1); i++) {
7227 len += scnprintf(buf + len, buf_len - len,
7228 " %d", ch_list[i].channel_num);
7229 }
7230 }
7231 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7232
7233 return len;
7234}
7235
7236static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7237 struct hdd_context *hdd_ctx,
7238 uint8_t *command,
7239 uint8_t command_len,
7240 struct hdd_priv_data *priv_data)
7241{
7242 char extra[512] = {0};
7243 int max_len, copied_length;
7244
7245 hdd_debug("Received Command to get disable Channels list");
7246
7247 max_len = QDF_MIN(priv_data->total_len, sizeof(extra));
7248 copied_length = hdd_get_disable_ch_list(hdd_ctx, extra, max_len);
7249 if (copied_length == 0) {
7250 hdd_err("disable channel list is not yet programmed");
7251 return -EINVAL;
7252 }
7253
7254 if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
7255 hdd_err("failed to copy data to user buffer");
7256 return -EFAULT;
7257 }
7258
7259 hdd_debug("data:%s", extra);
7260 return 0;
7261}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307262#else
7263
7264static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7265 struct hdd_context *hdd_ctx,
7266 uint8_t *command,
7267 uint8_t command_len,
7268 struct hdd_priv_data *priv_data)
7269{
7270 return 0;
7271}
7272
7273void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7274{
7275}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307276
7277static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7278 struct hdd_context *hdd_ctx,
7279 uint8_t *command,
7280 uint8_t command_len,
7281 struct hdd_priv_data *priv_data)
7282{
7283 return 0;
7284}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307285#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007286/*
7287 * The following table contains all supported WLAN HDD
7288 * IOCTL driver commands and the handler for each of them.
7289 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07007290static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307291 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false},
7292 {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true},
7293 {"P2P_SET_PS", drv_cmd_p2p_set_ps, true},
7294 {"SETBAND", drv_cmd_set_band, true},
7295 {"SETWMMPS", drv_cmd_set_wmmps, true},
7296 {"COUNTRY", drv_cmd_country, true},
7297 {"SETSUSPENDMODE", drv_cmd_dummy, false},
7298 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307299 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true},
7300 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false},
7301 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true},
7302 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false},
7303 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period,
7304 true},
7305 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period,
7306 false},
7307 {"SETROAMMODE", drv_cmd_set_roam_mode, true},
7308 {"GETROAMMODE", drv_cmd_get_roam_mode, false},
7309 {"SETROAMDELTA", drv_cmd_set_roam_delta, true},
7310 {"GETROAMDELTA", drv_cmd_get_roam_delta, false},
7311 {"GETBAND", drv_cmd_get_band, false},
7312 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels, true},
7313 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels, false},
7314 {"GETCCXMODE", drv_cmd_get_ccx_mode, false},
7315 {"GETOKCMODE", drv_cmd_get_okc_mode, false},
7316 {"GETFASTROAM", drv_cmd_get_fast_roam, false},
7317 {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false},
7318 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
7319 true},
7320 {"SENDACTIONFRAME", drv_cmd_send_action_frame, true},
7321 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
7322 false},
7323 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true},
7324 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false},
7325 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true},
7326 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false},
7327 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true},
7328 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false},
7329 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true},
7330 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false},
7331 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true},
7332 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false},
7333 {"REASSOC", drv_cmd_reassoc, true},
7334 {"SETWESMODE", drv_cmd_set_wes_mode, true},
7335 {"GETWESMODE", drv_cmd_get_wes_mode, false},
7336 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff,
7337 true},
7338 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff,
7339 false},
7340 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true},
7341 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false},
7342 {"SETFASTROAM", drv_cmd_set_fast_roam, true},
7343 {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true},
7344 {"FASTREASSOC", drv_cmd_fast_reassoc, true},
7345 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control, true},
7346 {"SETOKCMODE", drv_cmd_set_okc_mode, true},
7347 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control, false},
7348 {"BTCOEXMODE", drv_cmd_bt_coex_mode, true},
7349 {"SCAN-ACTIVE", drv_cmd_scan_active, false},
7350 {"SCAN-PASSIVE", drv_cmd_scan_passive, false},
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05307351#ifdef WLAN_AP_STA_CONCURRENCY
7352 {"CONCSETDWELLTIME", drv_cmd_conc_set_dwell_time, true},
7353#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307354 {"GETDWELLTIME", drv_cmd_get_dwell_time, false},
7355 {"SETDWELLTIME", drv_cmd_set_dwell_time, true},
7356 {"MIRACAST", drv_cmd_miracast, true},
7357 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05307358#ifdef FEATURE_WLAN_RMC
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307359 {"SETRMCENABLE", drv_cmd_set_rmc_enable, true},
7360 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05307361 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate, true},
7362#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307363 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all, false},
7364 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307365 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007366#ifdef FEATURE_WLAN_ESE
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307367 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true},
7368 {"GETTSMSTATS", drv_cmd_get_tsm_stats, true},
7369 {"SETCCKMIE", drv_cmd_set_cckm_ie, true},
7370 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true},
7371 {"CCXPLMREQ", drv_cmd_ccx_plm_req, true},
7372 {"SETCCXMODE", drv_cmd_set_ccx_mode, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007373#endif /* FEATURE_WLAN_ESE */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307374 {"SETMCRATE", drv_cmd_set_mc_rate, true},
7375 {"MAXTXPOWER", drv_cmd_max_tx_power, true},
7376 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true},
7377 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false},
7378 {"GETLINKSTATUS", drv_cmd_get_link_status, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007379#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307380 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true},
7381 {"SETAPP1PARAMS", drv_cmd_set_app1_params, true},
7382 {"SETAPP2PARAMS", drv_cmd_set_app2_params, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007383#endif
7384#ifdef FEATURE_WLAN_TDLS
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307385 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
7386 true},
7387 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true},
7388 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true},
7389 {"TDLSSCAN", drv_cmd_tdls_scan, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007390#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307391 {"RSSI", drv_cmd_get_rssi, false},
7392 {"LINKSPEED", drv_cmd_get_linkspeed, false},
Qiwei Cai4505fc62018-05-17 18:35:19 +08007393#ifdef WLAN_FEATURE_PACKET_FILTERING
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307394 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true},
7395 {"RXFILTER-ADD", drv_cmd_rx_filter_add, true},
Qiwei Cai4505fc62018-05-17 18:35:19 +08007396#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307397 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true},
7398 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true},
7399 {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true},
7400 {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false},
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307401 {"SET_DISABLE_CHANNEL_LIST", drv_cmd_set_disable_chan_list, true},
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307402 {"GET_DISABLE_CHANNEL_LIST", drv_cmd_get_disable_chan_list, false},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307403 {"STOP", drv_cmd_dummy, false},
Srinivas Girigowda836475e2018-04-17 14:42:23 -07007404 /* Deprecated commands */
7405 {"RXFILTER-START", drv_cmd_dummy, false},
7406 {"RXFILTER-STOP", drv_cmd_dummy, false},
7407 {"BTCOEXSCAN-START", drv_cmd_dummy, false},
7408 {"BTCOEXSCAN-STOP", drv_cmd_dummy, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007409};
7410
7411/**
7412 * hdd_drv_cmd_process() - chooses and runs the proper
7413 * handler based on the input command
7414 * @adapter: Pointer to the hdd adapter
7415 * @cmd: Pointer to the driver command
7416 * @priv_data: Pointer to the data associated with the command
7417 *
7418 * This function parses the input hdd driver command and runs
7419 * the proper handler
7420 *
7421 * Return: 0 for success non-zero for failure
7422 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007423static int hdd_drv_cmd_process(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007424 uint8_t *cmd,
Jeff Johnson353cd292017-08-17 06:47:26 -07007425 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007426{
Jeff Johnson621cf972017-08-28 11:58:44 -07007427 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007428 int i;
7429 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7430 uint8_t *cmd_i = NULL;
7431 hdd_drv_cmd_handler_t handler = NULL;
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307432 int len = 0, cmd_len = 0;
7433 uint8_t *ptr;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307434 bool args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007435
7436 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007437 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007438 return -EINVAL;
7439 }
7440
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307441 /* Calculate length of the first word */
7442 ptr = strchrnul(cmd, ' ');
7443 cmd_len = ptr - cmd;
7444
Jeff Johnson399c6272017-08-30 10:51:00 -07007445 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007446
7447 for (i = 0; i < cmd_num_total; i++) {
7448
7449 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7450 handler = hdd_drv_cmds[i].handler;
7451 len = strlen(cmd_i);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307452 args = hdd_drv_cmds[i].args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007453
7454 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007455 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007456 return -EINVAL;
7457 }
7458
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307459 if (len == cmd_len && strncasecmp(cmd, cmd_i, len) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307460 if (args && drv_cmd_validate(cmd, len))
7461 return -EINVAL;
7462
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007463 return handler(adapter, hdd_ctx,
7464 cmd, len, priv_data);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307465 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007466 }
7467
7468 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7469}
7470
7471/**
7472 * hdd_driver_command() - top level wlan hdd driver command handler
7473 * @adapter: Pointer to the hdd adapter
7474 * @priv_data: Pointer to the raw command data
7475 *
7476 * This function is the top level wlan hdd driver command handler. It
7477 * handles the command with the help of hdd_drv_cmd_process()
7478 *
7479 * Return: 0 for success non-zero for failure
7480 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007481static int hdd_driver_command(struct hdd_adapter *adapter,
Jeff Johnson353cd292017-08-17 06:47:26 -07007482 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007483{
7484 uint8_t *command = NULL;
7485 int ret = 0;
Jeff Johnson621cf972017-08-28 11:58:44 -07007486 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007487
Dustin Brown491d54b2018-03-14 12:39:11 -07007488 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307489
Anurag Chouhan6d760662016-02-20 16:05:43 +05307490 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007491 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007492 return -EINVAL;
7493 }
7494
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05307495 ret = wlan_hdd_validate_context(hdd_ctx);
7496 if (ret)
7497 return ret;
7498
7499 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
7500 hdd_err("Driver module is closed; command can not be processed");
7501 return -EINVAL;
7502 }
7503
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007504 /*
7505 * Note that valid pointers are provided by caller
7506 */
7507
7508 /* copy to local struct to avoid numerous changes to legacy code */
7509 if (priv_data->total_len <= 0 ||
7510 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007511 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007512 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007513 ret = -EINVAL;
7514 goto exit;
7515 }
7516
7517 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007518 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007519 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007520 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007521 ret = -ENOMEM;
7522 goto exit;
7523 }
7524
7525 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7526 ret = -EFAULT;
7527 goto exit;
7528 }
7529
7530 /* Make sure the command is NUL-terminated */
7531 command[priv_data->total_len] = '\0';
7532
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007533 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007534 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7535
7536exit:
7537 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007538 qdf_mem_free(command);
Dustin Browne74003f2018-03-14 12:51:58 -07007539 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007540 return ret;
7541}
7542
7543#ifdef CONFIG_COMPAT
Jeff Johnsone44b7012017-09-10 15:25:47 -07007544static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007545{
7546 struct {
7547 compat_uptr_t buf;
7548 int used_len;
7549 int total_len;
7550 } compat_priv_data;
Jeff Johnson353cd292017-08-17 06:47:26 -07007551 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007552 int ret = 0;
7553
7554 /*
7555 * Note that adapter and ifr have already been verified by caller,
7556 * and HDD context has also been validated
7557 */
7558 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7559 sizeof(compat_priv_data))) {
7560 ret = -EFAULT;
7561 goto exit;
7562 }
7563 priv_data.buf = compat_ptr(compat_priv_data.buf);
7564 priv_data.used_len = compat_priv_data.used_len;
7565 priv_data.total_len = compat_priv_data.total_len;
7566 ret = hdd_driver_command(adapter, &priv_data);
7567exit:
7568 return ret;
7569}
7570#else /* CONFIG_COMPAT */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007571static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007572{
7573 /* will never be invoked */
7574 return 0;
7575}
7576#endif /* CONFIG_COMPAT */
7577
Jeff Johnsone44b7012017-09-10 15:25:47 -07007578static int hdd_driver_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007579{
Jeff Johnson353cd292017-08-17 06:47:26 -07007580 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007581 int ret = 0;
7582
7583 /*
7584 * Note that adapter and ifr have already been verified by caller,
7585 * and HDD context has also been validated
7586 */
7587 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7588 ret = -EFAULT;
7589 else
7590 ret = hdd_driver_command(adapter, &priv_data);
7591
7592 return ret;
7593}
7594
7595/**
7596 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7597 * @dev: device upon which the ioctl was received
7598 * @ifr: ioctl request information
7599 * @cmd: ioctl command
7600 *
7601 * This function does initial processing of wlan device ioctls.
7602 * Currently two flavors of ioctls are supported. The primary ioctl
7603 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7604 * for Android "DRIVER" commands. The other ioctl that is
7605 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7606 * for FTM on some platforms. This function simply verifies that the
7607 * driver is in a sane state, and that the ioctl is one of the
7608 * supported flavors, in which case flavor-specific handlers are
7609 * dispatched.
7610 *
7611 * Return: 0 on success, non-zero on error
7612 */
7613static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7614{
Jeff Johnsone44b7012017-09-10 15:25:47 -07007615 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson621cf972017-08-28 11:58:44 -07007616 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007617 int ret;
7618
Dustin Brownfdf17c12018-03-14 12:55:34 -07007619 hdd_enter_dev(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307620
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007621 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007622 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007623 ret = -ENODEV;
7624 goto exit;
7625 }
7626
7627 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007628 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007629 ret = -EINVAL;
7630 goto exit;
7631 }
7632#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307633 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007634 if (SIOCIOCTLTX99 == cmd) {
7635 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7636 goto exit;
7637 }
7638 }
7639#endif
7640
7641 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7642 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307643 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007644 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007645
7646 switch (cmd) {
7647 case (SIOCDEVPRIVATE + 1):
Mahesh Kumar Kalikot Veetil885a77b2018-03-26 14:46:59 -07007648 if (in_compat_syscall())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007649 ret = hdd_driver_compat_ioctl(adapter, ifr);
7650 else
7651 ret = hdd_driver_ioctl(adapter, ifr);
7652 break;
7653 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007654 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007655 ret = -EINVAL;
7656 break;
7657 }
7658exit:
Dustin Browne74003f2018-03-14 12:51:58 -07007659 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007660 return ret;
7661}
7662
7663/**
7664 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7665 * @dev: device upon which the ioctl was received
7666 * @ifr: ioctl request information
7667 * @cmd: ioctl command
7668 *
7669 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7670 * which is where the ioctls are really handled.
7671 *
7672 * Return: 0 on success, non-zero on error
7673 */
7674int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7675{
7676 int ret;
7677
7678 cds_ssr_protect(__func__);
7679 ret = __hdd_ioctl(dev, ifr, cmd);
7680 cds_ssr_unprotect(__func__);
7681 return ret;
7682}