blob: bc35b99b14cca125db5bfacec1fffd76ee6696ef [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>
Pragaspathi Thilagaraj3cf0f652018-10-29 16:40:35 +053024#include "cfg_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080025#include "wlan_hdd_trace.h"
26#include "wlan_hdd_ioctl.h"
27#include "wlan_hdd_power.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070028#include "wlan_hdd_regulatory.h"
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -070029#include "wlan_osif_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080030#include "wlan_hdd_driver_ops.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080031#include "wlan_policy_mgr_api.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053032#include "wlan_hdd_hostapd.h"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080033#include "scheduler_api.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070034#include "wlan_reg_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080035#include "wlan_hdd_p2p.h"
36#include <linux/ctype.h>
37#include "wma.h"
38#include "wlan_hdd_napi.h"
Wu Gao93816212018-08-31 16:49:54 +080039#include "wlan_mlme_ucfg_api.h"
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080040#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080041#include <sme_api.h>
42#include <sir_api.h>
43#endif
44#include "hif.h"
Harprit Chhabada4691a472018-12-07 11:22:48 -080045#include "wlan_scan_ucfg_api.h"
46#include "cfg_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080047
48#if defined(LINUX_QCMBR)
49#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
50#endif
51
52/*
53 * Size of Driver command strings from upper layer
54 */
55#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
56#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
57
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080058/*
59 * Ibss prop IE from command will be of size:
60 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
61 * OUI_DATA should be at least 3 bytes long
62 */
63#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080064
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080065#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080066#define TID_MIN_VALUE 0
67#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080068#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069
70/*
71 * Maximum buffer size used for returning the data back to user space
72 */
73#define WLAN_MAX_BUF_SIZE 1024
74#define WLAN_PRIV_DATA_MAX_LEN 8192
75
76/*
77 * Driver miracast parameters 0-Disabled
78 * 1-Source, 2-Sink
79 */
80#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
81#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
82
83/*
84 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
85 * we will split the printing.
86 */
87#define NUM_OF_STA_DATA_TO_PRINT 16
88
Dundi Raviteja53de6c32018-05-16 16:56:30 +053089#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
90/**
91 * struct enable_ext_wow_priv - Private data structure for ext wow
92 * @ext_wow_should_suspend: Suspend status of ext wow
93 */
94struct enable_ext_wow_priv {
95 bool ext_wow_should_suspend;
96};
97#endif
98
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080099/*
100 * Android DRIVER command structures
101 */
102struct android_wifi_reassoc_params {
103 unsigned char bssid[18];
104 int channel;
105};
106
107#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
108struct android_wifi_af_params {
109 unsigned char bssid[18];
110 int channel;
111 int dwell_time;
112 int len;
113 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
114};
115
116/*
117 * Define HDD driver command handling entry, each contains a command
118 * string and the handler.
119 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700120typedef int (*hdd_drv_cmd_handler_t)(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -0700121 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800122 uint8_t *cmd,
123 uint8_t cmd_name_len,
Jeff Johnson353cd292017-08-17 06:47:26 -0700124 struct hdd_priv_data *priv_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800125
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530126/**
127 * struct hdd_drv_cmd - Structure to store ioctl command handling info
128 * @cmd: Name of the command
129 * @handler: Command handler to be invoked
130 * @args: Set to true if command expects input parameters
131 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700132struct hdd_drv_cmd {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800133 const char *cmd;
134 hdd_drv_cmd_handler_t handler;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530135 bool args;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700136};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800137
138#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
139#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
140#define WLAN_HDD_MAX_TCP_PORT 65535
141#endif
142
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800143static uint16_t cesium_pid;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800144
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530145/**
146 * drv_cmd_validate() - Validates for space in hdd driver command
147 * @command: pointer to input data (its a NULL terminated string)
148 * @len: length of command name
149 *
150 * This function checks for space after command name and if no space
151 * is found returns error.
152 *
153 * Return: 0 for success non-zero for failure
154 */
155static int drv_cmd_validate(uint8_t *command, int len)
156{
157 if (command[len] != ' ')
158 return -EINVAL;
159
160 return 0;
161}
162
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800163#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800164struct tsm_priv {
165 tAniTrafStrmMetrics tsm_metrics;
166};
167
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800168static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
169 const uint32_t staId, void *context)
170{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700171 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800172 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800173
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700174 request = osif_request_get(context);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800175 if (!request) {
176 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800177 return;
178 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700179 priv = osif_request_priv(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800180 priv->tsm_metrics = tsm_metrics;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700181 osif_request_complete(request);
182 osif_request_put(request);
Dustin Browne74003f2018-03-14 12:51:58 -0700183 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185}
186
Jeff Johnsone44b7012017-09-10 15:25:47 -0700187static int hdd_get_tsm_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800188 const uint8_t tid,
189 tAniTrafStrmMetrics *tsm_metrics)
190{
Jeff Johnson621cf972017-08-28 11:58:44 -0700191 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700192 struct hdd_station_ctx *hdd_sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800193 QDF_STATUS status;
194 int ret;
195 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700196 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800197 struct tsm_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700198 static const struct osif_request_params params = {
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800199 .priv_size = sizeof(*priv),
200 .timeout_ms = WLAN_WAIT_TIME_STATS,
201 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202
203 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700204 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800205 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800206 }
207
208 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
209 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
210
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700211 request = osif_request_alloc(&params);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800212 if (!request) {
213 hdd_err("Request allocation failure");
214 return -ENOMEM;
215 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700216 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800217
Jeff Johnsond549efa2018-06-13 20:27:47 -0700218 status = sme_get_tsm_stats(hdd_ctx->mac_handle, hdd_get_tsm_stats_cb,
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800219 hdd_sta_ctx->conn_info.staId[0],
220 hdd_sta_ctx->conn_info.bssId,
Jeff Johnson30f84552017-09-13 14:55:25 -0700221 cookie, tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800222 if (QDF_STATUS_SUCCESS != status) {
223 hdd_err("Unable to retrieve tsm statistics");
224 ret = qdf_status_to_os_return(status);
225 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800226 }
227
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700228 ret = osif_request_wait_for_response(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800229 if (ret) {
230 hdd_err("SME timed out while retrieving tsm statistics");
231 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800233
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700234 priv = osif_request_priv(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800235 *tsm_metrics = priv->tsm_metrics;
236
237 cleanup:
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700238 osif_request_put(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800239
240 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800241}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800242#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800243
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800244/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700245 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
246 * @UserData: Adapter private data
247 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800248 *
249 * This is an asynchronous callback function from SME when the peer info
250 * is received
251 *
252 * Return: 0 for success non-zero for failure
253 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700254void
255hdd_get_ibss_peer_info_cb(void *pUserData,
256 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800257{
Jeff Johnsone44b7012017-09-10 15:25:47 -0700258 struct hdd_adapter *adapter = (struct hdd_adapter *) pUserData;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700259 struct hdd_station_ctx *pStaCtx;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800260 uint8_t i;
261
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800262 if ((NULL == adapter) ||
263 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800264 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800265 return;
266 }
267
268 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
269 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700270 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530271 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
272 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700273 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530274 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800275 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530276 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
277 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
278
279 for (i = 0; i < pPeerInfo->numPeers; i++)
280 pStaCtx->ibss_peer_info.peerInfoParams[i] =
281 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800282 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800283 hdd_debug("peerInfo %s: status %u, numPeers %u",
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530284 pPeerInfo ? "valid" : "null",
285 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
286 pPeerInfo ? pPeerInfo->numPeers : 0);
287 pStaCtx->ibss_peer_info.numPeers = 0;
288 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800289 }
290
291 complete(&adapter->ibss_peer_info_comp);
292}
293
294/**
295 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
296 * @adapter: Adapter context
297 *
298 * Request function to get IBSS peer info from lower layers
299 *
300 * Return: 0 for success non-zero for failure
301 */
302static
Jeff Johnsone44b7012017-09-10 15:25:47 -0700303QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(struct hdd_adapter *adapter)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800304{
Jeff Johnsond549efa2018-06-13 20:27:47 -0700305 QDF_STATUS status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800306 unsigned long rc;
307
308 INIT_COMPLETION(adapter->ibss_peer_info_comp);
309
Jeff Johnsond549efa2018-06-13 20:27:47 -0700310 status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle,
311 adapter,
312 hdd_get_ibss_peer_info_cb,
313 true, 0xFF);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800314
Jeff Johnsond549efa2018-06-13 20:27:47 -0700315 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800316 rc = wait_for_completion_timeout
317 (&adapter->ibss_peer_info_comp,
318 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
319
320 /* status will be 0 if timed out */
321 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700322 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Jeff Johnsond549efa2018-06-13 20:27:47 -0700323 status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800324 }
325 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700326 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800327 }
328
Jeff Johnsond549efa2018-06-13 20:27:47 -0700329 return status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800330}
331
332/**
333 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
334 * @adapter: Adapter context
335 * @staIdx: Sta index for which the peer info is requested
336 *
337 * Request function to get IBSS peer info from lower layers
338 *
339 * Return: 0 for success non-zero for failure
340 */
341static QDF_STATUS
Jeff Johnsone44b7012017-09-10 15:25:47 -0700342hdd_cfg80211_get_ibss_peer_info(struct hdd_adapter *adapter, uint8_t staIdx)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800343{
344 unsigned long rc;
Jeff Johnsond549efa2018-06-13 20:27:47 -0700345 QDF_STATUS status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800346
347 INIT_COMPLETION(adapter->ibss_peer_info_comp);
348
Jeff Johnsond549efa2018-06-13 20:27:47 -0700349 status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle,
350 adapter,
351 hdd_get_ibss_peer_info_cb,
352 false, staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800353
Jeff Johnsond549efa2018-06-13 20:27:47 -0700354 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800355 rc = wait_for_completion_timeout(
356 &adapter->ibss_peer_info_comp,
357 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
358
359 /* status = 0 on timeout */
360 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700361 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Jeff Johnsond549efa2018-06-13 20:27:47 -0700362 status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800363 }
364 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700365 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800366 }
367
Jeff Johnsond549efa2018-06-13 20:27:47 -0700368 return status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800369}
370
371/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700372static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800373hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
374{
375 uint8_t *inPtr = pValue;
Min Liu5359ab12018-03-29 14:30:24 +0800376 size_t in_ptr_len = strlen(pValue);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700377
Min Liu5359ab12018-03-29 14:30:24 +0800378 inPtr = strnchr(pValue, in_ptr_len, SPACE_ASCII_VALUE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800379
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700380 if (NULL == inPtr)
381 return QDF_STATUS_E_FAILURE;
382 else if (SPACE_ASCII_VALUE != *inPtr)
383 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800384
385 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
386 inPtr++;
387
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700388 if ('\0' == *inPtr)
389 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800390
Min Liu5359ab12018-03-29 14:30:24 +0800391 in_ptr_len -= (inPtr - pValue);
392 if (in_ptr_len < 17)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700393 return QDF_STATUS_E_FAILURE;
Min Liu5359ab12018-03-29 14:30:24 +0800394
395 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
396 inPtr[11] != ':' || inPtr[14] != ':')
397 return QDF_STATUS_E_FAILURE;
398
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800399 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
400 (unsigned int *)&pPeerMacAddr->bytes[0],
401 (unsigned int *)&pPeerMacAddr->bytes[1],
402 (unsigned int *)&pPeerMacAddr->bytes[2],
403 (unsigned int *)&pPeerMacAddr->bytes[3],
404 (unsigned int *)&pPeerMacAddr->bytes[4],
405 (unsigned int *)&pPeerMacAddr->bytes[5]);
406
407 return QDF_STATUS_SUCCESS;
408}
409
Jeff Johnsond549efa2018-06-13 20:27:47 -0700410static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *ui_band)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800411{
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800412 enum band_info band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700413
Jeff Johnsond549efa2018-06-13 20:27:47 -0700414 sme_get_freq_band(hdd_ctx->mac_handle, &band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800415 switch (band) {
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800416 case BAND_ALL:
Jeff Johnsond549efa2018-06-13 20:27:47 -0700417 *ui_band = WLAN_HDD_UI_BAND_AUTO;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800418 break;
419
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800420 case BAND_2G:
Jeff Johnsond549efa2018-06-13 20:27:47 -0700421 *ui_band = WLAN_HDD_UI_BAND_2_4_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800422 break;
423
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800424 case BAND_5G:
Jeff Johnsond549efa2018-06-13 20:27:47 -0700425 *ui_band = WLAN_HDD_UI_BAND_5_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800426 break;
427
428 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700429 hdd_warn("Invalid Band %d", band);
Jeff Johnsond549efa2018-06-13 20:27:47 -0700430 *ui_band = -1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431 break;
432 }
433}
434
435/**
436 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
437 * @data: input data
438 * @target_ap_bssid: pointer to bssid (output parameter)
439 * @channel: pointer to channel (output parameter)
440 *
441 * Return: 0 if parsing is successful; -EINVAL otherwise
442 */
443static int _hdd_parse_bssid_and_chan(const uint8_t **data,
444 uint8_t *bssid,
445 uint8_t *channel)
446{
447 const uint8_t *in_ptr;
448 int v = 0;
449 int temp_int;
450 uint8_t temp_buf[32];
451
452 /* 12 hexa decimal digits, 5 ':' and '\0' */
453 uint8_t mac_addr[18];
454
455 if (!data || !*data)
456 return -EINVAL;
457
458 in_ptr = *data;
459
460 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
461 /* no argument after the command */
462 if (NULL == in_ptr)
463 goto error;
464 /* no space after the command */
465 else if (SPACE_ASCII_VALUE != *in_ptr)
466 goto error;
467
468 /* remove empty spaces */
469 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
470 in_ptr++;
471
472 /* no argument followed by spaces */
473 if ('\0' == *in_ptr)
474 goto error;
475
476 v = sscanf(in_ptr, "%17s", mac_addr);
477 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700478 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
479 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800480 goto error;
481 }
482
483 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
484 hex_to_bin(mac_addr[1]);
485 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
486 hex_to_bin(mac_addr[4]);
487 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
488 hex_to_bin(mac_addr[7]);
489 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
490 hex_to_bin(mac_addr[10]);
491 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
492 hex_to_bin(mac_addr[13]);
493 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
494 hex_to_bin(mac_addr[16]);
495
496 /* point to the next argument */
497 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
498 /* no argument after the command */
499 if (NULL == in_ptr)
500 goto error;
501
502 /* remove empty spaces */
503 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
504 in_ptr++;
505
506 /* no argument followed by spaces */
507 if ('\0' == *in_ptr)
508 goto error;
509
510 /* get the next argument ie the channel number */
511 v = sscanf(in_ptr, "%31s ", temp_buf);
512 if (1 != v)
513 goto error;
514
515 v = kstrtos32(temp_buf, 10, &temp_int);
516 if ((v < 0) || (temp_int < 0) ||
517 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
518 return -EINVAL;
519
520 *channel = temp_int;
521 *data = in_ptr;
522 return 0;
523error:
524 *data = in_ptr;
525 return -EINVAL;
526}
527
528/**
529 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
530 * @pValue: Pointer to input data
531 * @pTargetApBssid: Pointer to target Ap bssid
532 * @pChannel: Pointer to the Target AP channel
533 * @pDwellTime: Pointer to the time to stay off-channel
534 * after transmitting action frame
535 * @pBuf: Pointer to data
536 * @pBufLen: Pointer to data length
537 *
538 * This function parses the send action frame data passed in the format
539 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
540 *
541 * Return: 0 for success non-zero for failure
542 */
543static int
544hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
545 uint8_t *pTargetApBssid,
546 uint8_t *pChannel, uint8_t *pDwellTime,
547 uint8_t **pBuf, uint8_t *pBufLen)
548{
549 const uint8_t *inPtr = pValue;
550 const uint8_t *dataEnd;
551 int tempInt;
552 int j = 0;
553 int i = 0;
554 int v = 0;
555 uint8_t tempBuf[32];
556 uint8_t tempByte = 0;
557
558 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
559 return -EINVAL;
560
561 /* point to the next argument */
562 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
563 /* no argument after the command */
564 if (NULL == inPtr)
565 return -EINVAL;
566 /* removing empty spaces */
567 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
568 inPtr++;
569
570 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700571 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800572 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800573
574 /* getting the next argument ie the dwell time */
575 v = sscanf(inPtr, "%31s ", tempBuf);
576 if (1 != v)
577 return -EINVAL;
578
579 v = kstrtos32(tempBuf, 10, &tempInt);
580 if (v < 0 || tempInt < 0)
581 return -EINVAL;
582
583 *pDwellTime = tempInt;
584
585 /* point to the next argument */
586 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
587 /* no argument after the command */
588 if (NULL == inPtr)
589 return -EINVAL;
590 /* removing empty spaces */
591 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
592 inPtr++;
593
594 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700595 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800596 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800597
598 /* find the length of data */
599 dataEnd = inPtr;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700600 while (('\0' != *dataEnd))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800601 dataEnd++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700602
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800603 *pBufLen = dataEnd - inPtr;
604 if (*pBufLen <= 0)
605 return -EINVAL;
606
607 /*
608 * Allocate the number of bytes based on the number of input characters
609 * whether it is even or odd.
610 * if the number of input characters are even, then we need N/2 byte.
611 * if the number of input characters are odd, then we need do (N+1)/2
612 * to compensate rounding off.
613 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
614 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
615 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530616 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800617 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700618 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800619 return -ENOMEM;
620 }
621
622 /* the buffer received from the upper layer is character buffer,
623 * we need to prepare the buffer taking 2 characters in to a U8 hex
624 * decimal number for example 7f0000f0...form a buffer to contain 7f
625 * in 0th location, 00 in 1st and f0 in 3rd location
626 */
627 for (i = 0, j = 0; j < *pBufLen; j += 2) {
628 if (j + 1 == *pBufLen) {
629 tempByte = hex_to_bin(inPtr[j]);
630 } else {
631 tempByte =
632 (hex_to_bin(inPtr[j]) << 4) |
633 (hex_to_bin(inPtr[j + 1]));
634 }
635 (*pBuf)[i++] = tempByte;
636 }
637 *pBufLen = i;
638 return 0;
639}
640
641/**
642 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
643 * @pValue: Pointer to input data (its a NULL terminated string)
644 * @pTargetApBssid: Pointer to target Ap bssid
645 * @pChannel: Pointer to the Target AP channel
646 *
647 * This function parses the reasoc command data passed in the format
648 * REASSOC<space><bssid><space><channel>
649 *
650 * Return: 0 for success non-zero for failure
651 */
652static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
653 uint8_t *pTargetApBssid,
654 uint8_t *pChannel)
655{
656 const uint8_t *inPtr = pValue;
657
658 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
659 return -EINVAL;
660
661 return 0;
662}
663
Naveen Rawat05376ee2016-07-18 16:43:32 -0700664#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Abhinav Kumareab25932018-07-13 11:48:43 +0530665QDF_STATUS hdd_wma_send_fastreassoc_cmd(struct hdd_adapter *adapter,
666 const tSirMacAddr bssid,
667 int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700668{
Krunal Soni332f4af2017-06-01 14:36:17 -0700669 struct hdd_station_ctx *hdd_sta_ctx =
670 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnson8313b9d2018-03-14 15:09:28 -0700671 struct csr_roam_profile *roam_profile;
Krunal Soni332f4af2017-06-01 14:36:17 -0700672 tSirMacAddr connected_bssid;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700673
Jeff Johnson8313b9d2018-03-14 15:09:28 -0700674 roam_profile = hdd_roam_profile(adapter);
Krunal Soni332f4af2017-06-01 14:36:17 -0700675 qdf_mem_copy(connected_bssid, hdd_sta_ctx->conn_info.bssId.bytes,
676 ETH_ALEN);
Abhinav Kumareab25932018-07-13 11:48:43 +0530677 return sme_fast_reassoc(adapter->hdd_ctx->mac_handle,
678 roam_profile, bssid, channel,
679 adapter->session_id, connected_bssid);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700680}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700681#endif
682
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800683/**
684 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800685 * @adapter: Adapter upon which the command was received
686 * @bssid: BSSID with which to reassociate
687 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700688 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800689 *
690 * This function performs a userspace-directed reassoc operation
691 *
692 * Return: 0 for success non-zero for failure
693 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700694int hdd_reassoc(struct hdd_adapter *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800695 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800696{
Jeff Johnsond377dce2017-10-04 10:32:42 -0700697 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -0700698 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800699 int ret = 0;
Abhinav Kumareab25932018-07-13 11:48:43 +0530700 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800701
Naveen Rawat05376ee2016-07-18 16:43:32 -0700702 if (hdd_ctx == NULL) {
703 hdd_err("Invalid hdd ctx");
704 return -EINVAL;
705 }
706
Krunal Sonibe766b02016-03-10 13:00:44 -0800707 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -0700709 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800710 adapter->device_mode);
711 return -EINVAL;
712 }
713
Jeff Johnsond377dce2017-10-04 10:32:42 -0700714 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800715
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +0530716 /*
717 * pHddStaCtx->conn_info.connState is set to disconnected only
718 * after the disconnect done indication from SME. If the SME is
719 * in the process of disconnecting, the SME Connection state is
720 * set to disconnected and the pHddStaCtx->conn_info.connState
721 * will still be associated till the disconnect is done.
722 * So check both the HDD state and SME state here.
723 * If not associated, no need to proceed with reassoc
724 */
725 if ((eConnectionState_Associated != sta_ctx->conn_info.connState) ||
726 (!sme_is_conn_state_connected(hdd_ctx->mac_handle,
727 adapter->session_id))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800728 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800729 ret = -EINVAL;
730 goto exit;
731 }
732
733 /*
734 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800735 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800736 */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700737 if (!memcmp(bssid, sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530738 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800739 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Jeff Johnsond377dce2017-10-04 10:32:42 -0700740 channel = sta_ctx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800741 }
742
743 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530744 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800746 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800747 ret = -EINVAL;
748 goto exit;
749 }
750
751 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700752 if (roaming_offload_enabled(hdd_ctx)) {
Abhinav Kumareab25932018-07-13 11:48:43 +0530753 status = hdd_wma_send_fastreassoc_cmd(adapter,
754 bssid, (int)channel);
755 if (status != QDF_STATUS_SUCCESS) {
756 hdd_err("Failed to send fast reassoc cmd");
757 ret = -EINVAL;
758 }
Naveen Rawat05376ee2016-07-18 16:43:32 -0700759 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -0700760 tCsrHandoffRequest handoff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761
Jeff Johnsond549efa2018-06-13 20:27:47 -0700762 handoff.channel = channel;
763 handoff.src = src;
764 qdf_mem_copy(handoff.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
765 sme_handoff_request(hdd_ctx->mac_handle, adapter->session_id,
766 &handoff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800767 }
768exit:
769 return ret;
770}
771
772/**
773 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
774 * @adapter: Adapter upon which the command was received
775 * @command: ASCII text command that was received
776 *
777 * This function parses the v1 REASSOC command with the format
778 *
779 * REASSOC xx:xx:xx:xx:xx:xx CH
780 *
781 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
782 * BSSID and CH is the ASCII representation of the channel. For
783 * example
784 *
785 * REASSOC 00:0a:0b:11:22:33 48
786 *
787 * Return: 0 for success non-zero for failure
788 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700789static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800790{
791 uint8_t channel = 0;
792 tSirMacAddr bssid;
793 int ret;
794
795 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700796 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700797 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700798 else
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700799 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700800
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800801 return ret;
802}
803
804/**
805 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
806 * @adapter: Adapter upon which the command was received
807 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700808 * followed by binary data
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530809 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800810 *
811 * This function parses the v2 REASSOC command with the format
812 *
813 * REASSOC <android_wifi_reassoc_params>
814 *
815 * Return: 0 for success non-zero for failure
816 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700817static int hdd_parse_reassoc_v2(struct hdd_adapter *adapter,
818 const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530819 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820{
821 struct android_wifi_reassoc_params params;
822 tSirMacAddr bssid;
823 int ret;
824
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530825 if (total_len < sizeof(params) + 8) {
826 hdd_err("Invalid command length");
827 return -EINVAL;
828 }
829
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800830 /* The params are located after "REASSOC " */
831 memcpy(&params, command + 8, sizeof(params));
832
833 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700834 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800835 ret = -EINVAL;
836 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700837 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800838 }
839 return ret;
840}
841
842/**
843 * hdd_parse_reassoc() - parse the REASSOC command
844 * @adapter: Adapter upon which the command was received
845 * @command: Command that was received
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530846 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847 *
848 * There are two different versions of the REASSOC command. Version 1
849 * of the command contains a parameter list that is ASCII characters
850 * whereas version 2 contains a combination of ASCII and binary
851 * payload. Determine if a version 1 or a version 2 command is being
852 * parsed by examining the parameters, and then dispatch the parser
853 * that is appropriate for the command.
854 *
855 * Return: 0 for success non-zero for failure
856 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700857static int hdd_parse_reassoc(struct hdd_adapter *adapter, const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530858 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859{
860 int ret;
861
862 /* both versions start with "REASSOC "
863 * v1 has a bssid and channel # as an ASCII string
864 * REASSOC xx:xx:xx:xx:xx:xx CH
865 * v2 has a C struct
866 * REASSOC <binary c struct>
867 *
868 * The first field in the v2 struct is also the bssid in ASCII.
869 * But in the case of a v2 message the BSSID is NUL-terminated.
870 * Hence we can peek at that offset to see if this is V1 or V2
871 * REASSOC xx:xx:xx:xx:xx:xx*
872 * 1111111111222222
873 * 01234567890123456789012345
874 */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530875
876 if (total_len < 26) {
877 hdd_err("Invalid command, total_len = %d", total_len);
878 return -EINVAL;
879 }
880
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700881 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700883 else
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530884 ret = hdd_parse_reassoc_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800885
886 return ret;
887}
888
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800889/**
890 * hdd_sendactionframe() - send a userspace-supplied action frame
891 * @adapter: Adapter upon which the command was received
892 * @bssid: BSSID target of the action frame
893 * @channel: Channel upon which to send the frame
894 * @dwell_time: Amount of time to dwell when the frame is sent
895 * @payload_len:Length of the payload
896 * @payload: Payload of the frame
897 *
898 * This function sends a userspace-supplied action frame
899 *
900 * Return: 0 for success non-zero for failure
901 */
902static int
Jeff Johnsone44b7012017-09-10 15:25:47 -0700903hdd_sendactionframe(struct hdd_adapter *adapter, const uint8_t *bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800904 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700905 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800906{
907 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700908 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800909 uint8_t *frame;
910 struct ieee80211_hdr_3addr *hdr;
911 u64 cookie;
Jeff Johnsond377dce2017-10-04 10:32:42 -0700912 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -0700913 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800914 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
915 (tpSirMacVendorSpecificFrameHdr) payload;
916#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
917 struct cfg80211_mgmt_tx_params params;
918#endif
919
Krunal Sonibe766b02016-03-10 13:00:44 -0800920 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800921 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -0700922 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800923 adapter->device_mode);
924 return -EINVAL;
925 }
926
Jeff Johnsond377dce2017-10-04 10:32:42 -0700927 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800928 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
929
930 /* if not associated, no need to send action frame */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700931 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800932 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933 ret = -EINVAL;
934 goto exit;
935 }
936
937 /*
938 * if the target bssid is different from currently associated AP,
939 * then no need to send action frame
940 */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700941 if (memcmp(bssid, sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530942 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800943 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 ret = -EINVAL;
945 goto exit;
946 }
947
948 chan.center_freq = sme_chn_to_freq(channel);
949 /* Check if it is specific action frame */
950 if (pVendorSpecific->category ==
951 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
952 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700953
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530954 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800955 /*
956 * if the channel number is different from operating
957 * channel then no need to send action frame
958 */
959 if (channel != 0) {
960 if (channel !=
Jeff Johnsond377dce2017-10-04 10:32:42 -0700961 sta_ctx->conn_info.operationChannel) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800962 hdd_warn("channel(%d) is different from operating channel(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700963 channel,
Jeff Johnsond377dce2017-10-04 10:32:42 -0700964 sta_ctx->conn_info.
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700965 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800966 ret = -EINVAL;
967 goto exit;
968 }
969 /*
970 * If channel number is specified and same
971 * as home channel, ensure that action frame
972 * is sent immediately by cancelling
973 * roaming scans. Otherwise large dwell times
974 * may cause long delays in sending action
975 * frames.
976 */
Jeff Johnsond549efa2018-06-13 20:27:47 -0700977 sme_abort_roam_scan(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -0700978 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800979 } else {
980 /*
981 * 0 is accepted as current home channel,
982 * delayed transmission of action frame is ok.
983 */
984 chan.center_freq =
Jeff Johnsond377dce2017-10-04 10:32:42 -0700985 sme_chn_to_freq(sta_ctx->conn_info.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800986 operationChannel);
987 }
988 }
989 }
990 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800991 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800992 ret = -EINVAL;
993 goto exit;
994 }
995
996 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530997 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800998 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700999 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001000 ret = -ENOMEM;
1001 goto exit;
1002 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001003
1004 hdr = (struct ieee80211_hdr_3addr *)frame;
1005 hdr->frame_control =
1006 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301007 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson1e851a12017-10-28 14:36:12 -07001008 qdf_mem_copy(hdr->addr2, adapter->mac_addr.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301009 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301010 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1011 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001012
1013#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1014 params.chan = &chan;
1015 params.offchan = 0;
1016 params.wait = dwell_time;
1017 params.buf = frame;
1018 params.len = frame_len;
1019 params.no_cck = 1;
1020 params.dont_wait_for_ack = 1;
1021 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1022#else
1023 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001024 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001025 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001026
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 dwell_time, frame, frame_len, 1, 1, &cookie);
1028#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1029
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301030 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001031exit:
1032 return ret;
1033}
1034
1035/**
1036 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1037 * SENDACTIONFRAME command
1038 * @adapter: Adapter upon which the command was received
1039 * @command: ASCII text command that was received
1040 *
1041 * This function parses the v1 SENDACTIONFRAME command with the format
1042 *
1043 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1044 *
1045 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1046 * BSSID, CH is the ASCII representation of the channel, DW is the
1047 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1048 * payload. For example
1049 *
1050 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1051 *
1052 * Return: 0 for success non-zero for failure
1053 */
1054static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001055hdd_parse_sendactionframe_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001056{
1057 uint8_t channel = 0;
1058 uint8_t dwell_time = 0;
1059 uint8_t payload_len = 0;
1060 uint8_t *payload = NULL;
1061 tSirMacAddr bssid;
1062 int ret;
1063
1064 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1065 &dwell_time, &payload,
1066 &payload_len);
1067 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001068 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069 } else {
1070 ret = hdd_sendactionframe(adapter, bssid, channel,
1071 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301072 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073 }
1074
1075 return ret;
1076}
1077
1078/**
1079 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1080 * SENDACTIONFRAME command
1081 * @adapter: Adapter upon which the command was received
1082 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001083 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 *
1085 * This function parses the v2 SENDACTIONFRAME command with the format
1086 *
1087 * SENDACTIONFRAME <android_wifi_af_params>
1088 *
1089 * Return: 0 for success non-zero for failure
1090 */
1091static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001092hdd_parse_sendactionframe_v2(struct hdd_adapter *adapter,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001093 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001094{
1095 struct android_wifi_af_params *params;
1096 tSirMacAddr bssid;
1097 int ret;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301098 int len_wo_payload = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001099
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001100 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001101 total_len -= 16;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301102 len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE;
1103 if (total_len <= len_wo_payload) {
1104 hdd_err("Invalid command len");
1105 return -EINVAL;
1106 }
1107
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001108 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001110 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301111 (params->len > (total_len - len_wo_payload))) {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001112 hdd_err("Invalid payload length: %d", params->len);
1113 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001114 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001115
1116 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1117 hdd_err("MAC address parsing failed");
1118 return -EINVAL;
1119 }
1120
1121 if (params->channel < 0 ||
1122 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1123 hdd_err("Invalid channel: %d", params->channel);
1124 return -EINVAL;
1125 }
1126
1127 if (params->dwell_time < 0) {
1128 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1129 return -EINVAL;
1130 }
1131
1132 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1133 params->dwell_time, params->len, params->data);
1134
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001135 return ret;
1136}
1137
1138/**
1139 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1140 * @adapter: Adapter upon which the command was received
1141 * @command: Command that was received
1142 *
1143 * There are two different versions of the SENDACTIONFRAME command.
1144 * Version 1 of the command contains a parameter list that is ASCII
1145 * characters whereas version 2 contains a combination of ASCII and
1146 * binary payload. Determine if a version 1 or a version 2 command is
1147 * being parsed by examining the parameters, and then dispatch the
1148 * parser that is appropriate for the version of the command.
1149 *
1150 * Return: 0 for success non-zero for failure
1151 */
1152static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001153hdd_parse_sendactionframe(struct hdd_adapter *adapter, const char *command,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001154 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001155{
1156 int ret;
1157
1158 /*
1159 * both versions start with "SENDACTIONFRAME "
1160 * v1 has a bssid and other parameters as an ASCII string
1161 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1162 * v2 has a C struct
1163 * SENDACTIONFRAME <binary c struct>
1164 *
1165 * The first field in the v2 struct is also the bssid in ASCII.
1166 * But in the case of a v2 message the BSSID is NUL-terminated.
1167 * Hence we can peek at that offset to see if this is V1 or V2
1168 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1169 * 111111111122222222223333
1170 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001171 * For both the commands, a valid command must have atleast
1172 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001173 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001174 if (total_len < 34) {
1175 hdd_err("Invalid command (total_len=%d)", total_len);
1176 return -EINVAL;
1177 }
1178
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001179 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001180 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001181 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001182 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001183
1184 return ret;
1185}
1186
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001187/**
1188 * hdd_parse_channellist() - HDD Parse channel list
1189 * @pValue: Pointer to input channel list
1190 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001191 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001192 * @pNumChannels: Pointer to number of roam scan channels
1193 *
1194 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001195 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1196 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001197 * if the Number of channels (N) does not match with the actual number
1198 * of channels passed then take the minimum of N and count of
1199 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1200 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1201 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1202 * removing duplicate channels from the list
1203 *
1204 * Return: 0 for success non-zero for failure
1205 */
1206static int
1207hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1208 uint8_t *pNumChannels)
1209{
1210 const uint8_t *inPtr = pValue;
1211 int tempInt;
1212 int j = 0;
1213 int v = 0;
1214 char buf[32];
1215
1216 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1217 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001218 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001219 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001220 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001221 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001222
1223 /* remove empty spaces */
1224 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1225 inPtr++;
1226
1227 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001228 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230
1231 /* get the first argument ie the number of channels */
1232 v = sscanf(inPtr, "%31s ", buf);
1233 if (1 != v)
1234 return -EINVAL;
1235
1236 v = kstrtos32(buf, 10, &tempInt);
1237 if ((v < 0) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001238 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001239 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240
1241 *pNumChannels = tempInt;
1242
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001243 hdd_debug("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001244
1245 for (j = 0; j < (*pNumChannels); j++) {
1246 /*
1247 * inPtr pointing to the beginning of first space after number
1248 * of channels
1249 */
1250 inPtr = strpbrk(inPtr, " ");
1251 /* no channel list after the number of channels argument */
1252 if (NULL == inPtr) {
1253 if (0 != j) {
1254 *pNumChannels = j;
1255 return 0;
1256 } else {
1257 return -EINVAL;
1258 }
1259 }
1260
1261 /* remove empty space */
1262 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1263 inPtr++;
1264
1265 /*
1266 * no channel list after the number of channels
1267 * argument and spaces
1268 */
1269 if ('\0' == *inPtr) {
1270 if (0 != j) {
1271 *pNumChannels = j;
1272 return 0;
1273 } else {
1274 return -EINVAL;
1275 }
1276 }
1277
1278 v = sscanf(inPtr, "%31s ", buf);
1279 if (1 != v)
1280 return -EINVAL;
1281
1282 v = kstrtos32(buf, 10, &tempInt);
1283 if ((v < 0) ||
1284 (tempInt <= 0) ||
1285 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1286 return -EINVAL;
1287 }
1288 pChannelList[j] = tempInt;
1289
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001290 hdd_debug("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001291 pChannelList[j]);
1292 }
1293
1294 return 0;
1295}
1296
1297/**
1298 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1299 * SETROAMSCANCHANNELS command
1300 * @adapter: Adapter upon which the command was received
1301 * @command: ASCII text command that was received
1302 *
1303 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1304 *
1305 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1306 *
1307 * Where "N" is the ASCII representation of the number of channels and
1308 * C1 thru Cn is the ASCII representation of the channels. For example
1309 *
1310 * SETROAMSCANCHANNELS 4 36 40 44 48
1311 *
1312 * Return: 0 for success non-zero for failure
1313 */
1314static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001315hdd_parse_set_roam_scan_channels_v1(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001316 const char *command)
1317{
1318 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1319 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301320 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001321 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001322 int ret;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001323 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001324
1325 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1326 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001327 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001328 goto exit;
1329 }
1330
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301331 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001332 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001333 adapter->session_id, num_chan));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001334
1335 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001336 hdd_err("number of channels (%d) supported exceeded max (%d)",
1337 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001338 ret = -EINVAL;
1339 goto exit;
1340 }
1341
Jeff Johnsond549efa2018-06-13 20:27:47 -07001342 mac_handle = hdd_ctx->mac_handle;
1343 if (!sme_validate_channel_list(mac_handle, channel_list, num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301344 hdd_err("List contains invalid channel(s)");
1345 ret = -EINVAL;
1346 goto exit;
1347 }
1348
Jeff Johnsond549efa2018-06-13 20:27:47 -07001349 status = sme_change_roam_scan_channel_list(mac_handle,
1350 adapter->session_id,
1351 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301352 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001353 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354 ret = -EINVAL;
1355 goto exit;
1356 }
1357exit:
1358 return ret;
1359}
1360
1361/**
1362 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1363 * SETROAMSCANCHANNELS command
1364 * @adapter: Adapter upon which the command was received
1365 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001366 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001367 *
1368 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1369 *
1370 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1371 *
1372 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1373 * what follows the space is an array of u08 parameters. For example
1374 *
1375 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1376 *
1377 * Return: 0 for success non-zero for failure
1378 */
1379static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001380hdd_parse_set_roam_scan_channels_v2(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001381 const char *command)
1382{
1383 const uint8_t *value;
1384 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1385 uint8_t channel;
1386 uint8_t num_chan;
1387 int i;
Jeff Johnson621cf972017-08-28 11:58:44 -07001388 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301389 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001390 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001391 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001392
1393 /* array of values begins after "SETROAMSCANCHANNELS " */
1394 value = command + 20;
1395
1396 num_chan = *value++;
1397 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001398 hdd_err("number of channels (%d) supported exceeded max (%d)",
1399 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001400 ret = -EINVAL;
1401 goto exit;
1402 }
1403
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301404 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001406 adapter->session_id, num_chan));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001407
1408 for (i = 0; i < num_chan; i++) {
1409 channel = *value++;
Nachiket Kukadecaa2e842018-05-09 17:56:12 +05301410 if (!channel) {
1411 hdd_err("Channels end at index %d, expected %d",
1412 i, num_chan);
1413 ret = -EINVAL;
1414 goto exit;
1415 }
1416
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001417 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001418 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001419 i, channel);
1420 ret = -EINVAL;
1421 goto exit;
1422 }
1423 channel_list[i] = channel;
1424 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301425
Jeff Johnsond549efa2018-06-13 20:27:47 -07001426 mac_handle = hdd_ctx->mac_handle;
1427 if (!sme_validate_channel_list(mac_handle, channel_list, num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301428 hdd_err("List contains invalid channel(s)");
1429 ret = -EINVAL;
1430 goto exit;
1431 }
1432
Jeff Johnsond549efa2018-06-13 20:27:47 -07001433 status = sme_change_roam_scan_channel_list(mac_handle,
1434 adapter->session_id,
1435 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301436 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001437 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438 ret = -EINVAL;
1439 goto exit;
1440 }
1441exit:
1442 return ret;
1443}
1444
1445/**
1446 * hdd_parse_set_roam_scan_channels() - parse the
1447 * SETROAMSCANCHANNELS command
1448 * @adapter: Adapter upon which the command was received
1449 * @command: Command that was received
1450 *
1451 * There are two different versions of the SETROAMSCANCHANNELS command.
1452 * Version 1 of the command contains a parameter list that is ASCII
1453 * characters whereas version 2 contains a binary payload. Determine
1454 * if a version 1 or a version 2 command is being parsed by examining
1455 * the parameters, and then dispatch the parser that is appropriate for
1456 * the command.
1457 *
1458 * Return: 0 for success non-zero for failure
1459 */
1460static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001461hdd_parse_set_roam_scan_channels(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001462{
1463 const char *cursor;
1464 char ch;
1465 bool v1;
1466 int ret;
1467
1468 /* start after "SETROAMSCANCHANNELS " */
1469 cursor = command + 20;
1470
1471 /* assume we have a version 1 command until proven otherwise */
1472 v1 = true;
1473
1474 /* v1 params will only contain ASCII digits and space */
1475 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001476 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001477 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001478 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001479
1480 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001481 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001482 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001483 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001484
1485 return ret;
1486}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001487
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001488#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001489/**
1490 * hdd_parse_plm_cmd() - HDD Parse Plm command
1491 * @pValue: Pointer to input data
1492 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1493 *
1494 * This function parses the plm command passed in the format
1495 * CCXPLMREQ<space><enable><space><dialog_token><space>
1496 * <meas_token><space><num_of_bursts><space><burst_int><space>
1497 * <measu duration><space><burst_len><space><desired_tx_pwr>
1498 * <space><multcast_addr><space><number_of_channels>
1499 * <space><channel_numbers>
1500 *
1501 * Return: 0 for success non-zero for failure
1502 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001503static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001504{
1505 uint8_t *cmdPtr = NULL;
1506 int count, content = 0, ret = 0;
1507 char buf[32];
1508
1509 /* move to argument list */
1510 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1511 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301512 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513
1514 /* no space after the command */
1515 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301516 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001517
1518 /* remove empty spaces */
1519 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1520 cmdPtr++;
1521
1522 /* START/STOP PLM req */
1523 ret = sscanf(cmdPtr, "%31s ", buf);
1524 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301525 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001526
1527 ret = kstrtos32(buf, 10, &content);
1528 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301529 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001530
1531 pPlmRequest->enable = content;
1532 cmdPtr = strpbrk(cmdPtr, " ");
1533
1534 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301535 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001536
1537 /* remove empty spaces */
1538 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1539 cmdPtr++;
1540
1541 /* Dialog token of radio meas req containing meas reqIE */
1542 ret = sscanf(cmdPtr, "%31s ", buf);
1543 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301544 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001545
1546 ret = kstrtos32(buf, 10, &content);
1547 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301548 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549
1550 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001551 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001552 cmdPtr = strpbrk(cmdPtr, " ");
1553
1554 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301555 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001556
1557 /* remove empty spaces */
1558 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1559 cmdPtr++;
1560
1561 /* measurement token of meas req IE */
1562 ret = sscanf(cmdPtr, "%31s ", buf);
1563 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301564 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001565
1566 ret = kstrtos32(buf, 10, &content);
1567 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301568 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001569
1570 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001571 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001573 hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574 if (pPlmRequest->enable) {
1575
1576 cmdPtr = strpbrk(cmdPtr, " ");
1577
1578 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301579 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580
1581 /* remove empty spaces */
1582 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1583 cmdPtr++;
1584
1585 /* total number of bursts after which STA stops sending */
1586 ret = sscanf(cmdPtr, "%31s ", buf);
1587 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301588 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001589
1590 ret = kstrtos32(buf, 10, &content);
1591 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301592 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001593
1594 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301595 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001596
1597 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001598 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001599 cmdPtr = strpbrk(cmdPtr, " ");
1600
1601 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301602 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603
1604 /* remove empty spaces */
1605 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1606 cmdPtr++;
1607
1608 /* burst interval in seconds */
1609 ret = sscanf(cmdPtr, "%31s ", buf);
1610 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301611 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001612
1613 ret = kstrtos32(buf, 10, &content);
1614 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301615 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001616
1617 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301618 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619
1620 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001621 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622 cmdPtr = strpbrk(cmdPtr, " ");
1623
1624 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301625 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626
1627 /* remove empty spaces */
1628 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1629 cmdPtr++;
1630
1631 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1632 ret = sscanf(cmdPtr, "%31s ", buf);
1633 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301634 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001635
1636 ret = kstrtos32(buf, 10, &content);
1637 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301638 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001639
1640 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301641 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001642
1643 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001644 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645 cmdPtr = strpbrk(cmdPtr, " ");
1646
1647 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301648 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001649
1650 /* remove empty spaces */
1651 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1652 cmdPtr++;
1653
1654 /* burst length of PLM bursts */
1655 ret = sscanf(cmdPtr, "%31s ", buf);
1656 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301657 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658
1659 ret = kstrtos32(buf, 10, &content);
1660 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301661 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001662
1663 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301664 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001665
1666 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001667 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668 cmdPtr = strpbrk(cmdPtr, " ");
1669
1670 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301671 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672
1673 /* remove empty spaces */
1674 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1675 cmdPtr++;
1676
1677 /* desired tx power for transmission of PLM bursts */
1678 ret = sscanf(cmdPtr, "%31s ", buf);
1679 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301680 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001681
1682 ret = kstrtos32(buf, 10, &content);
1683 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301684 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685
1686 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301687 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688
1689 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001690 hdd_debug("desiredTxPwr %d",
1691 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692
Anurag Chouhan6d760662016-02-20 16:05:43 +05301693 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694 cmdPtr = strpbrk(cmdPtr, " ");
1695
1696 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301697 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698
1699 /* remove empty spaces */
1700 while ((SPACE_ASCII_VALUE == *cmdPtr)
1701 && ('\0' != *cmdPtr))
1702 cmdPtr++;
1703
1704 ret = sscanf(cmdPtr, "%31s ", buf);
1705 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301706 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001707
1708 ret = kstrtos32(buf, 16, &content);
1709 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301710 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001712 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001713 }
1714
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001715 hdd_debug("MC addr " MAC_ADDRESS_STR,
1716 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001717
1718 cmdPtr = strpbrk(cmdPtr, " ");
1719
1720 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301721 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722
1723 /* remove empty spaces */
1724 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1725 cmdPtr++;
1726
1727 /* number of channels */
1728 ret = sscanf(cmdPtr, "%31s ", buf);
1729 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301730 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731
1732 ret = kstrtos32(buf, 10, &content);
1733 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301734 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001735
1736 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301737 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001739 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001741 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742
1743 /* Channel numbers */
1744 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1745 cmdPtr = strpbrk(cmdPtr, " ");
1746
1747 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301748 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749
1750 /* remove empty spaces */
1751 while ((SPACE_ASCII_VALUE == *cmdPtr)
1752 && ('\0' != *cmdPtr))
1753 cmdPtr++;
1754
1755 ret = sscanf(cmdPtr, "%31s ", buf);
1756 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301757 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758
1759 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001760 if (ret < 0 || content <= 0 ||
1761 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301762 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763
1764 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001765 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766 }
1767 }
1768 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301769 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770}
1771#endif
1772
1773#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301774/**
1775 * wlan_hdd_ready_to_extwow() - Callback function for enable ext wow
1776 * @cookie: callback context
1777 * @is_success: suspend status of ext wow
1778 *
1779 * Return: none
1780 */
1781static void wlan_hdd_ready_to_extwow(void *cookie, bool is_success)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001782{
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301783 struct osif_request *request = NULL;
1784 struct enable_ext_wow_priv *priv = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001785
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301786 request = osif_request_get(cookie);
1787 if (!request) {
1788 hdd_err("Obselete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789 return;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301790 }
1791 priv = osif_request_priv(request);
1792 priv->ext_wow_should_suspend = is_success;
1793
1794 osif_request_complete(request);
1795 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001796}
1797
Jeff Johnsone44b7012017-09-10 15:25:47 -07001798static int hdd_enable_ext_wow(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001799 tpSirExtWoWParams arg_params)
1800{
1801 tSirExtWoWParams params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001802 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001803 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001804 int rc;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301805 struct enable_ext_wow_priv *priv = NULL;
1806 struct osif_request *request = NULL;
1807 void *cookie = NULL;
1808 struct osif_request_params hdd_params = {
1809 .priv_size = sizeof(*priv),
1810 .timeout_ms = WLAN_WAIT_TIME_READY_TO_EXTWOW,
1811 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301813 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001814
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301815 request = osif_request_alloc(&hdd_params);
1816 if (!request) {
1817 hdd_err("Request Allocation Failure");
1818 return -ENOMEM;
1819 }
1820 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821
Jeff Johnsond549efa2018-06-13 20:27:47 -07001822 status = sme_configure_ext_wow(hdd_ctx->mac_handle, &params,
1823 &wlan_hdd_ready_to_extwow,
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301824 cookie);
Jeff Johnsond549efa2018-06-13 20:27:47 -07001825 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001826 hdd_err("sme_configure_ext_wow returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07001827 status);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301828 rc = -EPERM;
1829 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830 }
1831
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301832 rc = osif_request_wait_for_response(request);
1833 if (rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001834 hdd_err("Failed to get ready to extwow");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301835 rc = -EPERM;
1836 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001837 }
1838
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301839 priv = osif_request_priv(request);
1840 if (!priv->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001841 hdd_err("Received ready to ExtWoW failure");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301842 rc = -EPERM;
1843 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844 }
1845
Wu Gao66454f12018-09-26 19:55:41 +08001846 if (ucfg_pmo_extwow_is_goto_suspend_enabled(hdd_ctx->psoc)) {
Jeff Johnson17d62672017-03-27 08:00:11 -07001847 hdd_info("Received ready to ExtWoW. Going to suspend");
1848
1849 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1850 if (rc < 0) {
1851 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1852 rc);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301853 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07001854 }
1855 rc = wlan_hdd_bus_suspend();
1856 if (rc) {
1857 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1858 rc);
1859 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301860 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07001861 }
1862 }
Wu Gao66454f12018-09-26 19:55:41 +08001863
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301864exit:
1865 osif_request_put(request);
1866 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001867}
1868
Jeff Johnsone44b7012017-09-10 15:25:47 -07001869static int hdd_enable_ext_wow_parser(struct hdd_adapter *adapter, int vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870 int value)
1871{
1872 tSirExtWoWParams params;
Jeff Johnson621cf972017-08-28 11:58:44 -07001873 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001874 int rc;
Wu Gao66454f12018-09-26 19:55:41 +08001875 uint8_t pin1, pin2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876
1877 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301878 if (rc)
1879 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001880
1881 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1882 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001883 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001884 return -EINVAL;
1885 }
1886
1887 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1888 hdd_ctx->is_extwow_app_type1_param_set)
1889 params.type = value;
1890 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1891 hdd_ctx->is_extwow_app_type2_param_set)
1892 params.type = value;
1893 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1894 hdd_ctx->is_extwow_app_type1_param_set &&
1895 hdd_ctx->is_extwow_app_type2_param_set)
1896 params.type = value;
1897 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001898 hdd_err("Set app params before enable it value %d",
1899 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900 return -EINVAL;
1901 }
1902
1903 params.vdev_id = vdev_id;
Wu Gao66454f12018-09-26 19:55:41 +08001904 pin1 = ucfg_pmo_extwow_app1_wakeup_pin_num(hdd_ctx->psoc);
1905 pin2 = ucfg_pmo_extwow_app2_wakeup_pin_num(hdd_ctx->psoc);
1906 params.wakeup_pin_num = pin1 | (pin2 << 8);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001907
1908 return hdd_enable_ext_wow(adapter, &params);
1909}
1910
Jeff Johnsond549efa2018-06-13 20:27:47 -07001911static int hdd_set_app_type1_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001912 tpSirAppType1Params arg_params)
1913{
1914 tSirAppType1Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001915 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001916
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301917 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918
Jeff Johnsond549efa2018-06-13 20:27:47 -07001919 status = sme_configure_app_type1_params(mac_handle, &params);
1920 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001921 hdd_err("sme_configure_app_type1_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07001922 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001923 return -EPERM;
1924 }
1925
1926 return 0;
1927}
1928
Jeff Johnsone44b7012017-09-10 15:25:47 -07001929static int hdd_set_app_type1_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001930 char *arg, int len)
1931{
Jeff Johnson621cf972017-08-28 11:58:44 -07001932 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933 char id[20], password[20];
1934 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001935 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936
1937 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301938 if (rc)
1939 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001940
1941 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001942 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001943 return -EINVAL;
1944 }
1945
1946 memset(&params, 0, sizeof(tSirAppType1Params));
Jeff Johnson1b780e42017-10-31 14:11:45 -07001947 params.vdev_id = adapter->session_id;
Jeff Johnson1e851a12017-10-28 14:36:12 -07001948 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001949
1950 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301951 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001952 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301953 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001955 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001956 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001957 params.identification_id, params.id_length,
1958 params.password, params.pass_length);
1959
Jeff Johnsond549efa2018-06-13 20:27:47 -07001960 return hdd_set_app_type1_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001961}
1962
Jeff Johnsond549efa2018-06-13 20:27:47 -07001963static int hdd_set_app_type2_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001964 tpSirAppType2Params arg_params)
1965{
1966 tSirAppType2Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001967 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001968
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301969 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970
Jeff Johnsond549efa2018-06-13 20:27:47 -07001971 status = sme_configure_app_type2_params(mac_handle, &params);
1972 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001973 hdd_err("sme_configure_app_type2_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07001974 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001975 return -EPERM;
1976 }
1977
1978 return 0;
1979}
1980
Jeff Johnsone44b7012017-09-10 15:25:47 -07001981static int hdd_set_app_type2_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001982 char *arg, int len)
1983{
Jeff Johnson621cf972017-08-28 11:58:44 -07001984 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05301986 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001987 tSirAppType2Params params;
1988 int ret;
1989
1990 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301991 if (ret)
1992 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993
1994 memset(&params, 0, sizeof(tSirAppType2Params));
1995
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05301996 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 -08001997 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
1998 (unsigned int *)&params.ip_device_ip,
1999 (unsigned int *)&params.ip_server_ip,
2000 (unsigned int *)&params.tcp_seq,
2001 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302002 (uint16_t *)&params.tcp_src_port,
2003 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004 (unsigned int *)&params.keepalive_init,
2005 (unsigned int *)&params.keepalive_min,
2006 (unsigned int *)&params.keepalive_max,
2007 (unsigned int *)&params.keepalive_inc,
2008 (unsigned int *)&params.tcp_tx_timeout_val,
2009 (unsigned int *)&params.tcp_rx_timeout_val);
2010
2011 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002012 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002013 return -EINVAL;
2014 }
2015
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002016 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
2017 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2018 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002019 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020 return -EINVAL;
2021 }
2022
2023 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2024 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002025 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002026 return -EINVAL;
2027 }
2028
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302029 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302030 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031
2032 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302033 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002034
Jeff Johnson1b780e42017-10-31 14:11:45 -07002035 params.vdev_id = adapter->session_id;
Wu Gao66454f12018-09-26 19:55:41 +08002036
2037 if (!params.tcp_src_port)
2038 params.tcp_src_port =
2039 ucfg_pmo_extwow_app2_tcp_src_port(hdd_ctx->psoc);
2040
2041 if (!params.tcp_dst_port)
2042 params.tcp_dst_port =
2043 ucfg_pmo_extwow_app2_tcp_dst_port(hdd_ctx->psoc);
2044
2045 if (!params.keepalive_init)
2046 params.keepalive_init =
2047 ucfg_pmo_extwow_app2_init_ping_interval(hdd_ctx->psoc);
2048
2049 if (!params.keepalive_min)
2050 params.keepalive_min =
2051 ucfg_pmo_extwow_app2_min_ping_interval(hdd_ctx->psoc);
2052
2053 if (!params.keepalive_max)
2054 params.keepalive_max =
2055 ucfg_pmo_extwow_app2_max_ping_interval(hdd_ctx->psoc);
2056
2057 if (!params.keepalive_inc)
2058 params.keepalive_inc =
2059 ucfg_pmo_extwow_app2_inc_ping_interval(hdd_ctx->psoc);
2060
2061 if (!params.tcp_tx_timeout_val)
2062 params.tcp_tx_timeout_val =
2063 ucfg_pmo_extwow_app2_tcp_tx_timeout(hdd_ctx->psoc);
2064
2065 if (!params.tcp_rx_timeout_val)
2066 params.tcp_rx_timeout_val =
2067 ucfg_pmo_extwow_app2_tcp_rx_timeout(hdd_ctx->psoc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002069 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002070 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002071 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2072 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2073 params.keepalive_init, params.keepalive_min,
2074 params.keepalive_max, params.keepalive_inc,
2075 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2076
Jeff Johnsond549efa2018-06-13 20:27:47 -07002077 return hdd_set_app_type2_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002078}
2079#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2080
2081/**
2082 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2083 * @pValue: Pointer to MAXTXPOWER command
2084 * @pDbm: Pointer to tx power
2085 *
2086 * This function parses the MAXTXPOWER command passed in the format
2087 * MAXTXPOWER<space>X(Tx power in dbm)
2088 *
2089 * For example input commands:
2090 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2091 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2092 *
2093 * Return: 0 for success non-zero for failure
2094 */
2095static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2096{
2097 uint8_t *inPtr = pValue;
2098 int tempInt;
2099 int v = 0;
2100 *pTxPower = 0;
2101
2102 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2103 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002104 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002105 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002106 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002107 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002108
2109 /* remove empty spaces */
2110 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2111 inPtr++;
2112
2113 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002114 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002115 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002116
2117 v = kstrtos32(inPtr, 10, &tempInt);
2118
2119 /* Range checking for passed parameter */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002120 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002121 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002122
2123 *pTxPower = tempInt;
2124
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002125 hdd_debug("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002126
2127 return 0;
2128} /* End of hdd_parse_setmaxtxpower_command */
2129
2130static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2131 char *extra, uint8_t n, uint8_t *len)
2132{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002133 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002134 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002135 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002136 }
2137
2138 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2139 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2140 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002141 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002142 }
Jeff Johnson68755312017-02-10 11:46:55 -08002143 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002144 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2145 (int)pCfg->nPassiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002146 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002147 }
Jeff Johnson68755312017-02-10 11:46:55 -08002148 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Srinivas Girigowdab9086af2017-10-14 14:41:13 -07002149 *len = scnprintf(extra, n, "GETDWELLTIME %u\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002150 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002151 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152 }
2153
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002154 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002155}
2156
Jeff Johnsone44b7012017-09-10 15:25:47 -07002157static int hdd_set_dwell_time(struct hdd_adapter *adapter, uint8_t *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002158{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002159 mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002160 struct hdd_config *pCfg;
2161 uint8_t *value = command;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302162 tSmeConfigParams *sme_config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002163 int val = 0, temp = 0;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302164 int retval = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002165
2166 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
Jeff Johnsonbacb4802018-08-20 09:31:17 -07002167 if (!pCfg || !mac_handle) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002168 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002169 return -EINVAL;
2170 }
2171
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302172 sme_config = qdf_mem_malloc(sizeof(*sme_config));
2173 if (!sme_config) {
2174 hdd_err("failed to allocate memory for sme_config");
2175 return -ENOMEM;
2176 }
2177 qdf_mem_zero(sme_config, sizeof(*sme_config));
Jeff Johnsond549efa2018-06-13 20:27:47 -07002178 sme_get_config_param(mac_handle, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002179
2180 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302181 if (drv_cmd_validate(command, 23))
2182 return -EINVAL;
2183
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002184 value = value + 24;
2185 temp = kstrtou32(value, 10, &val);
2186 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2187 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002188 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302189 retval = -EFAULT;
2190 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002191 }
2192 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302193 sme_config->csrConfig.nActiveMaxChnTime = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002194 sme_update_config(mac_handle, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002195 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302196 if (drv_cmd_validate(command, 24))
2197 return -EINVAL;
2198
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002199 value = value + 25;
2200 temp = kstrtou32(value, 10, &val);
2201 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2202 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002203 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302204 retval = -EFAULT;
2205 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002206 }
2207 pCfg->nPassiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302208 sme_config->csrConfig.nPassiveMaxChnTime = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002209 sme_update_config(mac_handle, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002210 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302211 if (drv_cmd_validate(command, 12))
2212 return -EINVAL;
2213
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002214 value = value + 13;
2215 temp = kstrtou32(value, 10, &val);
2216 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2217 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002218 hdd_err("argument passed for SETDWELLTIME is incorrect");
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302219 retval = -EFAULT;
2220 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002221 }
2222 pCfg->nActiveMaxChnTime = val;
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302223 sme_config->csrConfig.nActiveMaxChnTime = val;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002224 sme_update_config(mac_handle, sme_config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002225 } else {
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302226 retval = -EINVAL;
2227 goto free;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002228 }
2229
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302230free:
2231 qdf_mem_free(sme_config);
2232 return retval;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002233}
2234
Jeff Johnson253c0c22017-01-23 16:59:38 -08002235struct link_status_priv {
2236 uint8_t link_status;
2237};
2238
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302239#ifdef WLAN_AP_STA_CONCURRENCY
2240/**
2241 * hdd_conc_set_dwell_time() - Set Concurrent dwell time parameters
2242 * @adapter: Adapter upon which the command was received
2243 * @command: ASCII text command that is received
2244 *
2245 * Driver commands:
2246 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MAX <value>
2247 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MIN <value>
2248 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MAX <value>
2249 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MIN <value>
2250 *
2251 * Return: 0 for success non-zero for failure
2252 */
2253static int hdd_conc_set_dwell_time(hdd_context_t *hdd_ctx, uint8_t *command)
2254{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002255 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302256 struct hdd_config *p_cfg;
2257 u8 *value = command;
2258 tSmeConfigParams *sme_config;
2259 int val = 0, temp = 0;
2260 int retval = 0;
2261
2262 p_cfg = hdd_ctx->config;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002263 if (!p_cfg || !mac_handle) {
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302264 hdd_err("Argument passed for CONCSETDWELLTIME is incorrect");
2265 return -EINVAL;
2266 }
2267
2268 sme_config = qdf_mem_malloc(sizeof(*sme_config));
2269 if (!sme_config) {
2270 hdd_err("Failed to allocate memory for sme_config");
2271 return -ENOMEM;
2272 }
2273
2274 qdf_mem_zero(sme_config, sizeof(*sme_config));
Jeff Johnsond549efa2018-06-13 20:27:47 -07002275 sme_get_config_param(mac_handle, sme_config);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302276
2277 if (strncmp(command, "CONCSETDWELLTIME ACTIVE MAX", 27) == 0) {
2278 if (drv_cmd_validate(command, 27)) {
2279 hdd_err("Invalid driver command");
2280 retval = -EINVAL;
2281 goto sme_config_free;
2282 }
2283
2284 value = value + 28;
2285 temp = kstrtou32(value, 10, &val);
Harprit Chhabada4691a472018-12-07 11:22:48 -08002286 if (temp != 0 ||
2287 cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC, val)) {
2288 hdd_err("CONC ACTIVE MAX value %d incorrect", val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302289 retval = -EFAULT;
2290 goto sme_config_free;
2291 }
Harprit Chhabada4691a472018-12-07 11:22:48 -08002292 ucfg_scan_cfg_set_conc_active_dwelltime(hdd_ctx->psoc, val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302293 } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MAX", 28) == 0) {
2294 if (drv_cmd_validate(command, 28)) {
2295 hdd_err("Invalid driver command");
2296 retval = -EINVAL;
2297 goto sme_config_free;
2298 }
2299
2300 value = value + 29;
2301 temp = kstrtou32(value, 10, &val);
Harprit Chhabada4691a472018-12-07 11:22:48 -08002302 if (temp != 0 ||
2303 cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC, val)) {
2304 hdd_err("CONC PASSIVE MAX val %d incorrect", val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302305 retval = -EFAULT;
2306 goto sme_config_free;
2307 }
Harprit Chhabada4691a472018-12-07 11:22:48 -08002308 ucfg_scan_cfg_set_conc_passive_dwelltime(hdd_ctx->psoc, val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302309 } else {
2310 retval = -EINVAL;
2311 }
2312
2313sme_config_free:
2314 qdf_mem_free(sme_config);
2315 return retval;
2316}
2317#endif
2318
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002319static void hdd_get_link_status_cb(uint8_t status, void *context)
2320{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002321 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002322 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002323
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002324 request = osif_request_get(context);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002325 if (!request) {
2326 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002327 return;
2328 }
2329
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002330 priv = osif_request_priv(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002331 priv->link_status = status;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002332 osif_request_complete(request);
2333 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002334}
2335
2336/**
2337 * wlan_hdd_get_link_status() - get link status
Jeff Johnson25c77342017-10-02 13:28:03 -07002338 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339 *
2340 * This function sends a request to query the link status and waits
2341 * on a timer to invoke the callback. if the callback is invoked then
2342 * latest link status shall be returned or otherwise cached value
2343 * will be returned.
2344 *
2345 * Return: On success, link status shall be returned.
2346 * On error or not associated, link status 0 will be returned.
2347 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002348static int wlan_hdd_get_link_status(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002349{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002350 struct hdd_station_ctx *sta_ctx;
2351 QDF_STATUS status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002352 int ret;
2353 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002354 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002355 struct link_status_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002356 static const struct osif_request_params params = {
Jeff Johnson253c0c22017-01-23 16:59:38 -08002357 .priv_size = sizeof(*priv),
2358 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2359 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002360
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05302361 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002362 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2363 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002364 return 0;
2365 }
2366
Krunal Sonibe766b02016-03-10 13:00:44 -08002367 if ((QDF_STA_MODE != adapter->device_mode) &&
2368 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002369 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07002370 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002371 adapter->device_mode);
2372 return 0;
2373 }
2374
Jeff Johnsond377dce2017-10-04 10:32:42 -07002375 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2376 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002377 /* If not associated, then expected link status return
2378 * value is 0
2379 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002380 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002381 return 0;
2382 }
2383
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002384 request = osif_request_alloc(&params);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002385 if (!request) {
2386 hdd_err("Request allocation failure");
2387 return 0;
2388 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002389 cookie = osif_request_cookie(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002390
Jeff Johnsond549efa2018-06-13 20:27:47 -07002391 status = sme_get_link_status(adapter->hdd_ctx->mac_handle,
2392 hdd_get_link_status_cb,
2393 cookie, adapter->session_id);
2394 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002395 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002396 /* return a cached value */
2397 } else {
2398 /* request is sent -- wait for the response */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002399 ret = osif_request_wait_for_response(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002400 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002401 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002402 /* return a cached value */
2403 } else {
2404 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002405 priv = osif_request_priv(request);
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07002406 adapter->link_status = priv->link_status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002407 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002408 }
2409
Jeff Johnson253c0c22017-01-23 16:59:38 -08002410 /*
2411 * either we never sent a request, we sent a request and
2412 * received a response or we sent a request and timed out.
2413 * regardless we are done with the request.
2414 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002415 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002416
2417 /* either callback updated adapter stats or it has cached data */
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07002418 return adapter->link_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002419}
2420
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002421static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2422{
2423 int payload_len;
2424 struct sk_buff *skb;
2425 struct nlmsghdr *nlh;
2426 uint8_t *data;
2427
2428 payload_len = ETH_ALEN;
2429
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002430 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002431 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002432 return;
2433 }
2434
2435 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2436 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002437 hdd_err("nlmsg_new() failed for msg size[%d]",
2438 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002439 return;
2440 }
2441
2442 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2443
2444 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002445 hdd_err("nlmsg_put() failed for msg size[%d]",
2446 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002447
2448 kfree_skb(skb);
2449 return;
2450 }
2451
2452 data = nlmsg_data(nlh);
2453 memcpy(data, MacAddr, ETH_ALEN);
2454
2455 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002456 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2457 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002458 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002459}
2460
2461
2462/**
2463 * hdd_ParseuserParams - return a pointer to the next argument
2464 * @pValue: Input argument string
2465 * @ppArg: Output pointer to the next argument
2466 *
2467 * This function parses argument stream and finds the pointer
2468 * to the next argument
2469 *
2470 * Return: 0 if the next argument found; -EINVAL otherwise
2471 */
2472static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2473{
2474 uint8_t *pVal;
2475
2476 pVal = strnchr(pValue, strlen(pValue), ' ');
2477
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002478 if (NULL == pVal) /* no argument remains */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002479 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002480 else if (SPACE_ASCII_VALUE != *pVal)/* no space after the current arg */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002481 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002482
2483 pVal++;
2484
2485 /* remove empty spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002486 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002487 pVal++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002488
2489 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002490 if ('\0' == *pVal)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002491 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002492
2493 *ppArg = pVal;
2494
2495 return 0;
2496}
2497
2498/**
2499 * hdd_parse_ibsstx_fail_event_params - Parse params
2500 * for SETIBSSTXFAILEVENT
2501 * @pValue: Input ibss tx fail event argument
2502 * @tx_fail_count: (Output parameter) Tx fail counter
2503 * @pid: (Output parameter) PID
2504 *
2505 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2506 */
2507static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2508 uint8_t *tx_fail_count,
2509 uint16_t *pid)
2510{
2511 uint8_t *param = NULL;
2512 int ret;
2513
2514 ret = hdd_parse_user_params(pValue, &param);
2515
2516 if (0 == ret && NULL != param) {
2517 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2518 ret = -EINVAL;
2519 goto done;
2520 }
2521 } else {
2522 goto done;
2523 }
2524
2525 if (0 == *tx_fail_count) {
2526 *pid = 0;
2527 goto done;
2528 }
2529
2530 pValue = param;
2531 pValue++;
2532
2533 ret = hdd_parse_user_params(pValue, &param);
2534
2535 if (0 == ret) {
2536 if (1 != sscanf(param, "%hu", pid)) {
2537 ret = -EINVAL;
2538 goto done;
2539 }
2540 } else {
2541 goto done;
2542 }
2543
2544done:
2545 return ret;
2546}
2547
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002548#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002549/**
2550 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2551 * @pValue: Pointer to data
2552 * @pEseBcnReq: Output pointer to store parsed ie information
2553 *
2554 * This function parses the ese beacon request passed in the format
2555 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2556 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2557 * <space>Scan Mode N<space>Meas Duration N
2558 *
2559 * If the Number of bcn req fields (N) does not match with the
2560 * actual number of fields passed then take N.
2561 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2562 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2563 * This function does not take care of removing duplicate channels from the
2564 * list
2565 *
2566 * Return: 0 for success non-zero for failure
2567 */
2568static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2569 tCsrEseBeaconReq *pEseBcnReq)
2570{
2571 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002572 uint8_t input = 0;
2573 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002574 int j = 0, i = 0, v = 0;
2575 char buf[32];
2576
2577 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002578 if (NULL == inPtr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002579 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002580 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002581 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002582
2583 /* remove empty spaces */
2584 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2585 inPtr++;
2586
2587 /* no argument followed by spaces */
2588 if ('\0' == *inPtr)
2589 return -EINVAL;
2590
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002591 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002592 v = sscanf(inPtr, "%31s ", buf);
2593 if (1 != v)
2594 return -EINVAL;
2595
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002596 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002597 if (v < 0)
2598 return -EINVAL;
2599
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002600 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2601 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002602
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002603 hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002604
2605 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2606 for (i = 0; i < 4; i++) {
2607 /*
2608 * inPtr pointing to the beginning of 1st space
2609 * after number of ie fields
2610 */
2611 inPtr = strpbrk(inPtr, " ");
2612 /* no ie data after the number of ie fields argument */
2613 if (NULL == inPtr)
2614 return -EINVAL;
2615
2616 /* remove empty space */
2617 while ((SPACE_ASCII_VALUE == *inPtr)
2618 && ('\0' != *inPtr))
2619 inPtr++;
2620
2621 /*
2622 * no ie data after the number of ie fields
2623 * argument and spaces
2624 */
2625 if ('\0' == *inPtr)
2626 return -EINVAL;
2627
2628 v = sscanf(inPtr, "%31s ", buf);
2629 if (1 != v)
2630 return -EINVAL;
2631
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002632 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002633 if (v < 0)
2634 return -EINVAL;
2635
2636 switch (i) {
2637 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002638 if (!tempInt) {
2639 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002640 tempInt);
2641 return -EINVAL;
2642 }
2643 pEseBcnReq->bcnReq[j].measurementToken =
2644 tempInt;
2645 break;
2646
2647 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002648 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002649 (tempInt >
2650 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002651 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002652 tempInt);
2653 return -EINVAL;
2654 }
2655 pEseBcnReq->bcnReq[j].channel = tempInt;
2656 break;
2657
2658 case 2: /* Scan mode */
2659 if ((tempInt < eSIR_PASSIVE_SCAN)
2660 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002661 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002662 tempInt);
2663 return -EINVAL;
2664 }
2665 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2666 break;
2667
2668 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002669 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002670 && (pEseBcnReq->bcnReq[j].scanMode !=
2671 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002672 (pEseBcnReq->bcnReq[j].scanMode ==
2673 eSIR_BEACON_TABLE)) {
2674 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002675 tempInt);
2676 return -EINVAL;
2677 }
2678 pEseBcnReq->bcnReq[j].measurementDuration =
2679 tempInt;
2680 break;
2681 }
2682 }
2683 }
2684
2685 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002686 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002687 j,
2688 pEseBcnReq->bcnReq[j].measurementToken,
2689 pEseBcnReq->bcnReq[j].channel,
2690 pEseBcnReq->bcnReq[j].scanMode,
2691 pEseBcnReq->bcnReq[j].measurementDuration);
2692 }
2693
2694 return 0;
2695}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002696
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002697/**
2698 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2699 * @pValue: Pointer to input data
2700 * @pCckmIe: Pointer to output cckm Ie
2701 * @pCckmIeLen: Pointer to output cckm ie length
2702 *
2703 * This function parses the SETCCKM IE command
2704 * SETCCKMIE<space><ie data>
2705 *
2706 * Return: 0 for success non-zero for failure
2707 */
2708static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2709 uint8_t *pCckmIeLen)
2710{
2711 uint8_t *inPtr = pValue;
2712 uint8_t *dataEnd;
2713 int j = 0;
2714 int i = 0;
2715 uint8_t tempByte = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002716
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002717 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2718 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002719 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002721 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002722 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002723
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002724 /* remove empty spaces */
2725 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2726 inPtr++;
2727 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002728 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002729 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002730
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002731 /* find the length of data */
2732 dataEnd = inPtr;
2733 while (('\0' != *dataEnd)) {
2734 dataEnd++;
2735 ++(*pCckmIeLen);
2736 }
2737 if (*pCckmIeLen <= 0)
2738 return -EINVAL;
2739 /*
2740 * Allocate the number of bytes based on the number of input characters
2741 * whether it is even or odd.
2742 * if the number of input characters are even, then we need N / 2 byte.
2743 * if the number of input characters are odd, then we need do
2744 * (N + 1) / 2 to compensate rounding off.
2745 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2746 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2747 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302748 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002749 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002750 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002751 return -ENOMEM;
2752 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002753 /*
2754 * the buffer received from the upper layer is character buffer,
2755 * we need to prepare the buffer taking 2 characters in to a U8 hex
2756 * decimal number for example 7f0000f0...form a buffer to contain
2757 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2758 */
2759 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2760 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2761 (hex_to_bin(inPtr[j + 1]));
2762 (*pCckmIe)[i++] = tempByte;
2763 }
2764 *pCckmIeLen = i;
2765 return 0;
2766}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002767#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002768
Jeff Johnson25c77342017-10-02 13:28:03 -07002769int wlan_hdd_set_mc_rate(struct hdd_adapter *adapter, int targetRate)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002770{
2771 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302772 QDF_STATUS status;
Jeff Johnson25c77342017-10-02 13:28:03 -07002773 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsond549efa2018-06-13 20:27:47 -07002774 struct hdd_config *pConfig;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05302775 bool bval = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002776
Jeff Johnson6da2db12017-09-03 09:18:52 -07002777 if (hdd_ctx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002778 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002779 return -EINVAL;
2780 }
Jeff Johnson25c77342017-10-02 13:28:03 -07002781 if ((QDF_IBSS_MODE != adapter->device_mode) &&
2782 (QDF_SAP_MODE != adapter->device_mode) &&
2783 (QDF_STA_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002784 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07002785 qdf_opmode_str(adapter->device_mode),
2786 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002787 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002788 return -EINVAL;
2789 }
Jeff Johnson6da2db12017-09-03 09:18:52 -07002790 pConfig = hdd_ctx->config;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05302791
2792 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
2793 if (!QDF_IS_STATUS_SUCCESS(status)) {
2794 hdd_err("unable to get vht_enable2x2");
2795 return -EINVAL;
2796 }
2797 rateUpdate.nss = (bval == 0) ? 0 : 1;
2798
Jeff Johnson25c77342017-10-02 13:28:03 -07002799 rateUpdate.dev_mode = adapter->device_mode;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002800 rateUpdate.mcastDataRate24GHz = targetRate;
2801 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2802 rateUpdate.mcastDataRate5GHz = targetRate;
2803 rateUpdate.bcastDataRate = -1;
Jeff Johnson1e851a12017-10-28 14:36:12 -07002804 qdf_copy_macaddr(&rateUpdate.bssid, &adapter->mac_addr);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002805 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002806 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
Dustin Brown458027c2018-10-19 12:26:27 -07002807 qdf_opmode_str(adapter->device_mode), adapter->device_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07002808 status = sme_send_rate_update_ind(hdd_ctx->mac_handle, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302809 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002810 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002811 return -EFAULT;
2812 }
2813 return 0;
2814}
2815
Jeff Johnsone44b7012017-09-10 15:25:47 -07002816static int drv_cmd_p2p_dev_addr(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002817 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002818 uint8_t *command,
2819 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002820 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002821{
Dustin Brownee220712018-04-19 16:24:23 -07002822 struct qdf_mac_addr *addr = &hdd_ctx->p2p_device_address;
2823 size_t user_size = qdf_min(sizeof(addr->bytes),
2824 (size_t)priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002825
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302826 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002827 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002828 adapter->session_id,
Dustin Brownee220712018-04-19 16:24:23 -07002829 (unsigned int)(*(addr->bytes + 2) << 24 |
2830 *(addr->bytes + 3) << 16 |
2831 *(addr->bytes + 4) << 8 |
2832 *(addr->bytes + 5))));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002833
Dustin Brownee220712018-04-19 16:24:23 -07002834 if (copy_to_user(priv_data->buf, addr->bytes, user_size)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002835 hdd_err("failed to copy data to user buffer");
Dustin Brownee220712018-04-19 16:24:23 -07002836 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002837 }
2838
Dustin Brownee220712018-04-19 16:24:23 -07002839 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002840}
2841
2842/**
2843 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2844 * @adapter: Adapter on which the command was received
2845 * @hdd_ctx: HDD global context
2846 * @command: Entire driver command received from userspace
2847 * @command_len: Length of @command
2848 * @priv_data: Pointer to ioctl private data structure
2849 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07002850 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002851 * command to the actual command processor within the P2P module.
2852 *
2853 * Return: 0 on success, non-zero on failure
2854 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002855static int drv_cmd_p2p_set_noa(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002856 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002857 uint8_t *command,
2858 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002859 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002860{
2861 return hdd_set_p2p_noa(adapter->dev, command);
2862}
2863
2864/**
2865 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2866 * @adapter: Adapter on which the command was received
2867 * @hdd_ctx: HDD global context
2868 * @command: Entire driver command received from userspace
2869 * @command_len: Length of @command
2870 * @priv_data: Pointer to ioctl private data structure
2871 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07002872 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002873 * command to the actual command processor within the P2P module.
2874 *
2875 * Return: 0 on success, non-zero on failure
2876 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002877static int drv_cmd_p2p_set_ps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002878 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002879 uint8_t *command,
2880 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002881 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002882{
2883 return hdd_set_p2p_opps(adapter->dev, command);
2884}
2885
Jeff Johnsone44b7012017-09-10 15:25:47 -07002886static int drv_cmd_set_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002887 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002888 uint8_t *command,
2889 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002890 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002891{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002892 int err;
2893 uint8_t band;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002894
2895 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002896 * Parse the band value passed from userspace. The first 8 bytes
2897 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002898 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002899 err = kstrtou8(command + command_len + 1, 10, &band);
2900 if (err) {
2901 hdd_err("error %d parsing userspace band parameter", err);
2902 return err;
2903 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002904
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002905 return hdd_reg_set_band(adapter->dev, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002906}
2907
Jeff Johnsone44b7012017-09-10 15:25:47 -07002908static int drv_cmd_set_wmmps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002909 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002910 uint8_t *command,
2911 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002912 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002913{
2914 return hdd_wmmps_helper(adapter, command);
2915}
2916
Jeff Johnsone44b7012017-09-10 15:25:47 -07002917static inline int drv_cmd_country(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002918 struct hdd_context *hdd_ctx,
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002919 uint8_t *command,
2920 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002921 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002922{
Sourav Mohapatraa30c4572018-05-22 11:18:39 +05302923 char *country_code;
2924
2925 country_code = strnchr(command, strlen(command), ' ');
2926 /* no argument after the command */
2927 if (!country_code)
2928 return -EINVAL;
2929
2930 /* no space after the command */
2931 if (*country_code != SPACE_ASCII_VALUE)
2932 return -EINVAL;
2933
2934 country_code++;
2935
2936 /* removing empty spaces */
2937 while ((*country_code == SPACE_ASCII_VALUE) &&
2938 (*country_code != '\0'))
2939 country_code++;
2940
2941 /* no or less than 2 arguments followed by spaces */
2942 if (*country_code == '\0' || *(country_code + 1) == '\0')
2943 return -EINVAL;
2944
2945 return hdd_reg_set_country(hdd_ctx, country_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002946}
2947
Jeff Johnsone44b7012017-09-10 15:25:47 -07002948static int drv_cmd_set_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002949 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002950 uint8_t *command,
2951 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002952 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002953{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002954 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002955 uint8_t *value = command;
2956 int8_t rssi = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08002957 uint8_t lookup_threshold = cfg_default(
2958 CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302959 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002960
2961 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2962 value = value + command_len + 1;
2963
2964 /* Convert the value from ascii to integer */
2965 ret = kstrtos8(value, 10, &rssi);
2966 if (ret < 0) {
2967 /*
2968 * If the input value is greater than max value of datatype,
2969 * then also kstrtou8 fails
2970 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002971 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08002972 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
2973 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002974 ret = -EINVAL;
2975 goto exit;
2976 }
2977
Wu Gao1ab05582018-11-08 16:22:49 +08002978 lookup_threshold = abs(rssi);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002979
Wu Gao1ab05582018-11-08 16:22:49 +08002980 if (!cfg_in_range(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD,
2981 lookup_threshold)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002982 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08002983 lookup_threshold,
2984 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
2985 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002986 ret = -EINVAL;
2987 goto exit;
2988 }
2989
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302990 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002991 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
Wu Gao1ab05582018-11-08 16:22:49 +08002992 adapter->session_id, lookup_threshold));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002993 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08002994 lookup_threshold);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002995
Jeff Johnsond549efa2018-06-13 20:27:47 -07002996 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002997 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08002998 lookup_threshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302999 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003000 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003001 ret = -EPERM;
3002 goto exit;
3003 }
3004
3005exit:
3006 return ret;
3007}
3008
Jeff Johnsone44b7012017-09-10 15:25:47 -07003009static int drv_cmd_get_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003010 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003011 uint8_t *command,
3012 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003013 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014{
3015 int ret = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08003016 uint8_t lookup_threshold =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003017 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle);
Wu Gao1ab05582018-11-08 16:22:49 +08003018 int rssi = (-1) * lookup_threshold;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003019 char extra[32];
3020 uint8_t len = 0;
3021
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303022 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003023 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
Wu Gao1ab05582018-11-08 16:22:49 +08003024 adapter->session_id, lookup_threshold));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003025
3026 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303027 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003028 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003029 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003030 ret = -EFAULT;
3031 }
3032
3033 return ret;
3034}
3035
Jeff Johnsone44b7012017-09-10 15:25:47 -07003036static int drv_cmd_set_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003037 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003038 uint8_t *command,
3039 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003040 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003041{
3042 int ret = 0;
3043 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003044 uint8_t roam_scan_period = 0;
3045 uint16_t empty_scan_refresh_period =
3046 cfg_default(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003047
3048 /* input refresh period is in terms of seconds */
3049
3050 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3051 value = value + command_len + 1;
3052
3053 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003054 ret = kstrtou8(value, 10, &roam_scan_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055 if (ret < 0) {
3056 /*
3057 * If the input value is greater than max value of datatype,
3058 * then also kstrtou8 fails
3059 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003060 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003061 (cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000),
3062 (cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003063 ret = -EINVAL;
3064 goto exit;
3065 }
3066
Wu Gao1ab05582018-11-08 16:22:49 +08003067 if (!cfg_in_range(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD,
3068 roam_scan_period)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003069 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003070 roam_scan_period,
3071 (cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000),
3072 (cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003073 ret = -EINVAL;
3074 goto exit;
3075 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303076 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003077 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
Wu Gao1ab05582018-11-08 16:22:49 +08003078 adapter->session_id, roam_scan_period));
3079 empty_scan_refresh_period = roam_scan_period * 1000;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003080
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003081 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003082 roam_scan_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003083
Jeff Johnsond549efa2018-06-13 20:27:47 -07003084 sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003085 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003086 empty_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003087
3088exit:
3089 return ret;
3090}
3091
Jeff Johnsone44b7012017-09-10 15:25:47 -07003092static int drv_cmd_get_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003093 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003094 uint8_t *command,
3095 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003096 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003097{
3098 int ret = 0;
3099 uint16_t nEmptyScanRefreshPeriod =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003100 sme_get_empty_scan_refresh_period(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003102 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003103
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303104 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003105 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003106 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003107 nEmptyScanRefreshPeriod));
3108 len = scnprintf(extra, sizeof(extra), "%s %d",
3109 "GETROAMSCANPERIOD",
3110 (nEmptyScanRefreshPeriod / 1000));
3111 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303112 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003113 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003114 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003115 ret = -EFAULT;
3116 }
3117
3118 return ret;
3119}
3120
Jeff Johnsone44b7012017-09-10 15:25:47 -07003121static int drv_cmd_set_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003122 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003123 uint8_t *command,
3124 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003125 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003126{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003127 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003128 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003129 uint8_t roam_scan_refresh_period = 0;
3130 uint16_t neighbor_scan_refresh_period =
3131 cfg_default(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003132
3133 /* input refresh period is in terms of seconds */
3134 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3135 value = value + command_len + 1;
3136
3137 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003138 ret = kstrtou8(value, 10, &roam_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003139 if (ret < 0) {
3140 /*
3141 * If the input value is greater than max value of datatype,
3142 * then also kstrtou8 fails
3143 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003144 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003145 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003146 / 1000),
Wu Gao1ab05582018-11-08 16:22:49 +08003147 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003148 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003149 ret = -EINVAL;
3150 goto exit;
3151 }
Wu Gao1ab05582018-11-08 16:22:49 +08003152
3153 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD,
3154 roam_scan_refresh_period)) {
3155 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3156 roam_scan_refresh_period,
3157 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3158 / 1000),
3159 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3160 / 1000));
3161 ret = -EINVAL;
3162 goto exit;
3163 }
3164 neighbor_scan_refresh_period = roam_scan_refresh_period * 1000;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003165
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003166 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003167 neighbor_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003168
Jeff Johnsond549efa2018-06-13 20:27:47 -07003169 sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003170 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003171 neighbor_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003172
3173exit:
3174 return ret;
3175}
3176
Jeff Johnsone44b7012017-09-10 15:25:47 -07003177static int drv_cmd_get_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003178 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003179 uint8_t *command,
3180 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003181 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003182{
3183 int ret = 0;
3184 uint16_t value =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003185 sme_get_neighbor_scan_refresh_period(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003186 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003187 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003188
3189 len = scnprintf(extra, sizeof(extra), "%s %d",
3190 "GETROAMSCANREFRESHPERIOD",
3191 (value / 1000));
3192 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303193 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003194 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003195 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003196 ret = -EFAULT;
3197 }
3198
3199 return ret;
3200}
3201
Jeff Johnsone44b7012017-09-10 15:25:47 -07003202static int drv_cmd_set_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003203 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003204 uint8_t *command,
3205 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003206 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003207{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003208 mac_handle_t mac_handle;
3209 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003210 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003211 uint8_t roam_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003212
3213 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3214 value = value + SIZE_OF_SETROAMMODE + 1;
3215
3216 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003217 ret = kstrtou8(value, 10, &roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003218 if (ret < 0) {
3219 /*
3220 * If the input value is greater than max value of datatype,
3221 * then also kstrtou8 fails
3222 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003223 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003224 cfg_min(CFG_LFR_FEATURE_ENABLED),
3225 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003226 ret = -EINVAL;
3227 goto exit;
3228 }
Wu Gao1ab05582018-11-08 16:22:49 +08003229
3230 if (!cfg_in_range(CFG_LFR_FEATURE_ENABLED, roam_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003231 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003232 roam_mode,
3233 cfg_min(CFG_LFR_FEATURE_ENABLED),
3234 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003235 ret = -EINVAL;
3236 goto exit;
3237 }
3238
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003239 hdd_debug("Received Command to Set Roam Mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003240 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003241 /*
3242 * Note that
3243 * SETROAMMODE 0 is to enable LFR while
3244 * SETROAMMODE 1 is to disable LFR, but
3245 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3246 * enable/disable. So, we have to invert the value
3247 * to call sme_update_is_fast_roam_ini_feature_enabled.
3248 */
Wu Gao1ab05582018-11-08 16:22:49 +08003249 if (roam_mode) {
3250 /* Roam enable */
3251 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
3252 } else {
3253 /* Roam disable */
3254 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
3255 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003256
Wu Gao1ab05582018-11-08 16:22:49 +08003257 ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)roam_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07003258 mac_handle = hdd_ctx->mac_handle;
Wu Gao1ab05582018-11-08 16:22:49 +08003259 if (roam_mode) {
3260 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3261 (bool)roam_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07003262 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
3263 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003264 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003265 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07003266 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
3267 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003268 roam_mode);
3269 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3270 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003271 }
3272
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003273exit:
3274 return ret;
3275}
3276
Jeff Johnsone44b7012017-09-10 15:25:47 -07003277static int drv_cmd_get_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003278 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003279 uint8_t *command,
3280 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003281 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003282{
3283 int ret = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08003284 bool roam_mode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003285 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003286 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003287
3288 /*
3289 * roamMode value shall be inverted because the sementics is different.
3290 */
Wu Gao1ab05582018-11-08 16:22:49 +08003291 if (roam_mode)
3292 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003293 else
Wu Gao1ab05582018-11-08 16:22:49 +08003294 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003295
Wu Gao1ab05582018-11-08 16:22:49 +08003296 len = scnprintf(extra, sizeof(extra), "%s %d", command, roam_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303297 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003298 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003299 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003300 ret = -EFAULT;
3301 }
3302
3303 return ret;
3304}
3305
Jeff Johnsone44b7012017-09-10 15:25:47 -07003306static int drv_cmd_set_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003307 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003308 uint8_t *command,
3309 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003310 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003311{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003312 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003313 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003314 uint8_t roam_rssi_diff = cfg_default(CFG_LFR_ROAM_RSSI_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003315
3316 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3317 value = value + command_len + 1;
3318
3319 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003320 ret = kstrtou8(value, 10, &roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003321 if (ret < 0) {
3322 /*
3323 * If the input value is greater than max value of datatype,
3324 * then also kstrtou8 fails
3325 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003326 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003327 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3328 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003329 ret = -EINVAL;
3330 goto exit;
3331 }
3332
Wu Gao1ab05582018-11-08 16:22:49 +08003333 if (!cfg_in_range(CFG_LFR_ROAM_RSSI_DIFF, roam_rssi_diff)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003334 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003335 roam_rssi_diff,
3336 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3337 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003338 ret = -EINVAL;
3339 goto exit;
3340 }
3341
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003342 hdd_debug("Received Command to Set roam rssi diff = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003343 roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003344
Jeff Johnsond549efa2018-06-13 20:27:47 -07003345 sme_update_roam_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003346 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003347 roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003348
3349exit:
3350 return ret;
3351}
3352
Jeff Johnsone44b7012017-09-10 15:25:47 -07003353static int drv_cmd_get_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003354 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003355 uint8_t *command,
3356 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003357 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003358{
3359 int ret = 0;
3360 uint8_t roamRssiDiff =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003361 sme_get_roam_rssi_diff(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003362 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003363 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303365 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003366 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003367 adapter->session_id, roamRssiDiff));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003368
3369 len = scnprintf(extra, sizeof(extra), "%s %d",
3370 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303371 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003372
3373 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003374 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003375 ret = -EFAULT;
3376 }
3377
3378 return ret;
3379}
3380
Jeff Johnsone44b7012017-09-10 15:25:47 -07003381static int drv_cmd_get_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003382 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003383 uint8_t *command,
3384 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003385 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003386{
3387 int ret = 0;
3388 int band = -1;
3389 char extra[32];
3390 uint8_t len = 0;
3391
3392 hdd_get_band_helper(hdd_ctx, &band);
3393
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303394 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003395 TRACE_CODE_HDD_GETBAND_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003396 adapter->session_id, band));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003397
3398 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303399 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003400
3401 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003402 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403 ret = -EFAULT;
3404 }
3405
3406 return ret;
3407}
3408
Jeff Johnsone44b7012017-09-10 15:25:47 -07003409static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003410 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003411 uint8_t *command,
3412 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003413 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003414{
3415 return hdd_parse_set_roam_scan_channels(adapter, command);
3416}
3417
Jeff Johnsone44b7012017-09-10 15:25:47 -07003418static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003419 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003420 uint8_t *command,
3421 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003422 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423{
3424 int ret = 0;
3425 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3426 uint8_t numChannels = 0;
3427 uint8_t j = 0;
3428 char extra[128] = { 0 };
3429 int len;
3430
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303431 if (QDF_STATUS_SUCCESS !=
Jeff Johnsond549efa2018-06-13 20:27:47 -07003432 sme_get_roam_scan_channel_list(hdd_ctx->mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433 ChannelList,
3434 &numChannels,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003435 adapter->session_id)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003436 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003437 ret = -EFAULT;
3438 goto exit;
3439 }
3440
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303441 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003442 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003443 adapter->session_id, numChannels));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003444 /*
3445 * output channel list is of the format
3446 * [Number of roam scan channels][Channel1][Channel2]...
3447 * copy the number of channels in the 0th index
3448 */
3449 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3450 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303451 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452 len += scnprintf(extra + len, sizeof(extra) - len,
3453 " %d", ChannelList[j]);
3454
Anurag Chouhan6d760662016-02-20 16:05:43 +05303455 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003456 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003457 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003458 ret = -EFAULT;
3459 goto exit;
3460 }
3461
3462exit:
3463 return ret;
3464}
3465
Jeff Johnsone44b7012017-09-10 15:25:47 -07003466static int drv_cmd_get_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003467 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003468 uint8_t *command,
3469 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003470 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003471{
3472 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003473 mac_handle_t mac_handle = hdd_ctx->mac_handle;
3474 bool eseMode = sme_get_is_ese_feature_enabled(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003475 char extra[32];
3476 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003477 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003478
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003479 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003480 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003481 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003482 * then this operation is not permitted (return FAILURE)
3483 */
3484 if (eseMode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003485 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07003486 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003487 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003488 ret = -EPERM;
3489 goto exit;
3490 }
3491
3492 len = scnprintf(extra, sizeof(extra), "%s %d",
3493 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303494 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003495 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003496 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003497 ret = -EFAULT;
3498 goto exit;
3499 }
3500
3501exit:
3502 return ret;
3503}
3504
Jeff Johnsone44b7012017-09-10 15:25:47 -07003505static int drv_cmd_get_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003506 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003507 uint8_t *command,
3508 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003509 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003510{
3511 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003512 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003513 char extra[32];
3514 uint8_t len = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003515 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003516
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003517 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003518 /*
3519 * Check if the features OKC/ESE/11R are supported simultaneously,
3520 * then this operation is not permitted (return FAILURE)
3521 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003522 if (pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07003523 sme_get_is_ese_feature_enabled(mac_handle) &&
3524 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003525 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003526 ret = -EPERM;
3527 goto exit;
3528 }
3529
3530 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003531 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303532 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003533
3534 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003535 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003536 ret = -EFAULT;
3537 goto exit;
3538 }
3539
3540exit:
3541 return ret;
3542}
3543
Jeff Johnsone44b7012017-09-10 15:25:47 -07003544static int drv_cmd_get_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003545 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003546 uint8_t *command,
3547 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003548 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003549{
3550 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003551 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003552 char extra[32];
3553 uint8_t len = 0;
3554
3555 len = scnprintf(extra, sizeof(extra), "%s %d",
3556 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303557 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003558
3559 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003560 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003561 ret = -EFAULT;
3562 }
3563
3564 return ret;
3565}
3566
Jeff Johnsone44b7012017-09-10 15:25:47 -07003567static int drv_cmd_get_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003568 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003569 uint8_t *command,
3570 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003571 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003572{
3573 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003574 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003575 char extra[32];
3576 uint8_t len = 0;
3577
3578 len = scnprintf(extra, sizeof(extra), "%s %d",
3579 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303580 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003581
3582 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003583 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003584 ret = -EFAULT;
3585 }
3586
3587 return ret;
3588}
3589
Jeff Johnsone44b7012017-09-10 15:25:47 -07003590static int drv_cmd_set_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003591 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003592 uint8_t *command,
3593 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003594 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003595{
3596 int ret = 0;
3597 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003598 uint8_t min_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003599
3600 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3601 value = value + command_len + 1;
3602
3603 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003604 ret = kstrtou8(value, 10, &min_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003605 if (ret < 0) {
3606 /*
3607 * If the input value is greater than max value of datatype,
3608 * then also kstrtou8 fails
3609 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003610 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003611 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
3612 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 ret = -EINVAL;
3614 goto exit;
3615 }
3616
Wu Gao1ab05582018-11-08 16:22:49 +08003617 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME, min_time)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003618 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003619 min_time,
3620 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
3621 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003622 ret = -EINVAL;
3623 goto exit;
3624 }
3625
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303626 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003627 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
Wu Gao1ab05582018-11-08 16:22:49 +08003628 adapter->session_id, min_time));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003629 hdd_debug("Received Command to change channel min time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003630 min_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003631
Jeff Johnsond549efa2018-06-13 20:27:47 -07003632 sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
Wu Gao1ab05582018-11-08 16:22:49 +08003633 min_time,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003634 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003635
3636exit:
3637 return ret;
3638}
3639
Jeff Johnsone44b7012017-09-10 15:25:47 -07003640static int drv_cmd_send_action_frame(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003641 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003642 uint8_t *command,
3643 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003644 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003645{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003646 return hdd_parse_sendactionframe(adapter, command,
3647 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003648}
3649
Jeff Johnsone44b7012017-09-10 15:25:47 -07003650static int drv_cmd_get_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003651 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003652 uint8_t *command,
3653 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003654 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003655{
3656 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003657 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
3658 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003659 char extra[32];
3660 uint8_t len = 0;
3661
3662 /* value is interms of msec */
3663 len = scnprintf(extra, sizeof(extra), "%s %d",
3664 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303665 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003666
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303667 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003668 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003669 adapter->session_id, val));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003670
3671 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003672 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003673 ret = -EFAULT;
3674 }
3675
3676 return ret;
3677}
3678
Jeff Johnsone44b7012017-09-10 15:25:47 -07003679static int drv_cmd_set_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003680 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003681 uint8_t *command,
3682 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003683 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684{
3685 int ret = 0;
3686 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003687 uint16_t max_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003688
3689 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3690 value = value + command_len + 1;
3691
3692 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003693 ret = kstrtou16(value, 10, &max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003694 if (ret < 0) {
3695 /*
3696 * If the input value is greater than max value of datatype,
3697 * then also kstrtou8 fails
3698 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003699 hdd_err("kstrtou16 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003700 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
3701 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003702 ret = -EINVAL;
3703 goto exit;
3704 }
3705
Wu Gao1ab05582018-11-08 16:22:49 +08003706 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME, max_time)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003707 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003708 max_time,
3709 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
3710 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003711 ret = -EINVAL;
3712 goto exit;
3713 }
3714
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003715 hdd_debug("Received Command to change channel max time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003716 max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003717
Jeff Johnsond549efa2018-06-13 20:27:47 -07003718 sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003719 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003720 max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003721
3722exit:
3723 return ret;
3724}
3725
Jeff Johnsone44b7012017-09-10 15:25:47 -07003726static int drv_cmd_get_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003727 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003728 uint8_t *command,
3729 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003730 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731{
3732 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003733 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
3734 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003735 char extra[32];
3736 uint8_t len = 0;
3737
3738 /* value is interms of msec */
3739 len = scnprintf(extra, sizeof(extra), "%s %d",
3740 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303741 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003742
3743 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003744 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745 ret = -EFAULT;
3746 }
3747
3748 return ret;
3749}
3750
Jeff Johnsone44b7012017-09-10 15:25:47 -07003751static int drv_cmd_set_scan_home_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;
3758 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003759 uint16_t val = cfg_default(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003760
3761 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3762 value = value + command_len + 1;
3763
3764 /* Convert the value from ascii to integer */
3765 ret = kstrtou16(value, 10, &val);
3766 if (ret < 0) {
3767 /*
3768 * If the input value is greater than max value of datatype,
3769 * then also kstrtou8 fails
3770 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003771 hdd_err("kstrtou16 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003772 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
3773 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003774 ret = -EINVAL;
3775 goto exit;
3776 }
3777
Wu Gao1ab05582018-11-08 16:22:49 +08003778 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003779 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3780 val,
Wu Gao1ab05582018-11-08 16:22:49 +08003781 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
3782 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003783 ret = -EINVAL;
3784 goto exit;
3785 }
3786
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003787 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003788 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003789
Jeff Johnsond549efa2018-06-13 20:27:47 -07003790 sme_set_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003791 adapter->session_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003792
3793exit:
3794 return ret;
3795}
3796
Jeff Johnsone44b7012017-09-10 15:25:47 -07003797static int drv_cmd_get_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003798 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003799 uint8_t *command,
3800 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003801 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003802{
3803 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003804 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07003805 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003806 char extra[32];
3807 uint8_t len = 0;
3808
3809 /* value is interms of msec */
3810 len = scnprintf(extra, sizeof(extra), "%s %d",
3811 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303812 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003813
3814 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003815 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003816 ret = -EFAULT;
3817 }
3818
3819 return ret;
3820}
3821
Jeff Johnsone44b7012017-09-10 15:25:47 -07003822static int drv_cmd_set_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003823 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003824 uint8_t *command,
3825 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003826 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003827{
3828 int ret = 0;
3829 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003830 uint8_t val = cfg_default(CFG_LFR_ROAM_INTRA_BAND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003831
3832 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3833 value = value + command_len + 1;
3834
3835 /* Convert the value from ascii to integer */
3836 ret = kstrtou8(value, 10, &val);
3837 if (ret < 0) {
3838 /*
3839 * If the input value is greater than max value of datatype,
3840 * then also kstrtou8 fails
3841 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003842 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003843 cfg_min(CFG_LFR_ROAM_INTRA_BAND),
3844 cfg_max(CFG_LFR_ROAM_INTRA_BAND));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003845 ret = -EINVAL;
3846 goto exit;
3847 }
3848
Wu Gao1ab05582018-11-08 16:22:49 +08003849 if (!cfg_in_range(CFG_LFR_ROAM_INTRA_BAND, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003850 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003851 val, cfg_min(CFG_LFR_ROAM_INTRA_BAND),
3852 cfg_max(CFG_LFR_ROAM_INTRA_BAND));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003853 ret = -EINVAL;
3854 goto exit;
3855 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003856 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003857 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858
Wu Gao1ab05582018-11-08 16:22:49 +08003859 ucfg_mlme_set_roam_intra_band(hdd_ctx->psoc, (bool)val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003860
3861exit:
3862 return ret;
3863}
3864
Jeff Johnsone44b7012017-09-10 15:25:47 -07003865static int drv_cmd_get_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003866 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003867 uint8_t *command,
3868 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003869 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003870{
3871 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003872 uint16_t val = sme_get_roam_intra_band(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003873 char extra[32];
3874 uint8_t len = 0;
3875
3876 /* value is interms of msec */
3877 len = scnprintf(extra, sizeof(extra), "%s %d",
3878 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303879 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003880 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003881 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003882 ret = -EFAULT;
3883 }
3884
3885 return ret;
3886}
3887
Jeff Johnsone44b7012017-09-10 15:25:47 -07003888static int drv_cmd_set_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003889 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003890 uint8_t *command,
3891 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003892 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003893{
3894 int ret = 0;
3895 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003896 uint8_t nprobes = cfg_default(CFG_LFR_ROAM_SCAN_N_PROBES);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897
3898 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3899 value = value + command_len + 1;
3900
3901 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003902 ret = kstrtou8(value, 10, &nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903 if (ret < 0) {
3904 /*
3905 * If the input value is greater than max value of datatype,
3906 * then also kstrtou8 fails
3907 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003908 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003909 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
3910 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003911 ret = -EINVAL;
3912 goto exit;
3913 }
3914
Wu Gao1ab05582018-11-08 16:22:49 +08003915 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_N_PROBES, nprobes)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003916 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003917 nprobes,
3918 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
3919 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003920 ret = -EINVAL;
3921 goto exit;
3922 }
3923
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003924 hdd_debug("Received Command to Set nProbes = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003925 nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003926
Jeff Johnsond549efa2018-06-13 20:27:47 -07003927 sme_update_roam_scan_n_probes(hdd_ctx->mac_handle,
Wu Gao1ab05582018-11-08 16:22:49 +08003928 adapter->session_id, nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003929
3930exit:
3931 return ret;
3932}
3933
Jeff Johnsone44b7012017-09-10 15:25:47 -07003934static int drv_cmd_get_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003935 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003936 uint8_t *command,
3937 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003938 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003939{
3940 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003941 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003942 char extra[32];
3943 uint8_t len = 0;
3944
3945 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303946 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003947 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003948 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003949 ret = -EFAULT;
3950 }
3951
3952 return ret;
3953}
3954
Jeff Johnsone44b7012017-09-10 15:25:47 -07003955static int drv_cmd_set_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003956 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003957 uint8_t *command,
3958 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003959 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003960{
3961 int ret = 0;
3962 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003963 uint16_t home_away_time = cfg_default(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME);
3964 uint16_t current_home_away_time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003965
3966 /* input value is in units of msec */
3967
3968 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3969 value = value + command_len + 1;
3970
3971 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003972 ret = kstrtou16(value, 10, &home_away_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003973 if (ret < 0) {
3974 /*
3975 * If the input value is greater than max value of datatype,
3976 * then also kstrtou8 fails
3977 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003978 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003979 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
3980 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003981 ret = -EINVAL;
3982 goto exit;
3983 }
3984
Wu Gao1ab05582018-11-08 16:22:49 +08003985 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME, home_away_time)) {
3986 hdd_err("home_away_time value %d is out of range (min: %d max: %d)",
3987 home_away_time,
3988 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
3989 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003990 ret = -EINVAL;
3991 goto exit;
3992 }
3993
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003994 hdd_debug("Received Command to Set scan away time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003995 home_away_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003996
Wu Gao1ab05582018-11-08 16:22:49 +08003997 ucfg_mlme_get_home_away_time(hdd_ctx->psoc, &current_home_away_time);
3998 if (current_home_away_time != home_away_time) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07003999 sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004000 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004001 home_away_time,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004002 true);
4003 }
4004
4005exit:
4006 return ret;
4007}
4008
Jeff Johnsone44b7012017-09-10 15:25:47 -07004009static int drv_cmd_get_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004010 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004011 uint8_t *command,
4012 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004013 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004014{
4015 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004016 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004017 char extra[32];
4018 uint8_t len = 0;
4019
4020 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304021 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004022
4023 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004024 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004025 ret = -EFAULT;
4026 }
4027
4028 return ret;
4029}
4030
Jeff Johnsone44b7012017-09-10 15:25:47 -07004031static int drv_cmd_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004032 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004033 uint8_t *command,
4034 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004035 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004036{
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05304037 return hdd_parse_reassoc(adapter, command, priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004038}
4039
Jeff Johnsone44b7012017-09-10 15:25:47 -07004040static int drv_cmd_set_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004041 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004042 uint8_t *command,
4043 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004044 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004045{
4046 int ret = 0;
4047 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004048 uint8_t wes_mode = cfg_default(CFG_LFR_ENABLE_WES_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004049
4050 /* Move pointer to ahead of SETWESMODE<delimiter> */
4051 value = value + command_len + 1;
4052
4053 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004054 ret = kstrtou8(value, 10, &wes_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004055 if (ret < 0) {
4056 /*
4057 * If the input value is greater than max value of datatype,
4058 * then also kstrtou8 fails
4059 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004060 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004061 cfg_min(CFG_LFR_ENABLE_WES_MODE),
4062 cfg_max(CFG_LFR_ENABLE_WES_MODE));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004063 ret = -EINVAL;
4064 goto exit;
4065 }
4066
Wu Gao1ab05582018-11-08 16:22:49 +08004067 if (!cfg_in_range(CFG_LFR_ENABLE_WES_MODE, wes_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004068 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08004069 wes_mode, cfg_min(CFG_LFR_ENABLE_WES_MODE),
4070 cfg_max(CFG_LFR_ENABLE_WES_MODE));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071 ret = -EINVAL;
4072 goto exit;
4073 }
4074
Wu Gao1ab05582018-11-08 16:22:49 +08004075 hdd_debug("Received Command to Set WES Mode rssi diff = %d", wes_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004076
Wu Gao1ab05582018-11-08 16:22:49 +08004077 sme_update_wes_mode(hdd_ctx->mac_handle, wes_mode, adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004078
4079exit:
4080 return ret;
4081}
4082
Jeff Johnsone44b7012017-09-10 15:25:47 -07004083static int drv_cmd_get_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004084 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004085 uint8_t *command,
4086 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004087 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004088{
4089 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004090 bool wesMode = sme_get_wes_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004091 char extra[32];
4092 uint8_t len = 0;
4093
4094 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304095 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004096 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004097 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004098 ret = -EFAULT;
4099 }
4100
4101 return ret;
4102}
4103
Jeff Johnsone44b7012017-09-10 15:25:47 -07004104static int drv_cmd_set_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004105 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004106 uint8_t *command,
4107 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004108 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004109{
4110 int ret = 0;
4111 uint8_t *value = command;
4112 uint8_t nOpportunisticThresholdDiff =
Wu Gao1ab05582018-11-08 16:22:49 +08004113 cfg_default(CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004114
4115 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4116 value = value + command_len + 1;
4117
4118 /* Convert the value from ascii to integer */
4119 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4120 if (ret < 0) {
4121 /*
4122 * If the input value is greater than max value of datatype,
4123 * then also kstrtou8 fails
4124 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004125 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004126 ret = -EINVAL;
4127 goto exit;
4128 }
4129
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004130 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004131 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004132
Jeff Johnsond549efa2018-06-13 20:27:47 -07004133 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004134 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004135 nOpportunisticThresholdDiff);
4136
4137exit:
4138 return ret;
4139}
4140
Jeff Johnsone44b7012017-09-10 15:25:47 -07004141static int drv_cmd_get_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;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004148 mac_handle_t mac_handle = hdd_ctx->mac_handle;
4149 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004150 char extra[32];
4151 uint8_t len = 0;
4152
4153 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304154 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004155 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004156 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004157 ret = -EFAULT;
4158 }
4159
4160 return ret;
4161}
4162
Jeff Johnsone44b7012017-09-10 15:25:47 -07004163static int drv_cmd_set_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004164 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004165 uint8_t *command,
4166 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004167 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004168{
4169 int ret = 0;
4170 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004171 uint8_t rescan_rssi_diff = cfg_default(CFG_LFR_ROAM_RESCAN_RSSI_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004172
4173 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4174 value = value + command_len + 1;
4175
4176 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004177 ret = kstrtou8(value, 10, &rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004178 if (ret < 0) {
4179 /*
4180 * If the input value is greater than max value of datatype,
4181 * then also kstrtou8 fails
4182 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004183 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004184 ret = -EINVAL;
4185 goto exit;
4186 }
4187
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004188 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004189 rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190
Jeff Johnsond549efa2018-06-13 20:27:47 -07004191 sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004192 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004193 rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004194
4195exit:
4196 return ret;
4197}
4198
Jeff Johnsone44b7012017-09-10 15:25:47 -07004199static int drv_cmd_get_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004200 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004201 uint8_t *command,
4202 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004203 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004204{
4205 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004206 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004207 char extra[32];
4208 uint8_t len = 0;
4209
4210 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304211 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004212 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004213 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004214 ret = -EFAULT;
4215 }
4216
4217 return ret;
4218}
4219
Jeff Johnsone44b7012017-09-10 15:25:47 -07004220static int drv_cmd_set_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004221 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004222 uint8_t *command,
4223 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004224 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004225{
4226 int ret = 0;
4227 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004228 uint8_t lfr_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004229
4230 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4231 value = value + command_len + 1;
4232
4233 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004234 ret = kstrtou8(value, 10, &lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004235 if (ret < 0) {
4236 /*
4237 * If the input value is greater than max value of datatype,
4238 * then also kstrtou8 fails
4239 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004240 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004241 cfg_min(CFG_LFR_FEATURE_ENABLED),
4242 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004243 ret = -EINVAL;
4244 goto exit;
4245 }
4246
Wu Gao1ab05582018-11-08 16:22:49 +08004247 if (!cfg_in_range(CFG_LFR_FEATURE_ENABLED, lfr_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004248 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08004249 lfr_mode, cfg_min(CFG_LFR_FEATURE_ENABLED),
4250 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251 ret = -EINVAL;
4252 goto exit;
4253 }
4254
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004255 hdd_debug("Received Command to change lfr mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004256 lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257
Wu Gao1ab05582018-11-08 16:22:49 +08004258 ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)lfr_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07004259 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004260 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004261 lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004262
4263exit:
4264 return ret;
4265}
4266
Jeff Johnsone44b7012017-09-10 15:25:47 -07004267static int drv_cmd_set_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004268 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004269 uint8_t *command,
4270 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004271 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004272{
4273 int ret = 0;
4274 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004275 uint8_t ft = cfg_default(CFG_LFR_FAST_TRANSITION_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004276
4277 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4278 value = value + command_len + 1;
4279
4280 /* Convert the value from ascii to integer */
4281 ret = kstrtou8(value, 10, &ft);
4282 if (ret < 0) {
4283 /*
4284 * If the input value is greater than max value of datatype,
4285 * then also kstrtou8 fails
4286 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004287 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004288 cfg_min(CFG_LFR_FAST_TRANSITION_ENABLED),
4289 cfg_max(CFG_LFR_FAST_TRANSITION_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004290 ret = -EINVAL;
4291 goto exit;
4292 }
4293
Wu Gao1ab05582018-11-08 16:22:49 +08004294 if (!cfg_in_range(CFG_LFR_FAST_TRANSITION_ENABLED, ft)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004295 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08004296 ft, cfg_min(CFG_LFR_FAST_TRANSITION_ENABLED),
4297 cfg_max(CFG_LFR_FAST_TRANSITION_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004298 ret = -EINVAL;
4299 goto exit;
4300 }
4301
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004302 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004303
Wu Gao1ab05582018-11-08 16:22:49 +08004304 ucfg_mlme_set_fast_transition_enabled(hdd_ctx->psoc, (bool)ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004305
4306exit:
4307 return ret;
4308}
4309
Jeff Johnsone44b7012017-09-10 15:25:47 -07004310static int drv_cmd_fast_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004311 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004312 uint8_t *command,
4313 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004314 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004315{
4316 int ret = 0;
4317 uint8_t *value = command;
4318 uint8_t channel = 0;
4319 tSirMacAddr targetApBssid;
Krunal Sonibfd05492017-10-03 15:48:37 -07004320 uint32_t roamId = INVALID_ROAM_ID;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004321 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004322 tCsrHandoffRequest handoffInfo;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004323 struct hdd_station_ctx *sta_ctx;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004324 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004325
Krunal Sonibe766b02016-03-10 13:00:44 -08004326 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004327 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07004328 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004329 adapter->device_mode);
4330 return -EINVAL;
4331 }
4332
Jeff Johnsond377dce2017-10-04 10:32:42 -07004333 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334
4335 /* if not associated, no need to proceed with reassoc */
Jeff Johnsond377dce2017-10-04 10:32:42 -07004336 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004337 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004338 ret = -EINVAL;
4339 goto exit;
4340 }
4341
4342 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4343 &channel);
4344 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004345 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004346 goto exit;
4347 }
4348
Jeff Johnsond549efa2018-06-13 20:27:47 -07004349 mac_handle = hdd_ctx->mac_handle;
4350
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004351 /*
4352 * if the target bssid is same as currently associated AP,
4353 * issue reassoc to same AP
4354 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004355 if (!qdf_mem_cmp(targetApBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004356 sta_ctx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304357 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004358 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304359 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004360 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304361 targetApBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004362 sta_ctx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304363 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07004364 sme_get_modify_profile_fields(mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004365 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004366 &modProfileFields);
Jeff Johnsond549efa2018-06-13 20:27:47 -07004367 sme_roam_reassoc(mac_handle, adapter->session_id,
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304368 NULL, modProfileFields, &roamId, 1);
4369 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370 return 0;
4371 }
4372
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304373 /* Check channel number is a valid channel number */
Selvaraj, Sridhar64b0a9c2017-05-11 16:50:15 +05304374 if (channel && (QDF_STATUS_SUCCESS !=
4375 wlan_hdd_validate_operation_channel(adapter, channel))) {
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304376 hdd_err("Invalid Channel [%d]", channel);
4377 return -EINVAL;
4378 }
4379
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004380 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004381 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004382 targetApBssid, (int)channel);
4383 goto exit;
4384 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004385 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386 handoffInfo.channel = channel;
4387 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004388 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004389 sizeof(tSirMacAddr));
Jeff Johnsond549efa2018-06-13 20:27:47 -07004390 sme_handoff_request(mac_handle, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004391 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004392exit:
4393 return ret;
4394}
4395
Jeff Johnsone44b7012017-09-10 15:25:47 -07004396static int drv_cmd_set_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004397 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004398 uint8_t *command,
4399 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004400 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004401{
4402 int ret = 0;
4403 uint8_t *value = command;
4404 uint8_t roamScanControl = 0;
4405
4406 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4407 value = value + command_len + 1;
4408
4409 /* Convert the value from ascii to integer */
4410 ret = kstrtou8(value, 10, &roamScanControl);
4411 if (ret < 0) {
4412 /*
4413 * If the input value is greater than max value of datatype,
4414 * then also kstrtou8 fails
4415 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004416 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417 ret = -EINVAL;
4418 goto exit;
4419 }
4420
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004421 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004422 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423
4424 if (0 != roamScanControl) {
4425 ret = 0; /* return success but ignore param value "true" */
4426 goto exit;
4427 }
4428
Jeff Johnsond549efa2018-06-13 20:27:47 -07004429 sme_set_roam_scan_control(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004430 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431 roamScanControl);
4432
4433exit:
4434 return ret;
4435}
4436
Jeff Johnsone44b7012017-09-10 15:25:47 -07004437static int drv_cmd_set_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004438 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004439 uint8_t *command,
4440 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004441 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004442{
4443 int ret = 0;
4444 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004445 uint32_t okc_mode;
4446 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004447 mac_handle_t mac_handle;
Wu Gao93816212018-08-31 16:49:54 +08004448 uint32_t cur_pmkid_modes;
4449 QDF_STATUS status;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004450
4451 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004452
4453 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004454 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004455 * then this operation is not permitted (return FAILURE)
4456 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07004457 mac_handle = hdd_ctx->mac_handle;
4458 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004459 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07004460 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004461 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004462 ret = -EPERM;
4463 goto exit;
4464 }
4465
4466 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4467 value = value + command_len + 1;
4468
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004469 /* get the current configured value */
Dustin Brown1dbefe62018-09-11 16:32:03 -07004470 status = ucfg_mlme_get_pmkid_modes(hdd_ctx->psoc,
Wu Gao93816212018-08-31 16:49:54 +08004471 &cur_pmkid_modes);
4472 if (status != QDF_STATUS_SUCCESS)
4473 hdd_err("get pmkid modes failed");
4474
4475 okc_mode = cur_pmkid_modes & CFG_PMKID_MODES_OKC;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004476
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004477 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004478 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004479 if (ret < 0) {
4480 /*
4481 * If the input value is greater than max value of datatype,
4482 * then also kstrtou8 fails
4483 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004484 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004485 ret = -EINVAL;
4486 goto exit;
4487 }
4488
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004489 if ((okc_mode < 0) ||
4490 (okc_mode > 1)) {
4491 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4492 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004493 ret = -EINVAL;
4494 goto exit;
4495 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004496 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004497 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004499 if (okc_mode)
Wu Gao93816212018-08-31 16:49:54 +08004500 cur_pmkid_modes |= CFG_PMKID_MODES_OKC;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004501 else
Wu Gao93816212018-08-31 16:49:54 +08004502 cur_pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Dustin Brown1dbefe62018-09-11 16:32:03 -07004503 status = ucfg_mlme_set_pmkid_modes(hdd_ctx->psoc,
Wu Gao93816212018-08-31 16:49:54 +08004504 cur_pmkid_modes);
4505 if (status != QDF_STATUS_SUCCESS) {
4506 ret = -EPERM;
4507 hdd_err("set pmkid modes failed");
4508 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004509exit:
4510 return ret;
4511}
4512
Jeff Johnsone44b7012017-09-10 15:25:47 -07004513static int drv_cmd_get_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004514 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004515 uint8_t *command,
4516 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004517 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004518{
4519 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004520 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004521 char extra[32];
4522 uint8_t len = 0;
4523
4524 len = scnprintf(extra, sizeof(extra), "%s %d",
4525 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304526 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004527 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004528 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004529 ret = -EFAULT;
4530 }
4531
4532 return ret;
4533}
4534
Jeff Johnsone44b7012017-09-10 15:25:47 -07004535static int drv_cmd_bt_coex_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004536 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004537 uint8_t *command,
4538 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004539 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004540{
4541 int ret = 0;
4542 char *bcMode;
4543
4544 bcMode = command + 11;
4545 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004546 hdd_debug("BTCOEXMODE %d", *bcMode);
Jeff Johnson59b19312017-11-02 21:14:33 -07004547 hdd_ctx->bt_coex_mode_set = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004548 ret = wlan_hdd_scan_abort(adapter);
4549 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004550 hdd_err("Failed to abort existing scan status: %d",
4551 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004552 }
4553 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004554 hdd_debug("BTCOEXMODE %d", *bcMode);
Jeff Johnson59b19312017-11-02 21:14:33 -07004555 hdd_ctx->bt_coex_mode_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004556 }
4557
4558 return ret;
4559}
4560
Jeff Johnsone44b7012017-09-10 15:25:47 -07004561static int drv_cmd_scan_active(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004562 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563 uint8_t *command,
4564 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004565 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004566{
4567 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4568 return 0;
4569}
4570
Jeff Johnsone44b7012017-09-10 15:25:47 -07004571static int drv_cmd_scan_passive(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004572 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004573 uint8_t *command,
4574 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004575 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004576{
4577 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4578 return 0;
4579}
4580
Jeff Johnsone44b7012017-09-10 15:25:47 -07004581static int drv_cmd_get_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004582 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004583 uint8_t *command,
4584 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004585 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004586{
4587 int ret = 0;
4588 struct hdd_config *pCfg =
4589 (WLAN_HDD_GET_CTX(adapter))->config;
4590 char extra[32];
4591 uint8_t len = 0;
4592
4593 memset(extra, 0, sizeof(extra));
4594 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304595 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004596 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004597 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004598 ret = -EFAULT;
4599 goto exit;
4600 }
4601 ret = len;
4602exit:
4603 return ret;
4604}
4605
Jeff Johnsone44b7012017-09-10 15:25:47 -07004606static int drv_cmd_set_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004607 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004608 uint8_t *command,
4609 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004610 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004611{
4612 return hdd_set_dwell_time(adapter, command);
4613}
4614
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05304615#ifdef WLAN_AP_STA_CONCURRENCY
4616static int drv_cmd_conc_set_dwell_time(hdd_adapter_t *adapter,
4617 hdd_context_t *hdd_ctx,
4618 u8 *command,
4619 u8 command_len,
4620 hdd_priv_data_t *priv_data)
4621{
4622 return hdd_conc_set_dwell_time(hdd_ctx, command);
4623}
4624#endif
4625
Jeff Johnsone44b7012017-09-10 15:25:47 -07004626static int drv_cmd_miracast(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004627 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004628 uint8_t *command,
4629 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004630 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004631{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304632 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004633 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 uint8_t filterType = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004635 uint8_t *value;
4636
Jeff Johnson6da2db12017-09-03 09:18:52 -07004637 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004639
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 value = command + 9;
4641
4642 /* Convert the value from ascii to integer */
4643 ret = kstrtou8(value, 10, &filterType);
4644 if (ret < 0) {
4645 /*
4646 * If the input value is greater than max value of datatype,
4647 * then also kstrtou8 fails
4648 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004649 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004650 ret = -EINVAL;
4651 goto exit;
4652 }
4653 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4654 || (filterType >
4655 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004656 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004657 ret = -EINVAL;
4658 goto exit;
4659 }
4660 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
Jeff Johnson6da2db12017-09-03 09:18:52 -07004661 hdd_ctx->miracast_value = filterType;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004662
Jeff Johnsond549efa2018-06-13 20:27:47 -07004663 ret_status = sme_set_miracast(hdd_ctx->mac_handle, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304664 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004665 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004666 return -EBUSY;
4667 }
Dustin Brown1dbefe62018-09-11 16:32:03 -07004668 ret_status = ucfg_scan_set_miracast(hdd_ctx->psoc,
Abhishek Singhc87bb042018-01-30 17:10:42 +05304669 filterType ? true : false);
4670 if (QDF_IS_STATUS_ERROR(ret_status)) {
4671 hdd_err("Failed to set miracastn scan");
4672 return -EBUSY;
4673 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004674
Dustin Brown1dbefe62018-09-11 16:32:03 -07004675 if (policy_mgr_is_mcc_in_24G(hdd_ctx->psoc))
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004676 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004677
4678exit:
4679 return ret;
4680}
4681
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004682/* Function header is left blank intentionally */
4683static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4684 int32_t *oui_length, int32_t limit)
4685{
4686 uint8_t len;
4687 uint8_t data;
4688
4689 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4690 command++;
4691 limit--;
4692 }
4693
4694 len = 2;
4695
4696 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4697 (limit > 1)) {
4698 sscanf(command, "%02x", (unsigned int *)&data);
4699 ie[len++] = data;
4700 command += 2;
4701 limit -= 2;
4702 }
4703
4704 *oui_length = len - 2;
4705
4706 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4707 command++;
4708 limit--;
4709 }
4710
4711 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4712 (limit > 1)) {
4713 sscanf(command, "%02x", (unsigned int *)&data);
4714 ie[len++] = data;
4715 command += 2;
4716 limit -= 2;
4717 }
4718
4719 ie[0] = IE_EID_VENDOR;
4720 ie[1] = len - 2;
4721
4722 return len;
4723}
4724
4725/**
4726 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4727 * @adapter: Pointer to adapter
4728 * @hdd_ctx: Pointer to HDD context
4729 * @command: Pointer to command string
4730 * @command_len : Command length
4731 * @priv_data : Pointer to priv data
4732 *
4733 * Return:
4734 * int status code
4735 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07004736static int drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004737 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004738 uint8_t *command,
4739 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004740 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004741{
4742 int i = 0;
4743 int status;
4744 int ret = 0;
4745 uint8_t *ibss_ie;
4746 int32_t oui_length = 0;
4747 uint32_t ibss_ie_length;
4748 uint8_t *value = command;
4749 tSirModifyIE ibssModifyIE;
Jeff Johnson61b5e982018-03-15 11:33:31 -07004750 struct csr_roam_profile *roam_profile;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004751 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004752
Krunal Sonibe766b02016-03-10 13:00:44 -08004753 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004754 hdd_debug("Device_mode %s(%d) not IBSS",
Dustin Brown458027c2018-10-19 12:26:27 -07004755 qdf_opmode_str(adapter->device_mode),
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004756 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004757 return ret;
4758 }
4759
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004760 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004761
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004762 /* validate argument of command */
4763 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004764 hdd_err("No arguments in command length %zu",
4765 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004766 ret = -EFAULT;
4767 goto exit;
4768 }
4769
4770 /* moving to arguments of commands */
4771 value = value + command_len;
4772 command_len = strlen(value);
4773
4774 /* oui_data can't be less than 3 bytes */
4775 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004776 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4777 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004778 ret = -EFAULT;
4779 goto exit;
4780 }
4781
4782 ibss_ie = qdf_mem_malloc(command_len);
4783 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004784 hdd_err("Could not allocate memory for command length %d",
4785 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004786 ret = -ENOMEM;
4787 goto exit;
4788 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004789
4790 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4791 &oui_length,
4792 command_len);
4793 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004794 hdd_err("Could not parse command %s return length %d",
4795 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004796 ret = -EFAULT;
4797 qdf_mem_free(ibss_ie);
4798 goto exit;
4799 }
4800
Jeff Johnson8313b9d2018-03-14 15:09:28 -07004801 roam_profile = hdd_roam_profile(adapter);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004802
4803 qdf_copy_macaddr(&ibssModifyIE.bssid,
Jeff Johnson5b34fce2017-10-13 13:24:51 -07004804 roam_profile->BSSIDs.bssid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004805
Jeff Johnson1b780e42017-10-31 14:11:45 -07004806 ibssModifyIE.smeSessionId = adapter->session_id;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004807 ibssModifyIE.notify = true;
4808 ibssModifyIE.ieID = IE_EID_VENDOR;
4809 ibssModifyIE.ieIDLen = ibss_ie_length;
4810 ibssModifyIE.ieBufferlength = ibss_ie_length;
4811 ibssModifyIE.pIEBuffer = ibss_ie;
4812 ibssModifyIE.oui_length = oui_length;
4813
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004814 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4815 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004816 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004817 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004818
4819 /* Probe Bcn modification */
Jeff Johnsond549efa2018-06-13 20:27:47 -07004820 mac_handle = hdd_ctx->mac_handle;
4821 sme_modify_add_ie(mac_handle, &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004822
4823 /* Populating probe resp frame */
Jeff Johnsond549efa2018-06-13 20:27:47 -07004824 sme_modify_add_ie(mac_handle, &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004825
4826 qdf_mem_free(ibss_ie);
4827
Jeff Johnsond549efa2018-06-13 20:27:47 -07004828 status = sme_send_cesium_enable_ind(mac_handle,
4829 adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004830 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004831 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004832 status);
4833 ret = -EINVAL;
4834 goto exit;
4835 }
4836
4837exit:
4838 return ret;
4839}
4840
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304841#ifdef FEATURE_WLAN_RMC
4842/* Function header is left blank intentionally */
4843static int hdd_parse_setrmcenable_command(uint8_t *pValue,
4844 uint8_t *pRmcEnable)
4845{
4846 uint8_t *inPtr = pValue;
4847 int tempInt;
4848 int v = 0;
4849 char buf[32];
4850 *pRmcEnable = 0;
4851
4852 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
4853
4854 if (NULL == inPtr)
4855 return 0;
4856 else if (SPACE_ASCII_VALUE != *inPtr)
4857 return 0;
4858
4859 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
4860 inPtr++;
4861
4862 if ('\0' == *inPtr)
4863 return 0;
4864
4865 v = sscanf(inPtr, "%31s ", buf);
4866 if (1 != v)
4867 return -EINVAL;
4868
4869 v = kstrtos32(buf, 10, &tempInt);
4870 if (v < 0)
4871 return -EINVAL;
4872
4873 *pRmcEnable = tempInt;
4874
4875 hdd_debug("ucRmcEnable: %d", *pRmcEnable);
4876
4877 return 0;
4878}
4879
4880/* Function header is left blank intentionally */
Wu Gao1ab05582018-11-08 16:22:49 +08004881static int hdd_parse_setrmcactionperiod_command(uint8_t *pvalue,
4882 uint32_t *paction_period)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304883{
Wu Gao1ab05582018-11-08 16:22:49 +08004884 uint8_t *inptr = pvalue;
4885 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304886 int v = 0;
4887 char buf[32];
Wu Gao1ab05582018-11-08 16:22:49 +08004888 *paction_period = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304889
Wu Gao1ab05582018-11-08 16:22:49 +08004890 inptr = strnchr(pvalue, strlen(pvalue), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304891
Wu Gao1ab05582018-11-08 16:22:49 +08004892 if (NULL == inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304893 return -EINVAL;
Wu Gao1ab05582018-11-08 16:22:49 +08004894 else if (SPACE_ASCII_VALUE != *inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304895 return -EINVAL;
4896
Wu Gao1ab05582018-11-08 16:22:49 +08004897 while ((SPACE_ASCII_VALUE == *inptr) && ('\0' != *inptr))
4898 inptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304899
Wu Gao1ab05582018-11-08 16:22:49 +08004900 if ('\0' == *inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304901 return 0;
4902
Wu Gao1ab05582018-11-08 16:22:49 +08004903 v = sscanf(inptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304904 if (1 != v)
4905 return -EINVAL;
4906
Wu Gao1ab05582018-11-08 16:22:49 +08004907 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304908 if (v < 0)
4909 return -EINVAL;
4910
Wu Gao1ab05582018-11-08 16:22:49 +08004911 if (!cfg_in_range(CFG_RMC_ACTION_PERIOD_FREQUENCY, temp_int))
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304912 return -EINVAL;
4913
Wu Gao1ab05582018-11-08 16:22:49 +08004914 *paction_period = temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304915
Wu Gao1ab05582018-11-08 16:22:49 +08004916 hdd_debug("uActionPeriod: %d", *paction_period);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304917
4918 return 0;
4919}
4920
4921/* Function header is left blank intentionally */
4922static int hdd_parse_setrmcrate_command(uint8_t *pValue,
4923 uint32_t *pRate,
4924 enum tx_rate_info *pTxFlags)
4925{
4926 uint8_t *inPtr = pValue;
4927 int tempInt;
4928 int v = 0;
4929 char buf[32];
4930 *pRate = 0;
4931 *pTxFlags = 0;
4932
4933 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
4934
4935 if (NULL == inPtr)
4936 return -EINVAL;
4937 else if (SPACE_ASCII_VALUE != *inPtr)
4938 return -EINVAL;
4939
4940 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
4941 inPtr++;
4942
4943 if ('\0' == *inPtr)
4944 return 0;
4945
4946 v = sscanf(inPtr, "%31s ", buf);
4947 if (1 != v)
4948 return -EINVAL;
4949
4950 v = kstrtos32(buf, 10, &tempInt);
4951 if (v < 0)
4952 return -EINVAL;
4953
4954 switch (tempInt) {
4955 default:
4956 hdd_warn("Unsupported rate: %d", tempInt);
4957 return -EINVAL;
4958 case 0:
4959 case 6:
4960 case 9:
4961 case 12:
4962 case 18:
4963 case 24:
4964 case 36:
4965 case 48:
4966 case 54:
4967 *pTxFlags = TX_RATE_LEGACY;
4968 *pRate = tempInt * 10;
4969 break;
4970 case 65:
4971 *pTxFlags = TX_RATE_HT20;
4972 *pRate = tempInt * 10;
4973 break;
4974 case 72:
4975 *pTxFlags = TX_RATE_HT20 | TX_RATE_SGI;
4976 *pRate = 722;
4977 break;
4978 }
4979
4980 hdd_debug("Rate: %d", *pRate);
4981
4982 return 0;
4983}
4984
Jeff Johnsone44b7012017-09-10 15:25:47 -07004985static int drv_cmd_set_rmc_enable(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004986 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004987 uint8_t *command,
4988 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004989 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004990{
4991 int ret = 0;
4992 uint8_t *value = command;
4993 uint8_t ucRmcEnable = 0;
4994 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004995 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004996
Krunal Sonibe766b02016-03-10 13:00:44 -08004997 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4998 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004999 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005000 qdf_opmode_str(adapter->device_mode),
5001 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005002 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005003 ret = -EINVAL;
5004 goto exit;
5005 }
5006
5007 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
5008 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005009 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005010 ret = -EINVAL;
5011 goto exit;
5012 }
5013
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005014 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005015 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005016
5017 if (true == ucRmcEnable) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07005018 status = sme_enable_rmc(mac_handle, adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005019 } else if (false == ucRmcEnable) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07005020 status = sme_disable_rmc(mac_handle, adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005021 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07005022 hdd_err("Invalid SETRMCENABLE command %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005023 ret = -EINVAL;
5024 goto exit;
5025 }
5026
5027 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07005028 hdd_err("SETRMC %d failed status %d", ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005029 ret = -EINVAL;
5030 goto exit;
5031 }
5032
5033exit:
5034 return ret;
5035}
5036
Jeff Johnsone44b7012017-09-10 15:25:47 -07005037static int drv_cmd_set_rmc_action_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005038 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005039 uint8_t *command,
5040 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005041 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005042{
5043 int ret = 0;
5044 uint8_t *value = command;
5045 uint32_t uActionPeriod = 0;
5046 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005047 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005048
Krunal Sonibe766b02016-03-10 13:00:44 -08005049 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5050 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005051 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005052 qdf_opmode_str(adapter->device_mode),
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005053 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005054 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005055 ret = -EINVAL;
5056 goto exit;
5057 }
5058
5059 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
5060 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005061 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005062 ret = -EINVAL;
5063 goto exit;
5064 }
5065
Jeff Johnsond549efa2018-06-13 20:27:47 -07005066 hdd_debug("uActionPeriod %d", uActionPeriod);
5067 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005068
Dustin Brown05d81302018-09-11 16:49:22 -07005069 if (ucfg_mlme_set_rmc_action_period_freq(hdd_ctx->psoc,
Bala Venkatesh2fde2c62018-09-11 20:33:24 +05305070 uActionPeriod) !=
5071 QDF_STATUS_SUCCESS) {
5072 hdd_err("Could not set SETRMCACTIONPERIOD %d", uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005073 ret = -EINVAL;
5074 goto exit;
5075 }
5076
Jeff Johnsond549efa2018-06-13 20:27:47 -07005077 status = sme_send_rmc_action_period(mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005078 adapter->session_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005079 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005080 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005081 status);
5082 ret = -EINVAL;
5083 goto exit;
5084 }
5085
5086exit:
5087 return ret;
5088}
5089
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305090static int drv_cmd_set_rmc_tx_rate(struct hdd_adapter *adapter,
5091 struct hdd_context *hdd_ctx,
5092 uint8_t *command,
5093 uint8_t command_len,
5094 struct hdd_priv_data *priv_data)
5095{
5096 int ret = 0;
5097 uint8_t *value = command;
5098 uint32_t uRate = 0;
5099 enum tx_rate_info txFlags = 0;
5100 tSirRateUpdateInd rateUpdateParams = {0};
5101 int status;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05305102 bool bval = false;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305103
5104 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5105 (QDF_SAP_MODE != adapter->device_mode)) {
5106 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005107 qdf_opmode_str(adapter->device_mode),
5108 adapter->device_mode);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305109 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
5110 ret = -EINVAL;
5111 goto exit;
5112 }
5113
5114 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5115 if (status) {
5116 hdd_err("Invalid SETRMCTXRATE command");
5117 ret = -EINVAL;
5118 goto exit;
5119 }
5120 hdd_debug("uRate %d", uRate);
5121 /* -1 implies ignore this param */
5122 rateUpdateParams.ucastDataRate = -1;
5123
5124 /*
5125 * Fill the user specifieed RMC rate param
5126 * and the derived tx flags.
5127 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05305128 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
5129 if (!QDF_IS_STATUS_SUCCESS(status)) {
5130 hdd_err("unable to get vht_enable2x2");
5131 ret = -EINVAL;
5132 goto exit;
5133 }
5134 rateUpdateParams.nss = (bval == 0) ? 0 : 1;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305135 rateUpdateParams.reliableMcastDataRate = uRate;
5136 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5137 rateUpdateParams.dev_mode = adapter->device_mode;
5138 rateUpdateParams.bcastDataRate = -1;
5139 memcpy(rateUpdateParams.bssid.bytes,
5140 adapter->mac_addr.bytes,
5141 sizeof(rateUpdateParams.bssid));
5142 status = sme_send_rate_update_ind(hdd_ctx->mac_handle,
5143 &rateUpdateParams);
5144
5145exit:
5146 return ret;
5147}
5148#endif /* FEATURE_WLAN_RMC */
5149
Jeff Johnsone44b7012017-09-10 15:25:47 -07005150static int drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005151 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005152 uint8_t *command,
5153 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005154 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005155{
5156 int ret = 0;
5157 int status = QDF_STATUS_SUCCESS;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005158 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005159 char *extra = NULL;
5160 int idx = 0;
5161 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005162 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005163 uint32_t numOfBytestoPrint = 0;
5164
Krunal Sonibe766b02016-03-10 13:00:44 -08005165 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005166 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005167 qdf_opmode_str(adapter->device_mode),
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005168 adapter->device_mode);
5169 return -EINVAL;
5170 }
5171
Jeff Johnsond377dce2017-10-04 10:32:42 -07005172 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005173 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005174
5175 /* Handle the command */
5176 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5177 if (QDF_STATUS_SUCCESS == status) {
Dustin Brownc8e96f12018-04-19 09:27:42 -07005178 size_t user_size = qdf_min(WLAN_MAX_BUF_SIZE,
5179 priv_data->total_len);
5180
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005181 /*
5182 * The variable extra needed to be allocated on the heap since
5183 * amount of memory required to copy the data for 32 devices
5184 * exceeds the size of 1024 bytes of default stack size. On
5185 * 64 bit devices, the default max stack size of 2048 bytes
5186 */
Dustin Brownc8e96f12018-04-19 09:27:42 -07005187 extra = qdf_mem_malloc(user_size);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005188
5189 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005190 hdd_err("memory allocation failed");
5191 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005192 goto exit;
5193 }
5194
5195 /* Copy number of stations */
Dustin Brownc8e96f12018-04-19 09:27:42 -07005196 length = scnprintf(extra, user_size, "%d ",
Jeff Johnsond377dce2017-10-04 10:32:42 -07005197 sta_ctx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005198 numOfBytestoPrint = length;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005199 for (idx = 0; idx < sta_ctx->ibss_peer_info.numPeers;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005200 idx++) {
5201 int8_t rssi;
5202 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005203
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005204 qdf_mem_copy(mac_addr,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005205 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005206 mac_addr, sizeof(mac_addr));
5207
5208 tx_rate =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005209 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005210 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305211 /*
5212 * Only lower 3 bytes are rate info. Mask of the MSByte
5213 */
5214 tx_rate &= 0x00FFFFFF;
5215
Jeff Johnsond377dce2017-10-04 10:32:42 -07005216 rssi = sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005217 rssi;
5218
Dustin Brownc8e96f12018-04-19 09:27:42 -07005219 length += scnprintf(extra + length,
5220 user_size - length,
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005221 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5222 mac_addr[0], mac_addr[1], mac_addr[2],
5223 mac_addr[3], mac_addr[4], mac_addr[5],
5224 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005225 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005226 * cdf_trace_msg has limitation of 512 bytes for the
5227 * print buffer. Hence printing the data in two chunks.
5228 * The first chunk will have the data for 16 devices
5229 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005230 */
5231 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5232 numOfBytestoPrint = length;
5233 }
5234
5235 /*
5236 * Copy the data back into buffer, if the data to copy is
5237 * more than 512 bytes than we will split the data and do
5238 * it in two shots
5239 */
5240 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005241 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005242 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305243 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005244 }
5245
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005246 /* This overwrites the last space, which we already copied */
5247 extra[numOfBytestoPrint - 1] = '\0';
5248 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005249
5250 if (length > numOfBytestoPrint) {
5251 if (copy_to_user
5252 (priv_data->buf + numOfBytestoPrint,
5253 extra + numOfBytestoPrint,
5254 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005255 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005256 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305257 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005258 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005259 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005260 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005261 } else {
5262 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005263 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5264 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005265 ret = -EINVAL;
5266 goto exit;
5267 }
5268 ret = 0;
5269
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305270mem_free:
5271 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005272exit:
5273 return ret;
5274}
5275
5276/* Peer Info <Peer Addr> command */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005277static int drv_cmd_get_ibss_peer_info(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005278 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005279 uint8_t *command,
5280 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005281 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005282{
5283 int ret = 0;
5284 uint8_t *value = command;
5285 QDF_STATUS status;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005286 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005287 char extra[128] = { 0 };
5288 uint32_t length = 0;
5289 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005290 struct qdf_mac_addr peerMacAddr;
5291
Krunal Sonibe766b02016-03-10 13:00:44 -08005292 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005293 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005294 qdf_opmode_str(adapter->device_mode),
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005295 adapter->device_mode);
5296 return -EINVAL;
5297 }
5298
Jeff Johnsond377dce2017-10-04 10:32:42 -07005299 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005300
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005301 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005302
5303 /* if there are no peers, no need to continue with the command */
5304 if (eConnectionState_IbssConnected !=
Jeff Johnsond377dce2017-10-04 10:32:42 -07005305 sta_ctx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005306 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005307 ret = -EINVAL;
5308 goto exit;
5309 }
5310
5311 /* Parse the incoming command buffer */
5312 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5313 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005314 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005315 ret = -EINVAL;
5316 goto exit;
5317 }
5318
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005319 /* Get station index for the peer mac address and sanitize it */
Jeff Johnsond377dce2017-10-04 10:32:42 -07005320 hdd_get_peer_sta_id(sta_ctx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005321
Naveen Rawatc45d1622016-07-05 12:20:09 -07005322 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005323 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005324 ret = -EINVAL;
5325 goto exit;
5326 }
5327
5328 /* Handle the command */
5329 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5330 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005331 uint32_t txRate =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005332 sta_ctx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305333 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5334 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005335
5336 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005337 (int)txRate,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005338 (int)sta_ctx->ibss_peer_info.
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005339 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005340
5341 /* Copy the data back into buffer */
5342 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005343 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005344 ret = -EFAULT;
5345 goto exit;
5346 }
5347 } else {
5348 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005349 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5350 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005351 ret = -EINVAL;
5352 goto exit;
5353 }
5354
5355 /* Success ! */
Rajeev Kumar Sirasanagandla92ec9d92018-04-24 21:33:06 +05305356 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005357 ret = 0;
5358
5359exit:
5360 return ret;
5361}
5362
Jeff Johnsone44b7012017-09-10 15:25:47 -07005363static int drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005364 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005365 uint8_t *command,
5366 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005367 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005368{
5369 int ret = 0;
5370 char *value;
5371 uint8_t tx_fail_count = 0;
5372 uint16_t pid = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005373 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005374
5375 value = command;
5376
5377 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5378
5379 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005380 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005381 goto exit;
5382 }
5383
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005384 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005385 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005386
5387 if (0 == tx_fail_count) {
5388 /* Disable TX Fail Indication */
5389 if (QDF_STATUS_SUCCESS ==
Jeff Johnsond549efa2018-06-13 20:27:47 -07005390 sme_tx_fail_monitor_start_stop_ind(mac_handle,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005391 tx_fail_count,
5392 NULL)) {
5393 cesium_pid = 0;
5394 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005395 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005396 ret = -EINVAL;
5397 }
5398 } else {
5399 if (QDF_STATUS_SUCCESS ==
Jeff Johnsond549efa2018-06-13 20:27:47 -07005400 sme_tx_fail_monitor_start_stop_ind(mac_handle,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005401 tx_fail_count,
5402 (void *)hdd_tx_fail_ind_callback)) {
5403 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005404 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005405 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005406 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005407 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005408 ret = -EINVAL;
5409 }
5410 }
5411
5412exit:
5413 return ret;
5414}
5415
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005416#ifdef FEATURE_WLAN_ESE
Jeff Johnsone44b7012017-09-10 15:25:47 -07005417static int drv_cmd_set_ccx_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005418 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005419 uint8_t *command,
5420 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005421 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005422{
5423 int ret = 0;
5424 uint8_t *value = command;
5425 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5426 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305427 QDF_STATUS status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005428 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005429
5430 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5431 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005432 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005433 goto exit;
5434 }
5435 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005436 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005437 numChannels,
5438 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5439 ret = -EINVAL;
5440 goto exit;
5441 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305442
Jeff Johnsond549efa2018-06-13 20:27:47 -07005443 mac_handle = hdd_ctx->mac_handle;
5444 if (!sme_validate_channel_list(mac_handle, ChannelList, numChannels)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305445 hdd_err("List contains invalid channel(s)");
5446 ret = -EINVAL;
5447 goto exit;
5448 }
5449
Jeff Johnsond549efa2018-06-13 20:27:47 -07005450 status = sme_set_ese_roam_scan_channel_list(mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005451 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005452 ChannelList,
5453 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305454 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005455 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005456 ret = -EINVAL;
5457 goto exit;
5458 }
5459
5460exit:
5461 return ret;
5462}
5463
Jeff Johnsone44b7012017-09-10 15:25:47 -07005464static int drv_cmd_get_tsm_stats(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005465 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005466 uint8_t *command,
5467 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005468 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005469{
5470 int ret = 0;
5471 uint8_t *value = command;
5472 char extra[128] = { 0 };
5473 int len = 0;
5474 uint8_t tid = 0;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005475 struct hdd_station_ctx *sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005476 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005477
Krunal Sonibe766b02016-03-10 13:00:44 -08005478 if ((QDF_STA_MODE != adapter->device_mode) &&
5479 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005480 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005481 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005482 adapter->device_mode);
5483 return -EINVAL;
5484 }
5485
Jeff Johnsond377dce2017-10-04 10:32:42 -07005486 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005487
5488 /* if not associated, return error */
Jeff Johnsond377dce2017-10-04 10:32:42 -07005489 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005490 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005491 ret = -EINVAL;
5492 goto exit;
5493 }
5494
5495 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5496 value = value + command_len + 1;
5497
5498 /* Convert the value from ascii to integer */
5499 ret = kstrtou8(value, 10, &tid);
5500 if (ret < 0) {
5501 /*
5502 * If the input value is greater than max value of datatype,
5503 * then also kstrtou8 fails
5504 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005505 hdd_err("kstrtou8 failed range [%d - %d]",
5506 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005507 TID_MAX_VALUE);
5508 ret = -EINVAL;
5509 goto exit;
5510 }
5511 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005512 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005513 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5514 ret = -EINVAL;
5515 goto exit;
5516 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005517 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005518 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005519 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5520 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005521 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005522 goto exit;
5523 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005524 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005525 "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 -08005526 tsm_metrics.UplinkPktQueueDly,
5527 tsm_metrics.UplinkPktQueueDlyHist[0],
5528 tsm_metrics.UplinkPktQueueDlyHist[1],
5529 tsm_metrics.UplinkPktQueueDlyHist[2],
5530 tsm_metrics.UplinkPktQueueDlyHist[3],
5531 tsm_metrics.UplinkPktTxDly,
5532 tsm_metrics.UplinkPktLoss,
5533 tsm_metrics.UplinkPktCount,
5534 tsm_metrics.RoamingCount,
5535 tsm_metrics.RoamingDly);
5536 /*
5537 * Output TSM stats is of the format
5538 * GETTSMSTATS [PktQueueDly]
5539 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5540 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5541 */
5542 len = scnprintf(extra,
5543 sizeof(extra),
5544 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5545 command,
5546 tsm_metrics.UplinkPktQueueDly,
5547 tsm_metrics.UplinkPktQueueDlyHist[0],
5548 tsm_metrics.UplinkPktQueueDlyHist[1],
5549 tsm_metrics.UplinkPktQueueDlyHist[2],
5550 tsm_metrics.UplinkPktQueueDlyHist[3],
5551 tsm_metrics.UplinkPktTxDly,
5552 tsm_metrics.UplinkPktLoss,
5553 tsm_metrics.UplinkPktCount,
5554 tsm_metrics.RoamingCount,
5555 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305556 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005557 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005558 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005559 ret = -EFAULT;
5560 goto exit;
5561 }
5562
5563exit:
5564 return ret;
5565}
5566
Jeff Johnsone44b7012017-09-10 15:25:47 -07005567static int drv_cmd_set_cckm_ie(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005568 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005569 uint8_t *command,
5570 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005571 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005572{
5573 int ret;
5574 uint8_t *value = command;
5575 uint8_t *cckmIe = NULL;
5576 uint8_t cckmIeLen = 0;
5577
5578 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5579 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005580 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005581 goto exit;
5582 }
5583
5584 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005585 hdd_err("CCKM Ie input length is more than max[%d]",
5586 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005587 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305588 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005589 cckmIe = NULL;
5590 }
5591 ret = -EINVAL;
5592 goto exit;
5593 }
5594
Jeff Johnsond549efa2018-06-13 20:27:47 -07005595 sme_set_cckm_ie(hdd_ctx->mac_handle, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005596 cckmIe, cckmIeLen);
5597 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305598 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005599 cckmIe = NULL;
5600 }
5601
5602exit:
5603 return ret;
5604}
5605
Jeff Johnsone44b7012017-09-10 15:25:47 -07005606static int drv_cmd_ccx_beacon_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005607 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005608 uint8_t *command,
5609 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005610 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005611{
5612 int ret;
5613 uint8_t *value = command;
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305614 tCsrEseBeaconReq eseBcnReq = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305615 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005616
Krunal Sonibe766b02016-03-10 13:00:44 -08005617 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005618 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005619 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005620 adapter->device_mode);
5621 return -EINVAL;
5622 }
5623
5624 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5625 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005626 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005627 goto exit;
5628 }
5629
5630 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005631 hdd_debug("Not associated");
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305632
5633 if (!eseBcnReq.numBcnReqIe)
5634 return -EINVAL;
5635
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005636 hdd_indicate_ese_bcn_report_no_results(adapter,
5637 eseBcnReq.bcnReq[0].measurementToken,
5638 0x02, /* BIT(1) set for measurement done */
5639 0); /* no BSS */
5640 goto exit;
5641 }
5642
Jeff Johnsond549efa2018-06-13 20:27:47 -07005643 status = sme_set_ese_beacon_request(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005644 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005645 &eseBcnReq);
5646
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305647 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005648 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005649 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005650 ret = -EBUSY;
5651 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305652 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005653 hdd_err("sme_set_ese_beacon_request failed (%d)",
5654 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005655 ret = -EINVAL;
5656 goto exit;
5657 }
5658
5659exit:
5660 return ret;
5661}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005662
5663/**
5664 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5665 * @adapter: Pointer to the HDD adapter
5666 * @hdd_ctx: Pointer to the HDD context
5667 * @command: Driver command string
5668 * @command_len: Driver command string length
5669 * @priv_data: Private data coming with the driver command. Unused here
5670 *
5671 * This function handles driver command that sets the ESE PLM request
5672 *
5673 * Return: 0 on success; negative errno otherwise
5674 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005675static int drv_cmd_ccx_plm_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005676 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005677 uint8_t *command,
5678 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005679 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005680{
5681 int ret = 0;
5682 uint8_t *value = command;
5683 QDF_STATUS status = QDF_STATUS_SUCCESS;
5684 tpSirPlmReq pPlmRequest = NULL;
5685
5686 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5687 if (NULL == pPlmRequest) {
5688 ret = -ENOMEM;
5689 goto exit;
5690 }
5691
5692 status = hdd_parse_plm_cmd(value, pPlmRequest);
5693 if (QDF_STATUS_SUCCESS != status) {
5694 qdf_mem_free(pPlmRequest);
5695 pPlmRequest = NULL;
5696 ret = -EINVAL;
5697 goto exit;
5698 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07005699 pPlmRequest->sessionId = adapter->session_id;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005700
Jeff Johnsond549efa2018-06-13 20:27:47 -07005701 status = sme_set_plm_request(hdd_ctx->mac_handle, pPlmRequest);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005702 if (QDF_STATUS_SUCCESS != status) {
5703 qdf_mem_free(pPlmRequest);
5704 pPlmRequest = NULL;
5705 ret = -EINVAL;
5706 goto exit;
5707 }
5708
5709exit:
5710 return ret;
5711}
5712
5713/**
5714 * drv_cmd_set_ccx_mode() - Set ESE mode
5715 * @adapter: Pointer to the HDD adapter
5716 * @hdd_ctx: Pointer to the HDD context
5717 * @command: Driver command string
5718 * @command_len: Driver command string length
5719 * @priv_data: Private data coming with the driver command. Unused here
5720 *
5721 * This function handles driver command that sets ESE mode
5722 *
5723 * Return: 0 on success; negative errno otherwise
5724 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005725static int drv_cmd_set_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005726 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005727 uint8_t *command,
5728 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005729 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005730{
5731 int ret = 0;
5732 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08005733 uint8_t ese_mode = cfg_default(CFG_LFR_ESE_FEATURE_ENABLED);
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005734 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005735 mac_handle_t mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005736
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005737 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005738 mac_handle = hdd_ctx->mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005739 /*
5740 * Check if the features OKC/ESE/11R are supported simultaneously,
5741 * then this operation is not permitted (return FAILURE)
5742 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005743 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005744 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07005745 sme_get_is_ft_feature_enabled(mac_handle)) {
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005746 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5747 ret = -EPERM;
5748 goto exit;
5749 }
5750
5751 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5752 value = value + command_len + 1;
5753
5754 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08005755 ret = kstrtou8(value, 10, &ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005756 if (ret < 0) {
5757 /*
5758 * If the input value is greater than max value of datatype,
5759 * then also kstrtou8 fails
5760 */
5761 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08005762 cfg_min(CFG_LFR_ESE_FEATURE_ENABLED),
5763 cfg_max(CFG_LFR_ESE_FEATURE_ENABLED));
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005764 ret = -EINVAL;
5765 goto exit;
5766 }
5767
Wu Gao1ab05582018-11-08 16:22:49 +08005768 if (!cfg_in_range(CFG_LFR_ESE_FEATURE_ENABLED, ese_mode)) {
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005769 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08005770 ese_mode, cfg_min(CFG_LFR_ESE_FEATURE_ENABLED),
5771 cfg_max(CFG_LFR_ESE_FEATURE_ENABLED));
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005772 ret = -EINVAL;
5773 goto exit;
5774 }
Wu Gao1ab05582018-11-08 16:22:49 +08005775 hdd_debug("Received Command to change ese mode = %d", ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005776
Jeff Johnsond549efa2018-06-13 20:27:47 -07005777 sme_update_is_ese_feature_enabled(mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005778 adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08005779 ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005780
5781exit:
5782 return ret;
5783}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005784#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005785
Jeff Johnsone44b7012017-09-10 15:25:47 -07005786static int drv_cmd_set_mc_rate(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005787 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005788 uint8_t *command,
5789 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005790 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005791{
5792 int ret = 0;
5793 uint8_t *value = command;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005794 int target_rate = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005795
5796 /* input value is in units of hundred kbps */
5797
5798 /* Move pointer to ahead of SETMCRATE<delimiter> */
5799 value = value + command_len + 1;
5800
5801 /* Convert the value from ascii to integer, decimal base */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005802 ret = kstrtouint(value, 10, &target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005803
Jeff Johnsond549efa2018-06-13 20:27:47 -07005804 ret = wlan_hdd_set_mc_rate(adapter, target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005805 return ret;
5806}
5807
Jeff Johnsone44b7012017-09-10 15:25:47 -07005808static int drv_cmd_max_tx_power(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005809 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005810 uint8_t *command,
5811 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005812 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005813{
Jeff Johnsond549efa2018-06-13 20:27:47 -07005814 int ret;
5815 int tx_power;
5816 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005817 uint8_t *value = command;
Dustin Brownce5b3d32018-01-17 15:07:38 -08005818 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005819 struct qdf_mac_addr selfmac = QDF_MAC_ADDR_BCAST_INIT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005820
Jeff Johnsond549efa2018-06-13 20:27:47 -07005821 ret = hdd_parse_setmaxtxpower_command(value, &tx_power);
5822 if (ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005823 hdd_err("Invalid MAXTXPOWER command");
Jeff Johnsond549efa2018-06-13 20:27:47 -07005824 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005825 }
5826
Dustin Brown920397d2017-12-13 16:27:50 -08005827 hdd_for_each_adapter(hdd_ctx, adapter) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005828 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305829 qdf_copy_macaddr(&bssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005830 &adapter->mac_addr);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005831 qdf_copy_macaddr(&selfmac,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005832 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005833
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005834 hdd_debug("Device mode %d max tx power %d selfMac: "
Jeff Johnsond549efa2018-06-13 20:27:47 -07005835 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR,
5836 adapter->device_mode, tx_power,
5837 MAC_ADDR_ARRAY(selfmac.bytes),
5838 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005839
Jeff Johnsond549efa2018-06-13 20:27:47 -07005840 status = sme_set_max_tx_power(hdd_ctx->mac_handle,
5841 bssid, selfmac, tx_power);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305842 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005843 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005844 ret = -EINVAL;
5845 goto exit;
5846 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005847 hdd_debug("Set max tx power success");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005848 }
5849
5850exit:
5851 return ret;
5852}
5853
Jeff Johnsone44b7012017-09-10 15:25:47 -07005854static int drv_cmd_set_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005855 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005856 uint8_t *command,
5857 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005858 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005859{
5860 int ret = 0;
5861 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08005862 uint8_t dfs_scan_mode = cfg_default(CFG_LFR_ROAMING_DFS_CHANNEL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005863
5864 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5865 value = value + command_len + 1;
5866
5867 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08005868 ret = kstrtou8(value, 10, &dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005869 if (ret < 0) {
5870 /*
5871 * If the input value is greater than max value of datatype,
5872 * then also kstrtou8 fails
5873 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005874 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08005875 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5876 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005877 ret = -EINVAL;
5878 goto exit;
5879 }
5880
Wu Gao1ab05582018-11-08 16:22:49 +08005881 if (!cfg_in_range(CFG_LFR_ROAMING_DFS_CHANNEL, dfs_scan_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005882 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08005883 dfs_scan_mode,
5884 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5885 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005886 ret = -EINVAL;
5887 goto exit;
5888 }
5889
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005890 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08005891 dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005892
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005893 /* When DFS scanning is disabled, the DFS channels need to be
5894 * removed from the operation of device.
5895 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005896 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
Wu Gao1ab05582018-11-08 16:22:49 +08005897 dfs_scan_mode != ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005898 if (ret < 0) {
5899 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005900 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005901 goto exit;
5902 }
5903
Jeff Johnsond549efa2018-06-13 20:27:47 -07005904 sme_update_dfs_scan_mode(hdd_ctx->mac_handle, adapter->session_id,
Wu Gao1ab05582018-11-08 16:22:49 +08005905 dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005906
5907exit:
5908 return ret;
5909}
5910
Jeff Johnsone44b7012017-09-10 15:25:47 -07005911static int drv_cmd_get_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005912 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005913 uint8_t *command,
5914 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005915 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005916{
5917 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005918 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005919 char extra[32];
5920 uint8_t len = 0;
5921
5922 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305923 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005924 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005925 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005926 ret = -EFAULT;
5927 }
5928
5929 return ret;
5930}
5931
Jeff Johnsone44b7012017-09-10 15:25:47 -07005932static int drv_cmd_get_link_status(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005933 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005934 uint8_t *command,
5935 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005936 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005937{
5938 int ret = 0;
5939 int value = wlan_hdd_get_link_status(adapter);
5940 char extra[32];
5941 uint8_t len;
5942
5943 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305944 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005945 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005946 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005947 ret = -EFAULT;
5948 }
5949
5950 return ret;
5951}
5952
5953#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Jeff Johnsone44b7012017-09-10 15:25:47 -07005954static int drv_cmd_enable_ext_wow(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005955 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005956 uint8_t *command,
5957 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005958 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005959{
5960 uint8_t *value = command;
5961 int set_value;
5962
5963 /* Move pointer to ahead of ENABLEEXTWOW */
5964 value = value + command_len;
5965
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305966 if (!(sscanf(value, "%d", &set_value))) {
Dustin Browna2868622018-03-20 11:38:14 -07005967 hdd_info("No input identified");
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305968 return -EINVAL;
5969 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005970
5971 return hdd_enable_ext_wow_parser(adapter,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005972 adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005973 set_value);
5974}
5975
Jeff Johnsone44b7012017-09-10 15:25:47 -07005976static int drv_cmd_set_app1_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005977 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005978 uint8_t *command,
5979 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005980 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005981{
5982 int ret;
5983 uint8_t *value = command;
5984
5985 /* Move pointer to ahead of SETAPP1PARAMS */
5986 value = value + command_len;
5987
5988 ret = hdd_set_app_type1_parser(adapter,
5989 value, strlen(value));
5990 if (ret >= 0)
5991 hdd_ctx->is_extwow_app_type1_param_set = true;
5992
5993 return ret;
5994}
5995
Jeff Johnsone44b7012017-09-10 15:25:47 -07005996static int drv_cmd_set_app2_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005997 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005998 uint8_t *command,
5999 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006000 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006001{
6002 int ret;
6003 uint8_t *value = command;
6004
6005 /* Move pointer to ahead of SETAPP2PARAMS */
6006 value = value + command_len;
6007
6008 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
6009 if (ret >= 0)
6010 hdd_ctx->is_extwow_app_type2_param_set = true;
6011
6012 return ret;
6013}
6014#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
6015
6016#ifdef FEATURE_WLAN_TDLS
6017/**
6018 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
6019 * @adapter: Pointer to the HDD adapter
6020 * @hdd_ctx: Pointer to the HDD context
6021 * @command: Driver command string
6022 * @command_len: Driver command string length
6023 * @priv_data: Private data coming with the driver command. Unused here
6024 *
6025 * This function handles driver command that sets the secondary tdls off channel
6026 * offset
6027 *
6028 * Return: 0 on success; negative errno otherwise
6029 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006030static int drv_cmd_tdls_secondary_channel_offset(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006031 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006032 uint8_t *command,
6033 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006034 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006035{
6036 int ret;
6037 uint8_t *value = command;
6038 int set_value;
6039
6040 /* Move pointer to point the string */
6041 value += command_len;
6042
6043 ret = sscanf(value, "%d", &set_value);
6044 if (ret != 1)
6045 return -EINVAL;
6046
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006047 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006048
Bala Venkatesh113a9e62018-08-30 15:19:02 +05306049 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, adapter, set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006050
6051 return ret;
6052}
6053
6054/**
6055 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
6056 * @adapter: Pointer to the HDD adapter
6057 * @hdd_ctx: Pointer to the HDD context
6058 * @command: Driver command string
6059 * @command_len: Driver command string length
6060 * @priv_data: Private data coming with the driver command. Unused here
6061 *
6062 * This function handles driver command that sets tdls off channel mode
6063 *
6064 * Return: 0 on success; negative errno otherwise
6065 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006066static int drv_cmd_tdls_off_channel_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006067 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006068 uint8_t *command,
6069 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006070 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006071{
6072 int ret;
6073 uint8_t *value = command;
6074 int set_value;
6075
6076 /* Move pointer to point the string */
6077 value += command_len;
6078
6079 ret = sscanf(value, "%d", &set_value);
6080 if (ret != 1)
6081 return -EINVAL;
6082
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006083 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006084
Bala Venkatesh113a9e62018-08-30 15:19:02 +05306085 ret = hdd_set_tdls_offchannelmode(hdd_ctx, adapter, set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006086
6087 return ret;
6088}
6089
6090/**
6091 * drv_cmd_tdls_off_channel() - set tdls off channel number
6092 * @adapter: Pointer to the HDD adapter
6093 * @hdd_ctx: Pointer to the HDD context
6094 * @command: Driver command string
6095 * @command_len: Driver command string length
6096 * @priv_data: Private data coming with the driver command. Unused here
6097 *
6098 * This function handles driver command that sets tdls off channel number
6099 *
6100 * Return: 0 on success; negative errno otherwise
6101 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006102static int drv_cmd_tdls_off_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006103 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006104 uint8_t *command,
6105 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006106 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006107{
6108 int ret;
6109 uint8_t *value = command;
6110 int set_value;
6111
6112 /* Move pointer to point the string */
6113 value += command_len;
6114
6115 ret = sscanf(value, "%d", &set_value);
6116 if (ret != 1)
6117 return -EINVAL;
6118
Dustin Brown07901ec2018-09-07 11:02:41 -07006119 if (wlan_reg_is_dfs_ch(hdd_ctx->pdev, set_value)) {
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006120 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6121 set_value);
6122 return -EINVAL;
6123 }
6124
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006125 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006126
Bala Venkatesh113a9e62018-08-30 15:19:02 +05306127 ret = hdd_set_tdls_offchannel(hdd_ctx, adapter, set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006128
6129 return ret;
6130}
6131
6132/**
6133 * drv_cmd_tdls_scan() - set tdls scan type
6134 * @adapter: Pointer to the HDD adapter
6135 * @hdd_ctx: Pointer to the HDD context
6136 * @command: Driver command string
6137 * @command_len: Driver command string length
6138 * @priv_data: Private data coming with the driver command. Unused here
6139 *
6140 * This function handles driver command that sets tdls scan type
6141 *
6142 * Return: 0 on success; negative errno otherwise
6143 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006144static int drv_cmd_tdls_scan(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006145 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006146 uint8_t *command,
6147 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006148 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006149{
6150 int ret;
6151 uint8_t *value = command;
6152 int set_value;
6153
6154 /* Move pointer to point the string */
6155 value += command_len;
6156
6157 ret = sscanf(value, "%d", &set_value);
6158 if (ret != 1)
6159 return -EINVAL;
6160
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006161 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006162
6163 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6164
6165 return ret;
6166}
6167#endif
6168
Jeff Johnsone44b7012017-09-10 15:25:47 -07006169static int drv_cmd_get_rssi(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006170 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006171 uint8_t *command,
6172 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006173 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006174{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006175 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006176 int8_t rssi = 0;
6177 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006178
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006179 uint8_t len = 0;
6180
6181 wlan_hdd_get_rssi(adapter, &rssi);
6182
6183 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306184 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006185
6186 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006187 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006188 ret = -EFAULT;
6189 }
6190
6191 return ret;
6192}
6193
Jeff Johnsone44b7012017-09-10 15:25:47 -07006194static int drv_cmd_get_linkspeed(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006195 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006196 uint8_t *command,
6197 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006198 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006199{
6200 int ret;
6201 uint32_t link_speed = 0;
6202 char extra[32];
6203 uint8_t len = 0;
6204
6205 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6206 if (0 != ret)
6207 return ret;
6208
6209 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306210 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006211 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006212 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006213 ret = -EFAULT;
6214 }
6215
6216 return ret;
6217}
6218
Qiwei Cai4505fc62018-05-17 18:35:19 +08006219#ifdef WLAN_FEATURE_PACKET_FILTERING
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006220/**
6221 * hdd_set_rx_filter() - set RX filter
6222 * @adapter: Pointer to adapter
6223 * @action: Filter action
6224 * @pattern: Address pattern
6225 *
6226 * Address pattern is most significant byte of address for example
6227 * 0x01 for IPV4 multicast address
6228 * 0x33 for IPV6 multicast address
6229 * 0xFF for broadcast address
6230 *
6231 * Return: 0 for success, non-zero for failure
6232 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006233static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006234 uint8_t pattern)
6235{
6236 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006237 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006238 tSirRcvFltMcAddrList *filter;
Jeff Johnson621cf972017-08-28 11:58:44 -07006239 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006240 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006241
6242 ret = wlan_hdd_validate_context(hdd_ctx);
6243 if (0 != ret)
6244 return ret;
6245
Jeff Johnsond549efa2018-06-13 20:27:47 -07006246 mac_handle = hdd_ctx->mac_handle;
6247 if (!mac_handle) {
6248 hdd_err("MAC Handle is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006249 return -EINVAL;
6250 }
6251
Wu Gao66454f12018-09-26 19:55:41 +08006252 if (!ucfg_pmo_is_mc_addr_list_enabled(hdd_ctx->psoc)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006253 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306254 return -EINVAL;
6255 }
6256
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006257 /*
6258 * If action is false it means start dropping packets
6259 * Set addr_filter_pattern which will be used when sending
6260 * MC/BC address list to target
6261 */
6262 if (!action)
6263 adapter->addr_filter_pattern = pattern;
6264 else
6265 adapter->addr_filter_pattern = 0;
6266
Krunal Sonibe766b02016-03-10 13:00:44 -08006267 if (((adapter->device_mode == QDF_STA_MODE) ||
6268 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006269 adapter->mc_addr_list.mc_cnt &&
6270 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6271
6272
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306273 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006274 if (NULL == filter) {
6275 hdd_err("Could not allocate Memory");
6276 return -ENOMEM;
6277 }
6278 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006279 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006280 if (!memcmp(adapter->mc_addr_list.addr[i],
6281 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006282 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006283 adapter->mc_addr_list.addr[i],
6284 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006285
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006286 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006287 MAC_ADDRESS_STR,
6288 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006289 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6290 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006291 }
SaidiReddy Yenuga0b2c9f42017-02-03 12:26:38 +05306292 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
6293 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006294 }
Frank Liuf95e8132016-09-29 19:01:30 +08006295 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006296 /* Set rx filter */
Jeff Johnsond549efa2018-06-13 20:27:47 -07006297 sme_8023_multicast_list(mac_handle, adapter->session_id,
6298 filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306299 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006300 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006301 hdd_debug("mode %d mc_cnt %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07006302 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006303 }
6304
6305 return 0;
6306}
6307
6308/**
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006309 * hdd_driver_rxfilter_command_handler() - RXFILTER driver command handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006310 * @command: Pointer to input string driver command
6311 * @adapter: Pointer to adapter
6312 * @action: Action to enable/disable filtering
6313 *
6314 * If action == false
6315 * Start filtering out data packets based on type
6316 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6317 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6318 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6319 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6320 *
6321 * if action == true
6322 * Stop filtering data packets based on type
6323 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6324 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6325 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6326 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6327 *
6328 * Current implementation only supports IPV4 address filtering by
6329 * selectively allowing IPV4 multicast data packest based on
6330 * address list received in .ndo_set_rx_mode
6331 *
6332 * Return: 0 for success, non-zero for failure
6333 */
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006334static int hdd_driver_rxfilter_command_handler(uint8_t *command,
Jeff Johnsone44b7012017-09-10 15:25:47 -07006335 struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006336 bool action)
6337{
6338 int ret = 0;
6339 uint8_t *value;
6340 uint8_t type;
6341
6342 value = command;
6343 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6344 if (!action)
6345 value = command + 16;
6346 else
6347 value = command + 13;
6348 ret = kstrtou8(value, 10, &type);
6349 if (ret < 0) {
Dustin Brown933cd2a2018-04-18 11:28:15 -07006350 hdd_err("kstrtou8 failed invalid input value");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006351 return -EINVAL;
6352 }
6353
6354 switch (type) {
6355 case 2:
6356 /* Set rx filter for IPV4 multicast data packets */
6357 ret = hdd_set_rx_filter(adapter, action, 0x01);
6358 break;
6359 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006360 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006361 break;
6362 }
6363
6364 return ret;
6365}
6366
6367/**
6368 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6369 * @adapter: Pointer to network adapter
6370 * @hdd_ctx: Pointer to hdd context
6371 * @command: Pointer to input command
6372 * @command_len: Command length
6373 * @priv_data: Pointer to private data in command
6374 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006375static int drv_cmd_rx_filter_remove(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006376 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006377 uint8_t *command,
6378 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006379 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006380{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006381 return hdd_driver_rxfilter_command_handler(command, adapter, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006382}
6383
6384/**
6385 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6386 * @adapter: Pointer to network adapter
6387 * @hdd_ctx: Pointer to hdd context
6388 * @command: Pointer to input command
6389 * @command_len: Command length
6390 * @priv_data: Pointer to private data in command
6391 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006392static int drv_cmd_rx_filter_add(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006393 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006394 uint8_t *command,
6395 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006396 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006397{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006398 return hdd_driver_rxfilter_command_handler(command, adapter, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006399}
Qiwei Cai4505fc62018-05-17 18:35:19 +08006400#endif /* WLAN_FEATURE_PACKET_FILTERING */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006401
Archana Ramachandran393f3792015-11-13 17:13:21 -08006402/**
6403 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6404 * command
6405 * @value: Pointer to SETANTENNAMODE command
6406 * @mode: Pointer to antenna mode
6407 * @reason: Pointer to reason for set antenna mode
6408 *
6409 * This function parses the SETANTENNAMODE command passed in the format
6410 * SETANTENNAMODE<space>mode
6411 *
6412 * Return: 0 for success non-zero for failure
6413 */
6414static int hdd_parse_setantennamode_command(const uint8_t *value)
6415{
6416 const uint8_t *in_ptr = value;
6417 int tmp, v;
6418 char arg1[32];
6419
6420 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6421
6422 /* no argument after the command */
6423 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006424 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006425 return -EINVAL;
6426 }
6427
6428 /* no space after the command */
6429 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006430 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006431 return -EINVAL;
6432 }
6433
6434 /* remove empty spaces */
6435 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6436 in_ptr++;
6437
6438 /* no argument followed by spaces */
6439 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006440 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006441 return -EINVAL;
6442 }
6443
6444 /* get the argument i.e. antenna mode */
6445 v = sscanf(in_ptr, "%31s ", arg1);
6446 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006447 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006448 return -EINVAL;
6449 }
6450
6451 v = kstrtos32(arg1, 10, &tmp);
6452 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006453 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006454 return -EINVAL;
6455 }
6456
6457 return tmp;
6458}
6459
6460/**
6461 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6462 * mask is 2x2 mode
6463 * @hdd_ctx: Pointer to hdd contex
6464 *
6465 * Return: true if supported chain mask 2x2 else false
6466 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006467static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006468{
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306469 QDF_STATUS status;
6470 bool bval = false;
6471
6472/*
Archana Ramachandran393f3792015-11-13 17:13:21 -08006473 * Revisit and the update logic to determine the number
6474 * of TX/RX chains supported in the system when
6475 * antenna sharing per band chain mask support is
6476 * brought in
6477 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306478 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6479 if (!QDF_IS_STATUS_SUCCESS(status))
6480 hdd_err("unable to get vht_enable2x2");
6481
6482 return (bval == 0x01) ? true : false;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006483}
6484
6485/**
6486 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6487 * chain mask is 1x1
6488 * @hdd_ctx: Pointer to hdd contex
6489 *
6490 * Return: true if supported chain mask 1x1 else false
6491 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006492static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006493{
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306494 QDF_STATUS status;
6495 bool bval = false;
6496
Archana Ramachandran393f3792015-11-13 17:13:21 -08006497 /*
6498 * Revisit and update the logic to determine the number
6499 * of TX/RX chains supported in the system when
6500 * antenna sharing per band chain mask support is
6501 * brought in
6502 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306503 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6504 if (!QDF_IS_STATUS_SUCCESS(status))
6505 hdd_err("unable to get vht_enable2x2");
6506
6507 return (!bval) ? true : false;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006508}
6509
Jeff Johnson621cf972017-08-28 11:58:44 -07006510QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
Nitesh Shahe50711f2017-04-26 16:30:45 +05306511{
6512 QDF_STATUS status;
6513 uint8_t smps_mode;
6514 uint8_t smps_enable;
Jeff Johnsond549efa2018-06-13 20:27:47 -07006515 mac_handle_t mac_handle;
Nitesh Shahe50711f2017-04-26 16:30:45 +05306516
6517 /* Update SME SMPS config */
6518 if (HDD_ANTENNA_MODE_1X1 == mode) {
6519 smps_enable = true;
6520 smps_mode = HDD_SMPS_MODE_STATIC;
6521 } else {
6522 smps_enable = false;
6523 smps_mode = HDD_SMPS_MODE_DISABLED;
6524 }
6525
6526 hdd_debug("Update SME SMPS enable: %d mode: %d",
6527 smps_enable, smps_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006528 mac_handle = hdd_ctx->mac_handle;
6529 status = sme_update_mimo_power_save(mac_handle, smps_enable,
6530 smps_mode, false);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306531 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07006532 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
Nitesh Shahe50711f2017-04-26 16:30:45 +05306533 smps_enable, smps_mode, status);
6534 return QDF_STATUS_E_FAILURE;
6535 }
6536
6537 hdd_ctx->current_antenna_mode = mode;
6538 /*
6539 * Update the user requested nss in the mac context.
6540 * This will be used in tdls protocol engine to form tdls
6541 * Management frames.
6542 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07006543 sme_update_user_configured_nss(mac_handle,
6544 hdd_ctx->current_antenna_mode);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306545
6546 hdd_debug("Successfully switched to mode: %d x %d",
6547 hdd_ctx->current_antenna_mode,
6548 hdd_ctx->current_antenna_mode);
6549
6550 return QDF_STATUS_SUCCESS;
6551}
6552
Dundi Raviteja4016e932018-08-02 12:16:25 +05306553/**
6554 * wlan_hdd_soc_set_antenna_mode_cb() - Callback for set antenna mode
6555 * @status: Status of set antenna mode
6556 * @context: callback context
6557 *
6558 * Callback on setting antenna mode
6559 *
6560 * Return: None
6561 */
6562static void
6563wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status,
6564 void *context)
6565{
6566 struct osif_request *request = NULL;
6567
6568 hdd_debug("Status: %d", status);
6569
6570 request = osif_request_get(context);
6571 if (!request) {
6572 hdd_err("obselete request");
6573 return;
6574 }
6575
6576 /* Signal the completion of set dual mac config */
6577 osif_request_complete(request);
6578 osif_request_put(request);
6579}
6580
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306581static QDF_STATUS
6582hdd_populate_vdev_chains(struct wlan_mlme_nss_chains *nss_chains_cfg,
6583 uint8_t tx_chains,
6584 uint8_t rx_chains,
6585 enum nss_chains_band_info band,
6586 struct wlan_objmgr_vdev *vdev)
6587{
6588 struct wlan_mlme_nss_chains *dynamic_cfg;
6589
6590 nss_chains_cfg->num_rx_chains[band] = rx_chains;
6591 nss_chains_cfg->num_tx_chains[band] = tx_chains;
6592
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306593 dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306594 if (!dynamic_cfg) {
6595 hdd_err("nss chain dynamic config NULL");
6596 return QDF_STATUS_E_FAILURE;
6597 }
6598 /*
6599 * If user gives any nss value, then chains will be adjusted based on
6600 * nss (in SME func sme_validate_user_nss_chain_params).
6601 * If Chains are not suitable as per current NSS then, we need to
6602 * return, and the below logic is added for the same.
6603 */
6604
6605 if ((dynamic_cfg->rx_nss[band] > rx_chains) ||
6606 (dynamic_cfg->tx_nss[band] > tx_chains)) {
6607 hdd_err("Chains less than nss, configure correct nss first.");
6608 return QDF_STATUS_E_FAILURE;
6609 }
6610
6611 return QDF_STATUS_SUCCESS;
6612}
6613
6614static int
6615hdd_set_dynamic_antenna_mode(struct hdd_adapter *adapter,
6616 uint8_t num_rx_chains,
6617 uint8_t num_tx_chains)
6618{
6619 enum nss_chains_band_info band;
6620 struct wlan_mlme_nss_chains user_cfg;
6621 QDF_STATUS status;
6622 mac_handle_t mac_handle;
6623 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6624
6625 mac_handle = hdd_ctx->mac_handle;
6626 if (!mac_handle) {
6627 hdd_err("NULL MAC handle");
6628 return -EINVAL;
6629 }
6630
gaurank kathpalia6982d472018-10-31 21:54:15 +05306631 if (!hdd_is_vdev_in_conn_state(adapter)) {
6632 hdd_debug("Vdev (id %d) not in connected/started state, cannot accept command",
6633 adapter->session_id);
6634 return -EINVAL;
6635 }
6636
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306637 qdf_mem_zero(&user_cfg, sizeof(user_cfg));
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306638 for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) {
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306639 status = hdd_populate_vdev_chains(&user_cfg,
6640 num_rx_chains,
6641 num_tx_chains, band,
6642 adapter->vdev);
6643 if (QDF_IS_STATUS_ERROR(status))
6644 return -EINVAL;
6645 }
6646 status = sme_nss_chains_update(mac_handle,
6647 &user_cfg,
6648 adapter->session_id);
6649 if (QDF_IS_STATUS_ERROR(status))
6650 return -EINVAL;
6651
6652 return 0;
6653}
Abhishek Singh1571ca72018-04-17 15:14:21 +05306654int hdd_set_antenna_mode(struct hdd_adapter *adapter,
6655 struct hdd_context *hdd_ctx, int mode)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006656{
6657 struct sir_antenna_mode_param params;
6658 QDF_STATUS status;
6659 int ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306660 struct osif_request *request = NULL;
6661 static const struct osif_request_params request_params = {
6662 .priv_size = 0,
6663 .timeout_ms = WLAN_WAIT_TIME_ANTENNA_MODE_REQ,
6664 };
Archana Ramachandran393f3792015-11-13 17:13:21 -08006665
Archana Ramachandran393f3792015-11-13 17:13:21 -08006666 switch (mode) {
6667 case HDD_ANTENNA_MODE_1X1:
6668 params.num_rx_chains = 1;
6669 params.num_tx_chains = 1;
6670 break;
6671 case HDD_ANTENNA_MODE_2X2:
6672 params.num_rx_chains = 2;
6673 params.num_tx_chains = 2;
6674 break;
6675 default:
6676 hdd_err("unsupported antenna mode");
6677 ret = -EINVAL;
6678 goto exit;
6679 }
6680
gaurank kathpalia1281b302018-11-05 21:10:37 +05306681 if (hdd_ctx->dynamic_nss_chains_support)
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306682 return hdd_set_dynamic_antenna_mode(adapter,
6683 params.num_rx_chains,
6684 params.num_tx_chains);
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306685
gaurank kathpaliaf95ae682018-11-05 21:13:07 +05306686 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6687 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6688 hdd_err("System does not support 2x2 mode");
6689 ret = -EPERM;
6690 goto exit;
6691 }
6692
6693 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6694 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6695 hdd_err("System only supports 1x1 mode");
6696 goto exit;
6697 }
6698
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006699 /* Check TDLS status and update antenna mode */
6700 if ((QDF_STA_MODE == adapter->device_mode) &&
Dustin Brown1dbefe62018-09-11 16:32:03 -07006701 policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07006702 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter, mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006703 if (0 != ret)
6704 goto exit;
6705 }
6706
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306707 request = osif_request_alloc(&request_params);
6708 if (!request) {
6709 hdd_err("Request Allocation Failure");
6710 ret = -ENOMEM;
6711 goto exit;
6712 }
6713
6714 params.set_antenna_mode_ctx = osif_request_cookie(request);
6715 params.set_antenna_mode_resp = (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006716 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006717 params.num_rx_chains,
6718 params.num_tx_chains);
6719
Jeff Johnsond549efa2018-06-13 20:27:47 -07006720 status = sme_soc_set_antenna_mode(hdd_ctx->mac_handle, &params);
Abhishek Singh1571ca72018-04-17 15:14:21 +05306721 if (QDF_IS_STATUS_ERROR(status)) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006722 hdd_err("set antenna mode failed status : %d", status);
6723 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306724 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006725 }
6726
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306727 ret = osif_request_wait_for_response(request);
6728 if (ret) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006729 hdd_err("send set antenna mode timed out");
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306730 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006731 }
6732
Nitesh Shahe50711f2017-04-26 16:30:45 +05306733 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006734 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006735 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306736 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006737 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006738 ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306739request_put:
6740 osif_request_put(request);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006741exit:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006742 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006743 ret, hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006744
Abhishek Singh1571ca72018-04-17 15:14:21 +05306745 return ret;
6746}
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306747
Abhishek Singh1571ca72018-04-17 15:14:21 +05306748/**
6749 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6750 * handler
6751 * @adapter: Pointer to network adapter
6752 * @hdd_ctx: Pointer to hdd context
6753 * @command: Pointer to input command
6754 * @command_len: Command length
6755 * @priv_data: Pointer to private data in command
6756 */
6757static int drv_cmd_set_antenna_mode(struct hdd_adapter *adapter,
6758 struct hdd_context *hdd_ctx,
6759 uint8_t *command,
6760 uint8_t command_len,
6761 struct hdd_priv_data *priv_data)
6762{
6763 int mode;
6764 uint8_t *value = command;
6765
6766 mode = hdd_parse_setantennamode_command(value);
6767 if (mode < 0) {
6768 hdd_err("Invalid SETANTENNA command");
6769 return mode;
6770 }
6771
6772 hdd_debug("Processing antenna mode switch to: %d", mode);
6773
6774 return hdd_set_antenna_mode(adapter, hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006775}
6776
6777/**
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306778 * hdd_get_dynamic_antenna_mode() -get the dynamic antenna mode for vdev
6779 * @antenna_mode: pointer to antenna mode of vdev
6780 * @dynamic_nss_chains_support: feature support for dynamic nss chains update
6781 * @vdev: Pointer to vdev
6782 *
6783 * This API will check for the num of chains configured for the vdev, and fill
6784 * that info in the antenna mode if the dynamic chains per vdev are supported.
6785 *
6786 * Return: None
6787 */
6788static void
6789hdd_get_dynamic_antenna_mode(uint32_t *antenna_mode,
6790 bool dynamic_nss_chains_support,
6791 struct wlan_objmgr_vdev *vdev)
6792{
6793 struct wlan_mlme_nss_chains *nss_chains_dynamic_cfg;
6794
6795 if (!dynamic_nss_chains_support)
6796 return;
6797
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306798 nss_chains_dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306799 if (!nss_chains_dynamic_cfg) {
6800 hdd_err("nss chain dynamic config NULL");
6801 return;
6802 }
6803 /*
6804 * At present, this command doesn't include band, so by default
6805 * it will return the band 2ghz present rf chains.
6806 */
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306807 *antenna_mode =
6808 nss_chains_dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306809}
6810
6811/**
Archana Ramachandran393f3792015-11-13 17:13:21 -08006812 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6813 * handler
6814 * @adapter: Pointer to hdd adapter
6815 * @hdd_ctx: Pointer to hdd context
6816 * @command: Pointer to input command
6817 * @command_len: length of the command
6818 * @priv_data: private data coming with the driver command
6819 *
6820 * Return: 0 for success non-zero for failure
6821 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006822static inline int drv_cmd_get_antenna_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006823 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006824 uint8_t *command,
6825 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006826 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006827{
6828 uint32_t antenna_mode = 0;
6829 char extra[32];
6830 uint8_t len = 0;
6831
6832 antenna_mode = hdd_ctx->current_antenna_mode;
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306833 /* Overwrite this antenna mode if dynamic vdev chains are supported */
6834 hdd_get_dynamic_antenna_mode(&antenna_mode,
6835 hdd_ctx->dynamic_nss_chains_support,
6836 adapter->vdev);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006837 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6838 antenna_mode);
6839 len = QDF_MIN(priv_data->total_len, len + 1);
6840 if (copy_to_user(priv_data->buf, &extra, len)) {
6841 hdd_err("Failed to copy data to user buffer");
6842 return -EFAULT;
6843 }
6844
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006845 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006846
6847 return 0;
6848}
6849
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006850/*
6851 * dummy (no-op) hdd driver command handler
6852 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006853static int drv_cmd_dummy(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006854 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006855 uint8_t *command,
6856 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006857 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006858{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006859 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006860 adapter->dev->name, command);
6861 return 0;
6862}
6863
6864/*
6865 * handler for any unsupported wlan hdd driver command
6866 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006867static int drv_cmd_invalid(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006868 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006869 uint8_t *command,
6870 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006871 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006872{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306873 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006874 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
Jeff Johnson1b780e42017-10-31 14:11:45 -07006875 adapter->session_id, 0));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006876
6877 hdd_warn("%s: Unsupported driver command \"%s\"",
6878 adapter->dev->name, command);
6879
6880 return -ENOTSUPP;
6881}
6882
6883/**
6884 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6885 * @adapter: HDD adapter
6886 * @hdd_ctx: HDD context
6887 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6888 * @command_len: command len
6889 * @priv_data: private data
6890 *
6891 * Return: status
6892 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006893static int drv_cmd_set_fcc_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006894 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006895 uint8_t *command,
6896 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006897 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006898{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306899 QDF_STATUS status;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006900 uint8_t fcc_constraint;
6901 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006902
6903 /*
6904 * this command would be called by user-space when it detects WLAN
6905 * ON after airplane mode is set. When APM is set, WLAN turns off.
6906 * But it can be turned back on. Otherwise; when APM is turned back
6907 * off, WLAN would turn back on. So at that point the command is
6908 * expected to come down. 0 means disable, 1 means enable. The
6909 * constraint is removed when parameter 1 is set or different
6910 * country code is set
6911 */
6912
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006913 err = kstrtou8(command + command_len + 1, 10, &fcc_constraint);
6914 if (err) {
6915 hdd_err("error %d parsing userspace fcc parameter", err);
6916 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006917 }
6918
Dustin Brown07901ec2018-09-07 11:02:41 -07006919 status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev, fcc_constraint);
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006920
6921 if (QDF_IS_STATUS_ERROR(status))
6922 hdd_err("Failed to %s tx power for channels 12/13",
6923 fcc_constraint ? "reduce" : "restore");
6924
6925 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006926}
6927
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306928/**
6929 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6930 * command
6931 * @value: Pointer to the command
6932 * @chan_number: Pointer to the channel number
6933 * @chan_bw: Pointer to the channel bandwidth
6934 *
6935 * Parses and provides the channel number and channel width from the input
6936 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6937 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6938 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6939 *
6940 * Return: 0 for success, non-zero for failure
6941 */
6942static int hdd_parse_set_channel_switch_command(uint8_t *value,
6943 uint32_t *chan_number,
6944 uint32_t *chan_bw)
6945{
6946 const uint8_t *in_ptr = value;
6947 int ret;
6948
6949 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6950
6951 /* no argument after the command */
6952 if (NULL == in_ptr) {
6953 hdd_err("No argument after the command");
6954 return -EINVAL;
6955 }
6956
6957 /* no space after the command */
6958 if (SPACE_ASCII_VALUE != *in_ptr) {
6959 hdd_err("No space after the command ");
6960 return -EINVAL;
6961 }
6962
6963 /* remove empty spaces and move the next argument */
6964 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6965 in_ptr++;
6966
6967 /* no argument followed by spaces */
6968 if ('\0' == *in_ptr) {
6969 hdd_err("No argument followed by spaces");
6970 return -EINVAL;
6971 }
6972
6973 /* get the two arguments: channel number and bandwidth */
6974 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6975 if (ret != 2) {
6976 hdd_err("Arguments retrieval from cmd string failed");
6977 return -EINVAL;
6978 }
6979
6980 return 0;
6981}
6982
6983/**
6984 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6985 * @adapter: HDD adapter
6986 * @hdd_ctx: HDD context
6987 * @command: Pointer to the input command CHANNEL_SWITCH
6988 * @command_len: Command len
6989 * @priv_data: Private data
6990 *
6991 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6992 * of SAP/P2P-GO
6993 *
6994 * Return: 0 for success, non-zero for failure
6995 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006996static int drv_cmd_set_channel_switch(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006997 struct hdd_context *hdd_ctx,
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306998 uint8_t *command,
6999 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07007000 struct hdd_priv_data *priv_data)
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307001{
7002 struct net_device *dev = adapter->dev;
7003 int status;
7004 uint32_t chan_number = 0, chan_bw = 0;
7005 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007006 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307007
Krunal Sonibe766b02016-03-10 13:00:44 -08007008 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7009 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307010 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7011 adapter->device_mode);
7012 return -EINVAL;
7013 }
7014
7015 status = hdd_parse_set_channel_switch_command(value,
7016 &chan_number, &chan_bw);
7017 if (status) {
7018 hdd_err("Invalid CHANNEL_SWITCH command");
7019 return status;
7020 }
7021
7022 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7023 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7024 return -EINVAL;
7025 }
7026
7027 if (chan_bw == 80)
7028 width = CH_WIDTH_80MHZ;
7029 else if (chan_bw == 40)
7030 width = CH_WIDTH_40MHZ;
7031 else
7032 width = CH_WIDTH_20MHZ;
7033
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007034 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307035
Wu Gao9daee1a2018-05-22 14:49:59 +08007036 status = hdd_softap_set_channel_change(dev, chan_number, width, true);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307037 if (status) {
7038 hdd_err("Set channel change fail");
7039 return status;
7040 }
7041
7042 return 0;
7043}
7044
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307045#ifdef DISABLE_CHANNEL_LIST
7046void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7047{
7048 hdd_enter();
7049
7050 if (!hdd_ctx->original_channels)
7051 return;
7052
7053 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7054 hdd_ctx->original_channels->num_channels = 0;
7055 if (hdd_ctx->original_channels->channel_info) {
7056 qdf_mem_free(hdd_ctx->original_channels->channel_info);
7057 hdd_ctx->original_channels->channel_info = NULL;
7058 }
7059 qdf_mem_free(hdd_ctx->original_channels);
7060 hdd_ctx->original_channels = NULL;
7061 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7062
7063 hdd_exit();
7064}
7065
7066/**
7067 * hdd_alloc_chan_cache() - Allocate the memory to cache the channel
7068 * info for the channels received in command SET_DISABLE_CHANNEL_LIST
7069 * @hdd_ctx: Pointer to HDD context
7070 * @num_chan: Number of channels for which memory needs to
7071 * be allocated
7072 *
7073 * Return: 0 on success and error code on failure
7074 */
7075static int hdd_alloc_chan_cache(struct hdd_context *hdd_ctx, int num_chan)
7076{
7077 hdd_ctx->original_channels =
7078 qdf_mem_malloc(sizeof(struct hdd_cache_channels));
7079 if (!hdd_ctx->original_channels) {
7080 hdd_err("QDF_MALLOC_ERR");
7081 return -ENOMEM;
7082 }
7083 hdd_ctx->original_channels->num_channels = num_chan;
7084 hdd_ctx->original_channels->channel_info =
7085 qdf_mem_malloc(num_chan *
7086 sizeof(struct hdd_cache_channel_info));
7087 if (!hdd_ctx->original_channels->channel_info) {
7088 hdd_err("QDF_MALLOC_ERR");
7089 hdd_ctx->original_channels->num_channels = 0;
7090 qdf_mem_free(hdd_ctx->original_channels);
7091 hdd_ctx->original_channels = NULL;
7092 return -ENOMEM;
7093 }
7094 return 0;
7095}
7096
7097/**
7098 * hdd_parse_disable_chan_cmd() - Parse the channel list received
7099 * in command.
7100 * @adapter: pointer to hdd adapter
7101 * @ptr: Pointer to the command string
7102 *
7103 * This function parses the channel list received in the command.
7104 * command should be a string having format
7105 * SET_DISABLE_CHANNEL_LIST <num of channels>
7106 * <channels separated by spaces>.
7107 * If the command comes multiple times than this function will compare
7108 * the channels received in the command with the channles cached in the
7109 * first command, if the channel list matches with the cached channles,
7110 * it returns success otherwise returns failure.
7111 *
7112 * Return: 0 on success, Error code on failure
7113 */
7114
7115static int hdd_parse_disable_chan_cmd(struct hdd_adapter *adapter, uint8_t *ptr)
7116{
7117 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7118 uint8_t *param;
7119 int j, i, temp_int, ret = 0, num_channels;
7120 uint32_t parsed_channels[MAX_CHANNEL];
7121 bool is_command_repeated = false;
7122
7123 if (NULL == hdd_ctx) {
7124 hdd_err("HDD Context is NULL");
7125 return -EINVAL;
7126 }
7127
7128 param = strnchr(ptr, strlen(ptr), ' ');
7129 /*no argument after the command*/
7130 if (NULL == param)
7131 return -EINVAL;
7132
7133 /*no space after the command*/
7134 else if (SPACE_ASCII_VALUE != *param)
7135 return -EINVAL;
7136
7137 param++;
7138
7139 /*removing empty spaces*/
7140 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7141 param++;
7142
7143 /*no argument followed by spaces*/
7144 if ('\0' == *param)
7145 return -EINVAL;
7146
7147 /*getting the first argument ie the number of channels*/
7148 if (sscanf(param, "%d ", &temp_int) != 1) {
7149 hdd_err("Cannot get number of channels from input");
7150 return -EINVAL;
7151 }
7152
7153 if (temp_int < 0 || temp_int > MAX_CHANNEL) {
7154 hdd_err("Invalid Number of channel received");
7155 return -EINVAL;
7156 }
7157
7158 hdd_debug("Number of channel to disable are: %d", temp_int);
7159
7160 if (!temp_int) {
7161 if (!wlan_hdd_restore_channels(hdd_ctx, false)) {
7162 /*
7163 * Free the cache channels only when the command is
7164 * received with num channels as 0
7165 */
7166 wlan_hdd_free_cache_channels(hdd_ctx);
7167 }
7168 return 0;
7169 }
7170
7171 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7172
7173 if (!hdd_ctx->original_channels) {
7174 if (hdd_alloc_chan_cache(hdd_ctx, temp_int)) {
7175 ret = -ENOMEM;
7176 goto mem_alloc_failed;
7177 }
7178 } else if (hdd_ctx->original_channels->num_channels != temp_int) {
7179 hdd_err("Invalid Number of channels");
7180 ret = -EINVAL;
7181 is_command_repeated = true;
7182 goto parse_failed;
7183 } else {
7184 is_command_repeated = true;
7185 }
7186 num_channels = temp_int;
7187 for (j = 0; j < num_channels; j++) {
7188 /*
7189 * param pointing to the beginning of first space
7190 * after number of channels
7191 */
7192 param = strpbrk(param, " ");
7193 /*no channel list after the number of channels argument*/
7194 if (NULL == param) {
7195 hdd_err("Invalid No of channel provided in the list");
7196 ret = -EINVAL;
7197 goto parse_failed;
7198 }
7199
7200 param++;
7201
7202 /*removing empty space*/
7203 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7204 param++;
7205
7206 if ('\0' == *param) {
7207 hdd_err("No channel is provided in the list");
7208 ret = -EINVAL;
7209 goto parse_failed;
7210 }
7211
7212 if (sscanf(param, "%d ", &temp_int) != 1) {
7213 hdd_err("Cannot read channel number");
7214 ret = -EINVAL;
7215 goto parse_failed;
7216 }
7217
7218 if (!IS_CHANNEL_VALID(temp_int)) {
7219 hdd_err("Invalid channel number received");
7220 ret = -EINVAL;
7221 goto parse_failed;
7222 }
7223
7224 hdd_debug("channel[%d] = %d", j, temp_int);
7225 parsed_channels[j] = temp_int;
7226 }
7227
7228 /*extra arguments check*/
7229 param = strpbrk(param, " ");
7230 if (NULL != param) {
7231 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7232 param++;
7233
7234 if ('\0' != *param) {
7235 hdd_err("Invalid argument received");
7236 ret = -EINVAL;
7237 goto parse_failed;
7238 }
7239 }
7240
7241 /*
7242 * If command is received first time, cache the channels to
7243 * be disabled else compare the channels received in the
7244 * command with the cached channels, if channel list matches
7245 * return success otherewise return failure.
7246 */
7247 if (!is_command_repeated) {
7248 for (j = 0; j < num_channels; j++)
7249 hdd_ctx->original_channels->
7250 channel_info[j].channel_num =
7251 parsed_channels[j];
Dustin Brown3f0d7102018-08-02 12:01:52 -07007252
7253 /* Cache the channel list in regulatory also */
Dustin Brown07901ec2018-09-07 11:02:41 -07007254 ucfg_reg_cache_channel_state(hdd_ctx->pdev, parsed_channels,
Dustin Brown3f0d7102018-08-02 12:01:52 -07007255 num_channels);
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307256 } else {
7257 for (i = 0; i < num_channels; i++) {
7258 for (j = 0; j < num_channels; j++)
7259 if (hdd_ctx->original_channels->
7260 channel_info[i].channel_num ==
7261 parsed_channels[j])
7262 break;
7263 if (j == num_channels) {
7264 ret = -EINVAL;
7265 goto parse_failed;
7266 }
7267 }
7268 ret = 0;
7269 }
7270mem_alloc_failed:
7271
7272 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7273 hdd_exit();
7274
7275 return ret;
7276
7277parse_failed:
7278 if (!is_command_repeated)
7279 wlan_hdd_free_cache_channels(hdd_ctx);
7280 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7281 hdd_exit();
7282
7283 return ret;
7284}
7285
7286static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7287 struct hdd_context *hdd_ctx,
7288 uint8_t *command,
7289 uint8_t command_len,
7290 struct hdd_priv_data *priv_data)
7291{
7292 return hdd_parse_disable_chan_cmd(adapter, command);
7293}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307294
7295/**
7296 * hdd_get_disable_ch_list() - get disable channel list
7297 * @hdd_ctx: hdd context
7298 * @buf: buffer to hold disable channel list
7299 * @buf_len: buffer length
7300 *
7301 * Return: length of data copied to buf
7302 */
7303static int hdd_get_disable_ch_list(struct hdd_context *hdd_ctx, uint8_t *buf,
7304 uint32_t buf_len)
7305{
7306 struct hdd_cache_channel_info *ch_list;
7307 unsigned char i, num_ch;
7308 int len = 0;
7309
7310 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7311 if (hdd_ctx->original_channels &&
7312 hdd_ctx->original_channels->num_channels &&
7313 hdd_ctx->original_channels->channel_info) {
7314 num_ch = hdd_ctx->original_channels->num_channels;
7315
7316 len = scnprintf(buf, buf_len, "%s %hhu",
7317 "GET_DISABLE_CHANNEL_LIST", num_ch);
7318 ch_list = hdd_ctx->original_channels->channel_info;
7319 for (i = 0; (i < num_ch) && (len < buf_len - 1); i++) {
7320 len += scnprintf(buf + len, buf_len - len,
7321 " %d", ch_list[i].channel_num);
7322 }
7323 }
7324 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7325
7326 return len;
7327}
7328
7329static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7330 struct hdd_context *hdd_ctx,
7331 uint8_t *command,
7332 uint8_t command_len,
7333 struct hdd_priv_data *priv_data)
7334{
7335 char extra[512] = {0};
7336 int max_len, copied_length;
7337
7338 hdd_debug("Received Command to get disable Channels list");
7339
7340 max_len = QDF_MIN(priv_data->total_len, sizeof(extra));
7341 copied_length = hdd_get_disable_ch_list(hdd_ctx, extra, max_len);
7342 if (copied_length == 0) {
7343 hdd_err("disable channel list is not yet programmed");
7344 return -EINVAL;
7345 }
7346
7347 if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
7348 hdd_err("failed to copy data to user buffer");
7349 return -EFAULT;
7350 }
7351
7352 hdd_debug("data:%s", extra);
7353 return 0;
7354}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307355#else
7356
7357static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7358 struct hdd_context *hdd_ctx,
7359 uint8_t *command,
7360 uint8_t command_len,
7361 struct hdd_priv_data *priv_data)
7362{
7363 return 0;
7364}
7365
7366void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7367{
7368}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307369
7370static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7371 struct hdd_context *hdd_ctx,
7372 uint8_t *command,
7373 uint8_t command_len,
7374 struct hdd_priv_data *priv_data)
7375{
7376 return 0;
7377}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307378#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007379/*
7380 * The following table contains all supported WLAN HDD
7381 * IOCTL driver commands and the handler for each of them.
7382 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07007383static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307384 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false},
7385 {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true},
7386 {"P2P_SET_PS", drv_cmd_p2p_set_ps, true},
7387 {"SETBAND", drv_cmd_set_band, true},
7388 {"SETWMMPS", drv_cmd_set_wmmps, true},
7389 {"COUNTRY", drv_cmd_country, true},
7390 {"SETSUSPENDMODE", drv_cmd_dummy, false},
7391 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307392 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true},
7393 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false},
7394 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true},
7395 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false},
7396 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period,
7397 true},
7398 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period,
7399 false},
7400 {"SETROAMMODE", drv_cmd_set_roam_mode, true},
7401 {"GETROAMMODE", drv_cmd_get_roam_mode, false},
7402 {"SETROAMDELTA", drv_cmd_set_roam_delta, true},
7403 {"GETROAMDELTA", drv_cmd_get_roam_delta, false},
7404 {"GETBAND", drv_cmd_get_band, false},
7405 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels, true},
7406 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels, false},
7407 {"GETCCXMODE", drv_cmd_get_ccx_mode, false},
7408 {"GETOKCMODE", drv_cmd_get_okc_mode, false},
7409 {"GETFASTROAM", drv_cmd_get_fast_roam, false},
7410 {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false},
7411 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
7412 true},
7413 {"SENDACTIONFRAME", drv_cmd_send_action_frame, true},
7414 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
7415 false},
7416 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true},
7417 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false},
7418 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true},
7419 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false},
7420 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true},
7421 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false},
7422 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true},
7423 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false},
7424 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true},
7425 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false},
7426 {"REASSOC", drv_cmd_reassoc, true},
7427 {"SETWESMODE", drv_cmd_set_wes_mode, true},
7428 {"GETWESMODE", drv_cmd_get_wes_mode, false},
7429 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff,
7430 true},
7431 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff,
7432 false},
7433 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true},
7434 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false},
7435 {"SETFASTROAM", drv_cmd_set_fast_roam, true},
7436 {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true},
7437 {"FASTREASSOC", drv_cmd_fast_reassoc, true},
7438 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control, true},
7439 {"SETOKCMODE", drv_cmd_set_okc_mode, true},
7440 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control, false},
7441 {"BTCOEXMODE", drv_cmd_bt_coex_mode, true},
7442 {"SCAN-ACTIVE", drv_cmd_scan_active, false},
7443 {"SCAN-PASSIVE", drv_cmd_scan_passive, false},
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05307444#ifdef WLAN_AP_STA_CONCURRENCY
7445 {"CONCSETDWELLTIME", drv_cmd_conc_set_dwell_time, true},
7446#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307447 {"GETDWELLTIME", drv_cmd_get_dwell_time, false},
7448 {"SETDWELLTIME", drv_cmd_set_dwell_time, true},
7449 {"MIRACAST", drv_cmd_miracast, true},
7450 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05307451#ifdef FEATURE_WLAN_RMC
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307452 {"SETRMCENABLE", drv_cmd_set_rmc_enable, true},
7453 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05307454 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate, true},
7455#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307456 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all, false},
7457 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307458 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007459#ifdef FEATURE_WLAN_ESE
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307460 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true},
7461 {"GETTSMSTATS", drv_cmd_get_tsm_stats, true},
7462 {"SETCCKMIE", drv_cmd_set_cckm_ie, true},
7463 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true},
7464 {"CCXPLMREQ", drv_cmd_ccx_plm_req, true},
7465 {"SETCCXMODE", drv_cmd_set_ccx_mode, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007466#endif /* FEATURE_WLAN_ESE */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307467 {"SETMCRATE", drv_cmd_set_mc_rate, true},
7468 {"MAXTXPOWER", drv_cmd_max_tx_power, true},
7469 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true},
7470 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false},
7471 {"GETLINKSTATUS", drv_cmd_get_link_status, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007472#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307473 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true},
7474 {"SETAPP1PARAMS", drv_cmd_set_app1_params, true},
7475 {"SETAPP2PARAMS", drv_cmd_set_app2_params, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007476#endif
7477#ifdef FEATURE_WLAN_TDLS
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307478 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
7479 true},
7480 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true},
7481 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true},
7482 {"TDLSSCAN", drv_cmd_tdls_scan, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007483#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307484 {"RSSI", drv_cmd_get_rssi, false},
7485 {"LINKSPEED", drv_cmd_get_linkspeed, false},
Qiwei Cai4505fc62018-05-17 18:35:19 +08007486#ifdef WLAN_FEATURE_PACKET_FILTERING
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307487 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true},
7488 {"RXFILTER-ADD", drv_cmd_rx_filter_add, true},
Qiwei Cai4505fc62018-05-17 18:35:19 +08007489#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307490 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true},
7491 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true},
7492 {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true},
7493 {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false},
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307494 {"SET_DISABLE_CHANNEL_LIST", drv_cmd_set_disable_chan_list, true},
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307495 {"GET_DISABLE_CHANNEL_LIST", drv_cmd_get_disable_chan_list, false},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307496 {"STOP", drv_cmd_dummy, false},
Srinivas Girigowda836475e2018-04-17 14:42:23 -07007497 /* Deprecated commands */
7498 {"RXFILTER-START", drv_cmd_dummy, false},
7499 {"RXFILTER-STOP", drv_cmd_dummy, false},
7500 {"BTCOEXSCAN-START", drv_cmd_dummy, false},
7501 {"BTCOEXSCAN-STOP", drv_cmd_dummy, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007502};
7503
7504/**
7505 * hdd_drv_cmd_process() - chooses and runs the proper
7506 * handler based on the input command
7507 * @adapter: Pointer to the hdd adapter
7508 * @cmd: Pointer to the driver command
7509 * @priv_data: Pointer to the data associated with the command
7510 *
7511 * This function parses the input hdd driver command and runs
7512 * the proper handler
7513 *
7514 * Return: 0 for success non-zero for failure
7515 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007516static int hdd_drv_cmd_process(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007517 uint8_t *cmd,
Jeff Johnson353cd292017-08-17 06:47:26 -07007518 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007519{
Jeff Johnson621cf972017-08-28 11:58:44 -07007520 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007521 int i;
7522 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7523 uint8_t *cmd_i = NULL;
7524 hdd_drv_cmd_handler_t handler = NULL;
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307525 int len = 0, cmd_len = 0;
7526 uint8_t *ptr;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307527 bool args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007528
7529 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007530 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007531 return -EINVAL;
7532 }
7533
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307534 /* Calculate length of the first word */
7535 ptr = strchrnul(cmd, ' ');
7536 cmd_len = ptr - cmd;
7537
Jeff Johnson399c6272017-08-30 10:51:00 -07007538 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007539
7540 for (i = 0; i < cmd_num_total; i++) {
7541
7542 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7543 handler = hdd_drv_cmds[i].handler;
7544 len = strlen(cmd_i);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307545 args = hdd_drv_cmds[i].args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007546
7547 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007548 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007549 return -EINVAL;
7550 }
7551
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307552 if (len == cmd_len && strncasecmp(cmd, cmd_i, len) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307553 if (args && drv_cmd_validate(cmd, len))
7554 return -EINVAL;
7555
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007556 return handler(adapter, hdd_ctx,
7557 cmd, len, priv_data);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307558 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007559 }
7560
7561 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7562}
7563
7564/**
7565 * hdd_driver_command() - top level wlan hdd driver command handler
7566 * @adapter: Pointer to the hdd adapter
7567 * @priv_data: Pointer to the raw command data
7568 *
7569 * This function is the top level wlan hdd driver command handler. It
7570 * handles the command with the help of hdd_drv_cmd_process()
7571 *
7572 * Return: 0 for success non-zero for failure
7573 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007574static int hdd_driver_command(struct hdd_adapter *adapter,
Jeff Johnson353cd292017-08-17 06:47:26 -07007575 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007576{
7577 uint8_t *command = NULL;
7578 int ret = 0;
Jeff Johnson621cf972017-08-28 11:58:44 -07007579 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007580
Dustin Brown491d54b2018-03-14 12:39:11 -07007581 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307582
Anurag Chouhan6d760662016-02-20 16:05:43 +05307583 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007584 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007585 return -EINVAL;
7586 }
7587
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05307588 ret = wlan_hdd_validate_context(hdd_ctx);
7589 if (ret)
7590 return ret;
7591
7592 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
7593 hdd_err("Driver module is closed; command can not be processed");
7594 return -EINVAL;
7595 }
7596
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007597 /*
7598 * Note that valid pointers are provided by caller
7599 */
7600
7601 /* copy to local struct to avoid numerous changes to legacy code */
7602 if (priv_data->total_len <= 0 ||
7603 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007604 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007605 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007606 ret = -EINVAL;
7607 goto exit;
7608 }
7609
7610 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007611 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007612 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007613 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007614 ret = -ENOMEM;
7615 goto exit;
7616 }
7617
7618 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7619 ret = -EFAULT;
7620 goto exit;
7621 }
7622
7623 /* Make sure the command is NUL-terminated */
7624 command[priv_data->total_len] = '\0';
7625
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007626 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007627 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7628
7629exit:
7630 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007631 qdf_mem_free(command);
Dustin Browne74003f2018-03-14 12:51:58 -07007632 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007633 return ret;
7634}
7635
7636#ifdef CONFIG_COMPAT
Jeff Johnsone44b7012017-09-10 15:25:47 -07007637static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007638{
7639 struct {
7640 compat_uptr_t buf;
7641 int used_len;
7642 int total_len;
7643 } compat_priv_data;
Jeff Johnson353cd292017-08-17 06:47:26 -07007644 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007645 int ret = 0;
7646
7647 /*
7648 * Note that adapter and ifr have already been verified by caller,
7649 * and HDD context has also been validated
7650 */
7651 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7652 sizeof(compat_priv_data))) {
7653 ret = -EFAULT;
7654 goto exit;
7655 }
7656 priv_data.buf = compat_ptr(compat_priv_data.buf);
7657 priv_data.used_len = compat_priv_data.used_len;
7658 priv_data.total_len = compat_priv_data.total_len;
7659 ret = hdd_driver_command(adapter, &priv_data);
7660exit:
7661 return ret;
7662}
7663#else /* CONFIG_COMPAT */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007664static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007665{
7666 /* will never be invoked */
7667 return 0;
7668}
7669#endif /* CONFIG_COMPAT */
7670
Jeff Johnsone44b7012017-09-10 15:25:47 -07007671static int hdd_driver_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007672{
Jeff Johnson353cd292017-08-17 06:47:26 -07007673 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007674 int ret = 0;
7675
7676 /*
7677 * Note that adapter and ifr have already been verified by caller,
7678 * and HDD context has also been validated
7679 */
7680 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7681 ret = -EFAULT;
7682 else
7683 ret = hdd_driver_command(adapter, &priv_data);
7684
7685 return ret;
7686}
7687
7688/**
7689 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7690 * @dev: device upon which the ioctl was received
7691 * @ifr: ioctl request information
7692 * @cmd: ioctl command
7693 *
7694 * This function does initial processing of wlan device ioctls.
7695 * Currently two flavors of ioctls are supported. The primary ioctl
7696 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7697 * for Android "DRIVER" commands. The other ioctl that is
7698 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7699 * for FTM on some platforms. This function simply verifies that the
7700 * driver is in a sane state, and that the ioctl is one of the
7701 * supported flavors, in which case flavor-specific handlers are
7702 * dispatched.
7703 *
7704 * Return: 0 on success, non-zero on error
7705 */
7706static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7707{
Jeff Johnsone44b7012017-09-10 15:25:47 -07007708 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson621cf972017-08-28 11:58:44 -07007709 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007710 int ret;
7711
Dustin Brownfdf17c12018-03-14 12:55:34 -07007712 hdd_enter_dev(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307713
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007714 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007715 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007716 ret = -ENODEV;
7717 goto exit;
7718 }
7719
7720 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007721 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007722 ret = -EINVAL;
7723 goto exit;
7724 }
7725#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307726 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007727 if (SIOCIOCTLTX99 == cmd) {
7728 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7729 goto exit;
7730 }
7731 }
7732#endif
7733
7734 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7735 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307736 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007737 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007738
7739 switch (cmd) {
7740 case (SIOCDEVPRIVATE + 1):
Mahesh Kumar Kalikot Veetil885a77b2018-03-26 14:46:59 -07007741 if (in_compat_syscall())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007742 ret = hdd_driver_compat_ioctl(adapter, ifr);
7743 else
7744 ret = hdd_driver_ioctl(adapter, ifr);
7745 break;
7746 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007747 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007748 ret = -EINVAL;
7749 break;
7750 }
7751exit:
Dustin Browne74003f2018-03-14 12:51:58 -07007752 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007753 return ret;
7754}
7755
7756/**
7757 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7758 * @dev: device upon which the ioctl was received
7759 * @ifr: ioctl request information
7760 * @cmd: ioctl command
7761 *
7762 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7763 * which is where the ioctls are really handled.
7764 *
7765 * Return: 0 on success, non-zero on error
7766 */
7767int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7768{
7769 int ret;
7770
7771 cds_ssr_protect(__func__);
7772 ret = __hdd_ioctl(dev, ifr, cmd);
7773 cds_ssr_unprotect(__func__);
7774 return ret;
7775}