blob: 2b6ea66a5fa66d08890c3d557aecb5ffe7090ec0 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Arun Kumar Khandavalliafcb0552020-01-20 11:46:36 +05302 * Copyright (c) 2012-2020 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
Dustin Brown98f7c822019-03-06 12:25:49 -080021#include "osif_sync.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080022#include <wlan_hdd_includes.h>
23#include <wlan_hdd_wowl.h>
Jeff Johnson5fe539b2018-03-23 13:53:30 -070024#include <wlan_hdd_stats.h>
Pragaspathi Thilagaraj3cf0f652018-10-29 16:40:35 +053025#include "cfg_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080026#include "wlan_hdd_trace.h"
27#include "wlan_hdd_ioctl.h"
28#include "wlan_hdd_power.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070029#include "wlan_hdd_regulatory.h"
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -070030#include "wlan_osif_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080031#include "wlan_hdd_driver_ops.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080032#include "wlan_policy_mgr_api.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053033#include "wlan_hdd_hostapd.h"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080034#include "scheduler_api.h"
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -070035#include "wlan_reg_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080036#include "wlan_hdd_p2p.h"
37#include <linux/ctype.h>
38#include "wma.h"
39#include "wlan_hdd_napi.h"
Wu Gao93816212018-08-31 16:49:54 +080040#include "wlan_mlme_ucfg_api.h"
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080041#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080042#include <sme_api.h>
43#include <sir_api.h>
44#endif
45#include "hif.h"
Harprit Chhabada4691a472018-12-07 11:22:48 -080046#include "wlan_scan_ucfg_api.h"
Harprit Chhabada5dff30e2019-03-12 17:56:45 -070047#include "wlan_reg_ucfg_api.h"
Ashish Kumar Dhanotiya7efe26e2018-11-14 16:35:57 +053048#include "qdf_func_tracker.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080049
50#if defined(LINUX_QCMBR)
51#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
52#endif
53
54/*
55 * Size of Driver command strings from upper layer
56 */
57#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
58#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
Pragaspathi Thilagarajaa8320e2019-04-16 02:47:50 +053059#define SIZE_OF_SETSUSPENDMODE 14
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080060
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080061/*
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +053062 * Size of GETCOUNTRYREV output = (sizeof("GETCOUNTRYREV") = 14) + one (space) +
63 * (sizeof("country_code") = 3) +
64 * one (NULL terminating character)
65 */
66#define SIZE_OF_GETCOUNTRYREV_OUTPUT 20
67
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080068#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069#define TID_MIN_VALUE 0
70#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080071#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080072
73/*
74 * Maximum buffer size used for returning the data back to user space
75 */
76#define WLAN_MAX_BUF_SIZE 1024
77#define WLAN_PRIV_DATA_MAX_LEN 8192
78
79/*
80 * Driver miracast parameters 0-Disabled
81 * 1-Source, 2-Sink
82 */
83#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
84#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
85
86/*
87 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
88 * we will split the printing.
89 */
90#define NUM_OF_STA_DATA_TO_PRINT 16
91
Dundi Raviteja53de6c32018-05-16 16:56:30 +053092#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
93/**
94 * struct enable_ext_wow_priv - Private data structure for ext wow
95 * @ext_wow_should_suspend: Suspend status of ext wow
96 */
97struct enable_ext_wow_priv {
98 bool ext_wow_should_suspend;
99};
100#endif
101
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800102/*
103 * Android DRIVER command structures
104 */
105struct android_wifi_reassoc_params {
106 unsigned char bssid[18];
107 int channel;
108};
109
110#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
111struct android_wifi_af_params {
112 unsigned char bssid[18];
113 int channel;
114 int dwell_time;
115 int len;
116 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
117};
118
119/*
120 * Define HDD driver command handling entry, each contains a command
121 * string and the handler.
122 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700123typedef int (*hdd_drv_cmd_handler_t)(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -0700124 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800125 uint8_t *cmd,
126 uint8_t cmd_name_len,
Jeff Johnson353cd292017-08-17 06:47:26 -0700127 struct hdd_priv_data *priv_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800128
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530129/**
130 * struct hdd_drv_cmd - Structure to store ioctl command handling info
131 * @cmd: Name of the command
132 * @handler: Command handler to be invoked
133 * @args: Set to true if command expects input parameters
134 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700135struct hdd_drv_cmd {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800136 const char *cmd;
137 hdd_drv_cmd_handler_t handler;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530138 bool args;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700139};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140
141#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
142#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
143#define WLAN_HDD_MAX_TCP_PORT 65535
144#endif
145
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530146/**
147 * drv_cmd_validate() - Validates for space in hdd driver command
148 * @command: pointer to input data (its a NULL terminated string)
149 * @len: length of command name
150 *
151 * This function checks for space after command name and if no space
152 * is found returns error.
153 *
154 * Return: 0 for success non-zero for failure
155 */
156static int drv_cmd_validate(uint8_t *command, int len)
157{
158 if (command[len] != ' ')
159 return -EINVAL;
160
161 return 0;
162}
163
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800164#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800165struct tsm_priv {
166 tAniTrafStrmMetrics tsm_metrics;
167};
168
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800169static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
Sourav Mohapatradcd8f8d2019-07-03 15:43:15 +0530170 void *context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800171{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700172 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800173 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700175 request = osif_request_get(context);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800176 if (!request) {
177 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800178 return;
179 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700180 priv = osif_request_priv(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800181 priv->tsm_metrics = tsm_metrics;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700182 osif_request_complete(request);
183 osif_request_put(request);
Dustin Browne74003f2018-03-14 12:51:58 -0700184 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186}
187
Jeff Johnsone44b7012017-09-10 15:25:47 -0700188static int hdd_get_tsm_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800189 const uint8_t tid,
190 tAniTrafStrmMetrics *tsm_metrics)
191{
Jeff Johnson621cf972017-08-28 11:58:44 -0700192 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700193 struct hdd_station_ctx *hdd_sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800194 QDF_STATUS status;
195 int ret;
196 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700197 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800198 struct tsm_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700199 static const struct osif_request_params params = {
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800200 .priv_size = sizeof(*priv),
201 .timeout_ms = WLAN_WAIT_TIME_STATS,
202 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800203
Jeff Johnsond36fa332019-03-18 13:42:25 -0700204 if (!adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700205 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800206 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 }
208
209 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
210 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
211
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700212 request = osif_request_alloc(&params);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800213 if (!request) {
214 hdd_err("Request allocation failure");
215 return -ENOMEM;
216 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700217 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800218
Jeff Johnsond549efa2018-06-13 20:27:47 -0700219 status = sme_get_tsm_stats(hdd_ctx->mac_handle, hdd_get_tsm_stats_cb,
Jeff Johnsone04b6992019-02-27 14:06:55 -0800220 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
Abhishek Ambure68677462019-09-13 12:44:26 +0530244#ifdef QCA_IBSS_SUPPORT
245/*
246 * Ibss prop IE from command will be of size:
247 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
248 * OUI_DATA should be at least 3 bytes long
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800249 */
Abhishek Ambure68677462019-09-13 12:44:26 +0530250#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
251static uint16_t cesium_pid;
252
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700253void
Jeff Johnsonafa022c2019-02-26 09:24:17 -0800254hdd_get_ibss_peer_info_cb(void *context,
Jeff Johnson52f19d52019-02-26 08:35:38 -0800255 tSirPeerInfoRspParams *peer_info)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800256{
Jeff Johnsonafa022c2019-02-26 09:24:17 -0800257 struct hdd_adapter *adapter = context;
Jeff Johnson93107ad2019-02-26 08:14:46 -0800258 struct hdd_station_ctx *sta_ctx;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800259 uint8_t i;
260
Jeff Johnsond36fa332019-03-18 13:42:25 -0700261 if ((!adapter) ||
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800262 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800263 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800264 return;
265 }
266
Jeff Johnson93107ad2019-02-26 08:14:46 -0800267 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsond36fa332019-03-18 13:42:25 -0700268 if (peer_info && QDF_STATUS_SUCCESS == peer_info->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700269 /* validate number of peers */
Jeff Johnson52f19d52019-02-26 08:35:38 -0800270 if (peer_info->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530271 hdd_warn("Limiting num_peers %u to %u",
Jeff Johnson52f19d52019-02-26 08:35:38 -0800272 peer_info->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
273 peer_info->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800274 }
Jeff Johnson52f19d52019-02-26 08:35:38 -0800275 sta_ctx->ibss_peer_info.status = peer_info->status;
276 sta_ctx->ibss_peer_info.numPeers = peer_info->numPeers;
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530277
Jeff Johnson52f19d52019-02-26 08:35:38 -0800278 for (i = 0; i < peer_info->numPeers; i++)
Jeff Johnson93107ad2019-02-26 08:14:46 -0800279 sta_ctx->ibss_peer_info.peerInfoParams[i] =
Jeff Johnson52f19d52019-02-26 08:35:38 -0800280 peer_info->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800281 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800282 hdd_debug("peerInfo %s: status %u, numPeers %u",
Jeff Johnson52f19d52019-02-26 08:35:38 -0800283 peer_info ? "valid" : "null",
284 peer_info ? peer_info->status : QDF_STATUS_E_FAILURE,
285 peer_info ? peer_info->numPeers : 0);
Jeff Johnson93107ad2019-02-26 08:14:46 -0800286 sta_ctx->ibss_peer_info.numPeers = 0;
287 sta_ctx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800288 }
289
290 complete(&adapter->ibss_peer_info_comp);
291}
292
293/**
294 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
295 * @adapter: Adapter context
296 *
297 * Request function to get IBSS peer info from lower layers
298 *
299 * Return: 0 for success non-zero for failure
300 */
301static
Jeff Johnsone44b7012017-09-10 15:25:47 -0700302QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(struct hdd_adapter *adapter)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800303{
Jeff Johnsond549efa2018-06-13 20:27:47 -0700304 QDF_STATUS status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800305 unsigned long rc;
Yeshwanth Sriram Guntuka3f262102019-07-16 15:41:08 +0530306 struct qdf_mac_addr bcast = QDF_MAC_ADDR_BCAST_INIT;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800307
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,
Yeshwanth Sriram Guntuka3f262102019-07-16 15:41:08 +0530313 true, bcast.bytes);
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
Jeff Johnson0a082d92019-03-04 12:25:49 -0800335 * @sta_id: Sta index for which the peer info is requested
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800336 *
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
Sourav Mohapatraa3cf12a2019-08-19 15:40:49 +0530342hdd_cfg80211_get_ibss_peer_info(struct hdd_adapter *adapter, uint8_t *mac_addr)
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,
Sourav Mohapatraa3cf12a2019-08-19 15:40:49 +0530352 false, mac_addr);
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
Jeff Johnson6636e622019-02-26 10:22:39 -0800373hdd_parse_get_ibss_peer_info(uint8_t *command,
Jeff Johnson64ba9af2019-02-26 12:57:35 -0800374 struct qdf_mac_addr *peer_macaddr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800375{
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800376 uint8_t *in_ptr = command;
Jeff Johnson6636e622019-02-26 10:22:39 -0800377 size_t in_ptr_len = strlen(command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700378
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800379 in_ptr = strnchr(command, in_ptr_len, SPACE_ASCII_VALUE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800380
Jeff Johnsond36fa332019-03-18 13:42:25 -0700381 if (!in_ptr)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700382 return QDF_STATUS_E_FAILURE;
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800383 else if (SPACE_ASCII_VALUE != *in_ptr)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700384 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800385
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800386 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
387 in_ptr++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800388
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800389 if ('\0' == *in_ptr)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700390 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800391
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800392 in_ptr_len -= (in_ptr - command);
Min Liu5359ab12018-03-29 14:30:24 +0800393 if (in_ptr_len < 17)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700394 return QDF_STATUS_E_FAILURE;
Min Liu5359ab12018-03-29 14:30:24 +0800395
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800396 if (in_ptr[2] != ':' || in_ptr[5] != ':' || in_ptr[8] != ':' ||
397 in_ptr[11] != ':' || in_ptr[14] != ':')
Min Liu5359ab12018-03-29 14:30:24 +0800398 return QDF_STATUS_E_FAILURE;
399
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800400 sscanf(in_ptr, "%2x:%2x:%2x:%2x:%2x:%2x",
Jeff Johnson64ba9af2019-02-26 12:57:35 -0800401 (unsigned int *)&peer_macaddr->bytes[0],
402 (unsigned int *)&peer_macaddr->bytes[1],
403 (unsigned int *)&peer_macaddr->bytes[2],
404 (unsigned int *)&peer_macaddr->bytes[3],
405 (unsigned int *)&peer_macaddr->bytes[4],
406 (unsigned int *)&peer_macaddr->bytes[5]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800407
408 return QDF_STATUS_SUCCESS;
409}
410
Abhishek Ambure68677462019-09-13 12:44:26 +0530411static void hdd_tx_fail_ind_callback(uint8_t *macaddr, uint8_t seq_no)
412{
413 int payload_len;
414 struct sk_buff *skb;
415 struct nlmsghdr *nlh;
416 uint8_t *data;
417
418 payload_len = ETH_ALEN;
419
420 if (0 == cesium_pid || !cesium_nl_srv_sock) {
421 hdd_err("cesium process not registered");
422 return;
423 }
424
425 skb = nlmsg_new(payload_len, GFP_ATOMIC);
426 if (!skb) {
427 hdd_err("nlmsg_new() failed for msg size[%d]",
428 NLMSG_SPACE(payload_len));
429 return;
430 }
431
432 nlh = nlmsg_put(skb, cesium_pid, seq_no, 0, payload_len, NLM_F_REQUEST);
433
434 if (!nlh) {
435 hdd_err("nlmsg_put() failed for msg size[%d]",
436 NLMSG_SPACE(payload_len));
437
438 kfree_skb(skb);
439 return;
440 }
441
442 data = nlmsg_data(nlh);
443 memcpy(data, macaddr, ETH_ALEN);
444
445 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
446 hdd_err("nlmsg_unicast() failed for msg size[%d]",
447 NLMSG_SPACE(payload_len));
448 }
449}
450
451/**
452 * hdd_parse_user_params() - return a pointer to the next argument
453 * @command: Input argument string
454 * @arg: Output pointer to the next argument
455 *
456 * This function parses argument stream and finds the pointer
457 * to the next argument
458 *
459 * Return: 0 if the next argument found; -EINVAL otherwise
460 */
461static int hdd_parse_user_params(uint8_t *command, uint8_t **arg)
462{
463 uint8_t *cursor;
464
465 cursor = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
466
467 /* no argument remains ? */
468 if (!cursor)
469 return -EINVAL;
470
471 /* no space after the current arg ? */
472 if (SPACE_ASCII_VALUE != *cursor)
473 return -EINVAL;
474
475 cursor++;
476
477 /* remove empty spaces */
478 while (SPACE_ASCII_VALUE == *cursor)
479 cursor++;
480
481 /* no argument after the spaces ? */
482 if ('\0' == *cursor)
483 return -EINVAL;
484
485 *arg = cursor;
486
487 return 0;
488}
489
490/**
491 * hdd_parse_ibsstx_fail_event_params - Parse params
492 * for SETIBSSTXFAILEVENT
493 * @command: Input ibss tx fail event argument
494 * @tx_fail_count: (Output parameter) Tx fail counter
495 * @pid: (Output parameter) PID
496 *
497 * Return: 0 if the parsing succeeds; -EINVAL otherwise
498 */
499static int hdd_parse_ibsstx_fail_event_params(uint8_t *command,
500 uint8_t *tx_fail_count,
501 uint16_t *pid)
502{
503 uint8_t *param = NULL;
504 int ret;
505
506 ret = hdd_parse_user_params(command, &param);
507
508 if (0 == ret && param) {
509 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
510 ret = -EINVAL;
511 goto done;
512 }
513 } else {
514 goto done;
515 }
516
517 if (0 == *tx_fail_count) {
518 *pid = 0;
519 goto done;
520 }
521
522 command = param;
523 command++;
524
525 ret = hdd_parse_user_params(command, &param);
526
527 if (0 == ret) {
528 if (1 != sscanf(param, "%hu", pid)) {
529 ret = -EINVAL;
530 goto done;
531 }
532 } else {
533 goto done;
534 }
535
536done:
537 return ret;
538}
539
540/* Function header is left blank intentionally */
541static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
542 int32_t *oui_length, int32_t limit)
543{
544 uint8_t len;
545 uint8_t data;
546
547 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
548 command++;
549 limit--;
550 }
551
552 len = 2;
553
554 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
555 (limit > 1)) {
556 sscanf(command, "%02x", (unsigned int *)&data);
557 ie[len++] = data;
558 command += 2;
559 limit -= 2;
560 }
561
562 *oui_length = len - 2;
563
564 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
565 command++;
566 limit--;
567 }
568
569 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
570 (limit > 1)) {
571 sscanf(command, "%02x", (unsigned int *)&data);
572 ie[len++] = data;
573 command += 2;
574 limit -= 2;
575 }
576
577 ie[0] = WLAN_ELEMID_VENDOR;
578 ie[1] = len - 2;
579
580 return len;
581}
582
583/**
584 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
585 * @adapter: Pointer to adapter
586 * @hdd_ctx: Pointer to HDD context
587 * @command: Pointer to command string
588 * @command_len : Command length
589 * @priv_data : Pointer to priv data
590 *
591 * Return:
592 * int status code
593 */
594static int drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *adapter,
595 struct hdd_context *hdd_ctx,
596 uint8_t *command,
597 uint8_t command_len,
598 struct hdd_priv_data *priv_data)
599{
600 int i = 0;
601 int status;
602 int ret = 0;
603 uint8_t *ibss_ie;
604 int32_t oui_length = 0;
605 uint32_t ibss_ie_length;
606 uint8_t *value = command;
607 tSirModifyIE modify_ie;
608 struct csr_roam_profile *roam_profile;
609 mac_handle_t mac_handle;
610
611 if (QDF_IBSS_MODE != adapter->device_mode) {
612 hdd_debug("Device_mode %s(%d) not IBSS",
613 qdf_opmode_str(adapter->device_mode),
614 adapter->device_mode);
615 return ret;
616 }
617
618 hdd_debug("received command %s", ((char *)value));
619
620 /* validate argument of command */
621 if (strlen(value) <= command_len) {
622 hdd_err("No arguments in command length %zu",
623 strlen(value));
624 ret = -EFAULT;
625 goto exit;
626 }
627
628 /* moving to arguments of commands */
629 value = value + command_len;
630 command_len = strlen(value);
631
632 /* oui_data can't be less than 3 bytes */
633 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
634 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
635 command_len);
636 ret = -EFAULT;
637 goto exit;
638 }
639
640 ibss_ie = qdf_mem_malloc(command_len);
641 if (!ibss_ie) {
642 hdd_err("Could not allocate memory for command length %d",
643 command_len);
644 ret = -ENOMEM;
645 goto exit;
646 }
647
648 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
649 &oui_length,
650 command_len);
651 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
652 hdd_err("Could not parse command %s return length %d",
653 value, ibss_ie_length);
654 ret = -EFAULT;
655 qdf_mem_free(ibss_ie);
656 goto exit;
657 }
658
659 roam_profile = hdd_roam_profile(adapter);
660
661 qdf_copy_macaddr(&modify_ie.bssid,
662 roam_profile->BSSIDs.bssid);
663
Abhishek Singh5a2c42f2019-11-19 11:39:23 +0530664 modify_ie.vdev_id = adapter->vdev_id;
Abhishek Ambure68677462019-09-13 12:44:26 +0530665 modify_ie.notify = true;
666 modify_ie.ieID = WLAN_ELEMID_VENDOR;
667 modify_ie.ieIDLen = ibss_ie_length;
668 modify_ie.ieBufferlength = ibss_ie_length;
669 modify_ie.pIEBuffer = ibss_ie;
670 modify_ie.oui_length = oui_length;
671
672 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
673 ibss_ie_length, oui_length);
674 while (i < modify_ie.ieBufferlength)
675 hdd_warn("0x%x", ibss_ie[i++]);
676
677 /* Probe Bcn modification */
678 mac_handle = hdd_ctx->mac_handle;
679 sme_modify_add_ie(mac_handle, &modify_ie, eUPDATE_IE_PROBE_BCN);
680
681 /* Populating probe resp frame */
682 sme_modify_add_ie(mac_handle, &modify_ie, eUPDATE_IE_PROBE_RESP);
683
684 qdf_mem_free(ibss_ie);
685
686 status = sme_send_cesium_enable_ind(mac_handle,
687 adapter->vdev_id);
688 if (QDF_STATUS_SUCCESS != status) {
689 hdd_err("Could not send cesium enable indication %d",
690 status);
691 ret = -EINVAL;
692 goto exit;
693 }
694
695exit:
696 return ret;
697}
698
699static int drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *adapter,
700 struct hdd_context *hdd_ctx,
701 uint8_t *command,
702 uint8_t command_len,
703 struct hdd_priv_data *priv_data)
704{
705 int ret = 0;
706 int status = QDF_STATUS_SUCCESS;
707 struct hdd_station_ctx *sta_ctx = NULL;
708 char *extra = NULL;
709 int idx = 0;
710 int length = 0;
711 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
712 uint32_t print_break_index = 0;
713
714 if (QDF_IBSS_MODE != adapter->device_mode) {
715 hdd_warn("Unsupported in mode %s(%d)",
716 qdf_opmode_str(adapter->device_mode),
717 adapter->device_mode);
718 return -EINVAL;
719 }
720
721 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
722 hdd_debug("Received GETIBSSPEERINFOALL Command");
723
724 /* Handle the command */
725 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
726 if (QDF_STATUS_SUCCESS == status) {
727 size_t user_size = qdf_min(WLAN_MAX_BUF_SIZE,
728 priv_data->total_len);
729
730 /*
731 * The variable extra needed to be allocated on the heap since
732 * amount of memory required to copy the data for 32 devices
733 * exceeds the size of 1024 bytes of default stack size. On
734 * 64 bit devices, the default max stack size of 2048 bytes
735 */
736 extra = qdf_mem_malloc(user_size);
737
738 if (!extra) {
739 hdd_err("memory allocation failed");
740 ret = -ENOMEM;
741 goto exit;
742 }
743
744 /* Copy number of stations */
745 length = scnprintf(extra, user_size, "%d ",
746 sta_ctx->ibss_peer_info.numPeers);
747 print_break_index = length;
748 for (idx = 0; idx < sta_ctx->ibss_peer_info.numPeers;
749 idx++) {
750 int8_t rssi;
751 uint32_t tx_rate;
752
753 qdf_mem_copy(mac_addr,
754 sta_ctx->ibss_peer_info.peerInfoParams[idx].
755 mac_addr, sizeof(mac_addr));
756
757 tx_rate =
758 sta_ctx->ibss_peer_info.peerInfoParams[idx].
759 txRate;
760 /*
761 * Only lower 3 bytes are rate info. Mask of the MSByte
762 */
763 tx_rate &= 0x00FFFFFF;
764
765 rssi = sta_ctx->ibss_peer_info.peerInfoParams[idx].
766 rssi;
767
768 length += scnprintf(extra + length,
769 user_size - length,
Srinivas Girigowda9cd42962020-08-31 18:37:54 -0700770 QDF_FULL_MAC_FMT" %d %d ",
771 QDF_FULL_MAC_REF(mac_addr),
Abhishek Ambure68677462019-09-13 12:44:26 +0530772 tx_rate, rssi);
773 /*
774 * cdf_trace_msg has limitation of 512 bytes for the
775 * print buffer. Hence printing the data in two chunks.
776 * The first chunk will have the data for 16 devices
777 * and the second chunk will have the rest.
778 */
779 if (idx < NUM_OF_STA_DATA_TO_PRINT)
780 print_break_index = length;
781 }
782
783 /*
784 * Copy the data back into buffer, if the data to copy is
785 * more than 512 bytes than we will split the data and do
786 * it in two shots
787 */
788 if (copy_to_user(priv_data->buf, extra, print_break_index)) {
789 hdd_err("Copy into user data buffer failed");
790 ret = -EFAULT;
791 goto mem_free;
792 }
793
794 /* This overwrites the last space, which we already copied */
795 extra[print_break_index - 1] = '\0';
796 hdd_debug("%s", extra);
797
798 if (length > print_break_index) {
799 if (copy_to_user
800 (priv_data->buf + print_break_index,
801 extra + print_break_index,
802 length - print_break_index + 1)) {
803 hdd_err("Copy into user data buffer failed");
804 ret = -EFAULT;
805 goto mem_free;
806 }
807 hdd_debug("%s", &extra[print_break_index]);
808 }
809 } else {
810 /* Command failed, log error */
811 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
812 status);
813 ret = -EINVAL;
814 goto exit;
815 }
816 ret = 0;
817
818mem_free:
819 qdf_mem_free(extra);
820exit:
821 return ret;
822}
823
824/* Peer Info <Peer Addr> command */
825static int drv_cmd_get_ibss_peer_info(struct hdd_adapter *adapter,
826 struct hdd_context *hdd_ctx,
827 uint8_t *command,
828 uint8_t command_len,
829 struct hdd_priv_data *priv_data)
830{
831 int ret = 0;
832 uint8_t *value = command;
833 QDF_STATUS status;
834 struct hdd_station_ctx *sta_ctx = NULL;
835 char extra[128] = { 0 };
836 uint32_t length = 0;
Abhishek Ambure68677462019-09-13 12:44:26 +0530837 struct qdf_mac_addr peer_macaddr;
838
839 if (QDF_IBSS_MODE != adapter->device_mode) {
840 hdd_warn("Unsupported in mode %s(%d)",
841 qdf_opmode_str(adapter->device_mode),
842 adapter->device_mode);
843 return -EINVAL;
844 }
845
846 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
847
848 hdd_debug("Received GETIBSSPEERINFO Command");
849
850 /* if there are no peers, no need to continue with the command */
851 if (eConnectionState_IbssConnected !=
852 sta_ctx->conn_info.conn_state) {
853 hdd_err("No IBSS Peers coalesced");
854 ret = -EINVAL;
855 goto exit;
856 }
857
858 /* Parse the incoming command buffer */
859 status = hdd_parse_get_ibss_peer_info(value, &peer_macaddr);
860 if (QDF_STATUS_SUCCESS != status) {
861 hdd_err("Invalid GETIBSSPEERINFO command");
862 ret = -EINVAL;
863 goto exit;
864 }
865
Abhishek Ambure68677462019-09-13 12:44:26 +0530866 /* Handle the command */
Sourav Mohapatraa3cf12a2019-08-19 15:40:49 +0530867 status = hdd_cfg80211_get_ibss_peer_info(adapter, peer_macaddr.bytes);
Abhishek Ambure68677462019-09-13 12:44:26 +0530868 if (QDF_STATUS_SUCCESS == status) {
869 uint32_t tx_rate =
870 sta_ctx->ibss_peer_info.peerInfoParams[0].txRate;
871 /* Only lower 3 bytes are rate info. Mask of the MSByte */
872 tx_rate &= 0x00FFFFFF;
873
874 length = scnprintf(extra, sizeof(extra), "%d %d",
875 (int)tx_rate,
876 (int)sta_ctx->ibss_peer_info.
877 peerInfoParams[0].rssi);
878 length = QDF_MIN(priv_data->total_len, length + 1);
879
880 /* Copy the data back into buffer */
881 if (copy_to_user(priv_data->buf, &extra, length)) {
882 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
883 ret = -EFAULT;
884 goto exit;
885 }
886 } else {
887 /* Command failed, log error */
888 hdd_err("GETIBSSPEERINFO command failed with status code %d",
889 status);
890 ret = -EINVAL;
891 goto exit;
892 }
893
894 /* Success ! */
895 hdd_debug("%s", extra);
896 ret = 0;
897
898exit:
899 return ret;
900}
901
902static int drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *adapter,
903 struct hdd_context *hdd_ctx,
904 uint8_t *command,
905 uint8_t command_len,
906 struct hdd_priv_data *priv_data)
907{
908 int ret = 0;
909 char *value;
910 uint8_t tx_fail_count = 0;
911 uint16_t pid = 0;
912 mac_handle_t mac_handle;
913
914 value = command;
915
916 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
917
918 if (0 != ret) {
919 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
920 goto exit;
921 }
922
923 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
924 mac_handle = hdd_ctx->mac_handle;
925
926 if (0 == tx_fail_count) {
927 /* Disable TX Fail Indication */
928 if (QDF_STATUS_SUCCESS ==
929 sme_tx_fail_monitor_start_stop_ind(mac_handle,
930 tx_fail_count,
931 NULL)) {
932 cesium_pid = 0;
933 } else {
934 hdd_err("failed to disable TX Fail Event");
935 ret = -EINVAL;
936 }
937 } else {
938 if (QDF_STATUS_SUCCESS ==
939 sme_tx_fail_monitor_start_stop_ind(mac_handle,
940 tx_fail_count,
941 (void *)hdd_tx_fail_ind_callback)) {
942 cesium_pid = pid;
943 hdd_debug("Registered Cesium pid %u",
944 cesium_pid);
945 } else {
946 hdd_err("Failed to enable TX Fail Monitoring");
947 ret = -EINVAL;
948 }
949 }
950
951exit:
952 return ret;
953}
954#else
955/**
956 * drv_cmd_get_ibss_peer_info() - get ibss peer info all
957 * @adapter: Pointer to adapter
958 * @hdd_ctx: Pointer to HDD context
959 * @command: Pointer to command string
960 * @command_len : Command length
961 * @priv_data : Pointer to priv data
962 *
963 * This function is dummy
964 *
965 * Return: 0
966 */
967static inline int
968drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *adapter,
969 struct hdd_context *hdd_ctx,
970 uint8_t *command,
971 uint8_t command_len,
972 struct hdd_priv_data *priv_data)
973{
974 return 0;
975}
976
977/**
978 * drv_cmd_get_ibss_peer_info() - get ibss peer info
979 * @adapter: Pointer to adapter
980 * @hdd_ctx: Pointer to HDD context
981 * @command: Pointer to command string
982 * @command_len : Command length
983 * @priv_data : Pointer to priv data
984 *
985 * This function is dummy
986 *
987 * Return: 0
988 */
989static inline int
990drv_cmd_get_ibss_peer_info(struct hdd_adapter *adapter,
991 struct hdd_context *hdd_ctx,
992 uint8_t *command,
993 uint8_t command_len,
994 struct hdd_priv_data *priv_data)
995{
996 return 0;
997}
998
999/**
1000 * drv_cmd_set_ibss_tx_fail_event() - set ibss tx fail event
1001 * @adapter: Pointer to adapter
1002 * @hdd_ctx: Pointer to HDD context
1003 * @command: Pointer to command string
1004 * @command_len : Command length
1005 * @priv_data : Pointer to priv data
1006 *
1007 * This function is dummy
1008 *
1009 * Return: 0
1010 */
1011static inline int
1012drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *adapter,
1013 struct hdd_context *hdd_ctx,
1014 uint8_t *command,
1015 uint8_t command_len,
1016 struct hdd_priv_data *priv_data)
1017{
1018 return 0;
1019}
1020
1021/**
1022 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
1023 * @adapter: Pointer to adapter
1024 * @hdd_ctx: Pointer to HDD context
1025 * @command: Pointer to command string
1026 * @command_len : Command length
1027 * @priv_data : Pointer to priv data
1028 *
1029 * This function is dummy
1030 *
1031 * Return: 0
1032 */
1033static inline int
1034drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *adapter,
1035 struct hdd_context *hdd_ctx,
1036 uint8_t *command,
1037 uint8_t command_len,
1038 struct hdd_priv_data *priv_data)
1039{
1040 return 0;
1041}
1042#endif
1043
Jeff Johnsond549efa2018-06-13 20:27:47 -07001044static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *ui_band)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001045{
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -08001046 enum band_info band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001047
Harprit Chhabada5dff30e2019-03-12 17:56:45 -07001048 ucfg_reg_get_band(hdd_ctx->pdev, &band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001049 switch (band) {
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -08001050 case BAND_ALL:
Jeff Johnsond549efa2018-06-13 20:27:47 -07001051 *ui_band = WLAN_HDD_UI_BAND_AUTO;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052 break;
1053
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -08001054 case BAND_2G:
Jeff Johnsond549efa2018-06-13 20:27:47 -07001055 *ui_band = WLAN_HDD_UI_BAND_2_4_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001056 break;
1057
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -08001058 case BAND_5G:
Jeff Johnsond549efa2018-06-13 20:27:47 -07001059 *ui_band = WLAN_HDD_UI_BAND_5_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001060 break;
1061
1062 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001063 hdd_warn("Invalid Band %d", band);
Jeff Johnsond549efa2018-06-13 20:27:47 -07001064 *ui_band = -1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 break;
1066 }
1067}
1068
1069/**
Abhishek Ambured7429442020-08-25 01:03:57 +05301070 * hdd_check_and_fill_freq() - to validate chan and convert into freq
1071 * @in_chan: input as channel number or freq to be checked
1072 * @freq: frequency for input in_chan (output parameter)
1073 *
1074 * This function checks input "in_chan" is channel number, if yes then fills
1075 * appropriate frequency into "freq" out param. If the "in_param" is greater
1076 * than WNI_CFG_CURRENT_CHANNEL_STAMAX then checks for valid frequencies.
1077 *
1078 * Return: true if "in_chan" is valid channel/frequency; false otherwise
1079 */
1080static bool hdd_check_and_fill_freq(uint32_t in_chan, qdf_freq_t *freq)
1081{
1082 if (in_chan <= WNI_CFG_CURRENT_CHANNEL_STAMAX)
1083 *freq = wlan_chan_to_freq(in_chan);
1084 else if (WLAN_REG_IS_24GHZ_CH_FREQ(in_chan) ||
1085 WLAN_REG_IS_5GHZ_CH_FREQ(in_chan) ||
1086 WLAN_REG_IS_6GHZ_CHAN_FREQ(in_chan))
1087 *freq = in_chan;
1088 else
1089 return false;
1090
1091 return true;
1092}
1093
1094/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001095 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
1096 * @data: input data
1097 * @target_ap_bssid: pointer to bssid (output parameter)
Abhishek Ambured7429442020-08-25 01:03:57 +05301098 * @freq: pointer to freq (output parameter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001099 *
1100 * Return: 0 if parsing is successful; -EINVAL otherwise
1101 */
1102static int _hdd_parse_bssid_and_chan(const uint8_t **data,
1103 uint8_t *bssid,
Abhishek Ambured7429442020-08-25 01:03:57 +05301104 qdf_freq_t *freq)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105{
1106 const uint8_t *in_ptr;
1107 int v = 0;
1108 int temp_int;
1109 uint8_t temp_buf[32];
1110
1111 /* 12 hexa decimal digits, 5 ':' and '\0' */
1112 uint8_t mac_addr[18];
1113
1114 if (!data || !*data)
1115 return -EINVAL;
1116
1117 in_ptr = *data;
1118
1119 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
1120 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001121 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001122 goto error;
1123 /* no space after the command */
1124 else if (SPACE_ASCII_VALUE != *in_ptr)
1125 goto error;
1126
1127 /* remove empty spaces */
1128 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1129 in_ptr++;
1130
1131 /* no argument followed by spaces */
1132 if ('\0' == *in_ptr)
1133 goto error;
1134
1135 v = sscanf(in_ptr, "%17s", mac_addr);
1136 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001137 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
1138 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001139 goto error;
1140 }
1141
1142 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
1143 hex_to_bin(mac_addr[1]);
1144 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
1145 hex_to_bin(mac_addr[4]);
1146 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
1147 hex_to_bin(mac_addr[7]);
1148 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
1149 hex_to_bin(mac_addr[10]);
1150 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
1151 hex_to_bin(mac_addr[13]);
1152 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
1153 hex_to_bin(mac_addr[16]);
1154
1155 /* point to the next argument */
1156 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
1157 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001158 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001159 goto error;
1160
1161 /* remove empty spaces */
1162 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1163 in_ptr++;
1164
1165 /* no argument followed by spaces */
1166 if ('\0' == *in_ptr)
1167 goto error;
1168
Abhishek Ambured7429442020-08-25 01:03:57 +05301169 /* get the next argument ie the channel/freq number */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170 v = sscanf(in_ptr, "%31s ", temp_buf);
1171 if (1 != v)
1172 goto error;
1173
1174 v = kstrtos32(temp_buf, 10, &temp_int);
Abhishek Ambured7429442020-08-25 01:03:57 +05301175 if (v < 0 || temp_int < 0)
1176 goto error;
1177 else if (!hdd_check_and_fill_freq(temp_int, freq))
1178 goto error;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001179
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001180 *data = in_ptr;
1181 return 0;
1182error:
1183 *data = in_ptr;
1184 return -EINVAL;
1185}
1186
1187/**
Abhishek Ambured7429442020-08-25 01:03:57 +05301188 * hdd_parse_send_action_frame_v1_data() - HDD Parse send action frame data
Jeff Johnson6636e622019-02-26 10:22:39 -08001189 * @command: Pointer to input data
Jeff Johnsonb7d52792019-02-26 12:42:08 -08001190 * @bssid: Pointer to target Ap bssid
Jeff Johnsond727cdc2019-02-26 12:47:05 -08001191 * @channel: Pointer to the Target AP channel
Jeff Johnson80d220a2019-02-26 12:27:24 -08001192 * @dwell_time: Pointer to the time to stay off-channel
Jeff Johnson6636e622019-02-26 10:22:39 -08001193 * after transmitting action frame
Jeff Johnson5f3a6122019-02-26 17:20:59 -08001194 * @buf: Pointer to data
Jeff Johnson103f67a2019-02-26 17:11:01 -08001195 * @buf_len: Pointer to data length
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001196 *
1197 * This function parses the send action frame data passed in the format
Abhishek Ambured7429442020-08-25 01:03:57 +05301198 * SENDACTIONFRAME<space><bssid><space><channel | frequency><space><dwelltime>
1199 * <space><data>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001200 *
1201 * Return: 0 for success non-zero for failure
1202 */
1203static int
Jeff Johnson6636e622019-02-26 10:22:39 -08001204hdd_parse_send_action_frame_v1_data(const uint8_t *command,
Jeff Johnsonb7d52792019-02-26 12:42:08 -08001205 uint8_t *bssid,
Abhishek Ambured7429442020-08-25 01:03:57 +05301206 qdf_freq_t *freq, uint8_t *dwell_time,
Jeff Johnson5f3a6122019-02-26 17:20:59 -08001207 uint8_t **buf, uint8_t *buf_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001208{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001209 const uint8_t *in_ptr = command;
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08001210 const uint8_t *end_ptr;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001211 int temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001212 int j = 0;
1213 int i = 0;
1214 int v = 0;
Jeff Johnson72f498b2019-02-26 18:37:25 -08001215 uint8_t temp_buf[32];
1216 uint8_t temp_u8 = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217
Abhishek Ambured7429442020-08-25 01:03:57 +05301218 if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, freq))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001219 return -EINVAL;
1220
1221 /* point to the next argument */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001222 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001223 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001224 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001225 return -EINVAL;
1226 /* removing empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001227 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1228 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229
1230 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001231 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001233
1234 /* getting the next argument ie the dwell time */
Jeff Johnson72f498b2019-02-26 18:37:25 -08001235 v = sscanf(in_ptr, "%31s ", temp_buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 if (1 != v)
1237 return -EINVAL;
1238
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001239 v = kstrtos32(temp_buf, 10, &temp_int);
1240 if (v < 0 || temp_int < 0)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001241 return -EINVAL;
1242
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001243 *dwell_time = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001244
1245 /* point to the next argument */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001246 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001247 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001248 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249 return -EINVAL;
1250 /* removing empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001251 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1252 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253
1254 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001255 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001256 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257
1258 /* find the length of data */
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08001259 end_ptr = in_ptr;
1260 while (('\0' != *end_ptr))
1261 end_ptr++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001262
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08001263 *buf_len = end_ptr - in_ptr;
Jeff Johnson103f67a2019-02-26 17:11:01 -08001264 if (*buf_len <= 0)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265 return -EINVAL;
1266
1267 /*
1268 * Allocate the number of bytes based on the number of input characters
1269 * whether it is even or odd.
1270 * if the number of input characters are even, then we need N/2 byte.
1271 * if the number of input characters are odd, then we need do (N+1)/2
1272 * to compensate rounding off.
1273 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
1274 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
1275 */
Jeff Johnson5f3a6122019-02-26 17:20:59 -08001276 *buf = qdf_mem_malloc((*buf_len + 1) / 2);
Jeff Johnsond36fa332019-03-18 13:42:25 -07001277 if (!*buf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001278 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 return -ENOMEM;
1280 }
1281
1282 /* the buffer received from the upper layer is character buffer,
1283 * we need to prepare the buffer taking 2 characters in to a U8 hex
1284 * decimal number for example 7f0000f0...form a buffer to contain 7f
1285 * in 0th location, 00 in 1st and f0 in 3rd location
1286 */
Jeff Johnson103f67a2019-02-26 17:11:01 -08001287 for (i = 0, j = 0; j < *buf_len; j += 2) {
1288 if (j + 1 == *buf_len) {
Jeff Johnson72f498b2019-02-26 18:37:25 -08001289 temp_u8 = hex_to_bin(in_ptr[j]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001290 } else {
Jeff Johnson72f498b2019-02-26 18:37:25 -08001291 temp_u8 =
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001292 (hex_to_bin(in_ptr[j]) << 4) |
1293 (hex_to_bin(in_ptr[j + 1]));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001294 }
Jeff Johnson72f498b2019-02-26 18:37:25 -08001295 (*buf)[i++] = temp_u8;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001296 }
Jeff Johnson103f67a2019-02-26 17:11:01 -08001297 *buf_len = i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001298 return 0;
1299}
1300
1301/**
1302 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
Jeff Johnson6636e622019-02-26 10:22:39 -08001303 * @command: Pointer to input data (its a NULL terminated string)
Jeff Johnsonb7d52792019-02-26 12:42:08 -08001304 * @bssid: Pointer to target Ap bssid
Abhishek Ambured7429442020-08-25 01:03:57 +05301305 * @freq: Pointer to the Target AP frequency
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001306 *
1307 * This function parses the reasoc command data passed in the format
Abhishek Ambured7429442020-08-25 01:03:57 +05301308 * REASSOC<space><bssid><space><channel/frequency>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001309 *
1310 * Return: 0 for success non-zero for failure
1311 */
Jeff Johnson6636e622019-02-26 10:22:39 -08001312static int hdd_parse_reassoc_command_v1_data(const uint8_t *command,
Jeff Johnsonb7d52792019-02-26 12:42:08 -08001313 uint8_t *bssid,
Abhishek Ambured7429442020-08-25 01:03:57 +05301314 qdf_freq_t *freq)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001315{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001316 const uint8_t *in_ptr = command;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001317
Abhishek Ambured7429442020-08-25 01:03:57 +05301318 if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, freq))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001319 return -EINVAL;
1320
1321 return 0;
1322}
1323
Naveen Rawat05376ee2016-07-18 16:43:32 -07001324#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Abhinav Kumareab25932018-07-13 11:48:43 +05301325QDF_STATUS hdd_wma_send_fastreassoc_cmd(struct hdd_adapter *adapter,
1326 const tSirMacAddr bssid,
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001327 uint32_t ch_freq)
Naveen Rawat05376ee2016-07-18 16:43:32 -07001328{
Krunal Soni332f4af2017-06-01 14:36:17 -07001329 struct hdd_station_ctx *hdd_sta_ctx =
1330 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnson8313b9d2018-03-14 15:09:28 -07001331 struct csr_roam_profile *roam_profile;
Krunal Soni332f4af2017-06-01 14:36:17 -07001332 tSirMacAddr connected_bssid;
Naveen Rawat05376ee2016-07-18 16:43:32 -07001333
Jeff Johnson8313b9d2018-03-14 15:09:28 -07001334 roam_profile = hdd_roam_profile(adapter);
Jeff Johnsone04b6992019-02-27 14:06:55 -08001335 qdf_mem_copy(connected_bssid, hdd_sta_ctx->conn_info.bssid.bytes,
Krunal Soni332f4af2017-06-01 14:36:17 -07001336 ETH_ALEN);
Abhinav Kumareab25932018-07-13 11:48:43 +05301337 return sme_fast_reassoc(adapter->hdd_ctx->mac_handle,
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001338 roam_profile, bssid, ch_freq,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001339 adapter->vdev_id, connected_bssid);
Naveen Rawat05376ee2016-07-18 16:43:32 -07001340}
Naveen Rawat05376ee2016-07-18 16:43:32 -07001341#endif
1342
Jeff Johnsone44b7012017-09-10 15:25:47 -07001343int hdd_reassoc(struct hdd_adapter *adapter, const uint8_t *bssid,
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001344 uint32_t ch_freq, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001345{
Jeff Johnsond377dce2017-10-04 10:32:42 -07001346 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -07001347 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001348 int ret = 0;
Abhinav Kumareab25932018-07-13 11:48:43 +05301349 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001350
Jeff Johnsond36fa332019-03-18 13:42:25 -07001351 if (!hdd_ctx) {
Naveen Rawat05376ee2016-07-18 16:43:32 -07001352 hdd_err("Invalid hdd ctx");
1353 return -EINVAL;
1354 }
1355
Krunal Sonibe766b02016-03-10 13:00:44 -08001356 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001357 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07001358 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001359 adapter->device_mode);
1360 return -EINVAL;
1361 }
1362
Jeff Johnsond377dce2017-10-04 10:32:42 -07001363 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001364
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +05301365 /*
Jeff Johnsone7951512019-02-27 10:02:51 -08001366 * pHddStaCtx->conn_info.conn_state is set to disconnected only
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +05301367 * after the disconnect done indication from SME. If the SME is
1368 * in the process of disconnecting, the SME Connection state is
Jeff Johnsone7951512019-02-27 10:02:51 -08001369 * set to disconnected and the pHddStaCtx->conn_info.conn_state
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +05301370 * will still be associated till the disconnect is done.
1371 * So check both the HDD state and SME state here.
1372 * If not associated, no need to proceed with reassoc
1373 */
Jeff Johnsone7951512019-02-27 10:02:51 -08001374 if ((eConnectionState_Associated != sta_ctx->conn_info.conn_state) ||
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +05301375 (!sme_is_conn_state_connected(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001376 adapter->vdev_id))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001377 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001378 ret = -EINVAL;
1379 goto exit;
1380 }
1381
1382 /*
1383 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -08001384 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001385 */
Jeff Johnsone04b6992019-02-27 14:06:55 -08001386 if (!memcmp(bssid, sta_ctx->conn_info.bssid.bytes,
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001387 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001388 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001389 ch_freq = sta_ctx->conn_info.chan_freq;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001390 }
1391
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301392 if (QDF_STATUS_SUCCESS !=
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001393 wlan_hdd_validate_operation_channel(adapter, ch_freq)) {
1394 hdd_err("Invalid Ch freq: %d", ch_freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001395 ret = -EINVAL;
1396 goto exit;
1397 }
1398
1399 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -07001400 if (roaming_offload_enabled(hdd_ctx)) {
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001401 status = hdd_wma_send_fastreassoc_cmd(adapter, bssid, ch_freq);
Abhinav Kumareab25932018-07-13 11:48:43 +05301402 if (status != QDF_STATUS_SUCCESS) {
1403 hdd_err("Failed to send fast reassoc cmd");
1404 ret = -EINVAL;
1405 }
Naveen Rawat05376ee2016-07-18 16:43:32 -07001406 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07001407 tCsrHandoffRequest handoff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001408
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001409 handoff.ch_freq = ch_freq;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001410 handoff.src = src;
1411 qdf_mem_copy(handoff.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001412 sme_handoff_request(hdd_ctx->mac_handle, adapter->vdev_id,
Jeff Johnsond549efa2018-06-13 20:27:47 -07001413 &handoff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001414 }
1415exit:
1416 return ret;
1417}
1418
1419/**
1420 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
1421 * @adapter: Adapter upon which the command was received
1422 * @command: ASCII text command that was received
1423 *
1424 * This function parses the v1 REASSOC command with the format
1425 *
Abhishek Ambured7429442020-08-25 01:03:57 +05301426 * REASSOC xx:xx:xx:xx:xx:xx CH/FREQ
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001427 *
1428 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
Abhishek Ambured7429442020-08-25 01:03:57 +05301429 * BSSID and CH/FREQ is the ASCII representation of the channel/frequency.
1430 * For example
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001431 *
1432 * REASSOC 00:0a:0b:11:22:33 48
Abhishek Ambured7429442020-08-25 01:03:57 +05301433 * REASSOC 00:0a:0b:11:22:33 2412
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001434 *
1435 * Return: 0 for success non-zero for failure
1436 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07001437static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438{
Abhishek Ambured7429442020-08-25 01:03:57 +05301439 qdf_freq_t freq = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001440 tSirMacAddr bssid;
1441 int ret;
1442
Abhishek Ambured7429442020-08-25 01:03:57 +05301443 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &freq);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001444 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001445 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001446 else
Abhishek Ambured7429442020-08-25 01:03:57 +05301447 ret = hdd_reassoc(adapter, bssid, freq, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001448
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449 return ret;
1450}
1451
1452/**
1453 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
1454 * @adapter: Adapter upon which the command was received
1455 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001456 * followed by binary data
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301457 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001458 *
1459 * This function parses the v2 REASSOC command with the format
1460 *
1461 * REASSOC <android_wifi_reassoc_params>
1462 *
1463 * Return: 0 for success non-zero for failure
1464 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07001465static int hdd_parse_reassoc_v2(struct hdd_adapter *adapter,
1466 const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301467 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468{
1469 struct android_wifi_reassoc_params params;
1470 tSirMacAddr bssid;
Abhishek Ambured7429442020-08-25 01:03:57 +05301471 qdf_freq_t freq = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001472 int ret;
1473
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301474 if (total_len < sizeof(params) + 8) {
1475 hdd_err("Invalid command length");
1476 return -EINVAL;
1477 }
1478
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001479 /* The params are located after "REASSOC " */
1480 memcpy(&params, command + 8, sizeof(params));
1481
1482 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001483 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001484 ret = -EINVAL;
1485 } else {
Abhishek Ambured7429442020-08-25 01:03:57 +05301486 /*
1487 * In Reassoc command, user can send channel number or frequency
1488 * along with BSSID. If params.channel param of REASSOC command
1489 * is less than WNI_CFG_CURRENT_CHANNEL_STAMAX, then host
1490 * consider this as channel number else frequency.
1491 */
1492 if (!hdd_check_and_fill_freq(params.channel, &freq))
1493 return -EINVAL;
1494
1495 ret = hdd_reassoc(adapter, bssid, freq, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496 }
Abhishek Ambured7429442020-08-25 01:03:57 +05301497
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498 return ret;
1499}
1500
1501/**
1502 * hdd_parse_reassoc() - parse the REASSOC command
1503 * @adapter: Adapter upon which the command was received
1504 * @command: Command that was received
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301505 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001506 *
1507 * There are two different versions of the REASSOC command. Version 1
1508 * of the command contains a parameter list that is ASCII characters
1509 * whereas version 2 contains a combination of ASCII and binary
1510 * payload. Determine if a version 1 or a version 2 command is being
1511 * parsed by examining the parameters, and then dispatch the parser
1512 * that is appropriate for the command.
1513 *
1514 * Return: 0 for success non-zero for failure
1515 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07001516static int hdd_parse_reassoc(struct hdd_adapter *adapter, const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301517 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001518{
1519 int ret;
1520
1521 /* both versions start with "REASSOC "
1522 * v1 has a bssid and channel # as an ASCII string
Abhishek Ambured7429442020-08-25 01:03:57 +05301523 * REASSOC xx:xx:xx:xx:xx:xx CH/FREQ
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001524 * v2 has a C struct
1525 * REASSOC <binary c struct>
1526 *
1527 * The first field in the v2 struct is also the bssid in ASCII.
1528 * But in the case of a v2 message the BSSID is NUL-terminated.
1529 * Hence we can peek at that offset to see if this is V1 or V2
1530 * REASSOC xx:xx:xx:xx:xx:xx*
1531 * 1111111111222222
1532 * 01234567890123456789012345
1533 */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301534
1535 if (total_len < 26) {
1536 hdd_err("Invalid command, total_len = %d", total_len);
1537 return -EINVAL;
1538 }
1539
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001540 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001541 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001542 else
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301543 ret = hdd_parse_reassoc_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001544
1545 return ret;
1546}
1547
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001548/**
1549 * hdd_sendactionframe() - send a userspace-supplied action frame
1550 * @adapter: Adapter upon which the command was received
1551 * @bssid: BSSID target of the action frame
Abhishek Ambured7429442020-08-25 01:03:57 +05301552 * @freq: Frequency upon which to send the frame
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553 * @dwell_time: Amount of time to dwell when the frame is sent
1554 * @payload_len:Length of the payload
1555 * @payload: Payload of the frame
1556 *
1557 * This function sends a userspace-supplied action frame
1558 *
1559 * Return: 0 for success non-zero for failure
1560 */
1561static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001562hdd_sendactionframe(struct hdd_adapter *adapter, const uint8_t *bssid,
Abhishek Ambured7429442020-08-25 01:03:57 +05301563 const qdf_freq_t freq, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001564 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001565{
1566 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001567 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001568 uint8_t *frame;
1569 struct ieee80211_hdr_3addr *hdr;
1570 u64 cookie;
Jeff Johnsond377dce2017-10-04 10:32:42 -07001571 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -07001572 struct hdd_context *hdd_ctx;
Jeff Johnsonecdf83b2019-02-26 18:33:56 -08001573 tpSirMacVendorSpecificFrameHdr vendor =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574 (tpSirMacVendorSpecificFrameHdr) payload;
1575#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1576 struct cfg80211_mgmt_tx_params params;
1577#endif
1578
Sourav Mohapatra762ed1e2019-09-05 14:34:19 +05301579 if (payload_len < sizeof(tSirMacVendorSpecificFrameHdr)) {
1580 hdd_warn("Invalid payload length: %d", payload_len);
1581 return -EINVAL;
1582 }
1583
Krunal Sonibe766b02016-03-10 13:00:44 -08001584 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001585 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07001586 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001587 adapter->device_mode);
1588 return -EINVAL;
1589 }
1590
Jeff Johnsond377dce2017-10-04 10:32:42 -07001591 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001592 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1593
1594 /* if not associated, no need to send action frame */
Jeff Johnsone7951512019-02-27 10:02:51 -08001595 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001596 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001597 ret = -EINVAL;
1598 goto exit;
1599 }
1600
1601 /*
1602 * if the target bssid is different from currently associated AP,
1603 * then no need to send action frame
1604 */
Jeff Johnsone04b6992019-02-27 14:06:55 -08001605 if (memcmp(bssid, sta_ctx->conn_info.bssid.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301606 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001607 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608 ret = -EINVAL;
1609 goto exit;
1610 }
1611
Abhishek Ambured7429442020-08-25 01:03:57 +05301612 chan.center_freq = freq;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613 /* Check if it is specific action frame */
Jeff Johnsonecdf83b2019-02-26 18:33:56 -08001614 if (vendor->category ==
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001615 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
Jeff Johnson2971e3a2019-02-26 18:31:54 -08001616 static const uint8_t oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001617
Jeff Johnsonecdf83b2019-02-26 18:33:56 -08001618 if (!qdf_mem_cmp(vendor->Oui, oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619 /*
Abhishek Ambured7429442020-08-25 01:03:57 +05301620 * if the freq number is different from operating
1621 * freq then no need to send action frame
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622 */
Abhishek Ambured7429442020-08-25 01:03:57 +05301623 if (freq) {
1624 if (freq != sta_ctx->conn_info.chan_freq) {
1625 hdd_warn("freq(%u) is different from operating freq(%u)",
1626 freq,
1627 sta_ctx->conn_info.chan_freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628 ret = -EINVAL;
1629 goto exit;
1630 }
1631 /*
1632 * If channel number is specified and same
1633 * as home channel, ensure that action frame
1634 * is sent immediately by cancelling
1635 * roaming scans. Otherwise large dwell times
1636 * may cause long delays in sending action
1637 * frames.
1638 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07001639 sme_abort_roam_scan(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001640 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641 } else {
1642 /*
Abhishek Ambured7429442020-08-25 01:03:57 +05301643 * 0 is accepted as current home frequency,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001644 * delayed transmission of action frame is ok.
1645 */
Jingxiang Geae80dc62019-08-13 17:32:22 +08001646 chan.center_freq = sta_ctx->conn_info.chan_freq;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647 }
1648 }
1649 }
1650 if (chan.center_freq == 0) {
Abhishek Ambured7429442020-08-25 01:03:57 +05301651 hdd_nofl_err("Invalid freq : %d", freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001652 ret = -EINVAL;
1653 goto exit;
1654 }
1655
1656 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301657 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001659 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001660 ret = -ENOMEM;
1661 goto exit;
1662 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001663
1664 hdr = (struct ieee80211_hdr_3addr *)frame;
1665 hdr->frame_control =
1666 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301667 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson1e851a12017-10-28 14:36:12 -07001668 qdf_mem_copy(hdr->addr2, adapter->mac_addr.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301669 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301670 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1671 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672
1673#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1674 params.chan = &chan;
1675 params.offchan = 0;
1676 params.wait = dwell_time;
1677 params.buf = frame;
1678 params.len = frame_len;
1679 params.no_cck = 1;
1680 params.dont_wait_for_ack = 1;
1681 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1682#else
1683 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001684 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001686
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001687 dwell_time, frame, frame_len, 1, 1, &cookie);
1688#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1689
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301690 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691exit:
1692 return ret;
1693}
1694
1695/**
1696 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1697 * SENDACTIONFRAME command
1698 * @adapter: Adapter upon which the command was received
1699 * @command: ASCII text command that was received
1700 *
1701 * This function parses the v1 SENDACTIONFRAME command with the format
1702 *
1703 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1704 *
1705 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1706 * BSSID, CH is the ASCII representation of the channel, DW is the
1707 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1708 * payload. For example
1709 *
1710 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1711 *
1712 * Return: 0 for success non-zero for failure
1713 */
1714static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001715hdd_parse_sendactionframe_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716{
Abhishek Ambured7429442020-08-25 01:03:57 +05301717 qdf_freq_t freq = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718 uint8_t dwell_time = 0;
1719 uint8_t payload_len = 0;
1720 uint8_t *payload = NULL;
1721 tSirMacAddr bssid;
1722 int ret;
1723
Abhishek Ambured7429442020-08-25 01:03:57 +05301724 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &freq,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725 &dwell_time, &payload,
1726 &payload_len);
1727 if (ret) {
Abhishek Ambured7429442020-08-25 01:03:57 +05301728 hdd_nofl_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729 } else {
Abhishek Ambured7429442020-08-25 01:03:57 +05301730 ret = hdd_sendactionframe(adapter, bssid, freq,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301732 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733 }
1734
1735 return ret;
1736}
1737
1738/**
1739 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1740 * SENDACTIONFRAME command
1741 * @adapter: Adapter upon which the command was received
1742 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001743 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001744 *
1745 * This function parses the v2 SENDACTIONFRAME command with the format
1746 *
1747 * SENDACTIONFRAME <android_wifi_af_params>
1748 *
1749 * Return: 0 for success non-zero for failure
1750 */
1751static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001752hdd_parse_sendactionframe_v2(struct hdd_adapter *adapter,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001753 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001754{
1755 struct android_wifi_af_params *params;
1756 tSirMacAddr bssid;
1757 int ret;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301758 int len_wo_payload = 0;
Abhishek Ambured7429442020-08-25 01:03:57 +05301759 qdf_freq_t freq = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001760
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001761 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001762 total_len -= 16;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301763 len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE;
1764 if (total_len <= len_wo_payload) {
1765 hdd_err("Invalid command len");
1766 return -EINVAL;
1767 }
1768
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001769 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001771 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301772 (params->len > (total_len - len_wo_payload))) {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001773 hdd_err("Invalid payload length: %d", params->len);
1774 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001776
1777 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1778 hdd_err("MAC address parsing failed");
1779 return -EINVAL;
1780 }
1781
1782 if (params->channel < 0 ||
1783 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1784 hdd_err("Invalid channel: %d", params->channel);
1785 return -EINVAL;
1786 }
1787
1788 if (params->dwell_time < 0) {
1789 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1790 return -EINVAL;
1791 }
1792
Abhishek Ambured7429442020-08-25 01:03:57 +05301793 if (!hdd_check_and_fill_freq(params->channel, &freq)) {
1794 hdd_err("Invalid channel: %d", params->channel);
1795 return -EINVAL;
1796 }
1797
1798 ret = hdd_sendactionframe(adapter, bssid, freq, params->dwell_time,
1799 params->len, params->data);
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001800
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001801 return ret;
1802}
1803
1804/**
1805 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1806 * @adapter: Adapter upon which the command was received
1807 * @command: Command that was received
1808 *
1809 * There are two different versions of the SENDACTIONFRAME command.
1810 * Version 1 of the command contains a parameter list that is ASCII
1811 * characters whereas version 2 contains a combination of ASCII and
1812 * binary payload. Determine if a version 1 or a version 2 command is
1813 * being parsed by examining the parameters, and then dispatch the
1814 * parser that is appropriate for the version of the command.
1815 *
1816 * Return: 0 for success non-zero for failure
1817 */
1818static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001819hdd_parse_sendactionframe(struct hdd_adapter *adapter, const char *command,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001820 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821{
1822 int ret;
1823
1824 /*
1825 * both versions start with "SENDACTIONFRAME "
1826 * v1 has a bssid and other parameters as an ASCII string
1827 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1828 * v2 has a C struct
1829 * SENDACTIONFRAME <binary c struct>
1830 *
1831 * The first field in the v2 struct is also the bssid in ASCII.
1832 * But in the case of a v2 message the BSSID is NUL-terminated.
1833 * Hence we can peek at that offset to see if this is V1 or V2
1834 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1835 * 111111111122222222223333
1836 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001837 * For both the commands, a valid command must have atleast
1838 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001840 if (total_len < 34) {
1841 hdd_err("Invalid command (total_len=%d)", total_len);
1842 return -EINVAL;
1843 }
1844
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001845 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001847 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001848 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001849
1850 return ret;
1851}
1852
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001853/**
1854 * hdd_parse_channellist() - HDD Parse channel list
Liangwei Dong075afa72019-10-30 12:58:22 +08001855 * @hdd_ctx: hdd context
Jeff Johnson6636e622019-02-26 10:22:39 -08001856 * @command: Pointer to input channel list
Liangwei Dong075afa72019-10-30 12:58:22 +08001857 * @channel_freq_list: Pointer to local output array to record
Jeff Johnson6636e622019-02-26 10:22:39 -08001858 * channel list
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001859 * @num_channels: Pointer to number of roam scan channels
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860 *
1861 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001862 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1863 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001864 * if the Number of channels (N) does not match with the actual number
1865 * of channels passed then take the minimum of N and count of
1866 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1867 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1868 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1869 * removing duplicate channels from the list
1870 *
1871 * Return: 0 for success non-zero for failure
1872 */
1873static int
Liangwei Dong075afa72019-10-30 12:58:22 +08001874hdd_parse_channellist(struct hdd_context *hdd_ctx,
1875 const uint8_t *command,
1876 uint32_t *channel_freq_list,
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001877 uint8_t *num_channels)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001879 const uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001880 int temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881 int j = 0;
1882 int v = 0;
1883 char buf[32];
1884
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001885 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001886 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001887 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001888 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001889 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001890 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891
1892 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001893 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1894 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895
1896 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001897 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001898 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001899
1900 /* get the first argument ie the number of channels */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001901 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001902 if (1 != v)
1903 return -EINVAL;
1904
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001905 v = kstrtos32(buf, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001906 if ((v < 0) ||
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001907 (temp_int <= 0) || (temp_int > CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001909
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001910 *num_channels = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001912 hdd_debug("Number of channels are: %d", *num_channels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001913
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001914 for (j = 0; j < (*num_channels); j++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915 /*
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001916 * in_ptr pointing to the beginning of first space after number
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001917 * of channels
1918 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001919 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001920 /* no channel list after the number of channels argument */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001921 if (!in_ptr) {
Abhishek Amburef4e99462020-01-30 16:16:07 +05301922 if ((j != 0) && (*num_channels == j))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001923 return 0;
Abhishek Amburef4e99462020-01-30 16:16:07 +05301924 else
1925 goto cnt_mismatch;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001926 }
1927
1928 /* remove empty space */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001929 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1930 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001931
1932 /*
1933 * no channel list after the number of channels
1934 * argument and spaces
1935 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001936 if ('\0' == *in_ptr) {
Abhishek Amburef4e99462020-01-30 16:16:07 +05301937 if ((j != 0) && (*num_channels == j))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001938 return 0;
Abhishek Amburef4e99462020-01-30 16:16:07 +05301939 else
1940 goto cnt_mismatch;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941 }
1942
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001943 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001944 if (1 != v)
1945 return -EINVAL;
1946
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001947 v = kstrtos32(buf, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948 if ((v < 0) ||
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001949 (temp_int <= 0) ||
1950 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001951 return -EINVAL;
1952 }
Liangwei Dong075afa72019-10-30 12:58:22 +08001953 channel_freq_list[j] =
1954 wlan_reg_chan_to_freq(hdd_ctx->pdev, temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001955
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001956 hdd_debug("Channel %d added to preferred channel list",
Liangwei Dong075afa72019-10-30 12:58:22 +08001957 channel_freq_list[j]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958 }
1959
1960 return 0;
Abhishek Amburef4e99462020-01-30 16:16:07 +05301961
1962cnt_mismatch:
1963 hdd_debug("Mismatch in ch cnt: %d and num of ch: %d", *num_channels, j);
1964 *num_channels = 0;
1965 return -EINVAL;
1966
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967}
1968
1969/**
1970 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1971 * SETROAMSCANCHANNELS command
1972 * @adapter: Adapter upon which the command was received
1973 * @command: ASCII text command that was received
1974 *
1975 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1976 *
1977 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1978 *
1979 * Where "N" is the ASCII representation of the number of channels and
1980 * C1 thru Cn is the ASCII representation of the channels. For example
1981 *
1982 * SETROAMSCANCHANNELS 4 36 40 44 48
1983 *
1984 * Return: 0 for success non-zero for failure
1985 */
1986static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001987hdd_parse_set_roam_scan_channels_v1(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001988 const char *command)
1989{
Liangwei Dong075afa72019-10-30 12:58:22 +08001990 uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301992 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001993 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001994 int ret;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001995 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001996
Liangwei Dong075afa72019-10-30 12:58:22 +08001997 if (!hdd_ctx) {
1998 hdd_err("invalid hdd ctx");
1999 ret = -EINVAL;
2000 goto exit;
2001 }
2002
2003 ret = hdd_parse_channellist(hdd_ctx, command, channel_freq_list,
2004 &num_chan);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002005 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002006 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002007 goto exit;
2008 }
2009
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302010 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2011 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002012 adapter->vdev_id, num_chan);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002013
Wu Gao0821b0d2019-01-11 17:31:11 +08002014 if (num_chan > CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002015 hdd_err("number of channels (%d) supported exceeded max (%d)",
Wu Gao0821b0d2019-01-11 17:31:11 +08002016 num_chan, CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017 ret = -EINVAL;
2018 goto exit;
2019 }
2020
Jeff Johnsond549efa2018-06-13 20:27:47 -07002021 mac_handle = hdd_ctx->mac_handle;
Liangwei Dong075afa72019-10-30 12:58:22 +08002022 if (!sme_validate_channel_list(mac_handle,
2023 channel_freq_list, num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05302024 hdd_err("List contains invalid channel(s)");
2025 ret = -EINVAL;
2026 goto exit;
2027 }
2028
Jeff Johnsond549efa2018-06-13 20:27:47 -07002029 status = sme_change_roam_scan_channel_list(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002030 adapter->vdev_id,
Liangwei Dong075afa72019-10-30 12:58:22 +08002031 channel_freq_list,
2032 num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302033 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002034 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002035 ret = -EINVAL;
2036 goto exit;
2037 }
2038exit:
2039 return ret;
2040}
2041
2042/**
2043 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
2044 * SETROAMSCANCHANNELS command
2045 * @adapter: Adapter upon which the command was received
2046 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07002047 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048 *
2049 * This function parses the v2 SETROAMSCANCHANNELS command with the format
2050 *
2051 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
2052 *
2053 * The command begins with SETROAMSCANCHANNELS followed by a space, but
2054 * what follows the space is an array of u08 parameters. For example
2055 *
2056 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
2057 *
2058 * Return: 0 for success non-zero for failure
2059 */
2060static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07002061hdd_parse_set_roam_scan_channels_v2(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062 const char *command)
2063{
2064 const uint8_t *value;
Liangwei Dong075afa72019-10-30 12:58:22 +08002065 uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002066 uint8_t channel;
2067 uint8_t num_chan;
2068 int i;
Jeff Johnson621cf972017-08-28 11:58:44 -07002069 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302070 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002071 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002072 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002073
2074 /* array of values begins after "SETROAMSCANCHANNELS " */
2075 value = command + 20;
2076
2077 num_chan = *value++;
Wu Gao0821b0d2019-01-11 17:31:11 +08002078 if (num_chan > CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002079 hdd_err("number of channels (%d) supported exceeded max (%d)",
Wu Gao0821b0d2019-01-11 17:31:11 +08002080 num_chan, CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081 ret = -EINVAL;
2082 goto exit;
2083 }
2084
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302085 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2086 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002087 adapter->vdev_id, num_chan);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302088
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002089
2090 for (i = 0; i < num_chan; i++) {
2091 channel = *value++;
Nachiket Kukadecaa2e842018-05-09 17:56:12 +05302092 if (!channel) {
2093 hdd_err("Channels end at index %d, expected %d",
2094 i, num_chan);
2095 ret = -EINVAL;
2096 goto exit;
2097 }
2098
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002099 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002100 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002101 i, channel);
2102 ret = -EINVAL;
2103 goto exit;
2104 }
Liangwei Dong075afa72019-10-30 12:58:22 +08002105 channel_freq_list[i] = wlan_reg_chan_to_freq(hdd_ctx->pdev,
2106 channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002107 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05302108
Jeff Johnsond549efa2018-06-13 20:27:47 -07002109 mac_handle = hdd_ctx->mac_handle;
Liangwei Dong075afa72019-10-30 12:58:22 +08002110 if (!sme_validate_channel_list(mac_handle, channel_freq_list,
2111 num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05302112 hdd_err("List contains invalid channel(s)");
2113 ret = -EINVAL;
2114 goto exit;
2115 }
2116
Jeff Johnsond549efa2018-06-13 20:27:47 -07002117 status = sme_change_roam_scan_channel_list(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002118 adapter->vdev_id,
Liangwei Dong075afa72019-10-30 12:58:22 +08002119 channel_freq_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302120 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002121 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002122 ret = -EINVAL;
2123 goto exit;
2124 }
2125exit:
2126 return ret;
2127}
2128
2129/**
2130 * hdd_parse_set_roam_scan_channels() - parse the
2131 * SETROAMSCANCHANNELS command
2132 * @adapter: Adapter upon which the command was received
2133 * @command: Command that was received
2134 *
2135 * There are two different versions of the SETROAMSCANCHANNELS command.
2136 * Version 1 of the command contains a parameter list that is ASCII
2137 * characters whereas version 2 contains a binary payload. Determine
2138 * if a version 1 or a version 2 command is being parsed by examining
2139 * the parameters, and then dispatch the parser that is appropriate for
2140 * the command.
2141 *
2142 * Return: 0 for success non-zero for failure
2143 */
2144static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07002145hdd_parse_set_roam_scan_channels(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002146{
2147 const char *cursor;
2148 char ch;
2149 bool v1;
2150 int ret;
2151
2152 /* start after "SETROAMSCANCHANNELS " */
2153 cursor = command + 20;
2154
2155 /* assume we have a version 1 command until proven otherwise */
2156 v1 = true;
2157
2158 /* v1 params will only contain ASCII digits and space */
2159 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002160 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002162 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002163
2164 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002165 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002166 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002167 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002168
2169 return ret;
2170}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002171
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002172#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002173/**
2174 * hdd_parse_plm_cmd() - HDD Parse Plm command
Jeff Johnson6636e622019-02-26 10:22:39 -08002175 * @command: Pointer to input data
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002176 * @req: Pointer to output struct plm_req
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002177 *
2178 * This function parses the plm command passed in the format
2179 * CCXPLMREQ<space><enable><space><dialog_token><space>
2180 * <meas_token><space><num_of_bursts><space><burst_int><space>
2181 * <measu duration><space><burst_len><space><desired_tx_pwr>
2182 * <space><multcast_addr><space><number_of_channels>
2183 * <space><channel_numbers>
2184 *
2185 * Return: 0 for success non-zero for failure
2186 */
Jeff Johnson6636e622019-02-26 10:22:39 -08002187static QDF_STATUS hdd_parse_plm_cmd(uint8_t *command,
Jeff Johnson36583f02019-02-26 08:02:11 -08002188 struct plm_req_params *req)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002189{
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002190 uint8_t *in_ptr = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002191 int count, content = 0, ret = 0;
2192 char buf[32];
2193
2194 /* move to argument list */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002195 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Jeff Johnsond36fa332019-03-18 13:42:25 -07002196 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302197 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002198
2199 /* no space after the command */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002200 if (SPACE_ASCII_VALUE != *in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302201 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002202
2203 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002204 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2205 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002206
2207 /* START/STOP PLM req */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002208 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002209 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302210 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211
2212 ret = kstrtos32(buf, 10, &content);
2213 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302214 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002215
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002216 req->enable = content;
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002217 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002218
Jeff Johnsond36fa332019-03-18 13:42:25 -07002219 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302220 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002221
2222 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002223 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2224 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002225
2226 /* Dialog token of radio meas req containing meas reqIE */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002227 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002228 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302229 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002230
2231 ret = kstrtos32(buf, 10, &content);
2232 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302233 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002234
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002235 req->diag_token = content;
2236 hdd_debug("diag token %d", req->diag_token);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002237 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002238
Jeff Johnsond36fa332019-03-18 13:42:25 -07002239 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302240 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002241
2242 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002243 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2244 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002245
2246 /* measurement token of meas req IE */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002247 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002248 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302249 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002250
2251 ret = kstrtos32(buf, 10, &content);
2252 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302253 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002254
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002255 req->meas_token = content;
2256 hdd_debug("meas token %d", req->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002257
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002258 hdd_debug("PLM req %s", req->enable ? "START" : "STOP");
2259 if (req->enable) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002260
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002261 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002262
Jeff Johnsond36fa332019-03-18 13:42:25 -07002263 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302264 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002265
2266 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002267 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2268 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002269
2270 /* total number of bursts after which STA stops sending */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002271 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002272 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302273 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002274
2275 ret = kstrtos32(buf, 10, &content);
2276 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302277 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002278
2279 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302280 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002281
Jeff Johnson36583f02019-02-26 08:02:11 -08002282 req->num_bursts = content;
2283 hdd_debug("num bursts %d", req->num_bursts);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002284 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002285
Jeff Johnsond36fa332019-03-18 13:42:25 -07002286 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302287 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002288
2289 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002290 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2291 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002292
2293 /* burst interval in seconds */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002294 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002295 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302296 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002297
2298 ret = kstrtos32(buf, 10, &content);
2299 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302300 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002301
2302 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302303 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002304
Jeff Johnson36583f02019-02-26 08:02:11 -08002305 req->burst_int = content;
2306 hdd_debug("burst int %d", req->burst_int);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002307 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002308
Jeff Johnsond36fa332019-03-18 13:42:25 -07002309 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302310 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002311
2312 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002313 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2314 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002315
2316 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002317 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002318 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302319 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002320
2321 ret = kstrtos32(buf, 10, &content);
2322 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302323 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002324
2325 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302326 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002327
Jeff Johnson36583f02019-02-26 08:02:11 -08002328 req->meas_duration = content;
2329 hdd_debug("meas duration %d", req->meas_duration);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002330 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002331
Jeff Johnsond36fa332019-03-18 13:42:25 -07002332 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302333 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002334
2335 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002336 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2337 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002338
2339 /* burst length of PLM bursts */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002340 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002341 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302342 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002343
2344 ret = kstrtos32(buf, 10, &content);
2345 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302346 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002347
2348 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302349 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002350
Jeff Johnson36583f02019-02-26 08:02:11 -08002351 req->burst_len = content;
2352 hdd_debug("burst len %d", req->burst_len);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002353 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002354
Jeff Johnsond36fa332019-03-18 13:42:25 -07002355 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302356 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002357
2358 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002359 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2360 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002361
2362 /* desired tx power for transmission of PLM bursts */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002363 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002364 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302365 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002366
2367 ret = kstrtos32(buf, 10, &content);
2368 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302369 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002370
2371 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302372 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373
Jeff Johnson36583f02019-02-26 08:02:11 -08002374 req->desired_tx_pwr = content;
2375 hdd_debug("desired tx pwr %d", req->desired_tx_pwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002376
Anurag Chouhan6d760662016-02-20 16:05:43 +05302377 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002378 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002379
Jeff Johnsond36fa332019-03-18 13:42:25 -07002380 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302381 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002382
2383 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002384 while ((SPACE_ASCII_VALUE == *in_ptr)
2385 && ('\0' != *in_ptr))
2386 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002387
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002388 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002389 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302390 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002391
2392 ret = kstrtos32(buf, 16, &content);
2393 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302394 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002395
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002396 req->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002397 }
2398
Srinivas Girigowda951b3f62020-08-10 16:54:46 -07002399 hdd_debug("MAC addr " QDF_MAC_ADDR_FMT,
2400 QDF_MAC_ADDR_REF(req->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002401
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002402 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002403
Jeff Johnsond36fa332019-03-18 13:42:25 -07002404 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302405 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002406
2407 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002408 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2409 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002410
2411 /* number of channels */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002412 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002413 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302414 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002415
2416 ret = kstrtos32(buf, 10, &content);
2417 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302418 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002419
2420 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302421 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002422
Wu Gao0821b0d2019-01-11 17:31:11 +08002423 content = QDF_MIN(content, CFG_VALID_CHANNEL_LIST_LEN);
Jeff Johnson36583f02019-02-26 08:02:11 -08002424 req->plm_num_ch = content;
2425 hdd_debug("num ch: %d", req->plm_num_ch);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002426
2427 /* Channel numbers */
Jeff Johnson36583f02019-02-26 08:02:11 -08002428 for (count = 0; count < req->plm_num_ch; count++) {
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002429 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002430
Jeff Johnsond36fa332019-03-18 13:42:25 -07002431 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302432 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002433
2434 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002435 while ((SPACE_ASCII_VALUE == *in_ptr)
2436 && ('\0' != *in_ptr))
2437 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002438
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002439 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002440 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302441 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002442
2443 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07002444 if (ret < 0 || content <= 0 ||
2445 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302446 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002447
wadesong88aa89a2019-11-04 12:34:12 +08002448 req->plm_ch_freq_list[count] =
2449 cds_chan_to_freq(content);
2450 hdd_debug(" ch-freq- %d", req->plm_ch_freq_list[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002451 }
2452 }
2453 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302454 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002455}
2456#endif
2457
2458#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302459/**
2460 * wlan_hdd_ready_to_extwow() - Callback function for enable ext wow
2461 * @cookie: callback context
2462 * @is_success: suspend status of ext wow
2463 *
2464 * Return: none
2465 */
2466static void wlan_hdd_ready_to_extwow(void *cookie, bool is_success)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002467{
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302468 struct osif_request *request = NULL;
2469 struct enable_ext_wow_priv *priv = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002470
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302471 request = osif_request_get(cookie);
2472 if (!request) {
2473 hdd_err("Obselete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002474 return;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302475 }
2476 priv = osif_request_priv(request);
2477 priv->ext_wow_should_suspend = is_success;
2478
2479 osif_request_complete(request);
2480 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002481}
2482
Jeff Johnsone44b7012017-09-10 15:25:47 -07002483static int hdd_enable_ext_wow(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002484 tpSirExtWoWParams arg_params)
2485{
2486 tSirExtWoWParams params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002487 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07002488 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002489 int rc;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302490 struct enable_ext_wow_priv *priv = NULL;
2491 struct osif_request *request = NULL;
2492 void *cookie = NULL;
2493 struct osif_request_params hdd_params = {
2494 .priv_size = sizeof(*priv),
2495 .timeout_ms = WLAN_WAIT_TIME_READY_TO_EXTWOW,
2496 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002497
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302498 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002499
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302500 request = osif_request_alloc(&hdd_params);
2501 if (!request) {
2502 hdd_err("Request Allocation Failure");
2503 return -ENOMEM;
2504 }
2505 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002506
Jeff Johnsond549efa2018-06-13 20:27:47 -07002507 status = sme_configure_ext_wow(hdd_ctx->mac_handle, &params,
2508 &wlan_hdd_ready_to_extwow,
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302509 cookie);
Jeff Johnsond549efa2018-06-13 20:27:47 -07002510 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002511 hdd_err("sme_configure_ext_wow returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07002512 status);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302513 rc = -EPERM;
2514 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002515 }
2516
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302517 rc = osif_request_wait_for_response(request);
2518 if (rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002519 hdd_err("Failed to get ready to extwow");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302520 rc = -EPERM;
2521 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002522 }
2523
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302524 priv = osif_request_priv(request);
2525 if (!priv->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002526 hdd_err("Received ready to ExtWoW failure");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302527 rc = -EPERM;
2528 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002529 }
2530
Wu Gao66454f12018-09-26 19:55:41 +08002531 if (ucfg_pmo_extwow_is_goto_suspend_enabled(hdd_ctx->psoc)) {
Jeff Johnson17d62672017-03-27 08:00:11 -07002532 hdd_info("Received ready to ExtWoW. Going to suspend");
2533
2534 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
2535 if (rc < 0) {
2536 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
2537 rc);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302538 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07002539 }
2540 rc = wlan_hdd_bus_suspend();
2541 if (rc) {
2542 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
2543 rc);
2544 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302545 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07002546 }
2547 }
Wu Gao66454f12018-09-26 19:55:41 +08002548
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302549exit:
2550 osif_request_put(request);
2551 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002552}
2553
Jeff Johnsone44b7012017-09-10 15:25:47 -07002554static int hdd_enable_ext_wow_parser(struct hdd_adapter *adapter, int vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002555 int value)
2556{
2557 tSirExtWoWParams params;
Jeff Johnson621cf972017-08-28 11:58:44 -07002558 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002559 int rc;
Wu Gao66454f12018-09-26 19:55:41 +08002560 uint8_t pin1, pin2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002561
2562 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302563 if (rc)
2564 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002565
2566 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
2567 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002568 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002569 return -EINVAL;
2570 }
2571
2572 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
2573 hdd_ctx->is_extwow_app_type1_param_set)
2574 params.type = value;
2575 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
2576 hdd_ctx->is_extwow_app_type2_param_set)
2577 params.type = value;
2578 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
2579 hdd_ctx->is_extwow_app_type1_param_set &&
2580 hdd_ctx->is_extwow_app_type2_param_set)
2581 params.type = value;
2582 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002583 hdd_err("Set app params before enable it value %d",
2584 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002585 return -EINVAL;
2586 }
2587
2588 params.vdev_id = vdev_id;
Wu Gao66454f12018-09-26 19:55:41 +08002589 pin1 = ucfg_pmo_extwow_app1_wakeup_pin_num(hdd_ctx->psoc);
2590 pin2 = ucfg_pmo_extwow_app2_wakeup_pin_num(hdd_ctx->psoc);
2591 params.wakeup_pin_num = pin1 | (pin2 << 8);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002592
2593 return hdd_enable_ext_wow(adapter, &params);
2594}
2595
Jeff Johnsond549efa2018-06-13 20:27:47 -07002596static int hdd_set_app_type1_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002597 tpSirAppType1Params arg_params)
2598{
2599 tSirAppType1Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002600 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002601
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302602 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002603
Jeff Johnsond549efa2018-06-13 20:27:47 -07002604 status = sme_configure_app_type1_params(mac_handle, &params);
2605 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002606 hdd_err("sme_configure_app_type1_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07002607 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002608 return -EPERM;
2609 }
2610
2611 return 0;
2612}
2613
Jeff Johnsone44b7012017-09-10 15:25:47 -07002614static int hdd_set_app_type1_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002615 char *arg, int len)
2616{
Jeff Johnson621cf972017-08-28 11:58:44 -07002617 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002618 char id[20], password[20];
2619 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002620 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002621
2622 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302623 if (rc)
2624 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002625
2626 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002627 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002628 return -EINVAL;
2629 }
2630
2631 memset(&params, 0, sizeof(tSirAppType1Params));
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002632 params.vdev_id = adapter->vdev_id;
Jeff Johnson1e851a12017-10-28 14:36:12 -07002633 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002634
2635 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302636 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302638 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002639
Srinivas Girigowda951b3f62020-08-10 16:54:46 -07002640 hdd_debug("%d "QDF_MAC_ADDR_FMT" %.8s %u %.16s %u",
2641 params.vdev_id,
2642 QDF_MAC_ADDR_REF(params.wakee_mac_addr.bytes),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002643 params.identification_id, params.id_length,
2644 params.password, params.pass_length);
2645
Jeff Johnsond549efa2018-06-13 20:27:47 -07002646 return hdd_set_app_type1_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002647}
2648
Jeff Johnsond549efa2018-06-13 20:27:47 -07002649static int hdd_set_app_type2_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002650 tpSirAppType2Params arg_params)
2651{
2652 tSirAppType2Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002653 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002654
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302655 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002656
Jeff Johnsond549efa2018-06-13 20:27:47 -07002657 status = sme_configure_app_type2_params(mac_handle, &params);
2658 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002659 hdd_err("sme_configure_app_type2_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07002660 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002661 return -EPERM;
2662 }
2663
2664 return 0;
2665}
2666
Jeff Johnsone44b7012017-09-10 15:25:47 -07002667static int hdd_set_app_type2_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002668 char *arg, int len)
2669{
Jeff Johnson621cf972017-08-28 11:58:44 -07002670 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002671 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302672 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002673 tSirAppType2Params params;
2674 int ret;
2675
2676 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302677 if (ret)
2678 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002679
2680 memset(&params, 0, sizeof(tSirAppType2Params));
2681
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302682 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 -08002683 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2684 (unsigned int *)&params.ip_device_ip,
2685 (unsigned int *)&params.ip_server_ip,
2686 (unsigned int *)&params.tcp_seq,
2687 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302688 (uint16_t *)&params.tcp_src_port,
2689 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002690 (unsigned int *)&params.keepalive_init,
2691 (unsigned int *)&params.keepalive_min,
2692 (unsigned int *)&params.keepalive_max,
2693 (unsigned int *)&params.keepalive_inc,
2694 (unsigned int *)&params.tcp_tx_timeout_val,
2695 (unsigned int *)&params.tcp_rx_timeout_val);
2696
2697 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002698 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002699 return -EINVAL;
2700 }
2701
Srinivas Girigowda951b3f62020-08-10 16:54:46 -07002702 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002703 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2704 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002705 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002706 return -EINVAL;
2707 }
2708
2709 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2710 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002711 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002712 return -EINVAL;
2713 }
2714
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302715 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302716 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002717
2718 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302719 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002721 params.vdev_id = adapter->vdev_id;
Wu Gao66454f12018-09-26 19:55:41 +08002722
2723 if (!params.tcp_src_port)
2724 params.tcp_src_port =
2725 ucfg_pmo_extwow_app2_tcp_src_port(hdd_ctx->psoc);
2726
2727 if (!params.tcp_dst_port)
2728 params.tcp_dst_port =
2729 ucfg_pmo_extwow_app2_tcp_dst_port(hdd_ctx->psoc);
2730
2731 if (!params.keepalive_init)
2732 params.keepalive_init =
2733 ucfg_pmo_extwow_app2_init_ping_interval(hdd_ctx->psoc);
2734
2735 if (!params.keepalive_min)
2736 params.keepalive_min =
2737 ucfg_pmo_extwow_app2_min_ping_interval(hdd_ctx->psoc);
2738
2739 if (!params.keepalive_max)
2740 params.keepalive_max =
2741 ucfg_pmo_extwow_app2_max_ping_interval(hdd_ctx->psoc);
2742
2743 if (!params.keepalive_inc)
2744 params.keepalive_inc =
2745 ucfg_pmo_extwow_app2_inc_ping_interval(hdd_ctx->psoc);
2746
2747 if (!params.tcp_tx_timeout_val)
2748 params.tcp_tx_timeout_val =
2749 ucfg_pmo_extwow_app2_tcp_tx_timeout(hdd_ctx->psoc);
2750
2751 if (!params.tcp_rx_timeout_val)
2752 params.tcp_rx_timeout_val =
2753 ucfg_pmo_extwow_app2_tcp_rx_timeout(hdd_ctx->psoc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002754
Srinivas Girigowda951b3f62020-08-10 16:54:46 -07002755 hdd_debug(QDF_MAC_ADDR_FMT" %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2756 QDF_MAC_ADDR_REF(gateway_mac), rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002757 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2758 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2759 params.keepalive_init, params.keepalive_min,
2760 params.keepalive_max, params.keepalive_inc,
2761 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2762
Jeff Johnsond549efa2018-06-13 20:27:47 -07002763 return hdd_set_app_type2_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002764}
2765#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2766
2767/**
2768 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
Jeff Johnson6636e622019-02-26 10:22:39 -08002769 * @command: Pointer to MAXTXPOWER command
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002770 * @tx_power: Pointer to tx power
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002771 *
2772 * This function parses the MAXTXPOWER command passed in the format
2773 * MAXTXPOWER<space>X(Tx power in dbm)
2774 *
2775 * For example input commands:
2776 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2777 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2778 *
2779 * Return: 0 for success non-zero for failure
2780 */
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002781static int hdd_parse_setmaxtxpower_command(uint8_t *command, int *tx_power)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002782{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002783 uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002784 int temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002785 int v = 0;
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002786 *tx_power = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002787
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002788 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002789 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07002790 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002791 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002792 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002793 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002794
2795 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002796 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2797 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002798
2799 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002800 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002801 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002802
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002803 v = kstrtos32(in_ptr, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002804
2805 /* Range checking for passed parameter */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002806 if ((temp_int < HDD_MIN_TX_POWER) || (temp_int > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002807 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002808
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002809 *tx_power = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002810
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002811 hdd_debug("SETMAXTXPOWER: %d", *tx_power);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002812
2813 return 0;
2814} /* End of hdd_parse_setmaxtxpower_command */
2815
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302816static int hdd_get_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002817 char *extra, uint8_t n, uint8_t *len)
2818{
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302819 uint32_t val = 0;
2820
2821 if (!psoc || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002822 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002823 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002824 }
2825
2826 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302827 ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
2828 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n", val);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002829 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002830 }
Jeff Johnson68755312017-02-10 11:46:55 -08002831 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302832 ucfg_scan_cfg_get_passive_dwelltime(psoc, &val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002833 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302834 val);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002835 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002836 }
Ashish Kumar Dhanotiya223fdc42020-02-12 12:58:09 +05302837 if (strncmp(command, "GETDWELLTIME 2G MAX", 19) == 0) {
2838 ucfg_scan_cfg_get_active_2g_dwelltime(psoc, &val);
2839 *len = scnprintf(extra, n, "GETDWELLTIME 2G MAX %u\n",
2840 val);
2841 return 0;
2842 }
Jeff Johnson68755312017-02-10 11:46:55 -08002843 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302844 ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
2845 *len = scnprintf(extra, n, "GETDWELLTIME %u\n", val);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002846 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002847 }
2848
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002849 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002850}
2851
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302852static int hdd_set_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002853{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002854 uint8_t *value = command;
Srinivas Girigowdaa9ce5e62019-03-28 13:44:31 -07002855 int retval = 0, temp = 0;
2856 uint32_t val = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002857
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302858 if (!psoc) {
2859 hdd_err("psoc is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002860 return -EINVAL;
2861 }
2862
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002863 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302864 if (drv_cmd_validate(command, 23))
2865 return -EINVAL;
2866
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002867 value = value + 24;
2868 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302869 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
Ashish Kumar Dhanotiya223fdc42020-02-12 12:58:09 +05302870 hdd_err_rl("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302871 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002872 }
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302873 ucfg_scan_cfg_set_active_dwelltime(psoc, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002874 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302875 if (drv_cmd_validate(command, 24))
2876 return -EINVAL;
2877
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002878 value = value + 25;
2879 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302880 if (temp || !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME, val)) {
Ashish Kumar Dhanotiya223fdc42020-02-12 12:58:09 +05302881 hdd_err_rl("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302882 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002883 }
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302884 ucfg_scan_cfg_set_passive_dwelltime(psoc, val);
Ashish Kumar Dhanotiya223fdc42020-02-12 12:58:09 +05302885 } else if (strncmp(command, "SETDWELLTIME 2G MAX", 19) == 0) {
2886 if (drv_cmd_validate(command, 19))
2887 return -EINVAL;
2888
2889 value = value + 20;
2890 temp = kstrtou32(value, 10, &val);
2891 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_2G_CHANNEL_TIME,
2892 val)) {
2893 hdd_err_rl("argument passed for SETDWELLTIME 2G MAX is incorrect");
2894 return -EFAULT;
2895 }
2896 ucfg_scan_cfg_set_active_2g_dwelltime(psoc, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002897 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302898 if (drv_cmd_validate(command, 12))
2899 return -EINVAL;
2900
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002901 value = value + 13;
2902 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302903 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
Ashish Kumar Dhanotiya223fdc42020-02-12 12:58:09 +05302904 hdd_err_rl("argument passed for SETDWELLTIME is incorrect");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302905 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002906 }
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302907 ucfg_scan_cfg_set_active_dwelltime(psoc, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002908 } else {
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302909 retval = -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002910 }
2911
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302912 return retval;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002913}
2914
Jeff Johnson253c0c22017-01-23 16:59:38 -08002915struct link_status_priv {
2916 uint8_t link_status;
2917};
2918
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302919/**
2920 * hdd_conc_set_dwell_time() - Set Concurrent dwell time parameters
2921 * @adapter: Adapter upon which the command was received
2922 * @command: ASCII text command that is received
2923 *
2924 * Driver commands:
2925 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MAX <value>
2926 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MIN <value>
2927 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MAX <value>
2928 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MIN <value>
2929 *
2930 * Return: 0 for success non-zero for failure
2931 */
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05302932static int hdd_conc_set_dwell_time(struct hdd_adapter *adapter,
2933 uint8_t *command)
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302934{
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302935 u8 *value = command;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302936 int val = 0, temp = 0;
2937 int retval = 0;
2938
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302939 if (strncmp(command, "CONCSETDWELLTIME ACTIVE MAX", 27) == 0) {
2940 if (drv_cmd_validate(command, 27)) {
2941 hdd_err("Invalid driver command");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302942 return -EINVAL;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302943 }
2944
2945 value = value + 28;
2946 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302947 if (temp ||
2948 !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC, val)) {
Harprit Chhabada4691a472018-12-07 11:22:48 -08002949 hdd_err("CONC ACTIVE MAX value %d incorrect", val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302950 return -EFAULT;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302951 }
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05302952 ucfg_scan_cfg_set_conc_active_dwelltime(
2953 (WLAN_HDD_GET_CTX(adapter))->psoc, val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302954 } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MAX", 28) == 0) {
2955 if (drv_cmd_validate(command, 28)) {
2956 hdd_err("Invalid driver command");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302957 return -EINVAL;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302958 }
2959
2960 value = value + 29;
2961 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302962 if (temp ||
2963 !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC, val)) {
Harprit Chhabada4691a472018-12-07 11:22:48 -08002964 hdd_err("CONC PASSIVE MAX val %d incorrect", val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302965 return -EFAULT;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302966 }
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05302967 ucfg_scan_cfg_set_conc_passive_dwelltime(
2968 (WLAN_HDD_GET_CTX(adapter))->psoc, val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302969 } else {
2970 retval = -EINVAL;
2971 }
2972
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302973 return retval;
2974}
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302975
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002976static void hdd_get_link_status_cb(uint8_t status, void *context)
2977{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002978 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002979 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002980
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002981 request = osif_request_get(context);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002982 if (!request) {
2983 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002984 return;
2985 }
2986
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002987 priv = osif_request_priv(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002988 priv->link_status = status;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002989 osif_request_complete(request);
2990 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002991}
2992
2993/**
2994 * wlan_hdd_get_link_status() - get link status
Jeff Johnson25c77342017-10-02 13:28:03 -07002995 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002996 *
2997 * This function sends a request to query the link status and waits
2998 * on a timer to invoke the callback. if the callback is invoked then
2999 * latest link status shall be returned or otherwise cached value
3000 * will be returned.
3001 *
3002 * Return: On success, link status shall be returned.
3003 * On error or not associated, link status 0 will be returned.
3004 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07003005static int wlan_hdd_get_link_status(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003006{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003007 struct hdd_station_ctx *sta_ctx;
3008 QDF_STATUS status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08003009 int ret;
3010 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07003011 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08003012 struct link_status_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07003013 static const struct osif_request_params params = {
Jeff Johnson253c0c22017-01-23 16:59:38 -08003014 .priv_size = sizeof(*priv),
3015 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
3016 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003017
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05303018 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003019 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
3020 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003021 return 0;
3022 }
3023
Krunal Sonibe766b02016-03-10 13:00:44 -08003024 if ((QDF_STA_MODE != adapter->device_mode) &&
3025 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003026 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07003027 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003028 adapter->device_mode);
3029 return 0;
3030 }
3031
Jeff Johnsond377dce2017-10-04 10:32:42 -07003032 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsone7951512019-02-27 10:02:51 -08003033 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003034 /* If not associated, then expected link status return
3035 * value is 0
3036 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003037 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003038 return 0;
3039 }
3040
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07003041 request = osif_request_alloc(&params);
Jeff Johnson253c0c22017-01-23 16:59:38 -08003042 if (!request) {
3043 hdd_err("Request allocation failure");
3044 return 0;
3045 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07003046 cookie = osif_request_cookie(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08003047
Jeff Johnsond549efa2018-06-13 20:27:47 -07003048 status = sme_get_link_status(adapter->hdd_ctx->mac_handle,
3049 hdd_get_link_status_cb,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003050 cookie, adapter->vdev_id);
Jeff Johnsond549efa2018-06-13 20:27:47 -07003051 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003052 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003053 /* return a cached value */
3054 } else {
3055 /* request is sent -- wait for the response */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07003056 ret = osif_request_wait_for_response(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08003057 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003058 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08003059 /* return a cached value */
3060 } else {
3061 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07003062 priv = osif_request_priv(request);
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07003063 adapter->link_status = priv->link_status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08003064 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003065 }
3066
Jeff Johnson253c0c22017-01-23 16:59:38 -08003067 /*
3068 * either we never sent a request, we sent a request and
3069 * received a response or we sent a request and timed out.
3070 * regardless we are done with the request.
3071 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07003072 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003073
3074 /* either callback updated adapter stats or it has cached data */
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07003075 return adapter->link_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003076}
3077
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08003078#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003079/**
3080 * hdd_parse_ese_beacon_req() - Parse ese beacon request
Jeff Johnson6636e622019-02-26 10:22:39 -08003081 * @command: Pointer to data
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003082 * @req: Output pointer to store parsed ie information
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003083 *
3084 * This function parses the ese beacon request passed in the format
3085 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
3086 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
3087 * <space>Scan Mode N<space>Meas Duration N
3088 *
3089 * If the Number of bcn req fields (N) does not match with the
3090 * actual number of fields passed then take N.
3091 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
3092 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
3093 * This function does not take care of removing duplicate channels from the
3094 * list
3095 *
3096 * Return: 0 for success non-zero for failure
3097 */
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05303098static int hdd_parse_ese_beacon_req(struct wlan_objmgr_pdev *pdev,
3099 uint8_t *command,
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003100 tCsrEseBeaconReq *req)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003102 uint8_t *in_ptr = command;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003103 uint8_t input = 0;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003104 uint32_t temp_int = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003105 int j = 0, i = 0, v = 0;
3106 char buf[32];
3107
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003108 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Jeff Johnsond36fa332019-03-18 13:42:25 -07003109 if (!in_ptr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003110 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003111 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003112 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003113
3114 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003115 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
3116 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003117
3118 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003119 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003120 return -EINVAL;
3121
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07003122 /* Getting the first argument ie Number of IE fields */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003123 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003124 if (1 != v)
3125 return -EINVAL;
3126
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003127 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003128 if (v < 0)
3129 return -EINVAL;
3130
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003131 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003132 req->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003133
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003134 hdd_debug("Number of Bcn Req Ie fields: %d", req->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003136 for (j = 0; j < (req->numBcnReqIe); j++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003137 for (i = 0; i < 4; i++) {
3138 /*
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003139 * in_ptr pointing to the beginning of 1st space
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003140 * after number of ie fields
3141 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003142 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003143 /* no ie data after the number of ie fields argument */
Jeff Johnsond36fa332019-03-18 13:42:25 -07003144 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003145 return -EINVAL;
3146
3147 /* remove empty space */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003148 while ((SPACE_ASCII_VALUE == *in_ptr)
3149 && ('\0' != *in_ptr))
3150 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003151
3152 /*
3153 * no ie data after the number of ie fields
3154 * argument and spaces
3155 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003156 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003157 return -EINVAL;
3158
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003159 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003160 if (1 != v)
3161 return -EINVAL;
3162
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003163 v = kstrtou32(buf, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003164 if (v < 0)
3165 return -EINVAL;
3166
3167 switch (i) {
3168 case 0: /* Measurement token */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003169 if (!temp_int) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003170 hdd_err("Invalid Measurement Token: %u",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003171 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003172 return -EINVAL;
3173 }
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003174 req->bcnReq[j].measurementToken =
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003175 temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003176 break;
3177
3178 case 1: /* Channel number */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003179 if (!temp_int ||
3180 (temp_int >
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003181 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003182 hdd_err("Invalid Channel Number: %u",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003183 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003184 return -EINVAL;
3185 }
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05303186 req->bcnReq[j].ch_freq =
3187 wlan_reg_chan_to_freq(pdev, temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003188 break;
3189
3190 case 2: /* Scan mode */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003191 if ((temp_int < eSIR_PASSIVE_SCAN)
3192 || (temp_int > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003193 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003194 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003195 return -EINVAL;
3196 }
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003197 req->bcnReq[j].scanMode = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003198 break;
3199
3200 case 3: /* Measurement duration */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003201 if ((!temp_int
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003202 && (req->bcnReq[j].scanMode !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003203 eSIR_BEACON_TABLE)) ||
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003204 (req->bcnReq[j].scanMode ==
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003205 eSIR_BEACON_TABLE)) {
3206 hdd_err("Invalid Measurement Duration: %u",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003207 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003208 return -EINVAL;
3209 }
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003210 req->bcnReq[j].measurementDuration =
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003211 temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003212 break;
3213 }
3214 }
3215 }
3216
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003217 for (j = 0; j < req->numBcnReqIe; j++) {
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05303218 hdd_debug("Index: %d Measurement Token: %u ch_freq: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003219 j,
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003220 req->bcnReq[j].measurementToken,
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05303221 req->bcnReq[j].ch_freq,
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003222 req->bcnReq[j].scanMode,
3223 req->bcnReq[j].measurementDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003224 }
3225
3226 return 0;
3227}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003228
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003229/**
3230 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
Jeff Johnson6636e622019-02-26 10:22:39 -08003231 * @command: Pointer to input data
Jeff Johnson64c01b12019-02-26 13:12:50 -08003232 * @cckm_ie: Pointer to output cckm Ie
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003233 * @cckm_ie_len: Pointer to output cckm ie length
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003234 *
3235 * This function parses the SETCCKM IE command
3236 * SETCCKMIE<space><ie data>
3237 *
3238 * Return: 0 for success non-zero for failure
3239 */
Jeff Johnson64c01b12019-02-26 13:12:50 -08003240static int hdd_parse_get_cckm_ie(uint8_t *command, uint8_t **cckm_ie,
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003241 uint8_t *cckm_ie_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003242{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003243 uint8_t *in_ptr = command;
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08003244 uint8_t *end_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003245 int j = 0;
3246 int i = 0;
Jeff Johnson72f498b2019-02-26 18:37:25 -08003247 uint8_t temp_u8 = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07003248
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003249 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003250 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07003251 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003252 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003253 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003254 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07003255
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003256 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003257 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
3258 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003259 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003260 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003261 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07003262
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003263 /* find the length of data */
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08003264 end_ptr = in_ptr;
3265 while (('\0' != *end_ptr)) {
3266 end_ptr++;
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003267 ++(*cckm_ie_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003268 }
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003269 if (*cckm_ie_len <= 0)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003270 return -EINVAL;
3271 /*
3272 * Allocate the number of bytes based on the number of input characters
3273 * whether it is even or odd.
3274 * if the number of input characters are even, then we need N / 2 byte.
3275 * if the number of input characters are odd, then we need do
3276 * (N + 1) / 2 to compensate rounding off.
3277 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
3278 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
3279 */
Jeff Johnson64c01b12019-02-26 13:12:50 -08003280 *cckm_ie = qdf_mem_malloc((*cckm_ie_len + 1) / 2);
Jeff Johnsond36fa332019-03-18 13:42:25 -07003281 if (!*cckm_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003282 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003283 return -ENOMEM;
3284 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003285 /*
3286 * the buffer received from the upper layer is character buffer,
3287 * we need to prepare the buffer taking 2 characters in to a U8 hex
3288 * decimal number for example 7f0000f0...form a buffer to contain
3289 * 7f in 0th location, 00 in 1st and f0 in 3rd location
3290 */
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003291 for (i = 0, j = 0; j < *cckm_ie_len; j += 2) {
Jeff Johnson72f498b2019-02-26 18:37:25 -08003292 temp_u8 = (hex_to_bin(in_ptr[j]) << 4) |
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003293 (hex_to_bin(in_ptr[j + 1]));
Jeff Johnson72f498b2019-02-26 18:37:25 -08003294 (*cckm_ie)[i++] = temp_u8;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003295 }
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003296 *cckm_ie_len = i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003297 return 0;
3298}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08003299#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003300
Jeff Johnsonb3f80432019-02-26 20:25:38 -08003301int wlan_hdd_set_mc_rate(struct hdd_adapter *adapter, int target_rate)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003302{
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08003303 tSirRateUpdateInd rate_update = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303304 QDF_STATUS status;
Jeff Johnson25c77342017-10-02 13:28:03 -07003305 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05303306 bool bval = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003307
Jeff Johnsond36fa332019-03-18 13:42:25 -07003308 if (!hdd_ctx) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003309 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003310 return -EINVAL;
3311 }
Jeff Johnson25c77342017-10-02 13:28:03 -07003312 if ((QDF_IBSS_MODE != adapter->device_mode) &&
3313 (QDF_SAP_MODE != adapter->device_mode) &&
3314 (QDF_STA_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003315 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07003316 qdf_opmode_str(adapter->device_mode),
3317 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003318 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003319 return -EINVAL;
3320 }
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05303321
3322 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
3323 if (!QDF_IS_STATUS_SUCCESS(status)) {
3324 hdd_err("unable to get vht_enable2x2");
3325 return -EINVAL;
3326 }
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08003327 rate_update.nss = (bval == 0) ? 0 : 1;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05303328
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08003329 rate_update.dev_mode = adapter->device_mode;
3330 rate_update.mcastDataRate24GHz = target_rate;
3331 rate_update.mcastDataRate24GHzTxFlag = 1;
3332 rate_update.mcastDataRate5GHz = target_rate;
3333 rate_update.bcastDataRate = -1;
3334 qdf_copy_macaddr(&rate_update.bssid, &adapter->mac_addr);
Srinivas Girigowda951b3f62020-08-10 16:54:46 -07003335 hdd_debug("MC Target rate %d, mac = "QDF_MAC_ADDR_FMT", dev_mode %s(%d)",
3336 rate_update.mcastDataRate24GHz,
3337 QDF_MAC_ADDR_REF(rate_update.bssid.bytes),
Dustin Brown458027c2018-10-19 12:26:27 -07003338 qdf_opmode_str(adapter->device_mode), adapter->device_mode);
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08003339 status = sme_send_rate_update_ind(hdd_ctx->mac_handle, &rate_update);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303340 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003341 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003342 return -EFAULT;
3343 }
3344 return 0;
3345}
3346
Jeff Johnsone44b7012017-09-10 15:25:47 -07003347static int drv_cmd_p2p_dev_addr(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003348 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003349 uint8_t *command,
3350 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003351 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003352{
Dustin Brownee220712018-04-19 16:24:23 -07003353 struct qdf_mac_addr *addr = &hdd_ctx->p2p_device_address;
3354 size_t user_size = qdf_min(sizeof(addr->bytes),
3355 (size_t)priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003356
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303357 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3358 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003359 adapter->vdev_id,
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303360 (unsigned int)(*(addr->bytes + 2) << 24 |
Dustin Brownee220712018-04-19 16:24:23 -07003361 *(addr->bytes + 3) << 16 |
3362 *(addr->bytes + 4) << 8 |
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303363 *(addr->bytes + 5)));
3364
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003365
Dustin Brownee220712018-04-19 16:24:23 -07003366 if (copy_to_user(priv_data->buf, addr->bytes, user_size)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003367 hdd_err("failed to copy data to user buffer");
Dustin Brownee220712018-04-19 16:24:23 -07003368 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003369 }
3370
Dustin Brownee220712018-04-19 16:24:23 -07003371 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003372}
3373
3374/**
3375 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
3376 * @adapter: Adapter on which the command was received
3377 * @hdd_ctx: HDD global context
3378 * @command: Entire driver command received from userspace
3379 * @command_len: Length of @command
3380 * @priv_data: Pointer to ioctl private data structure
3381 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07003382 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003383 * command to the actual command processor within the P2P module.
3384 *
3385 * Return: 0 on success, non-zero on failure
3386 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07003387static int drv_cmd_p2p_set_noa(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003388 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003389 uint8_t *command,
3390 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003391 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003392{
3393 return hdd_set_p2p_noa(adapter->dev, command);
3394}
3395
3396/**
3397 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
3398 * @adapter: Adapter on which the command was received
3399 * @hdd_ctx: HDD global context
3400 * @command: Entire driver command received from userspace
3401 * @command_len: Length of @command
3402 * @priv_data: Pointer to ioctl private data structure
3403 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07003404 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003405 * command to the actual command processor within the P2P module.
3406 *
3407 * Return: 0 on success, non-zero on failure
3408 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07003409static int drv_cmd_p2p_set_ps(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_set_p2p_opps(adapter->dev, command);
3416}
3417
Jeff Johnsone44b7012017-09-10 15:25:47 -07003418static int drv_cmd_set_band(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{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07003424 int err;
3425 uint8_t band;
Lincoln Tran0fb32be2020-06-16 13:37:06 -07003426 uint32_t band_bitmap;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003427
3428 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07003429 * Parse the band value passed from userspace. The first 8 bytes
3430 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003431 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07003432 err = kstrtou8(command + command_len + 1, 10, &band);
3433 if (err) {
3434 hdd_err("error %d parsing userspace band parameter", err);
3435 return err;
3436 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003437
Lincoln Tran0fb32be2020-06-16 13:37:06 -07003438 band_bitmap = hdd_reg_legacy_setband_to_reg_wifi_band_bitmap(band);
3439
3440 return hdd_reg_set_band(adapter->dev, band_bitmap);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003441}
3442
Jeff Johnsone44b7012017-09-10 15:25:47 -07003443static int drv_cmd_set_wmmps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003444 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003445 uint8_t *command,
3446 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003447 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003448{
3449 return hdd_wmmps_helper(adapter, command);
3450}
3451
Jeff Johnsone44b7012017-09-10 15:25:47 -07003452static inline int drv_cmd_country(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003453 struct hdd_context *hdd_ctx,
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07003454 uint8_t *command,
3455 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003456 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457{
Sourav Mohapatraa30c4572018-05-22 11:18:39 +05303458 char *country_code;
3459
3460 country_code = strnchr(command, strlen(command), ' ');
3461 /* no argument after the command */
3462 if (!country_code)
3463 return -EINVAL;
3464
3465 /* no space after the command */
3466 if (*country_code != SPACE_ASCII_VALUE)
3467 return -EINVAL;
3468
3469 country_code++;
3470
3471 /* removing empty spaces */
3472 while ((*country_code == SPACE_ASCII_VALUE) &&
3473 (*country_code != '\0'))
3474 country_code++;
3475
3476 /* no or less than 2 arguments followed by spaces */
3477 if (*country_code == '\0' || *(country_code + 1) == '\0')
3478 return -EINVAL;
3479
3480 return hdd_reg_set_country(hdd_ctx, country_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003481}
3482
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +05303483/**
3484 * drv_cmd_get_country() - Helper function to get current county code
3485 * @adapter: pointer to adapter on which request is received
3486 * @hdd_ctx: pointer to hdd context
3487 * @command: command name
3488 * @command_len: command buffer length
3489 * @priv_data: output pointer to hold current country code
3490 *
3491 * Return: On success 0, negative value on error.
3492 */
3493static int drv_cmd_get_country(struct hdd_adapter *adapter,
3494 struct hdd_context *hdd_ctx,
3495 uint8_t *command, uint8_t command_len,
3496 struct hdd_priv_data *priv_data)
3497{
3498 uint8_t buf[SIZE_OF_GETCOUNTRYREV_OUTPUT] = {0};
3499 uint8_t cc[REG_ALPHA2_LEN + 1];
3500 int ret = 0, len;
3501
3502 qdf_mem_copy(cc, hdd_ctx->reg.alpha2, REG_ALPHA2_LEN);
3503 cc[REG_ALPHA2_LEN] = '\0';
3504
3505 len = scnprintf(buf, sizeof(buf), "%s %s",
3506 "GETCOUNTRYREV", cc);
3507 hdd_debug("buf = %s", buf);
3508 len = QDF_MIN(priv_data->total_len, len + 1);
3509 if (copy_to_user(priv_data->buf, buf, len)) {
3510 hdd_err("failed to copy data to user buffer");
3511 ret = -EFAULT;
3512 }
3513
3514 return ret;
3515}
3516
Jeff Johnsone44b7012017-09-10 15:25:47 -07003517static int drv_cmd_set_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003518 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003519 uint8_t *command,
3520 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003521 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003522{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003523 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524 uint8_t *value = command;
3525 int8_t rssi = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08003526 uint8_t lookup_threshold = cfg_default(
3527 CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303528 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003529
3530 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3531 value = value + command_len + 1;
3532
3533 /* Convert the value from ascii to integer */
3534 ret = kstrtos8(value, 10, &rssi);
3535 if (ret < 0) {
3536 /*
3537 * If the input value is greater than max value of datatype,
3538 * then also kstrtou8 fails
3539 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003540 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003541 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
3542 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003543 ret = -EINVAL;
3544 goto exit;
3545 }
3546
Wu Gao1ab05582018-11-08 16:22:49 +08003547 lookup_threshold = abs(rssi);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003548
Wu Gao1ab05582018-11-08 16:22:49 +08003549 if (!cfg_in_range(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD,
3550 lookup_threshold)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003551 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003552 lookup_threshold,
3553 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
3554 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003555 ret = -EINVAL;
3556 goto exit;
3557 }
3558
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303559 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3560 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003561 adapter->vdev_id, lookup_threshold);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303562
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003563 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003564 lookup_threshold);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003565
Jeff Johnsond549efa2018-06-13 20:27:47 -07003566 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003567 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003568 lookup_threshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303569 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003570 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003571 ret = -EPERM;
3572 goto exit;
3573 }
3574
3575exit:
3576 return ret;
3577}
3578
Jeff Johnsone44b7012017-09-10 15:25:47 -07003579static int drv_cmd_get_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003580 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003581 uint8_t *command,
3582 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003583 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003584{
3585 int ret = 0;
Srinivas Dasari9249a982019-09-16 14:56:27 +05303586 uint8_t lookup_threshold;
3587 int rssi;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003588 char extra[32];
3589 uint8_t len = 0;
Srinivas Dasari9249a982019-09-16 14:56:27 +05303590 QDF_STATUS status;
3591
3592 status = sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle,
3593 adapter->vdev_id,
3594 &lookup_threshold);
3595 if (QDF_IS_STATUS_ERROR(status))
3596 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003597
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303598 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3599 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003600 adapter->vdev_id, lookup_threshold);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003601
Srinivas Dasari9249a982019-09-16 14:56:27 +05303602 hdd_debug("vdev_id: %u, lookup_threshold: %u",
3603 adapter->vdev_id, lookup_threshold);
3604
3605 rssi = (-1) * lookup_threshold;
3606
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003607 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303608 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003609 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003610 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003611 ret = -EFAULT;
3612 }
3613
3614 return ret;
3615}
3616
Jeff Johnsone44b7012017-09-10 15:25:47 -07003617static int drv_cmd_set_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003618 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003619 uint8_t *command,
3620 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003621 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003622{
3623 int ret = 0;
3624 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003625 uint8_t roam_scan_period = 0;
3626 uint16_t empty_scan_refresh_period =
3627 cfg_default(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003628
3629 /* input refresh period is in terms of seconds */
3630
3631 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3632 value = value + command_len + 1;
3633
3634 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003635 ret = kstrtou8(value, 10, &roam_scan_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636 if (ret < 0) {
3637 /*
3638 * If the input value is greater than max value of datatype,
3639 * then also kstrtou8 fails
3640 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003641 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003642 (cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000),
3643 (cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003644 ret = -EINVAL;
3645 goto exit;
3646 }
3647
Srinivas Dasarib5d9f3e2019-08-22 01:43:42 +05303648 if (!ucfg_mlme_validate_scan_period(roam_scan_period * 1000)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003649 ret = -EINVAL;
3650 goto exit;
3651 }
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303652
3653 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3654 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003655 adapter->vdev_id, roam_scan_period);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303656
Wu Gao1ab05582018-11-08 16:22:49 +08003657 empty_scan_refresh_period = roam_scan_period * 1000;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003659 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003660 roam_scan_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003661
Jeff Johnsond549efa2018-06-13 20:27:47 -07003662 sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003663 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003664 empty_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003665
3666exit:
3667 return ret;
3668}
3669
Jeff Johnsone44b7012017-09-10 15:25:47 -07003670static int drv_cmd_get_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003671 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003672 uint8_t *command,
3673 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003674 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003675{
3676 int ret = 0;
Srinivas Dasari456aa702019-09-17 14:19:50 +05303677 uint16_t empty_scan_refresh_period;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003678 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003679 uint8_t len;
Srinivas Dasari456aa702019-09-17 14:19:50 +05303680 QDF_STATUS status;
3681
3682 status = sme_get_empty_scan_refresh_period(hdd_ctx->mac_handle,
3683 adapter->vdev_id,
3684 &empty_scan_refresh_period);
3685 if (QDF_IS_STATUS_ERROR(status))
3686 return qdf_status_to_os_return(status);
3687
3688 hdd_debug("vdev_id: %u, empty_scan_refresh_period: %u",
3689 adapter->vdev_id, empty_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003690
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303691 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3692 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003693 adapter->vdev_id,
Jeff Johnson96259452019-02-26 20:38:17 -08003694 empty_scan_refresh_period);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303695
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003696 len = scnprintf(extra, sizeof(extra), "%s %d",
3697 "GETROAMSCANPERIOD",
Jeff Johnson96259452019-02-26 20:38:17 -08003698 (empty_scan_refresh_period / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003699 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303700 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003701 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003702 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003703 ret = -EFAULT;
3704 }
3705
3706 return ret;
3707}
3708
Jeff Johnsone44b7012017-09-10 15:25:47 -07003709static int drv_cmd_set_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003710 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003711 uint8_t *command,
3712 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003713 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003714{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003715 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003716 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003717 uint8_t roam_scan_refresh_period = 0;
3718 uint16_t neighbor_scan_refresh_period =
3719 cfg_default(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003720
3721 /* input refresh period is in terms of seconds */
3722 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3723 value = value + command_len + 1;
3724
3725 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003726 ret = kstrtou8(value, 10, &roam_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003727 if (ret < 0) {
3728 /*
3729 * If the input value is greater than max value of datatype,
3730 * then also kstrtou8 fails
3731 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003732 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003733 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003734 / 1000),
Wu Gao1ab05582018-11-08 16:22:49 +08003735 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003736 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003737 ret = -EINVAL;
3738 goto exit;
3739 }
Wu Gao1ab05582018-11-08 16:22:49 +08003740
3741 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD,
3742 roam_scan_refresh_period)) {
3743 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3744 roam_scan_refresh_period,
3745 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3746 / 1000),
3747 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3748 / 1000));
3749 ret = -EINVAL;
3750 goto exit;
3751 }
3752 neighbor_scan_refresh_period = roam_scan_refresh_period * 1000;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003753
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003754 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003755 neighbor_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003756
Jeff Johnsond549efa2018-06-13 20:27:47 -07003757 sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003758 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003759 neighbor_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003760
3761exit:
3762 return ret;
3763}
3764
Jeff Johnsone44b7012017-09-10 15:25:47 -07003765static int drv_cmd_get_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003766 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003767 uint8_t *command,
3768 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003769 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003770{
3771 int ret = 0;
3772 uint16_t value =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003773 sme_get_neighbor_scan_refresh_period(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003774 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003775 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003776
3777 len = scnprintf(extra, sizeof(extra), "%s %d",
3778 "GETROAMSCANREFRESHPERIOD",
3779 (value / 1000));
3780 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303781 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003782 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003783 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003784 ret = -EFAULT;
3785 }
3786
3787 return ret;
3788}
3789
Jeff Johnsone44b7012017-09-10 15:25:47 -07003790static int drv_cmd_set_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003791 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003792 uint8_t *command,
3793 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003794 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003795{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003796 mac_handle_t mac_handle;
3797 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003798 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003799 uint8_t roam_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003800
3801 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3802 value = value + SIZE_OF_SETROAMMODE + 1;
3803
3804 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003805 ret = kstrtou8(value, 10, &roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003806 if (ret < 0) {
3807 /*
3808 * If the input value is greater than max value of datatype,
3809 * then also kstrtou8 fails
3810 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003811 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003812 cfg_min(CFG_LFR_FEATURE_ENABLED),
3813 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003814 ret = -EINVAL;
3815 goto exit;
3816 }
Wu Gao1ab05582018-11-08 16:22:49 +08003817
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003818 hdd_debug("Received Command to Set Roam Mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003819 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003820 /*
3821 * Note that
3822 * SETROAMMODE 0 is to enable LFR while
3823 * SETROAMMODE 1 is to disable LFR, but
3824 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3825 * enable/disable. So, we have to invert the value
3826 * to call sme_update_is_fast_roam_ini_feature_enabled.
3827 */
Wu Gao1ab05582018-11-08 16:22:49 +08003828 if (roam_mode) {
3829 /* Roam enable */
3830 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
3831 } else {
3832 /* Roam disable */
3833 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
3834 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003835
Wu Gao1ab05582018-11-08 16:22:49 +08003836 ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)roam_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07003837 mac_handle = hdd_ctx->mac_handle;
Wu Gao1ab05582018-11-08 16:22:49 +08003838 if (roam_mode) {
3839 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3840 (bool)roam_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07003841 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003842 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003843 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003844 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07003845 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003846 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003847 roam_mode);
3848 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3849 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003850 }
3851
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003852exit:
3853 return ret;
3854}
3855
Pragaspathi Thilagarajaa8320e2019-04-16 02:47:50 +05303856static int drv_cmd_set_suspend_mode(struct hdd_adapter *adapter,
3857 struct hdd_context *hdd_ctx,
3858 uint8_t *command,
3859 uint8_t command_len,
3860 struct hdd_priv_data *priv_data)
3861{
3862 int errno;
3863 uint8_t *value = command;
3864 QDF_STATUS status;
3865 uint8_t idle_monitor;
3866
3867 if (QDF_STA_MODE != adapter->device_mode) {
3868 hdd_debug("Non-STA interface");
3869 return 0;
3870 }
3871
3872 /* Move pointer to ahead of SETSUSPENDMODE<delimiter> */
3873 value = value + SIZE_OF_SETSUSPENDMODE + 1;
3874
3875 /* Convert the value from ascii to integer */
3876 errno = kstrtou8(value, 10, &idle_monitor);
3877 if (errno < 0) {
3878 /*
3879 * If the input value is greater than max value of datatype,
3880 * then also kstrtou8 fails
3881 */
3882 hdd_err("Range validation failed");
3883 return -EINVAL;
3884 }
3885
3886 hdd_debug("idle_monitor:%d", idle_monitor);
3887 status = ucfg_pmo_tgt_psoc_send_idle_roam_suspend_mode(hdd_ctx->psoc,
3888 idle_monitor);
3889 if (QDF_IS_STATUS_ERROR(status)) {
3890 hdd_debug("Send suspend mode to fw failed");
3891 return -EINVAL;
3892 }
3893 return 0;
3894}
3895
Jeff Johnsone44b7012017-09-10 15:25:47 -07003896static int drv_cmd_get_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003897 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003898 uint8_t *command,
3899 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003900 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003901{
3902 int ret = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08003903 bool roam_mode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003904 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003905 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003906
3907 /*
3908 * roamMode value shall be inverted because the sementics is different.
3909 */
Wu Gao1ab05582018-11-08 16:22:49 +08003910 if (roam_mode)
3911 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003912 else
Wu Gao1ab05582018-11-08 16:22:49 +08003913 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003914
Wu Gao1ab05582018-11-08 16:22:49 +08003915 len = scnprintf(extra, sizeof(extra), "%s %d", command, roam_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303916 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003917 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003918 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003919 ret = -EFAULT;
3920 }
3921
3922 return ret;
3923}
3924
Jeff Johnsone44b7012017-09-10 15:25:47 -07003925static int drv_cmd_set_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003926 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927 uint8_t *command,
3928 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003929 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003930{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003931 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003932 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003933 uint8_t roam_rssi_diff = cfg_default(CFG_LFR_ROAM_RSSI_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003934
3935 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3936 value = value + command_len + 1;
3937
3938 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003939 ret = kstrtou8(value, 10, &roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003940 if (ret < 0) {
3941 /*
3942 * If the input value is greater than max value of datatype,
3943 * then also kstrtou8 fails
3944 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003945 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003946 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3947 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003948 ret = -EINVAL;
3949 goto exit;
3950 }
3951
Wu Gao1ab05582018-11-08 16:22:49 +08003952 if (!cfg_in_range(CFG_LFR_ROAM_RSSI_DIFF, roam_rssi_diff)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003953 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003954 roam_rssi_diff,
3955 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3956 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003957 ret = -EINVAL;
3958 goto exit;
3959 }
3960
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003961 hdd_debug("Received Command to Set roam rssi diff = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003962 roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003963
Jeff Johnsond549efa2018-06-13 20:27:47 -07003964 sme_update_roam_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003965 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003966 roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967
3968exit:
3969 return ret;
3970}
3971
Jeff Johnsone44b7012017-09-10 15:25:47 -07003972static int drv_cmd_get_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003973 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003974 uint8_t *command,
3975 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003976 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003977{
3978 int ret = 0;
Srinivas Dasari7f48ac02019-09-16 17:44:43 +05303979 uint8_t rssi_diff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003980 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003981 uint8_t len;
Srinivas Dasari7f48ac02019-09-16 17:44:43 +05303982 QDF_STATUS status;
3983
3984 status = sme_get_roam_rssi_diff(hdd_ctx->mac_handle, adapter->vdev_id,
3985 &rssi_diff);
3986 if (QDF_IS_STATUS_ERROR(status))
3987 return qdf_status_to_os_return(status);
3988
3989 hdd_debug("vdev_id: %u, rssi_diff: %u", adapter->vdev_id, rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003990
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303991 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3992 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
Jeff Johnson65003802019-02-26 20:50:49 -08003993 adapter->vdev_id, rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003994 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnson65003802019-02-26 20:50:49 -08003995 command, rssi_diff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303996 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003997
3998 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003999 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004000 ret = -EFAULT;
4001 }
4002
4003 return ret;
4004}
4005
Jeff Johnsone44b7012017-09-10 15:25:47 -07004006static int drv_cmd_get_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004007 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004008 uint8_t *command,
4009 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004010 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004011{
4012 int ret = 0;
4013 int band = -1;
4014 char extra[32];
4015 uint8_t len = 0;
4016
4017 hdd_get_band_helper(hdd_ctx, &band);
4018
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304019 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
4020 TRACE_CODE_HDD_GETBAND_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004021 adapter->vdev_id, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004022
4023 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304024 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004025
4026 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004027 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028 ret = -EFAULT;
4029 }
4030
4031 return ret;
4032}
4033
Jeff Johnsone44b7012017-09-10 15:25:47 -07004034static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004035 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004036 uint8_t *command,
4037 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004038 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004039{
4040 return hdd_parse_set_roam_scan_channels(adapter, command);
4041}
4042
Abhishek Ambure5e9b6a42020-02-12 21:32:35 +05304043#ifdef WLAN_FEATURE_ROAM_OFFLOAD
4044static bool is_roam_ch_from_fw_supported(struct hdd_context *hdd_ctx)
4045{
4046 return hdd_ctx->roam_ch_from_fw_supported;
4047}
4048
4049struct roam_ch_priv {
4050 struct roam_scan_ch_resp roam_ch;
4051};
4052
4053void hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle,
4054 struct roam_scan_ch_resp *roam_ch,
4055 void *context)
4056{
4057 struct osif_request *request;
4058 struct roam_ch_priv *priv;
4059 uint8_t *event = NULL, i = 0;
4060 uint32_t *freq = NULL, len;
4061 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
4062
4063 hdd_debug("roam scan ch list event received : vdev_id:%d command resp: %d",
4064 roam_ch->vdev_id, roam_ch->command_resp);
4065 /**
4066 * If command response is set in the response message, then it is
4067 * getroamscanchannels command response else this event is asyncronous
4068 * event raised by firmware.
4069 */
4070 if (!roam_ch->command_resp) {
4071 len = roam_ch->num_channels * sizeof(roam_ch->chan_list[0]);
sheenam monga6d9aaff2020-03-16 11:53:23 +05304072 if (!len) {
4073 hdd_err("Invalid len");
4074 return;
4075 }
Abhishek Ambure5e9b6a42020-02-12 21:32:35 +05304076 event = (uint8_t *)qdf_mem_malloc(len);
4077 if (!event) {
4078 hdd_err("Failed to alloc event response buf vdev_id: %d",
4079 roam_ch->vdev_id);
4080 return;
4081 }
4082 freq = (uint32_t *)event;
4083 for (i = 0; i < roam_ch->num_channels &&
4084 i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) {
4085 freq[i] = roam_ch->chan_list[i];
4086 }
4087
Abhishek Ambure3823c362020-03-18 14:15:08 +05304088 hdd_send_roam_scan_ch_list_event(hdd_ctx, roam_ch->vdev_id,
4089 len, event);
Abhishek Ambure5e9b6a42020-02-12 21:32:35 +05304090 qdf_mem_free(event);
4091 return;
4092 }
4093
4094 request = osif_request_get(context);
4095 if (!request) {
4096 hdd_err("Obsolete request");
4097 return;
4098 }
4099 priv = osif_request_priv(request);
4100
4101 priv->roam_ch.num_channels = roam_ch->num_channels;
4102 for (i = 0; i < priv->roam_ch.num_channels &&
4103 i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++)
4104 priv->roam_ch.chan_list[i] = roam_ch->chan_list[i];
4105
4106 osif_request_complete(request);
4107 osif_request_put(request);
4108}
4109
4110static uint32_t
4111hdd_get_roam_chan_from_fw(struct hdd_adapter *adapter, uint32_t *chan_list,
4112 uint8_t *num_channels)
4113{
4114 QDF_STATUS status = QDF_STATUS_E_INVAL;
4115 struct hdd_context *hdd_ctx;
4116 int ret, i;
4117 void *cookie;
4118 struct osif_request *request;
4119 struct roam_ch_priv *priv;
4120 struct roam_scan_ch_resp *p_roam_ch;
4121 static const struct osif_request_params params = {
4122 .priv_size = sizeof(*priv) +
4123 sizeof(priv->roam_ch.chan_list[0]) *
4124 WNI_CFG_VALID_CHANNEL_LIST_LEN,
4125 .timeout_ms = WLAN_WAIT_TIME_STATS,
4126 };
4127
4128 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
4129 request = osif_request_alloc(&params);
4130 if (!request) {
4131 hdd_err("Request allocation failure");
4132 return -ENOMEM;
4133 }
4134
4135 priv = osif_request_priv(request);
4136 p_roam_ch = &priv->roam_ch;
4137 /** channel list starts after response structure*/
4138 priv->roam_ch.chan_list = (uint32_t *)(p_roam_ch + 1);
4139 cookie = osif_request_cookie(request);
4140 status = sme_get_roam_scan_ch(hdd_ctx->mac_handle,
4141 adapter->vdev_id, cookie);
4142
4143 if (QDF_IS_STATUS_ERROR(status)) {
4144 hdd_err("Unable to retrieve roam channels");
4145 ret = qdf_status_to_os_return(status);
4146 goto cleanup;
4147 }
4148
4149 ret = osif_request_wait_for_response(request);
4150 if (ret) {
4151 hdd_err("SME timed out while retrieving raom channels");
4152 goto cleanup;
4153 }
4154
4155 priv = osif_request_priv(request);
4156 *num_channels = priv->roam_ch.num_channels;
4157 for (i = 0; i < *num_channels; i++)
4158 chan_list[i] = priv->roam_ch.chan_list[i];
4159
4160cleanup:
4161 osif_request_put(request);
4162
4163 return ret;
4164}
Abhishek Ambure5e9b6a42020-02-12 21:32:35 +05304165
Abhishek Ambured9c047f2020-07-06 02:26:37 +05304166int
4167hdd_get_roam_scan_freq(struct hdd_adapter *adapter, mac_handle_t mac_handle,
4168 uint32_t *chan_list, uint8_t *num_channels)
Abhishek Ambure5e9b6a42020-02-12 21:32:35 +05304169{
Abhishek Ambured9c047f2020-07-06 02:26:37 +05304170 int ret = 0;
4171
4172 if (!adapter || !mac_handle || !chan_list || !num_channels) {
4173 hdd_err("failed to get roam scan channel, invalid input");
4174 return -EFAULT;
4175 }
4176
4177 if (is_roam_ch_from_fw_supported(adapter->hdd_ctx)) {
4178 ret = hdd_get_roam_chan_from_fw(adapter, chan_list,
4179 num_channels);
4180 if (ret != QDF_STATUS_SUCCESS) {
4181 hdd_err("failed to get roam scan channel list from FW");
4182 return -EFAULT;
4183 }
4184
4185 return ret;
4186 }
4187
4188 if (sme_get_roam_scan_channel_list(mac_handle, chan_list,
4189 num_channels, adapter->vdev_id) !=
4190 QDF_STATUS_SUCCESS) {
4191 hdd_err("failed to get roam scan channel list");
4192 return -EFAULT;
4193 }
4194
4195 return ret;
Abhishek Ambure5e9b6a42020-02-12 21:32:35 +05304196}
4197#endif
4198
Jeff Johnsone44b7012017-09-10 15:25:47 -07004199static int drv_cmd_get_roam_scan_channels(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;
Jianmin Zhu203d7532019-10-28 17:17:05 +08004206 uint32_t freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08004207 uint8_t num_channels = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004208 uint8_t j = 0;
4209 char extra[128] = { 0 };
4210 int len;
Jianmin Zhu203d7532019-10-28 17:17:05 +08004211 uint8_t chan;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004212
Abhishek Ambured9c047f2020-07-06 02:26:37 +05304213 ret = hdd_get_roam_scan_freq(adapter, hdd_ctx->mac_handle, freq_list,
4214 &num_channels);
4215 if (ret != QDF_STATUS_SUCCESS)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004216 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004217
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304218 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
4219 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08004220 adapter->vdev_id, num_channels);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304221
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004222 /*
4223 * output channel list is of the format
4224 * [Number of roam scan channels][Channel1][Channel2]...
4225 * copy the number of channels in the 0th index
4226 */
4227 len = scnprintf(extra, sizeof(extra), "%s %d", command,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08004228 num_channels);
Jianmin Zhu203d7532019-10-28 17:17:05 +08004229 for (j = 0; (j < num_channels) && len <= sizeof(extra); j++) {
4230 chan = wlan_reg_freq_to_chan(hdd_ctx->pdev, freq_list[j]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004231 len += scnprintf(extra + len, sizeof(extra) - len,
Jianmin Zhu203d7532019-10-28 17:17:05 +08004232 " %d", chan);
4233 }
Anurag Chouhan6d760662016-02-20 16:05:43 +05304234 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004235 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004236 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004237 ret = -EFAULT;
4238 goto exit;
4239 }
4240
4241exit:
4242 return ret;
4243}
4244
Jeff Johnsone44b7012017-09-10 15:25:47 -07004245static int drv_cmd_get_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004246 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004247 uint8_t *command,
4248 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004249 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004250{
4251 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004252 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Jeff Johnson22345e12019-02-26 21:33:02 -08004253 bool ese_mode = sme_get_is_ese_feature_enabled(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 char extra[32];
4255 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004256 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004258 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004259 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004260 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004261 * then this operation is not permitted (return FAILURE)
4262 */
Jeff Johnson22345e12019-02-26 21:33:02 -08004263 if (ese_mode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004264 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07004265 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004266 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004267 ret = -EPERM;
4268 goto exit;
4269 }
4270
4271 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnson22345e12019-02-26 21:33:02 -08004272 "GETCCXMODE", ese_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304273 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004274 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004275 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004276 ret = -EFAULT;
4277 goto exit;
4278 }
4279
4280exit:
4281 return ret;
4282}
4283
Jeff Johnsone44b7012017-09-10 15:25:47 -07004284static int drv_cmd_get_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004285 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004286 uint8_t *command,
4287 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004288 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004289{
4290 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004291 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004292 char extra[32];
4293 uint8_t len = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004294 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004295
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004296 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004297 /*
4298 * Check if the features OKC/ESE/11R are supported simultaneously,
4299 * then this operation is not permitted (return FAILURE)
4300 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004301 if (pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07004302 sme_get_is_ese_feature_enabled(mac_handle) &&
4303 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004304 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004305 ret = -EPERM;
4306 goto exit;
4307 }
4308
4309 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004310 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304311 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004312
4313 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004314 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004315 ret = -EFAULT;
4316 goto exit;
4317 }
4318
4319exit:
4320 return ret;
4321}
4322
Jeff Johnsone44b7012017-09-10 15:25:47 -07004323static int drv_cmd_get_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004324 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004325 uint8_t *command,
4326 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004327 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004328{
4329 int ret = 0;
Jeff Johnson22345e12019-02-26 21:33:02 -08004330 bool lfr_mode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004331 char extra[32];
4332 uint8_t len = 0;
4333
4334 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnson22345e12019-02-26 21:33:02 -08004335 "GETFASTROAM", lfr_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304336 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004337
4338 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004339 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 ret = -EFAULT;
4341 }
4342
4343 return ret;
4344}
4345
Jeff Johnsone44b7012017-09-10 15:25:47 -07004346static int drv_cmd_get_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004347 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004348 uint8_t *command,
4349 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004350 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004351{
4352 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004353 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004354 char extra[32];
4355 uint8_t len = 0;
4356
4357 len = scnprintf(extra, sizeof(extra), "%s %d",
4358 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304359 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004360
4361 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004362 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363 ret = -EFAULT;
4364 }
4365
4366 return ret;
4367}
4368
Jeff Johnsone44b7012017-09-10 15:25:47 -07004369static int drv_cmd_set_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004370 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004371 uint8_t *command,
4372 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004373 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004374{
4375 int ret = 0;
4376 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004377 uint8_t min_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004378
4379 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
4380 value = value + command_len + 1;
4381
4382 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004383 ret = kstrtou8(value, 10, &min_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004384 if (ret < 0) {
4385 /*
4386 * If the input value is greater than max value of datatype,
4387 * then also kstrtou8 fails
4388 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004389 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004390 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
4391 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004392 ret = -EINVAL;
4393 goto exit;
4394 }
4395
Wu Gao1ab05582018-11-08 16:22:49 +08004396 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME, min_time)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004397 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08004398 min_time,
4399 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
4400 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004401 ret = -EINVAL;
4402 goto exit;
4403 }
4404
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304405 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
4406 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004407 adapter->vdev_id, min_time);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304408
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004409 hdd_debug("Received Command to change channel min time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004410 min_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004411
Jeff Johnsond549efa2018-06-13 20:27:47 -07004412 sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
Wu Gao1ab05582018-11-08 16:22:49 +08004413 min_time,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004414 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004415
4416exit:
4417 return ret;
4418}
4419
Jeff Johnsone44b7012017-09-10 15:25:47 -07004420static int drv_cmd_send_action_frame(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004421 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004422 uint8_t *command,
4423 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004424 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004425{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07004426 return hdd_parse_sendactionframe(adapter, command,
4427 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004428}
4429
Jeff Johnsone44b7012017-09-10 15:25:47 -07004430static int drv_cmd_get_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004431 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004432 uint8_t *command,
4433 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004434 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004435{
4436 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004437 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004438 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004439 char extra[32];
4440 uint8_t len = 0;
4441
4442 /* value is interms of msec */
4443 len = scnprintf(extra, sizeof(extra), "%s %d",
4444 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304445 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004446
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304447 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
4448 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004449 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004450
4451 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004452 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004453 ret = -EFAULT;
4454 }
4455
4456 return ret;
4457}
4458
Jeff Johnsone44b7012017-09-10 15:25:47 -07004459static int drv_cmd_set_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004460 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004461 uint8_t *command,
4462 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004463 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004464{
4465 int ret = 0;
4466 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004467 uint16_t max_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468
4469 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
4470 value = value + command_len + 1;
4471
4472 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004473 ret = kstrtou16(value, 10, &max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004474 if (ret < 0) {
4475 /*
4476 * If the input value is greater than max value of datatype,
4477 * then also kstrtou8 fails
4478 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004479 hdd_err("kstrtou16 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004480 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
4481 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004482 ret = -EINVAL;
4483 goto exit;
4484 }
4485
Wu Gao1ab05582018-11-08 16:22:49 +08004486 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME, max_time)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004487 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08004488 max_time,
4489 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
4490 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004491 ret = -EINVAL;
4492 goto exit;
4493 }
4494
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004495 hdd_debug("Received Command to change channel max time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004496 max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004497
Jeff Johnsond549efa2018-06-13 20:27:47 -07004498 sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004499 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004500 max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004501
4502exit:
4503 return ret;
4504}
4505
Jeff Johnsone44b7012017-09-10 15:25:47 -07004506static int drv_cmd_get_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004507 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004508 uint8_t *command,
4509 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004510 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004511{
4512 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004513 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004514 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004515 char extra[32];
4516 uint8_t len = 0;
4517
4518 /* value is interms of msec */
4519 len = scnprintf(extra, sizeof(extra), "%s %d",
4520 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304521 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004522
4523 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004524 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004525 ret = -EFAULT;
4526 }
4527
4528 return ret;
4529}
4530
Jeff Johnsone44b7012017-09-10 15:25:47 -07004531static int drv_cmd_set_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004532 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004533 uint8_t *command,
4534 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004535 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004536{
4537 int ret = 0;
4538 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004539 uint16_t val = cfg_default(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004540
4541 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
4542 value = value + command_len + 1;
4543
4544 /* Convert the value from ascii to integer */
4545 ret = kstrtou16(value, 10, &val);
4546 if (ret < 0) {
4547 /*
4548 * If the input value is greater than max value of datatype,
4549 * then also kstrtou8 fails
4550 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004551 hdd_err("kstrtou16 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004552 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
4553 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004554 ret = -EINVAL;
4555 goto exit;
4556 }
4557
Wu Gao1ab05582018-11-08 16:22:49 +08004558 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004559 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
4560 val,
Wu Gao1ab05582018-11-08 16:22:49 +08004561 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
4562 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563 ret = -EINVAL;
4564 goto exit;
4565 }
4566
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004567 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004568 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004569
Jeff Johnsond549efa2018-06-13 20:27:47 -07004570 sme_set_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004571 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004572
4573exit:
4574 return ret;
4575}
4576
Jeff Johnsone44b7012017-09-10 15:25:47 -07004577static int drv_cmd_get_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004578 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004579 uint8_t *command,
4580 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004581 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004582{
4583 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004584 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004585 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004586 char extra[32];
4587 uint8_t len = 0;
4588
4589 /* value is interms of msec */
4590 len = scnprintf(extra, sizeof(extra), "%s %d",
4591 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304592 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004593
4594 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004595 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004596 ret = -EFAULT;
4597 }
4598
4599 return ret;
4600}
4601
Jeff Johnsone44b7012017-09-10 15:25:47 -07004602static int drv_cmd_set_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004603 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004604 uint8_t *command,
4605 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004606 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004607{
4608 int ret = 0;
4609 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004610 uint8_t val = cfg_default(CFG_LFR_ROAM_INTRA_BAND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004611
4612 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
4613 value = value + command_len + 1;
4614
4615 /* Convert the value from ascii to integer */
4616 ret = kstrtou8(value, 10, &val);
4617 if (ret < 0) {
4618 /*
4619 * If the input value is greater than max value of datatype,
4620 * then also kstrtou8 fails
4621 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004622 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004623 cfg_min(CFG_LFR_ROAM_INTRA_BAND),
4624 cfg_max(CFG_LFR_ROAM_INTRA_BAND));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004625 ret = -EINVAL;
4626 goto exit;
4627 }
4628
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004629 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004630 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004631
Wu Gao1ab05582018-11-08 16:22:49 +08004632 ucfg_mlme_set_roam_intra_band(hdd_ctx->psoc, (bool)val);
Jianmin Zhu0b505a62019-04-30 16:22:49 +08004633 policy_mgr_set_pcl_for_existing_combo(
4634 hdd_ctx->psoc,
4635 PM_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004636
4637exit:
4638 return ret;
4639}
4640
Jeff Johnsone44b7012017-09-10 15:25:47 -07004641static int drv_cmd_get_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004642 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004643 uint8_t *command,
4644 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004645 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004646{
4647 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004648 uint16_t val = sme_get_roam_intra_band(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004649 char extra[32];
4650 uint8_t len = 0;
4651
4652 /* value is interms of msec */
4653 len = scnprintf(extra, sizeof(extra), "%s %d",
4654 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304655 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004656 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004657 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658 ret = -EFAULT;
4659 }
4660
4661 return ret;
4662}
4663
Jeff Johnsone44b7012017-09-10 15:25:47 -07004664static int drv_cmd_set_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004665 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004666 uint8_t *command,
4667 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004668 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669{
4670 int ret = 0;
4671 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004672 uint8_t nprobes = cfg_default(CFG_LFR_ROAM_SCAN_N_PROBES);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004673
4674 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
4675 value = value + command_len + 1;
4676
4677 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004678 ret = kstrtou8(value, 10, &nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004679 if (ret < 0) {
4680 /*
4681 * If the input value is greater than max value of datatype,
4682 * then also kstrtou8 fails
4683 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004684 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004685 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
4686 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004687 ret = -EINVAL;
4688 goto exit;
4689 }
4690
Wu Gao1ab05582018-11-08 16:22:49 +08004691 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_N_PROBES, nprobes)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004692 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08004693 nprobes,
4694 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
4695 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004696 ret = -EINVAL;
4697 goto exit;
4698 }
4699
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004700 hdd_debug("Received Command to Set nProbes = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004701 nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004702
Jeff Johnsond549efa2018-06-13 20:27:47 -07004703 sme_update_roam_scan_n_probes(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004704 adapter->vdev_id, nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004705
4706exit:
4707 return ret;
4708}
4709
Jeff Johnsone44b7012017-09-10 15:25:47 -07004710static int drv_cmd_get_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004711 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004712 uint8_t *command,
4713 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004714 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004715{
4716 int ret = 0;
Srinivas Dasaria5a42fa2019-09-20 12:47:15 +05304717 uint8_t val;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004718 char extra[32];
4719 uint8_t len = 0;
Srinivas Dasaria5a42fa2019-09-20 12:47:15 +05304720 QDF_STATUS status;
4721
4722 status = sme_get_roam_scan_n_probes(hdd_ctx->mac_handle,
4723 adapter->vdev_id,
4724 &val);
4725 if (QDF_IS_STATUS_ERROR(status))
4726 return qdf_status_to_os_return(status);
4727
4728 hdd_debug("vdev_id: %u, scan_n_probes: %u",
4729 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004730
4731 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304732 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004733 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004734 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004735 ret = -EFAULT;
4736 }
4737
4738 return ret;
4739}
4740
Jeff Johnsone44b7012017-09-10 15:25:47 -07004741static int drv_cmd_set_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004742 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004743 uint8_t *command,
4744 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004745 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004746{
4747 int ret = 0;
4748 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004749 uint16_t home_away_time = cfg_default(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004750
4751 /* input value is in units of msec */
4752
4753 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4754 value = value + command_len + 1;
4755
4756 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004757 ret = kstrtou16(value, 10, &home_away_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004758 if (ret < 0) {
4759 /*
4760 * If the input value is greater than max value of datatype,
4761 * then also kstrtou8 fails
4762 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004763 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004764 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4765 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004766 ret = -EINVAL;
4767 goto exit;
4768 }
4769
Wu Gao1ab05582018-11-08 16:22:49 +08004770 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME, home_away_time)) {
4771 hdd_err("home_away_time value %d is out of range (min: %d max: %d)",
4772 home_away_time,
4773 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4774 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004775 ret = -EINVAL;
4776 goto exit;
4777 }
4778
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004779 hdd_debug("Received Command to Set scan away time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004780 home_away_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004781
Srinivas Dasari7bedcd12019-09-20 12:43:11 +05304782 sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle,
4783 adapter->vdev_id,
4784 home_away_time,
4785 true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004786
4787exit:
4788 return ret;
4789}
4790
Jeff Johnsone44b7012017-09-10 15:25:47 -07004791static int drv_cmd_get_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004792 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004793 uint8_t *command,
4794 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004795 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004796{
4797 int ret = 0;
Srinivas Dasari7bedcd12019-09-20 12:43:11 +05304798 uint16_t val;
Abhishek Ambure7b4b2ff2020-01-29 17:47:05 +05304799 char extra[32] = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004800 uint8_t len = 0;
Srinivas Dasari7bedcd12019-09-20 12:43:11 +05304801 QDF_STATUS status;
4802
4803 status = sme_get_roam_scan_home_away_time(hdd_ctx->mac_handle,
4804 adapter->vdev_id,
4805 &val);
4806 if (QDF_IS_STATUS_ERROR(status))
4807 return qdf_status_to_os_return(status);
4808
4809 hdd_debug("vdev_id: %u, scan home away time: %u",
4810 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004811
4812 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304813 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004814
4815 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004816 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004817 ret = -EFAULT;
4818 }
4819
4820 return ret;
4821}
4822
Jeff Johnsone44b7012017-09-10 15:25:47 -07004823static int drv_cmd_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004824 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004825 uint8_t *command,
4826 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004827 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004828{
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05304829 return hdd_parse_reassoc(adapter, command, priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004830}
4831
Jeff Johnsone44b7012017-09-10 15:25:47 -07004832static int drv_cmd_set_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004833 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004834 uint8_t *command,
4835 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004836 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004837{
4838 int ret = 0;
4839 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004840 uint8_t wes_mode = cfg_default(CFG_LFR_ENABLE_WES_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004841
4842 /* Move pointer to ahead of SETWESMODE<delimiter> */
4843 value = value + command_len + 1;
4844
4845 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004846 ret = kstrtou8(value, 10, &wes_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004847 if (ret < 0) {
4848 /*
4849 * If the input value is greater than max value of datatype,
4850 * then also kstrtou8 fails
4851 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004852 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004853 cfg_min(CFG_LFR_ENABLE_WES_MODE),
4854 cfg_max(CFG_LFR_ENABLE_WES_MODE));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004855 ret = -EINVAL;
4856 goto exit;
4857 }
4858
Wu Gao1ab05582018-11-08 16:22:49 +08004859 hdd_debug("Received Command to Set WES Mode rssi diff = %d", wes_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004860
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004861 sme_update_wes_mode(hdd_ctx->mac_handle, wes_mode, adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004862
4863exit:
4864 return ret;
4865}
4866
Jeff Johnsone44b7012017-09-10 15:25:47 -07004867static int drv_cmd_get_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004868 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004869 uint8_t *command,
4870 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004871 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004872{
4873 int ret = 0;
Jeff Johnson22345e12019-02-26 21:33:02 -08004874 bool wes_mode = sme_get_wes_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004875 char extra[32];
4876 uint8_t len = 0;
4877
Jeff Johnson22345e12019-02-26 21:33:02 -08004878 len = scnprintf(extra, sizeof(extra), "%s %d", command, wes_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304879 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004880 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004881 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004882 ret = -EFAULT;
4883 }
4884
4885 return ret;
4886}
4887
Jeff Johnsone44b7012017-09-10 15:25:47 -07004888static int drv_cmd_set_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004889 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004890 uint8_t *command,
4891 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004892 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004893{
4894 int ret = 0;
4895 uint8_t *value = command;
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004896 uint8_t diff =
Wu Gao1ab05582018-11-08 16:22:49 +08004897 cfg_default(CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004898
4899 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4900 value = value + command_len + 1;
4901
4902 /* Convert the value from ascii to integer */
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004903 ret = kstrtou8(value, 10, &diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004904 if (ret < 0) {
4905 /*
4906 * If the input value is greater than max value of datatype,
4907 * then also kstrtou8 fails
4908 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004909 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004910 ret = -EINVAL;
4911 goto exit;
4912 }
4913
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004914 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004915 diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004916
Jeff Johnsond549efa2018-06-13 20:27:47 -07004917 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle,
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004918 adapter->vdev_id,
4919 diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004920
4921exit:
4922 return ret;
4923}
4924
Jeff Johnsone44b7012017-09-10 15:25:47 -07004925static int drv_cmd_get_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004926 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004927 uint8_t *command,
4928 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004929 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004930{
4931 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004932 mac_handle_t mac_handle = hdd_ctx->mac_handle;
4933 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004934 char extra[32];
4935 uint8_t len = 0;
4936
4937 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304938 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004939 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004940 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004941 ret = -EFAULT;
4942 }
4943
4944 return ret;
4945}
4946
Jeff Johnsone44b7012017-09-10 15:25:47 -07004947static int drv_cmd_set_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004948 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004949 uint8_t *command,
4950 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004951 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004952{
4953 int ret = 0;
4954 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004955 uint8_t rescan_rssi_diff = cfg_default(CFG_LFR_ROAM_RESCAN_RSSI_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004956
4957 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4958 value = value + command_len + 1;
4959
4960 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004961 ret = kstrtou8(value, 10, &rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004962 if (ret < 0) {
4963 /*
4964 * If the input value is greater than max value of datatype,
4965 * then also kstrtou8 fails
4966 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004967 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004968 ret = -EINVAL;
4969 goto exit;
4970 }
4971
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004972 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004973 rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004974
Jeff Johnsond549efa2018-06-13 20:27:47 -07004975 sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004976 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004977 rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004978
4979exit:
4980 return ret;
4981}
4982
Jeff Johnsone44b7012017-09-10 15:25:47 -07004983static int drv_cmd_get_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004984 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004985 uint8_t *command,
4986 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004987 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004988{
4989 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004990 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004991 char extra[32];
4992 uint8_t len = 0;
4993
4994 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304995 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004996 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004997 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004998 ret = -EFAULT;
4999 }
5000
5001 return ret;
5002}
5003
Jeff Johnsone44b7012017-09-10 15:25:47 -07005004static int drv_cmd_set_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005005 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005006 uint8_t *command,
5007 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005008 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005009{
5010 int ret = 0;
5011 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08005012 uint8_t lfr_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005013
5014 /* Move pointer to ahead of SETFASTROAM<delimiter> */
5015 value = value + command_len + 1;
5016
5017 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08005018 ret = kstrtou8(value, 10, &lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005019 if (ret < 0) {
5020 /*
5021 * If the input value is greater than max value of datatype,
5022 * then also kstrtou8 fails
5023 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005024 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08005025 cfg_min(CFG_LFR_FEATURE_ENABLED),
5026 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005027 ret = -EINVAL;
5028 goto exit;
5029 }
5030
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005031 hdd_debug("Received Command to change lfr mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08005032 lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005033
Wu Gao1ab05582018-11-08 16:22:49 +08005034 ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)lfr_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005035 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005036 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08005037 lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005038
5039exit:
5040 return ret;
5041}
5042
Jeff Johnsone44b7012017-09-10 15:25:47 -07005043static int drv_cmd_set_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005044 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005045 uint8_t *command,
5046 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005047 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005048{
5049 int ret = 0;
5050 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08005051 uint8_t ft = cfg_default(CFG_LFR_FAST_TRANSITION_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005052
5053 /* Move pointer to ahead of SETFASTROAM<delimiter> */
5054 value = value + command_len + 1;
5055
5056 /* Convert the value from ascii to integer */
5057 ret = kstrtou8(value, 10, &ft);
5058 if (ret < 0) {
5059 /*
5060 * If the input value is greater than max value of datatype,
5061 * then also kstrtou8 fails
5062 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005063 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08005064 cfg_min(CFG_LFR_FAST_TRANSITION_ENABLED),
5065 cfg_max(CFG_LFR_FAST_TRANSITION_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005066 ret = -EINVAL;
5067 goto exit;
5068 }
5069
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005070 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005071
Wu Gao1ab05582018-11-08 16:22:49 +08005072 ucfg_mlme_set_fast_transition_enabled(hdd_ctx->psoc, (bool)ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005073
5074exit:
5075 return ret;
5076}
5077
Jeff Johnsone44b7012017-09-10 15:25:47 -07005078static int drv_cmd_fast_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005079 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005080 uint8_t *command,
5081 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005082 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005083{
5084 int ret = 0;
5085 uint8_t *value = command;
Abhishek Ambured7429442020-08-25 01:03:57 +05305086 qdf_freq_t freq = 0;
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08005087 tSirMacAddr bssid;
Jeff Johnson29c78672019-02-26 21:05:53 -08005088 uint32_t roam_id = INVALID_ROAM_ID;
Jeff Johnson9ff16952019-02-26 20:58:44 -08005089 tCsrRoamModifyProfileFields mod_fields;
Jeff Johnsondcaa8fc2019-02-26 21:26:31 -08005090 tCsrHandoffRequest req;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005091 struct hdd_station_ctx *sta_ctx;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005092 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005093
Krunal Sonibe766b02016-03-10 13:00:44 -08005094 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005095 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005096 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005097 adapter->device_mode);
5098 return -EINVAL;
5099 }
5100
Jeff Johnsond377dce2017-10-04 10:32:42 -07005101 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jingxiang Gece7c5472019-07-23 16:19:23 +08005102 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005103
5104 /* if not associated, no need to proceed with reassoc */
Jeff Johnsone7951512019-02-27 10:02:51 -08005105 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005106 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005107 ret = -EINVAL;
5108 goto exit;
5109 }
5110
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08005111 ret = hdd_parse_reassoc_command_v1_data(value, bssid,
Abhishek Ambured7429442020-08-25 01:03:57 +05305112 &freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005113 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005114 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005115 goto exit;
5116 }
5117
Jeff Johnsond549efa2018-06-13 20:27:47 -07005118 mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005119 /*
5120 * if the target bssid is same as currently associated AP,
5121 * issue reassoc to same AP
5122 */
Jeff Johnsone04b6992019-02-27 14:06:55 -08005123 if (!qdf_mem_cmp(bssid, sta_ctx->conn_info.bssid.bytes,
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08005124 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005125 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05305126 if (roaming_offload_enabled(hdd_ctx)) {
Abhishek Ambured7429442020-08-25 01:03:57 +05305127 hdd_wma_send_fastreassoc_cmd(
5128 adapter, bssid, sta_ctx->conn_info.chan_freq);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05305129 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07005130 sme_get_modify_profile_fields(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005131 adapter->vdev_id,
Jeff Johnson9ff16952019-02-26 20:58:44 -08005132 &mod_fields);
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005133 sme_roam_reassoc(mac_handle, adapter->vdev_id,
Jeff Johnson29c78672019-02-26 21:05:53 -08005134 NULL, mod_fields, &roam_id, 1);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05305135 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005136 return 0;
5137 }
5138
Abhishek Ambured7429442020-08-25 01:03:57 +05305139 /* Check freq number is a valid freq number */
5140 if (freq && QDF_STATUS_SUCCESS !=
5141 wlan_hdd_validate_operation_channel(adapter, freq)) {
5142 hdd_err("Invalid freq [%d]", freq);
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05305143 return -EINVAL;
5144 }
5145
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07005146 if (roaming_offload_enabled(hdd_ctx)) {
Abhishek Ambured7429442020-08-25 01:03:57 +05305147 hdd_wma_send_fastreassoc_cmd(adapter, bssid, freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005148 goto exit;
5149 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005150 /* Proceed with reassoc */
Abhishek Ambured7429442020-08-25 01:03:57 +05305151 req.ch_freq = freq;
Jeff Johnsondcaa8fc2019-02-26 21:26:31 -08005152 req.src = FASTREASSOC;
5153 qdf_mem_copy(req.bssid.bytes, bssid, sizeof(tSirMacAddr));
5154 sme_handoff_request(mac_handle, adapter->vdev_id, &req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005155exit:
5156 return ret;
5157}
5158
Jeff Johnsone44b7012017-09-10 15:25:47 -07005159static int drv_cmd_set_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005160 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005161 uint8_t *command,
5162 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005163 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005164{
5165 int ret = 0;
5166 uint8_t *value = command;
Jeff Johnsond7ee4762019-02-26 21:01:00 -08005167 uint8_t roam_scan_control = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005168
5169 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
5170 value = value + command_len + 1;
5171
5172 /* Convert the value from ascii to integer */
Jeff Johnsond7ee4762019-02-26 21:01:00 -08005173 ret = kstrtou8(value, 10, &roam_scan_control);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005174 if (ret < 0) {
5175 /*
5176 * If the input value is greater than max value of datatype,
5177 * then also kstrtou8 fails
5178 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005179 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005180 ret = -EINVAL;
5181 goto exit;
5182 }
5183
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005184 hdd_debug("Received Command to Set roam scan control = %d",
Jeff Johnsond7ee4762019-02-26 21:01:00 -08005185 roam_scan_control);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005186
Jeff Johnsond7ee4762019-02-26 21:01:00 -08005187 if (0 != roam_scan_control) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005188 ret = 0; /* return success but ignore param value "true" */
5189 goto exit;
5190 }
5191
Jeff Johnsond549efa2018-06-13 20:27:47 -07005192 sme_set_roam_scan_control(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005193 adapter->vdev_id,
Jeff Johnsond7ee4762019-02-26 21:01:00 -08005194 roam_scan_control);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005195
5196exit:
5197 return ret;
5198}
5199
Jeff Johnsone44b7012017-09-10 15:25:47 -07005200static int drv_cmd_set_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005201 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005202 uint8_t *command,
5203 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005204 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005205{
5206 int ret = 0;
5207 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005208 uint32_t okc_mode;
5209 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005210 mac_handle_t mac_handle;
Wu Gao93816212018-08-31 16:49:54 +08005211 uint32_t cur_pmkid_modes;
5212 QDF_STATUS status;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005213
5214 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005215
5216 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005217 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005218 * then this operation is not permitted (return FAILURE)
5219 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005220 mac_handle = hdd_ctx->mac_handle;
5221 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005222 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07005223 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005224 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005225 ret = -EPERM;
5226 goto exit;
5227 }
5228
5229 /* Move pointer to ahead of SETOKCMODE<delimiter> */
5230 value = value + command_len + 1;
5231
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005232 /* get the current configured value */
Dustin Brown1dbefe62018-09-11 16:32:03 -07005233 status = ucfg_mlme_get_pmkid_modes(hdd_ctx->psoc,
Wu Gao93816212018-08-31 16:49:54 +08005234 &cur_pmkid_modes);
5235 if (status != QDF_STATUS_SUCCESS)
5236 hdd_err("get pmkid modes failed");
5237
5238 okc_mode = cur_pmkid_modes & CFG_PMKID_MODES_OKC;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005239
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005240 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005241 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005242 if (ret < 0) {
5243 /*
5244 * If the input value is greater than max value of datatype,
5245 * then also kstrtou8 fails
5246 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005247 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005248 ret = -EINVAL;
5249 goto exit;
5250 }
5251
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005252 if ((okc_mode < 0) ||
5253 (okc_mode > 1)) {
5254 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
5255 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005256 ret = -EINVAL;
5257 goto exit;
5258 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005259 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005260 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005261
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005262 if (okc_mode)
Wu Gao93816212018-08-31 16:49:54 +08005263 cur_pmkid_modes |= CFG_PMKID_MODES_OKC;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005264 else
Wu Gao93816212018-08-31 16:49:54 +08005265 cur_pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Dustin Brown1dbefe62018-09-11 16:32:03 -07005266 status = ucfg_mlme_set_pmkid_modes(hdd_ctx->psoc,
Wu Gao93816212018-08-31 16:49:54 +08005267 cur_pmkid_modes);
5268 if (status != QDF_STATUS_SUCCESS) {
5269 ret = -EPERM;
5270 hdd_err("set pmkid modes failed");
5271 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005272exit:
5273 return ret;
5274}
5275
Jeff Johnsone44b7012017-09-10 15:25:47 -07005276static int drv_cmd_get_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005277 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005278 uint8_t *command,
5279 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005280 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005281{
5282 int ret = 0;
Jeff Johnsond7ee4762019-02-26 21:01:00 -08005283 bool roam_scan_control = sme_get_roam_scan_control(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005284 char extra[32];
5285 uint8_t len = 0;
5286
5287 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnsond7ee4762019-02-26 21:01:00 -08005288 command, roam_scan_control);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305289 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005290 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005291 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005292 ret = -EFAULT;
5293 }
5294
5295 return ret;
5296}
5297
Jeff Johnsone44b7012017-09-10 15:25:47 -07005298static int drv_cmd_bt_coex_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005299 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005300 uint8_t *command,
5301 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005302 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005303{
5304 int ret = 0;
Jeff Johnson30192412019-02-26 20:32:52 -08005305 char *coex_mode;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005306
Jeff Johnson30192412019-02-26 20:32:52 -08005307 coex_mode = command + 11;
5308 if ('1' == *coex_mode) {
5309 hdd_debug("BTCOEXMODE %d", *coex_mode);
Jeff Johnson59b19312017-11-02 21:14:33 -07005310 hdd_ctx->bt_coex_mode_set = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005311 ret = wlan_hdd_scan_abort(adapter);
5312 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005313 hdd_err("Failed to abort existing scan status: %d",
5314 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005315 }
Jeff Johnson30192412019-02-26 20:32:52 -08005316 } else if ('2' == *coex_mode) {
5317 hdd_debug("BTCOEXMODE %d", *coex_mode);
Jeff Johnson59b19312017-11-02 21:14:33 -07005318 hdd_ctx->bt_coex_mode_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005319 }
5320
5321 return ret;
5322}
5323
Jeff Johnsone44b7012017-09-10 15:25:47 -07005324static int drv_cmd_scan_active(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005325 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005326 uint8_t *command,
5327 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005328 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005329{
5330 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
5331 return 0;
5332}
5333
Jeff Johnsone44b7012017-09-10 15:25:47 -07005334static int drv_cmd_scan_passive(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005335 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005336 uint8_t *command,
5337 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005338 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005339{
5340 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
5341 return 0;
5342}
5343
Jeff Johnsone44b7012017-09-10 15:25:47 -07005344static int drv_cmd_get_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005345 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005346 uint8_t *command,
5347 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005348 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005349{
5350 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005351 char extra[32];
5352 uint8_t len = 0;
5353
5354 memset(extra, 0, sizeof(extra));
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05305355 ret = hdd_get_dwell_time(hdd_ctx->psoc, command, extra,
5356 sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305357 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005358 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005359 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005360 ret = -EFAULT;
5361 goto exit;
5362 }
5363 ret = len;
5364exit:
5365 return ret;
5366}
5367
Jeff Johnsone44b7012017-09-10 15:25:47 -07005368static int drv_cmd_set_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005369 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005370 uint8_t *command,
5371 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005372 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005373{
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05305374 return hdd_set_dwell_time(hdd_ctx->psoc, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005375}
5376
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05305377static int drv_cmd_conc_set_dwell_time(struct hdd_adapter *adapter,
5378 struct hdd_context *hdd_ctx,
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05305379 u8 *command,
5380 u8 command_len,
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05305381 struct hdd_priv_data *priv_data)
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05305382{
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05305383 return hdd_conc_set_dwell_time(adapter, command);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05305384}
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05305385
Jeff Johnsone44b7012017-09-10 15:25:47 -07005386static int drv_cmd_miracast(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005387 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005388 uint8_t *command,
5389 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005390 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005391{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305392 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005393 int ret = 0;
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005394 uint8_t filter_type = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005395 uint8_t *value;
5396
Jeff Johnson6da2db12017-09-03 09:18:52 -07005397 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005398 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005399
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005400 value = command + 9;
5401
5402 /* Convert the value from ascii to integer */
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005403 ret = kstrtou8(value, 10, &filter_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005404 if (ret < 0) {
5405 /*
5406 * If the input value is greater than max value of datatype,
5407 * then also kstrtou8 fails
5408 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005409 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005410 ret = -EINVAL;
5411 goto exit;
5412 }
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005413 if ((filter_type < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL) ||
5414 (filter_type > WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005415 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005416 ret = -EINVAL;
5417 goto exit;
5418 }
5419 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005420 hdd_ctx->miracast_value = filter_type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005421
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005422 ret_status = sme_set_miracast(hdd_ctx->mac_handle, filter_type);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305423 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005424 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005425 return -EBUSY;
5426 }
Dustin Brown1dbefe62018-09-11 16:32:03 -07005427 ret_status = ucfg_scan_set_miracast(hdd_ctx->psoc,
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005428 filter_type ? true : false);
Abhishek Singhc87bb042018-01-30 17:10:42 +05305429 if (QDF_IS_STATUS_ERROR(ret_status)) {
5430 hdd_err("Failed to set miracastn scan");
5431 return -EBUSY;
5432 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005433
Dustin Brown1dbefe62018-09-11 16:32:03 -07005434 if (policy_mgr_is_mcc_in_24G(hdd_ctx->psoc))
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005435 return wlan_hdd_set_mas(adapter, filter_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005436
5437exit:
5438 return ret;
5439}
5440
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305441#ifdef FEATURE_WLAN_RMC
5442/* Function header is left blank intentionally */
Jeff Johnson6636e622019-02-26 10:22:39 -08005443static int hdd_parse_setrmcenable_command(uint8_t *command,
Jeff Johnson259f3e92019-02-26 13:36:01 -08005444 uint8_t *rmc_enable)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305445{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005446 uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005447 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305448 int v = 0;
5449 char buf[32];
Jeff Johnson259f3e92019-02-26 13:36:01 -08005450 *rmc_enable = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305451
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005452 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305453
Jeff Johnsond36fa332019-03-18 13:42:25 -07005454 if (!in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305455 return 0;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005456 else if (SPACE_ASCII_VALUE != *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305457 return 0;
5458
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005459 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
5460 in_ptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305461
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005462 if ('\0' == *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305463 return 0;
5464
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005465 v = sscanf(in_ptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305466 if (1 != v)
5467 return -EINVAL;
5468
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005469 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305470 if (v < 0)
5471 return -EINVAL;
5472
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005473 *rmc_enable = temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305474
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005475 hdd_debug("rmc_enable: %d", *rmc_enable);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305476
5477 return 0;
5478}
5479
5480/* Function header is left blank intentionally */
Wu Gao1ab05582018-11-08 16:22:49 +08005481static int hdd_parse_setrmcactionperiod_command(uint8_t *pvalue,
5482 uint32_t *paction_period)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305483{
Wu Gao1ab05582018-11-08 16:22:49 +08005484 uint8_t *inptr = pvalue;
5485 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305486 int v = 0;
5487 char buf[32];
Wu Gao1ab05582018-11-08 16:22:49 +08005488 *paction_period = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305489
Wu Gao1ab05582018-11-08 16:22:49 +08005490 inptr = strnchr(pvalue, strlen(pvalue), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305491
Jeff Johnsond36fa332019-03-18 13:42:25 -07005492 if (!inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305493 return -EINVAL;
Wu Gao1ab05582018-11-08 16:22:49 +08005494 else if (SPACE_ASCII_VALUE != *inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305495 return -EINVAL;
5496
Wu Gao1ab05582018-11-08 16:22:49 +08005497 while ((SPACE_ASCII_VALUE == *inptr) && ('\0' != *inptr))
5498 inptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305499
Wu Gao1ab05582018-11-08 16:22:49 +08005500 if ('\0' == *inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305501 return 0;
5502
Wu Gao1ab05582018-11-08 16:22:49 +08005503 v = sscanf(inptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305504 if (1 != v)
5505 return -EINVAL;
5506
Wu Gao1ab05582018-11-08 16:22:49 +08005507 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305508 if (v < 0)
5509 return -EINVAL;
5510
Wu Gao1ab05582018-11-08 16:22:49 +08005511 if (!cfg_in_range(CFG_RMC_ACTION_PERIOD_FREQUENCY, temp_int))
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305512 return -EINVAL;
5513
Wu Gao1ab05582018-11-08 16:22:49 +08005514 *paction_period = temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305515
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005516 hdd_debug("action_period: %d", *paction_period);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305517
5518 return 0;
5519}
5520
5521/* Function header is left blank intentionally */
Jeff Johnson6636e622019-02-26 10:22:39 -08005522static int hdd_parse_setrmcrate_command(uint8_t *command,
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08005523 uint32_t *rate,
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005524 enum tx_rate_info *tx_flags)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305525{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005526 uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005527 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305528 int v = 0;
5529 char buf[32];
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08005530 *rate = 0;
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005531 *tx_flags = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305532
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005533 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305534
Jeff Johnsond36fa332019-03-18 13:42:25 -07005535 if (!in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305536 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005537 else if (SPACE_ASCII_VALUE != *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305538 return -EINVAL;
5539
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005540 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
5541 in_ptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305542
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005543 if ('\0' == *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305544 return 0;
5545
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005546 v = sscanf(in_ptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305547 if (1 != v)
5548 return -EINVAL;
5549
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005550 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305551 if (v < 0)
5552 return -EINVAL;
5553
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005554 switch (temp_int) {
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305555 default:
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005556 hdd_warn("Unsupported rate: %d", temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305557 return -EINVAL;
5558 case 0:
5559 case 6:
5560 case 9:
5561 case 12:
5562 case 18:
5563 case 24:
5564 case 36:
5565 case 48:
5566 case 54:
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005567 *tx_flags = TX_RATE_LEGACY;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005568 *rate = temp_int * 10;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305569 break;
5570 case 65:
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005571 *tx_flags = TX_RATE_HT20;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005572 *rate = temp_int * 10;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305573 break;
5574 case 72:
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005575 *tx_flags = TX_RATE_HT20 | TX_RATE_SGI;
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08005576 *rate = 722;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305577 break;
5578 }
5579
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08005580 hdd_debug("Rate: %d", *rate);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305581
5582 return 0;
5583}
5584
Jeff Johnsone44b7012017-09-10 15:25:47 -07005585static int drv_cmd_set_rmc_enable(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005586 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005587 uint8_t *command,
5588 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005589 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005590{
5591 int ret = 0;
5592 uint8_t *value = command;
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005593 uint8_t rmc_enable = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005594 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005595 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005596
Krunal Sonibe766b02016-03-10 13:00:44 -08005597 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5598 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005599 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005600 qdf_opmode_str(adapter->device_mode),
5601 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005602 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005603 ret = -EINVAL;
5604 goto exit;
5605 }
5606
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005607 status = hdd_parse_setrmcenable_command(value, &rmc_enable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005608 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005609 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005610 ret = -EINVAL;
5611 goto exit;
5612 }
5613
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005614 hdd_debug("rmc_enable %d", rmc_enable);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005615 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005616
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005617 if (true == rmc_enable) {
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005618 status = sme_enable_rmc(mac_handle, adapter->vdev_id);
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005619 } else if (false == rmc_enable) {
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005620 status = sme_disable_rmc(mac_handle, adapter->vdev_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005621 } else {
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005622 hdd_err("Invalid SETRMCENABLE command %d", rmc_enable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005623 ret = -EINVAL;
5624 goto exit;
5625 }
5626
5627 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005628 hdd_err("SETRMC %d failed status %d", rmc_enable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005629 ret = -EINVAL;
5630 goto exit;
5631 }
5632
5633exit:
5634 return ret;
5635}
5636
Jeff Johnsone44b7012017-09-10 15:25:47 -07005637static int drv_cmd_set_rmc_action_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005638 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005639 uint8_t *command,
5640 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005641 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005642{
5643 int ret = 0;
5644 uint8_t *value = command;
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005645 uint32_t action_period = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005646 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005647 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005648
Krunal Sonibe766b02016-03-10 13:00:44 -08005649 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5650 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005651 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005652 qdf_opmode_str(adapter->device_mode),
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005653 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005654 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005655 ret = -EINVAL;
5656 goto exit;
5657 }
5658
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005659 status = hdd_parse_setrmcactionperiod_command(value, &action_period);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005660 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005661 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005662 ret = -EINVAL;
5663 goto exit;
5664 }
5665
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005666 hdd_debug("action_period %d", action_period);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005667 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005668
Dustin Brown05d81302018-09-11 16:49:22 -07005669 if (ucfg_mlme_set_rmc_action_period_freq(hdd_ctx->psoc,
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005670 action_period) !=
Bala Venkatesh2fde2c62018-09-11 20:33:24 +05305671 QDF_STATUS_SUCCESS) {
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005672 hdd_err("Could not set SETRMCACTIONPERIOD %d", action_period);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005673 ret = -EINVAL;
5674 goto exit;
5675 }
5676
Jeff Johnsond549efa2018-06-13 20:27:47 -07005677 status = sme_send_rmc_action_period(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005678 adapter->vdev_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005679 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005680 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005681 status);
5682 ret = -EINVAL;
5683 goto exit;
5684 }
5685
5686exit:
5687 return ret;
5688}
5689
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305690static int drv_cmd_set_rmc_tx_rate(struct hdd_adapter *adapter,
5691 struct hdd_context *hdd_ctx,
5692 uint8_t *command,
5693 uint8_t command_len,
5694 struct hdd_priv_data *priv_data)
5695{
5696 int ret = 0;
5697 uint8_t *value = command;
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005698 uint32_t rate = 0;
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005699 enum tx_rate_info tx_flags = 0;
Jeff Johnson2370b852019-02-26 17:03:12 -08005700 tSirRateUpdateInd params = {0};
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305701 int status;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05305702 bool bval = false;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305703
5704 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5705 (QDF_SAP_MODE != adapter->device_mode)) {
5706 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005707 qdf_opmode_str(adapter->device_mode),
5708 adapter->device_mode);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305709 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
5710 ret = -EINVAL;
5711 goto exit;
5712 }
5713
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005714 status = hdd_parse_setrmcrate_command(value, &rate, &tx_flags);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305715 if (status) {
5716 hdd_err("Invalid SETRMCTXRATE command");
5717 ret = -EINVAL;
5718 goto exit;
5719 }
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005720 hdd_debug("rate %d", rate);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305721
5722 /*
5723 * Fill the user specifieed RMC rate param
5724 * and the derived tx flags.
5725 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05305726 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
5727 if (!QDF_IS_STATUS_SUCCESS(status)) {
5728 hdd_err("unable to get vht_enable2x2");
5729 ret = -EINVAL;
5730 goto exit;
5731 }
Jeff Johnson2370b852019-02-26 17:03:12 -08005732 params.nss = (bval == 0) ? 0 : 1;
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005733 params.reliableMcastDataRate = rate;
Jeff Johnson2370b852019-02-26 17:03:12 -08005734 params.reliableMcastDataRateTxFlag = tx_flags;
5735 params.dev_mode = adapter->device_mode;
5736 params.bcastDataRate = -1;
5737 memcpy(params.bssid.bytes,
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305738 adapter->mac_addr.bytes,
Jeff Johnson2370b852019-02-26 17:03:12 -08005739 sizeof(params.bssid));
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305740 status = sme_send_rate_update_ind(hdd_ctx->mac_handle,
Jeff Johnson2370b852019-02-26 17:03:12 -08005741 &params);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305742
5743exit:
5744 return ret;
5745}
5746#endif /* FEATURE_WLAN_RMC */
5747
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005748#ifdef FEATURE_WLAN_ESE
Jeff Johnsone44b7012017-09-10 15:25:47 -07005749static int drv_cmd_set_ccx_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005750 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005751 uint8_t *command,
5752 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005753 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005754{
5755 int ret = 0;
5756 uint8_t *value = command;
Liangwei Dong075afa72019-10-30 12:58:22 +08005757 uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005758 uint8_t num_channels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305759 QDF_STATUS status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005760 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005761
Liangwei Dong075afa72019-10-30 12:58:22 +08005762 if (!hdd_ctx) {
5763 hdd_err("invalid hdd ctx");
5764 ret = -EINVAL;
5765 goto exit;
5766 }
5767
5768 ret = hdd_parse_channellist(hdd_ctx, value, channel_freq_list,
5769 &num_channels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005770 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005771 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005772 goto exit;
5773 }
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005774 if (num_channels > CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005775 hdd_err("number of channels (%d) supported exceeded max (%d)",
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005776 num_channels,
5777 CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005778 ret = -EINVAL;
5779 goto exit;
5780 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305781
Jeff Johnsond549efa2018-06-13 20:27:47 -07005782 mac_handle = hdd_ctx->mac_handle;
Liangwei Dong075afa72019-10-30 12:58:22 +08005783 if (!sme_validate_channel_list(mac_handle, channel_freq_list,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005784 num_channels)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305785 hdd_err("List contains invalid channel(s)");
5786 ret = -EINVAL;
5787 goto exit;
5788 }
5789
Jeff Johnsond549efa2018-06-13 20:27:47 -07005790 status = sme_set_ese_roam_scan_channel_list(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005791 adapter->vdev_id,
Liangwei Dong075afa72019-10-30 12:58:22 +08005792 channel_freq_list,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005793 num_channels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305794 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005795 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005796 ret = -EINVAL;
5797 goto exit;
5798 }
5799
5800exit:
5801 return ret;
5802}
5803
Jeff Johnsone44b7012017-09-10 15:25:47 -07005804static int drv_cmd_get_tsm_stats(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005805 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005806 uint8_t *command,
5807 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005808 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005809{
5810 int ret = 0;
5811 uint8_t *value = command;
5812 char extra[128] = { 0 };
5813 int len = 0;
5814 uint8_t tid = 0;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005815 struct hdd_station_ctx *sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005816 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005817
Krunal Sonibe766b02016-03-10 13:00:44 -08005818 if ((QDF_STA_MODE != adapter->device_mode) &&
5819 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005820 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005821 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005822 adapter->device_mode);
5823 return -EINVAL;
5824 }
5825
Jeff Johnsond377dce2017-10-04 10:32:42 -07005826 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005827
5828 /* if not associated, return error */
Jeff Johnsone7951512019-02-27 10:02:51 -08005829 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005830 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005831 ret = -EINVAL;
5832 goto exit;
5833 }
5834
5835 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5836 value = value + command_len + 1;
5837
5838 /* Convert the value from ascii to integer */
5839 ret = kstrtou8(value, 10, &tid);
5840 if (ret < 0) {
5841 /*
5842 * If the input value is greater than max value of datatype,
5843 * then also kstrtou8 fails
5844 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005845 hdd_err("kstrtou8 failed range [%d - %d]",
5846 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005847 TID_MAX_VALUE);
5848 ret = -EINVAL;
5849 goto exit;
5850 }
5851 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005852 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005853 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5854 ret = -EINVAL;
5855 goto exit;
5856 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005857 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005858 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005859 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5860 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005861 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005862 goto exit;
5863 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005864 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005865 "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 -08005866 tsm_metrics.UplinkPktQueueDly,
5867 tsm_metrics.UplinkPktQueueDlyHist[0],
5868 tsm_metrics.UplinkPktQueueDlyHist[1],
5869 tsm_metrics.UplinkPktQueueDlyHist[2],
5870 tsm_metrics.UplinkPktQueueDlyHist[3],
5871 tsm_metrics.UplinkPktTxDly,
5872 tsm_metrics.UplinkPktLoss,
5873 tsm_metrics.UplinkPktCount,
5874 tsm_metrics.RoamingCount,
5875 tsm_metrics.RoamingDly);
5876 /*
5877 * Output TSM stats is of the format
5878 * GETTSMSTATS [PktQueueDly]
5879 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5880 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5881 */
5882 len = scnprintf(extra,
5883 sizeof(extra),
5884 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5885 command,
5886 tsm_metrics.UplinkPktQueueDly,
5887 tsm_metrics.UplinkPktQueueDlyHist[0],
5888 tsm_metrics.UplinkPktQueueDlyHist[1],
5889 tsm_metrics.UplinkPktQueueDlyHist[2],
5890 tsm_metrics.UplinkPktQueueDlyHist[3],
5891 tsm_metrics.UplinkPktTxDly,
5892 tsm_metrics.UplinkPktLoss,
5893 tsm_metrics.UplinkPktCount,
5894 tsm_metrics.RoamingCount,
5895 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305896 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005897 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005898 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005899 ret = -EFAULT;
5900 goto exit;
5901 }
5902
5903exit:
5904 return ret;
5905}
5906
Jeff Johnsone44b7012017-09-10 15:25:47 -07005907static int drv_cmd_set_cckm_ie(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005908 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005909 uint8_t *command,
5910 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005911 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005912{
5913 int ret;
5914 uint8_t *value = command;
Jeff Johnson264e2d32019-02-26 13:16:58 -08005915 uint8_t *cckm_ie = NULL;
Jeff Johnsonb9eeef32019-02-26 13:15:49 -08005916 uint8_t cckm_ie_len = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005917
Jeff Johnson264e2d32019-02-26 13:16:58 -08005918 ret = hdd_parse_get_cckm_ie(value, &cckm_ie, &cckm_ie_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005919 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005920 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005921 goto exit;
5922 }
5923
Jeff Johnsonb9eeef32019-02-26 13:15:49 -08005924 if (cckm_ie_len > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005925 hdd_err("CCKM Ie input length is more than max[%d]",
5926 DOT11F_IE_RSN_MAX_LEN);
Jeff Johnsond36fa332019-03-18 13:42:25 -07005927 if (cckm_ie) {
Jeff Johnson264e2d32019-02-26 13:16:58 -08005928 qdf_mem_free(cckm_ie);
5929 cckm_ie = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005930 }
5931 ret = -EINVAL;
5932 goto exit;
5933 }
5934
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005935 sme_set_cckm_ie(hdd_ctx->mac_handle, adapter->vdev_id,
Jeff Johnson264e2d32019-02-26 13:16:58 -08005936 cckm_ie, cckm_ie_len);
Jeff Johnsond36fa332019-03-18 13:42:25 -07005937 if (cckm_ie) {
Jeff Johnson264e2d32019-02-26 13:16:58 -08005938 qdf_mem_free(cckm_ie);
5939 cckm_ie = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005940 }
5941
5942exit:
5943 return ret;
5944}
5945
Jeff Johnsone44b7012017-09-10 15:25:47 -07005946static int drv_cmd_ccx_beacon_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005947 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005948 uint8_t *command,
5949 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005950 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005951{
5952 int ret;
5953 uint8_t *value = command;
Jeff Johnson210bc972019-02-26 19:55:01 -08005954 tCsrEseBeaconReq req = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305955 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005956
Krunal Sonibe766b02016-03-10 13:00:44 -08005957 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005958 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005959 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005960 adapter->device_mode);
5961 return -EINVAL;
5962 }
5963
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05305964 ret = hdd_parse_ese_beacon_req(hdd_ctx->pdev, value, &req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005965 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005966 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005967 goto exit;
5968 }
5969
5970 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005971 hdd_debug("Not associated");
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305972
Jeff Johnson210bc972019-02-26 19:55:01 -08005973 if (!req.numBcnReqIe)
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305974 return -EINVAL;
5975
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005976 hdd_indicate_ese_bcn_report_no_results(adapter,
Jeff Johnson210bc972019-02-26 19:55:01 -08005977 req.bcnReq[0].measurementToken,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005978 0x02, /* BIT(1) set for measurement done */
5979 0); /* no BSS */
5980 goto exit;
5981 }
5982
Jeff Johnsond549efa2018-06-13 20:27:47 -07005983 status = sme_set_ese_beacon_request(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005984 adapter->vdev_id,
Jeff Johnson210bc972019-02-26 19:55:01 -08005985 &req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005986
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305987 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005988 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005989 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005990 ret = -EBUSY;
5991 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305992 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005993 hdd_err("sme_set_ese_beacon_request failed (%d)",
5994 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005995 ret = -EINVAL;
5996 goto exit;
5997 }
5998
5999exit:
6000 return ret;
6001}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006002
6003/**
6004 * drv_cmd_ccx_plm_req() - Set ESE PLM request
Jeff Johnson36583f02019-02-26 08:02:11 -08006005 * @adapter: Pointer to the HDD adapter
6006 * @hdd_ctx: Pointer to the HDD context
6007 * @command: Driver command string
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006008 * @command_len: Driver command string length
Jeff Johnson36583f02019-02-26 08:02:11 -08006009 * @priv_data: Private data coming with the driver command. Unused here
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006010 *
6011 * This function handles driver command that sets the ESE PLM request
6012 *
6013 * Return: 0 on success; negative errno otherwise
6014 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006015static int drv_cmd_ccx_plm_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006016 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006017 uint8_t *command,
6018 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006019 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006020{
Jeff Johnson36583f02019-02-26 08:02:11 -08006021 QDF_STATUS status;
6022 struct plm_req_params *req;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006023
Jeff Johnson36583f02019-02-26 08:02:11 -08006024 req = qdf_mem_malloc(sizeof(*req));
6025 if (!req)
6026 return -ENOMEM;
6027
6028 status = hdd_parse_plm_cmd(command, req);
6029 if (QDF_IS_STATUS_SUCCESS(status)) {
6030 req->vdev_id = adapter->vdev_id;
6031 status = sme_set_plm_request(hdd_ctx->mac_handle, req);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006032 }
Jeff Johnson36583f02019-02-26 08:02:11 -08006033 qdf_mem_free(req);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006034
Jeff Johnson36583f02019-02-26 08:02:11 -08006035 return qdf_status_to_os_return(status);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006036}
6037
6038/**
6039 * drv_cmd_set_ccx_mode() - Set ESE mode
6040 * @adapter: Pointer to the HDD adapter
6041 * @hdd_ctx: Pointer to the HDD context
6042 * @command: Driver command string
6043 * @command_len: Driver command string length
6044 * @priv_data: Private data coming with the driver command. Unused here
6045 *
6046 * This function handles driver command that sets ESE mode
6047 *
6048 * Return: 0 on success; negative errno otherwise
6049 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006050static int drv_cmd_set_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006051 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006052 uint8_t *command,
6053 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006054 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006055{
6056 int ret = 0;
6057 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08006058 uint8_t ese_mode = cfg_default(CFG_LFR_ESE_FEATURE_ENABLED);
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08006059 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07006060 mac_handle_t mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006061
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08006062 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006063 mac_handle = hdd_ctx->mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006064 /*
6065 * Check if the features OKC/ESE/11R are supported simultaneously,
6066 * then this operation is not permitted (return FAILURE)
6067 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07006068 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08006069 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07006070 sme_get_is_ft_feature_enabled(mac_handle)) {
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006071 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
6072 ret = -EPERM;
6073 goto exit;
6074 }
6075
6076 /* Move pointer to ahead of SETCCXMODE<delimiter> */
6077 value = value + command_len + 1;
6078
6079 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08006080 ret = kstrtou8(value, 10, &ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006081 if (ret < 0) {
6082 /*
6083 * If the input value is greater than max value of datatype,
6084 * then also kstrtou8 fails
6085 */
6086 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08006087 cfg_min(CFG_LFR_ESE_FEATURE_ENABLED),
6088 cfg_max(CFG_LFR_ESE_FEATURE_ENABLED));
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006089 ret = -EINVAL;
6090 goto exit;
6091 }
6092
Wu Gao1ab05582018-11-08 16:22:49 +08006093 hdd_debug("Received Command to change ese mode = %d", ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006094
Jeff Johnsond549efa2018-06-13 20:27:47 -07006095 sme_update_is_ese_feature_enabled(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006096 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08006097 ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006098
6099exit:
6100 return ret;
6101}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006102#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006103
Jeff Johnsone44b7012017-09-10 15:25:47 -07006104static int drv_cmd_set_mc_rate(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006105 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006106 uint8_t *command,
6107 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006108 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006109{
6110 int ret = 0;
6111 uint8_t *value = command;
Srinivas Girigowda9d550152019-03-26 12:19:45 -07006112 uint32_t target_rate = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006113
6114 /* input value is in units of hundred kbps */
6115
6116 /* Move pointer to ahead of SETMCRATE<delimiter> */
6117 value = value + command_len + 1;
6118
6119 /* Convert the value from ascii to integer, decimal base */
Jeff Johnsond549efa2018-06-13 20:27:47 -07006120 ret = kstrtouint(value, 10, &target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006121
Jeff Johnsond549efa2018-06-13 20:27:47 -07006122 ret = wlan_hdd_set_mc_rate(adapter, target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006123 return ret;
6124}
6125
Jeff Johnsone44b7012017-09-10 15:25:47 -07006126static int drv_cmd_max_tx_power(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006127 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006128 uint8_t *command,
6129 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006130 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006131{
Jeff Johnsond549efa2018-06-13 20:27:47 -07006132 int ret;
6133 int tx_power;
6134 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006135 uint8_t *value = command;
Dustin Brownce5b3d32018-01-17 15:07:38 -08006136 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
Jeff Johnsond549efa2018-06-13 20:27:47 -07006137 struct qdf_mac_addr selfmac = QDF_MAC_ADDR_BCAST_INIT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006138
Jeff Johnsond549efa2018-06-13 20:27:47 -07006139 ret = hdd_parse_setmaxtxpower_command(value, &tx_power);
6140 if (ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006141 hdd_err("Invalid MAXTXPOWER command");
Jeff Johnsond549efa2018-06-13 20:27:47 -07006142 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006143 }
6144
Dustin Brown920397d2017-12-13 16:27:50 -08006145 hdd_for_each_adapter(hdd_ctx, adapter) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006146 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05306147 qdf_copy_macaddr(&bssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07006148 &adapter->mac_addr);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006149 qdf_copy_macaddr(&selfmac,
Jeff Johnson1e851a12017-10-28 14:36:12 -07006150 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006151
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006152 hdd_debug("Device mode %d max tx power %d selfMac: "
Srinivas Girigowda951b3f62020-08-10 16:54:46 -07006153 QDF_MAC_ADDR_FMT " bssId: " QDF_MAC_ADDR_FMT,
Jeff Johnsond549efa2018-06-13 20:27:47 -07006154 adapter->device_mode, tx_power,
Srinivas Girigowda951b3f62020-08-10 16:54:46 -07006155 QDF_MAC_ADDR_REF(selfmac.bytes),
6156 QDF_MAC_ADDR_REF(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006157
Jeff Johnsond549efa2018-06-13 20:27:47 -07006158 status = sme_set_max_tx_power(hdd_ctx->mac_handle,
6159 bssid, selfmac, tx_power);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306160 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006161 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006162 ret = -EINVAL;
6163 goto exit;
6164 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006165 hdd_debug("Set max tx power success");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006166 }
6167
6168exit:
6169 return ret;
6170}
6171
Jeff Johnsone44b7012017-09-10 15:25:47 -07006172static int drv_cmd_set_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006173 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006174 uint8_t *command,
6175 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006176 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006177{
6178 int ret = 0;
6179 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08006180 uint8_t dfs_scan_mode = cfg_default(CFG_LFR_ROAMING_DFS_CHANNEL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006181
6182 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
6183 value = value + command_len + 1;
6184
6185 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08006186 ret = kstrtou8(value, 10, &dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006187 if (ret < 0) {
6188 /*
6189 * If the input value is greater than max value of datatype,
6190 * then also kstrtou8 fails
6191 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006192 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08006193 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
6194 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006195 ret = -EINVAL;
6196 goto exit;
6197 }
6198
Wu Gao1ab05582018-11-08 16:22:49 +08006199 if (!cfg_in_range(CFG_LFR_ROAMING_DFS_CHANNEL, dfs_scan_mode)) {
Jeff Johnson68605512019-02-26 21:30:04 -08006200 hdd_err("dfs_scan_mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08006201 dfs_scan_mode,
6202 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
6203 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006204 ret = -EINVAL;
6205 goto exit;
6206 }
6207
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006208 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08006209 dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006210
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08006211 /* When DFS scanning is disabled, the DFS channels need to be
6212 * removed from the operation of device.
6213 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006214 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
Wu Gao1ab05582018-11-08 16:22:49 +08006215 dfs_scan_mode != ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08006216 if (ret < 0) {
6217 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006218 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08006219 goto exit;
6220 }
6221
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006222 sme_update_dfs_scan_mode(hdd_ctx->mac_handle, adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08006223 dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006224
6225exit:
6226 return ret;
6227}
6228
Jeff Johnsone44b7012017-09-10 15:25:47 -07006229static int drv_cmd_get_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006230 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006231 uint8_t *command,
6232 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006233 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006234{
6235 int ret = 0;
Jeff Johnson68605512019-02-26 21:30:04 -08006236 uint8_t dfs_scan_mode = sme_get_dfs_scan_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006237 char extra[32];
6238 uint8_t len = 0;
6239
Jeff Johnson68605512019-02-26 21:30:04 -08006240 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfs_scan_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306241 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006242 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006243 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006244 ret = -EFAULT;
6245 }
6246
6247 return ret;
6248}
6249
Jeff Johnsone44b7012017-09-10 15:25:47 -07006250static int drv_cmd_get_link_status(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006251 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006252 uint8_t *command,
6253 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006254 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006255{
6256 int ret = 0;
6257 int value = wlan_hdd_get_link_status(adapter);
6258 char extra[32];
6259 uint8_t len;
6260
6261 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306262 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006263 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006264 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006265 ret = -EFAULT;
6266 }
6267
6268 return ret;
6269}
6270
6271#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Jeff Johnsone44b7012017-09-10 15:25:47 -07006272static int drv_cmd_enable_ext_wow(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006273 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006274 uint8_t *command,
6275 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006276 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006277{
6278 uint8_t *value = command;
6279 int set_value;
6280
6281 /* Move pointer to ahead of ENABLEEXTWOW */
6282 value = value + command_len;
6283
Anurag Chouhan43e0c752016-09-03 16:17:02 +05306284 if (!(sscanf(value, "%d", &set_value))) {
Dustin Browna2868622018-03-20 11:38:14 -07006285 hdd_info("No input identified");
Anurag Chouhan43e0c752016-09-03 16:17:02 +05306286 return -EINVAL;
6287 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006288
6289 return hdd_enable_ext_wow_parser(adapter,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006290 adapter->vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006291 set_value);
6292}
6293
Jeff Johnsone44b7012017-09-10 15:25:47 -07006294static int drv_cmd_set_app1_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006295 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006296 uint8_t *command,
6297 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006298 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006299{
6300 int ret;
6301 uint8_t *value = command;
6302
6303 /* Move pointer to ahead of SETAPP1PARAMS */
6304 value = value + command_len;
6305
6306 ret = hdd_set_app_type1_parser(adapter,
6307 value, strlen(value));
6308 if (ret >= 0)
6309 hdd_ctx->is_extwow_app_type1_param_set = true;
6310
6311 return ret;
6312}
6313
Jeff Johnsone44b7012017-09-10 15:25:47 -07006314static int drv_cmd_set_app2_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006315 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006316 uint8_t *command,
6317 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006318 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006319{
6320 int ret;
6321 uint8_t *value = command;
6322
6323 /* Move pointer to ahead of SETAPP2PARAMS */
6324 value = value + command_len;
6325
6326 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
6327 if (ret >= 0)
6328 hdd_ctx->is_extwow_app_type2_param_set = true;
6329
6330 return ret;
6331}
6332#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
6333
6334#ifdef FEATURE_WLAN_TDLS
6335/**
6336 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
6337 * @adapter: Pointer to the HDD adapter
6338 * @hdd_ctx: Pointer to the HDD context
6339 * @command: Driver command string
6340 * @command_len: Driver command string length
6341 * @priv_data: Private data coming with the driver command. Unused here
6342 *
6343 * This function handles driver command that sets the secondary tdls off channel
6344 * offset
6345 *
6346 * Return: 0 on success; negative errno otherwise
6347 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006348static int drv_cmd_tdls_secondary_channel_offset(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006349 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006350 uint8_t *command,
6351 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006352 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006353{
6354 int ret;
6355 uint8_t *value = command;
6356 int set_value;
6357
6358 /* Move pointer to point the string */
6359 value += command_len;
6360
6361 ret = sscanf(value, "%d", &set_value);
6362 if (ret != 1)
6363 return -EINVAL;
6364
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006365 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006366
Bala Venkatesh113a9e62018-08-30 15:19:02 +05306367 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, adapter, set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006368
6369 return ret;
6370}
6371
6372/**
6373 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
6374 * @adapter: Pointer to the HDD adapter
6375 * @hdd_ctx: Pointer to the HDD context
6376 * @command: Driver command string
6377 * @command_len: Driver command string length
6378 * @priv_data: Private data coming with the driver command. Unused here
6379 *
6380 * This function handles driver command that sets tdls off channel mode
6381 *
6382 * Return: 0 on success; negative errno otherwise
6383 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006384static int drv_cmd_tdls_off_channel_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006385 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006386 uint8_t *command,
6387 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006388 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006389{
6390 int ret;
6391 uint8_t *value = command;
6392 int set_value;
6393
6394 /* Move pointer to point the string */
6395 value += command_len;
6396
6397 ret = sscanf(value, "%d", &set_value);
6398 if (ret != 1)
6399 return -EINVAL;
6400
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006401 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006402
Bala Venkatesh113a9e62018-08-30 15:19:02 +05306403 ret = hdd_set_tdls_offchannelmode(hdd_ctx, adapter, set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006404
6405 return ret;
6406}
6407
6408/**
6409 * drv_cmd_tdls_off_channel() - set tdls off channel number
6410 * @adapter: Pointer to the HDD adapter
6411 * @hdd_ctx: Pointer to the HDD context
6412 * @command: Driver command string
6413 * @command_len: Driver command string length
6414 * @priv_data: Private data coming with the driver command. Unused here
6415 *
6416 * This function handles driver command that sets tdls off channel number
6417 *
6418 * Return: 0 on success; negative errno otherwise
6419 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006420static int drv_cmd_tdls_off_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006421 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006422 uint8_t *command,
6423 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006424 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006425{
6426 int ret;
6427 uint8_t *value = command;
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306428 int channel;
6429 enum channel_state reg_state;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006430
6431 /* Move pointer to point the string */
6432 value += command_len;
6433
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306434 ret = sscanf(value, "%d", &channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006435 if (ret != 1)
6436 return -EINVAL;
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306437 reg_state = wlan_reg_get_channel_state(hdd_ctx->pdev, channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006438
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306439 if (reg_state == CHANNEL_STATE_DFS ||
6440 reg_state == CHANNEL_STATE_DISABLE ||
6441 reg_state == CHANNEL_STATE_INVALID) {
6442 hdd_err("reg state of the channel %d is %d and not supported",
6443 channel, reg_state);
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006444 return -EINVAL;
6445 }
6446
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306447 hdd_debug("Tdls offchannel num: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006448
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306449 ret = hdd_set_tdls_offchannel(hdd_ctx, adapter, channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006450
6451 return ret;
6452}
6453
6454/**
6455 * drv_cmd_tdls_scan() - set tdls scan type
6456 * @adapter: Pointer to the HDD adapter
6457 * @hdd_ctx: Pointer to the HDD context
6458 * @command: Driver command string
6459 * @command_len: Driver command string length
6460 * @priv_data: Private data coming with the driver command. Unused here
6461 *
6462 * This function handles driver command that sets tdls scan type
6463 *
6464 * Return: 0 on success; negative errno otherwise
6465 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006466static int drv_cmd_tdls_scan(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006467 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006468 uint8_t *command,
6469 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006470 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006471{
6472 int ret;
6473 uint8_t *value = command;
6474 int set_value;
6475
6476 /* Move pointer to point the string */
6477 value += command_len;
6478
6479 ret = sscanf(value, "%d", &set_value);
6480 if (ret != 1)
6481 return -EINVAL;
6482
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006483 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006484
6485 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6486
6487 return ret;
6488}
6489#endif
6490
Jeff Johnsone44b7012017-09-10 15:25:47 -07006491static int drv_cmd_get_rssi(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006492 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006493 uint8_t *command,
6494 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006495 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006496{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006497 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006498 int8_t rssi = 0;
6499 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006500
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006501 uint8_t len = 0;
6502
6503 wlan_hdd_get_rssi(adapter, &rssi);
6504
6505 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306506 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006507
6508 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006509 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006510 ret = -EFAULT;
6511 }
6512
6513 return ret;
6514}
6515
Jeff Johnsone44b7012017-09-10 15:25:47 -07006516static int drv_cmd_get_linkspeed(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006517 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006518 uint8_t *command,
6519 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006520 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006521{
6522 int ret;
6523 uint32_t link_speed = 0;
6524 char extra[32];
6525 uint8_t len = 0;
6526
6527 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6528 if (0 != ret)
6529 return ret;
6530
6531 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306532 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006533 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006534 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006535 ret = -EFAULT;
6536 }
6537
6538 return ret;
6539}
6540
Qiwei Cai4505fc62018-05-17 18:35:19 +08006541#ifdef WLAN_FEATURE_PACKET_FILTERING
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006542/**
6543 * hdd_set_rx_filter() - set RX filter
6544 * @adapter: Pointer to adapter
6545 * @action: Filter action
6546 * @pattern: Address pattern
6547 *
6548 * Address pattern is most significant byte of address for example
6549 * 0x01 for IPV4 multicast address
6550 * 0x33 for IPV6 multicast address
6551 * 0xFF for broadcast address
6552 *
6553 * Return: 0 for success, non-zero for failure
6554 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006555static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006556 uint8_t pattern)
6557{
6558 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006559 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006560 tSirRcvFltMcAddrList *filter;
Jeff Johnson621cf972017-08-28 11:58:44 -07006561 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006562 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006563
6564 ret = wlan_hdd_validate_context(hdd_ctx);
6565 if (0 != ret)
6566 return ret;
6567
Jeff Johnsond549efa2018-06-13 20:27:47 -07006568 mac_handle = hdd_ctx->mac_handle;
6569 if (!mac_handle) {
6570 hdd_err("MAC Handle is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006571 return -EINVAL;
6572 }
6573
Wu Gao66454f12018-09-26 19:55:41 +08006574 if (!ucfg_pmo_is_mc_addr_list_enabled(hdd_ctx->psoc)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006575 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306576 return -EINVAL;
6577 }
6578
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006579 /*
6580 * If action is false it means start dropping packets
6581 * Set addr_filter_pattern which will be used when sending
6582 * MC/BC address list to target
6583 */
6584 if (!action)
6585 adapter->addr_filter_pattern = pattern;
6586 else
6587 adapter->addr_filter_pattern = 0;
6588
Krunal Sonibe766b02016-03-10 13:00:44 -08006589 if (((adapter->device_mode == QDF_STA_MODE) ||
6590 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006591 adapter->mc_addr_list.mc_cnt &&
6592 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6593
6594
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306595 filter = qdf_mem_malloc(sizeof(*filter));
Jeff Johnsond36fa332019-03-18 13:42:25 -07006596 if (!filter) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006597 hdd_err("Could not allocate Memory");
6598 return -ENOMEM;
6599 }
6600 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006601 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006602 if (!memcmp(adapter->mc_addr_list.addr[i],
6603 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006604 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006605 adapter->mc_addr_list.addr[i],
6606 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006607
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006608 hdd_debug("%s RX filter : addr ="
Srinivas Girigowda951b3f62020-08-10 16:54:46 -07006609 QDF_MAC_ADDR_FMT,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006610 action ? "setting" : "clearing",
Srinivas Girigowda951b3f62020-08-10 16:54:46 -07006611 QDF_MAC_ADDR_REF(filter->multicastAddr[j].bytes));
Frank Liuf95e8132016-09-29 19:01:30 +08006612 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006613 }
SaidiReddy Yenuga0b2c9f42017-02-03 12:26:38 +05306614 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
6615 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006616 }
Frank Liuf95e8132016-09-29 19:01:30 +08006617 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006618 /* Set rx filter */
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006619 sme_8023_multicast_list(mac_handle, adapter->vdev_id,
Jeff Johnsond549efa2018-06-13 20:27:47 -07006620 filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306621 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006622 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006623 hdd_debug("mode %d mc_cnt %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07006624 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006625 }
6626
6627 return 0;
6628}
6629
6630/**
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006631 * hdd_driver_rxfilter_command_handler() - RXFILTER driver command handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006632 * @command: Pointer to input string driver command
6633 * @adapter: Pointer to adapter
6634 * @action: Action to enable/disable filtering
6635 *
6636 * If action == false
6637 * Start filtering out data packets based on type
6638 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6639 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6640 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6641 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6642 *
6643 * if action == true
6644 * Stop filtering data packets based on type
6645 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6646 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6647 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6648 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6649 *
6650 * Current implementation only supports IPV4 address filtering by
6651 * selectively allowing IPV4 multicast data packest based on
6652 * address list received in .ndo_set_rx_mode
6653 *
6654 * Return: 0 for success, non-zero for failure
6655 */
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006656static int hdd_driver_rxfilter_command_handler(uint8_t *command,
Jeff Johnsone44b7012017-09-10 15:25:47 -07006657 struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006658 bool action)
6659{
6660 int ret = 0;
6661 uint8_t *value;
6662 uint8_t type;
6663
6664 value = command;
6665 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6666 if (!action)
6667 value = command + 16;
6668 else
6669 value = command + 13;
6670 ret = kstrtou8(value, 10, &type);
6671 if (ret < 0) {
Dustin Brown933cd2a2018-04-18 11:28:15 -07006672 hdd_err("kstrtou8 failed invalid input value");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006673 return -EINVAL;
6674 }
6675
6676 switch (type) {
6677 case 2:
6678 /* Set rx filter for IPV4 multicast data packets */
6679 ret = hdd_set_rx_filter(adapter, action, 0x01);
6680 break;
6681 default:
Arun Kumar Khandavalliafcb0552020-01-20 11:46:36 +05306682 hdd_debug("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006683 break;
6684 }
6685
6686 return ret;
6687}
6688
6689/**
6690 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6691 * @adapter: Pointer to network adapter
6692 * @hdd_ctx: Pointer to hdd context
6693 * @command: Pointer to input command
6694 * @command_len: Command length
6695 * @priv_data: Pointer to private data in command
6696 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006697static int drv_cmd_rx_filter_remove(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006698 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006699 uint8_t *command,
6700 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006701 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006702{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006703 return hdd_driver_rxfilter_command_handler(command, adapter, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006704}
6705
6706/**
6707 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6708 * @adapter: Pointer to network adapter
6709 * @hdd_ctx: Pointer to hdd context
6710 * @command: Pointer to input command
6711 * @command_len: Command length
6712 * @priv_data: Pointer to private data in command
6713 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006714static int drv_cmd_rx_filter_add(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006715 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006716 uint8_t *command,
6717 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006718 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006719{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006720 return hdd_driver_rxfilter_command_handler(command, adapter, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006721}
Qiwei Cai4505fc62018-05-17 18:35:19 +08006722#endif /* WLAN_FEATURE_PACKET_FILTERING */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006723
Archana Ramachandran393f3792015-11-13 17:13:21 -08006724/**
6725 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6726 * command
6727 * @value: Pointer to SETANTENNAMODE command
6728 * @mode: Pointer to antenna mode
6729 * @reason: Pointer to reason for set antenna mode
6730 *
6731 * This function parses the SETANTENNAMODE command passed in the format
6732 * SETANTENNAMODE<space>mode
6733 *
6734 * Return: 0 for success non-zero for failure
6735 */
6736static int hdd_parse_setantennamode_command(const uint8_t *value)
6737{
6738 const uint8_t *in_ptr = value;
6739 int tmp, v;
6740 char arg1[32];
6741
6742 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6743
6744 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07006745 if (!in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006746 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006747 return -EINVAL;
6748 }
6749
6750 /* no space after the command */
6751 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006752 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006753 return -EINVAL;
6754 }
6755
6756 /* remove empty spaces */
6757 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6758 in_ptr++;
6759
6760 /* no argument followed by spaces */
6761 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006762 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006763 return -EINVAL;
6764 }
6765
6766 /* get the argument i.e. antenna mode */
6767 v = sscanf(in_ptr, "%31s ", arg1);
6768 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006769 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006770 return -EINVAL;
6771 }
6772
6773 v = kstrtos32(arg1, 10, &tmp);
6774 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006775 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006776 return -EINVAL;
6777 }
6778
6779 return tmp;
6780}
6781
6782/**
6783 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6784 * mask is 2x2 mode
6785 * @hdd_ctx: Pointer to hdd contex
6786 *
6787 * Return: true if supported chain mask 2x2 else false
6788 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006789static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006790{
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306791 QDF_STATUS status;
6792 bool bval = false;
6793
6794/*
Archana Ramachandran393f3792015-11-13 17:13:21 -08006795 * Revisit and the update logic to determine the number
6796 * of TX/RX chains supported in the system when
6797 * antenna sharing per band chain mask support is
6798 * brought in
6799 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306800 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6801 if (!QDF_IS_STATUS_SUCCESS(status))
6802 hdd_err("unable to get vht_enable2x2");
6803
6804 return (bval == 0x01) ? true : false;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006805}
6806
6807/**
6808 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6809 * chain mask is 1x1
6810 * @hdd_ctx: Pointer to hdd contex
6811 *
6812 * Return: true if supported chain mask 1x1 else false
6813 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006814static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006815{
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306816 QDF_STATUS status;
6817 bool bval = false;
6818
Archana Ramachandran393f3792015-11-13 17:13:21 -08006819 /*
6820 * Revisit and update the logic to determine the number
6821 * of TX/RX chains supported in the system when
6822 * antenna sharing per band chain mask support is
6823 * brought in
6824 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306825 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6826 if (!QDF_IS_STATUS_SUCCESS(status))
6827 hdd_err("unable to get vht_enable2x2");
6828
6829 return (!bval) ? true : false;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006830}
6831
Jeff Johnson621cf972017-08-28 11:58:44 -07006832QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
Nitesh Shahe50711f2017-04-26 16:30:45 +05306833{
6834 QDF_STATUS status;
6835 uint8_t smps_mode;
6836 uint8_t smps_enable;
Jeff Johnsond549efa2018-06-13 20:27:47 -07006837 mac_handle_t mac_handle;
Nitesh Shahe50711f2017-04-26 16:30:45 +05306838
6839 /* Update SME SMPS config */
6840 if (HDD_ANTENNA_MODE_1X1 == mode) {
6841 smps_enable = true;
6842 smps_mode = HDD_SMPS_MODE_STATIC;
6843 } else {
6844 smps_enable = false;
6845 smps_mode = HDD_SMPS_MODE_DISABLED;
6846 }
6847
6848 hdd_debug("Update SME SMPS enable: %d mode: %d",
6849 smps_enable, smps_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006850 mac_handle = hdd_ctx->mac_handle;
6851 status = sme_update_mimo_power_save(mac_handle, smps_enable,
6852 smps_mode, false);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306853 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07006854 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
Nitesh Shahe50711f2017-04-26 16:30:45 +05306855 smps_enable, smps_mode, status);
6856 return QDF_STATUS_E_FAILURE;
6857 }
6858
6859 hdd_ctx->current_antenna_mode = mode;
6860 /*
6861 * Update the user requested nss in the mac context.
6862 * This will be used in tdls protocol engine to form tdls
6863 * Management frames.
6864 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07006865 sme_update_user_configured_nss(mac_handle,
6866 hdd_ctx->current_antenna_mode);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306867
6868 hdd_debug("Successfully switched to mode: %d x %d",
6869 hdd_ctx->current_antenna_mode,
6870 hdd_ctx->current_antenna_mode);
6871
6872 return QDF_STATUS_SUCCESS;
6873}
6874
Dundi Raviteja4016e932018-08-02 12:16:25 +05306875/**
6876 * wlan_hdd_soc_set_antenna_mode_cb() - Callback for set antenna mode
6877 * @status: Status of set antenna mode
6878 * @context: callback context
6879 *
6880 * Callback on setting antenna mode
6881 *
6882 * Return: None
6883 */
6884static void
6885wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status,
6886 void *context)
6887{
6888 struct osif_request *request = NULL;
6889
6890 hdd_debug("Status: %d", status);
6891
6892 request = osif_request_get(context);
6893 if (!request) {
6894 hdd_err("obselete request");
6895 return;
6896 }
6897
6898 /* Signal the completion of set dual mac config */
6899 osif_request_complete(request);
6900 osif_request_put(request);
6901}
6902
Abhishek Singh1571ca72018-04-17 15:14:21 +05306903int hdd_set_antenna_mode(struct hdd_adapter *adapter,
6904 struct hdd_context *hdd_ctx, int mode)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006905{
6906 struct sir_antenna_mode_param params;
6907 QDF_STATUS status;
6908 int ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306909 struct osif_request *request = NULL;
6910 static const struct osif_request_params request_params = {
6911 .priv_size = 0,
Abhishek Singhd1f21c72019-01-21 15:16:34 +05306912 .timeout_ms = SME_POLICY_MGR_CMD_TIMEOUT,
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306913 };
Archana Ramachandran393f3792015-11-13 17:13:21 -08006914
Archana Ramachandran393f3792015-11-13 17:13:21 -08006915 switch (mode) {
6916 case HDD_ANTENNA_MODE_1X1:
6917 params.num_rx_chains = 1;
6918 params.num_tx_chains = 1;
6919 break;
6920 case HDD_ANTENNA_MODE_2X2:
6921 params.num_rx_chains = 2;
6922 params.num_tx_chains = 2;
6923 break;
6924 default:
6925 hdd_err("unsupported antenna mode");
6926 ret = -EINVAL;
6927 goto exit;
6928 }
6929
gaurank kathpalia1281b302018-11-05 21:10:37 +05306930 if (hdd_ctx->dynamic_nss_chains_support)
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306931 return hdd_set_dynamic_antenna_mode(adapter,
6932 params.num_rx_chains,
6933 params.num_tx_chains);
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306934
gaurank kathpaliaf95ae682018-11-05 21:13:07 +05306935 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6936 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6937 hdd_err("System does not support 2x2 mode");
6938 ret = -EPERM;
6939 goto exit;
6940 }
6941
6942 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6943 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6944 hdd_err("System only supports 1x1 mode");
6945 goto exit;
6946 }
6947
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006948 /* Check TDLS status and update antenna mode */
6949 if ((QDF_STA_MODE == adapter->device_mode) &&
Dustin Brown1dbefe62018-09-11 16:32:03 -07006950 policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07006951 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter, mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006952 if (0 != ret)
6953 goto exit;
6954 }
6955
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306956 request = osif_request_alloc(&request_params);
6957 if (!request) {
6958 hdd_err("Request Allocation Failure");
6959 ret = -ENOMEM;
6960 goto exit;
6961 }
6962
6963 params.set_antenna_mode_ctx = osif_request_cookie(request);
6964 params.set_antenna_mode_resp = (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006965 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006966 params.num_rx_chains,
6967 params.num_tx_chains);
6968
Jeff Johnsond549efa2018-06-13 20:27:47 -07006969 status = sme_soc_set_antenna_mode(hdd_ctx->mac_handle, &params);
Abhishek Singh1571ca72018-04-17 15:14:21 +05306970 if (QDF_IS_STATUS_ERROR(status)) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006971 hdd_err("set antenna mode failed status : %d", status);
6972 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306973 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006974 }
6975
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306976 ret = osif_request_wait_for_response(request);
6977 if (ret) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006978 hdd_err("send set antenna mode timed out");
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306979 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006980 }
6981
Nitesh Shahe50711f2017-04-26 16:30:45 +05306982 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006983 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006984 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306985 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006986 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006987 ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306988request_put:
6989 osif_request_put(request);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006990exit:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006991 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006992 ret, hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006993
Abhishek Singh1571ca72018-04-17 15:14:21 +05306994 return ret;
6995}
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306996
Abhishek Singh1571ca72018-04-17 15:14:21 +05306997/**
6998 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6999 * handler
7000 * @adapter: Pointer to network adapter
7001 * @hdd_ctx: Pointer to hdd context
7002 * @command: Pointer to input command
7003 * @command_len: Command length
7004 * @priv_data: Pointer to private data in command
7005 */
7006static int drv_cmd_set_antenna_mode(struct hdd_adapter *adapter,
7007 struct hdd_context *hdd_ctx,
7008 uint8_t *command,
7009 uint8_t command_len,
7010 struct hdd_priv_data *priv_data)
7011{
7012 int mode;
7013 uint8_t *value = command;
7014
7015 mode = hdd_parse_setantennamode_command(value);
7016 if (mode < 0) {
7017 hdd_err("Invalid SETANTENNA command");
7018 return mode;
7019 }
7020
7021 hdd_debug("Processing antenna mode switch to: %d", mode);
7022
7023 return hdd_set_antenna_mode(adapter, hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08007024}
7025
7026/**
gaurank kathpalia2472fb92018-10-31 17:40:18 +05307027 * hdd_get_dynamic_antenna_mode() -get the dynamic antenna mode for vdev
7028 * @antenna_mode: pointer to antenna mode of vdev
7029 * @dynamic_nss_chains_support: feature support for dynamic nss chains update
7030 * @vdev: Pointer to vdev
7031 *
7032 * This API will check for the num of chains configured for the vdev, and fill
7033 * that info in the antenna mode if the dynamic chains per vdev are supported.
7034 *
7035 * Return: None
7036 */
7037static void
7038hdd_get_dynamic_antenna_mode(uint32_t *antenna_mode,
7039 bool dynamic_nss_chains_support,
7040 struct wlan_objmgr_vdev *vdev)
7041{
7042 struct wlan_mlme_nss_chains *nss_chains_dynamic_cfg;
7043
7044 if (!dynamic_nss_chains_support)
7045 return;
7046
gaurank kathpaliab414bce2018-11-09 18:44:46 +05307047 nss_chains_dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
gaurank kathpalia2472fb92018-10-31 17:40:18 +05307048 if (!nss_chains_dynamic_cfg) {
7049 hdd_err("nss chain dynamic config NULL");
7050 return;
7051 }
7052 /*
7053 * At present, this command doesn't include band, so by default
7054 * it will return the band 2ghz present rf chains.
7055 */
gaurank kathpaliab414bce2018-11-09 18:44:46 +05307056 *antenna_mode =
7057 nss_chains_dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
gaurank kathpalia2472fb92018-10-31 17:40:18 +05307058}
7059
7060/**
Archana Ramachandran393f3792015-11-13 17:13:21 -08007061 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
7062 * handler
7063 * @adapter: Pointer to hdd adapter
7064 * @hdd_ctx: Pointer to hdd context
7065 * @command: Pointer to input command
7066 * @command_len: length of the command
7067 * @priv_data: private data coming with the driver command
7068 *
7069 * Return: 0 for success non-zero for failure
7070 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007071static inline int drv_cmd_get_antenna_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07007072 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08007073 uint8_t *command,
7074 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07007075 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08007076{
7077 uint32_t antenna_mode = 0;
7078 char extra[32];
7079 uint8_t len = 0;
7080
7081 antenna_mode = hdd_ctx->current_antenna_mode;
gaurank kathpalia2472fb92018-10-31 17:40:18 +05307082 /* Overwrite this antenna mode if dynamic vdev chains are supported */
7083 hdd_get_dynamic_antenna_mode(&antenna_mode,
7084 hdd_ctx->dynamic_nss_chains_support,
7085 adapter->vdev);
Archana Ramachandran393f3792015-11-13 17:13:21 -08007086 len = scnprintf(extra, sizeof(extra), "%s %d", command,
7087 antenna_mode);
7088 len = QDF_MIN(priv_data->total_len, len + 1);
7089 if (copy_to_user(priv_data->buf, &extra, len)) {
7090 hdd_err("Failed to copy data to user buffer");
7091 return -EFAULT;
7092 }
7093
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007094 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08007095
7096 return 0;
7097}
7098
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007099/*
7100 * dummy (no-op) hdd driver command handler
7101 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007102static int drv_cmd_dummy(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07007103 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007104 uint8_t *command,
7105 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07007106 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007107{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007108 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007109 adapter->dev->name, command);
7110 return 0;
7111}
7112
7113/*
7114 * handler for any unsupported wlan hdd driver command
7115 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007116static int drv_cmd_invalid(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07007117 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007118 uint8_t *command,
7119 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07007120 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007121{
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05307122 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
7123 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08007124 adapter->vdev_id, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007125
7126 hdd_warn("%s: Unsupported driver command \"%s\"",
7127 adapter->dev->name, command);
7128
7129 return -ENOTSUPP;
7130}
7131
7132/**
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307133 * drv_cmd_set_fcc_channel() - Handle fcc constraint request
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007134 * @adapter: HDD adapter
7135 * @hdd_ctx: HDD context
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307136 * @command: command ptr, SET_FCC_CHANNEL 0/-1 is the command
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007137 * @command_len: command len
7138 * @priv_data: private data
7139 *
7140 * Return: status
7141 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007142static int drv_cmd_set_fcc_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07007143 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007144 uint8_t *command,
7145 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07007146 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007147{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05307148 QDF_STATUS status;
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307149 int8_t input_value;
7150 bool fcc_constraint;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07007151 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007152
7153 /*
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307154 * This command would be called by user-space when it detects WLAN
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007155 * ON after airplane mode is set. When APM is set, WLAN turns off.
7156 * But it can be turned back on. Otherwise; when APM is turned back
7157 * off, WLAN would turn back on. So at that point the command is
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307158 * expected to come down. 0 means reduce power as per fcc constraint
7159 * and -1 means remove constraint.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007160 */
7161
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307162 err = kstrtos8(command + command_len + 1, 10, &input_value);
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07007163 if (err) {
7164 hdd_err("error %d parsing userspace fcc parameter", err);
7165 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007166 }
7167
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307168 fcc_constraint = input_value ? false : true;
7169 hdd_debug("input_value = %d && fcc_constraint = %u",
7170 input_value, fcc_constraint);
7171
Dustin Brown07901ec2018-09-07 11:02:41 -07007172 status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev, fcc_constraint);
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07007173
7174 if (QDF_IS_STATUS_ERROR(status))
7175 hdd_err("Failed to %s tx power for channels 12/13",
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307176 fcc_constraint ? "restore" : "reduce");
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07007177
7178 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007179}
7180
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307181/**
7182 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
7183 * command
7184 * @value: Pointer to the command
7185 * @chan_number: Pointer to the channel number
7186 * @chan_bw: Pointer to the channel bandwidth
7187 *
7188 * Parses and provides the channel number and channel width from the input
7189 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
7190 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
7191 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
7192 *
7193 * Return: 0 for success, non-zero for failure
7194 */
7195static int hdd_parse_set_channel_switch_command(uint8_t *value,
7196 uint32_t *chan_number,
7197 uint32_t *chan_bw)
7198{
7199 const uint8_t *in_ptr = value;
7200 int ret;
7201
7202 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
7203
7204 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07007205 if (!in_ptr) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307206 hdd_err("No argument after the command");
7207 return -EINVAL;
7208 }
7209
7210 /* no space after the command */
7211 if (SPACE_ASCII_VALUE != *in_ptr) {
7212 hdd_err("No space after the command ");
7213 return -EINVAL;
7214 }
7215
7216 /* remove empty spaces and move the next argument */
7217 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
7218 in_ptr++;
7219
7220 /* no argument followed by spaces */
7221 if ('\0' == *in_ptr) {
7222 hdd_err("No argument followed by spaces");
7223 return -EINVAL;
7224 }
7225
7226 /* get the two arguments: channel number and bandwidth */
7227 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7228 if (ret != 2) {
7229 hdd_err("Arguments retrieval from cmd string failed");
7230 return -EINVAL;
7231 }
7232
7233 return 0;
7234}
7235
7236/**
7237 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7238 * @adapter: HDD adapter
7239 * @hdd_ctx: HDD context
7240 * @command: Pointer to the input command CHANNEL_SWITCH
7241 * @command_len: Command len
7242 * @priv_data: Private data
7243 *
7244 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7245 * of SAP/P2P-GO
7246 *
7247 * Return: 0 for success, non-zero for failure
7248 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007249static int drv_cmd_set_channel_switch(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07007250 struct hdd_context *hdd_ctx,
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307251 uint8_t *command,
7252 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07007253 struct hdd_priv_data *priv_data)
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307254{
7255 struct net_device *dev = adapter->dev;
7256 int status;
7257 uint32_t chan_number = 0, chan_bw = 0;
7258 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007259 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307260
Krunal Sonibe766b02016-03-10 13:00:44 -08007261 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7262 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307263 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7264 adapter->device_mode);
7265 return -EINVAL;
7266 }
7267
7268 status = hdd_parse_set_channel_switch_command(value,
7269 &chan_number, &chan_bw);
7270 if (status) {
7271 hdd_err("Invalid CHANNEL_SWITCH command");
7272 return status;
7273 }
7274
7275 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7276 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7277 return -EINVAL;
7278 }
7279
7280 if (chan_bw == 80)
7281 width = CH_WIDTH_80MHZ;
7282 else if (chan_bw == 40)
7283 width = CH_WIDTH_40MHZ;
7284 else
7285 width = CH_WIDTH_20MHZ;
7286
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007287 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307288
Bala Venkatesh8b9bbde2019-07-03 16:25:16 +05307289 wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, adapter->vdev_id,
7290 CSA_REASON_USER_INITIATED);
Tushnim Bhattacharyya6c40b112019-10-30 11:39:25 -07007291 status = hdd_softap_set_channel_change(dev,
7292 wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, chan_number),
7293 width, true);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307294 if (status) {
7295 hdd_err("Set channel change fail");
7296 return status;
7297 }
7298
7299 return 0;
7300}
7301
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307302#ifdef DISABLE_CHANNEL_LIST
7303void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7304{
7305 hdd_enter();
7306
7307 if (!hdd_ctx->original_channels)
7308 return;
7309
7310 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7311 hdd_ctx->original_channels->num_channels = 0;
7312 if (hdd_ctx->original_channels->channel_info) {
7313 qdf_mem_free(hdd_ctx->original_channels->channel_info);
7314 hdd_ctx->original_channels->channel_info = NULL;
7315 }
7316 qdf_mem_free(hdd_ctx->original_channels);
7317 hdd_ctx->original_channels = NULL;
7318 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7319
7320 hdd_exit();
7321}
7322
7323/**
7324 * hdd_alloc_chan_cache() - Allocate the memory to cache the channel
7325 * info for the channels received in command SET_DISABLE_CHANNEL_LIST
7326 * @hdd_ctx: Pointer to HDD context
7327 * @num_chan: Number of channels for which memory needs to
7328 * be allocated
7329 *
7330 * Return: 0 on success and error code on failure
7331 */
7332static int hdd_alloc_chan_cache(struct hdd_context *hdd_ctx, int num_chan)
7333{
7334 hdd_ctx->original_channels =
7335 qdf_mem_malloc(sizeof(struct hdd_cache_channels));
7336 if (!hdd_ctx->original_channels) {
7337 hdd_err("QDF_MALLOC_ERR");
7338 return -ENOMEM;
7339 }
7340 hdd_ctx->original_channels->num_channels = num_chan;
7341 hdd_ctx->original_channels->channel_info =
7342 qdf_mem_malloc(num_chan *
7343 sizeof(struct hdd_cache_channel_info));
7344 if (!hdd_ctx->original_channels->channel_info) {
7345 hdd_err("QDF_MALLOC_ERR");
7346 hdd_ctx->original_channels->num_channels = 0;
7347 qdf_mem_free(hdd_ctx->original_channels);
7348 hdd_ctx->original_channels = NULL;
7349 return -ENOMEM;
7350 }
7351 return 0;
7352}
7353
7354/**
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307355 * check_disable_channels() - Check for disable channel
7356 * @hdd_ctx: Pointer to hdd context
7357 * @operating_channel: Current operating channel of adapter
7358 *
7359 * This function checks original_channels array for a specific channel
7360 *
7361 * Return: 0 if channel not found, 1 if channel found
7362 */
7363static bool check_disable_channels(struct hdd_context *hdd_ctx,
7364 uint8_t operating_channel)
7365{
7366 uint32_t num_channels;
7367 uint8_t i;
7368
7369 if (!hdd_ctx || !hdd_ctx->original_channels ||
7370 !hdd_ctx->original_channels->channel_info)
7371 return false;
7372
7373 num_channels = hdd_ctx->original_channels->num_channels;
7374 for (i = 0; i < num_channels; i++)
7375 if (hdd_ctx->original_channels->channel_info[i].channel_num ==
7376 operating_channel)
7377 return true;
7378 return false;
7379}
7380
7381/**
7382 * disconnect_sta_and_stop_sap() - Disconnect STA and stop SAP
7383 *
7384 * @hdd_ctx: Pointer to hdd context
Srinivas Dasarie2495dc2020-02-13 09:49:24 +05307385 * @reason: Disconnect reason code as per @enum eSirMacReasonCodes
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307386 *
7387 * Disable channels provided by user and disconnect STA if it is
7388 * connected to any AP, stop SAP and send deauthentication request
7389 * to STAs connected to SAP.
7390 *
7391 * Return: None
7392 */
Srinivas Dasarie2495dc2020-02-13 09:49:24 +05307393static void disconnect_sta_and_stop_sap(struct hdd_context *hdd_ctx,
7394 enum eSirMacReasonCodes reason)
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307395{
7396 struct hdd_adapter *adapter, *next = NULL;
7397 QDF_STATUS status;
Will Huang4b097f52019-08-29 10:51:56 -07007398 uint8_t ap_ch;
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307399
7400 if (!hdd_ctx)
7401 return;
7402
Srinivas Dasarie2495dc2020-02-13 09:49:24 +05307403 hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx, reason);
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307404
7405 status = hdd_get_front_adapter(hdd_ctx, &adapter);
7406 while (adapter && (status == QDF_STATUS_SUCCESS)) {
7407 if (!hdd_validate_adapter(adapter) &&
Will Huang4b097f52019-08-29 10:51:56 -07007408 adapter->device_mode == QDF_SAP_MODE) {
7409 ap_ch = wlan_reg_freq_to_chan(
7410 hdd_ctx->pdev,
7411 adapter->session.ap.operating_chan_freq);
7412 if (check_disable_channels(hdd_ctx, ap_ch))
7413 wlan_hdd_stop_sap(adapter);
7414 }
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307415
7416 status = hdd_get_next_adapter(hdd_ctx, adapter, &next);
7417 adapter = next;
7418 }
7419}
7420
7421/**
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307422 * hdd_parse_disable_chan_cmd() - Parse the channel list received
7423 * in command.
7424 * @adapter: pointer to hdd adapter
7425 * @ptr: Pointer to the command string
7426 *
7427 * This function parses the channel list received in the command.
7428 * command should be a string having format
7429 * SET_DISABLE_CHANNEL_LIST <num of channels>
7430 * <channels separated by spaces>.
7431 * If the command comes multiple times than this function will compare
7432 * the channels received in the command with the channles cached in the
7433 * first command, if the channel list matches with the cached channles,
7434 * it returns success otherwise returns failure.
7435 *
7436 * Return: 0 on success, Error code on failure
7437 */
7438
7439static int hdd_parse_disable_chan_cmd(struct hdd_adapter *adapter, uint8_t *ptr)
7440{
7441 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7442 uint8_t *param;
7443 int j, i, temp_int, ret = 0, num_channels;
Liangwei Dong2eb654f2019-09-11 15:54:09 +08007444 uint32_t parsed_channels[NUM_CHANNELS];
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307445 bool is_command_repeated = false;
7446
Jeff Johnsond36fa332019-03-18 13:42:25 -07007447 if (!hdd_ctx) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307448 hdd_err("HDD Context is NULL");
7449 return -EINVAL;
7450 }
7451
7452 param = strnchr(ptr, strlen(ptr), ' ');
7453 /*no argument after the command*/
Jeff Johnsond36fa332019-03-18 13:42:25 -07007454 if (!param)
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307455 return -EINVAL;
7456
7457 /*no space after the command*/
7458 else if (SPACE_ASCII_VALUE != *param)
7459 return -EINVAL;
7460
7461 param++;
7462
7463 /*removing empty spaces*/
7464 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7465 param++;
7466
7467 /*no argument followed by spaces*/
7468 if ('\0' == *param)
7469 return -EINVAL;
7470
7471 /*getting the first argument ie the number of channels*/
7472 if (sscanf(param, "%d ", &temp_int) != 1) {
7473 hdd_err("Cannot get number of channels from input");
7474 return -EINVAL;
7475 }
7476
Liangwei Dong2eb654f2019-09-11 15:54:09 +08007477 if (temp_int < 0 || temp_int > NUM_CHANNELS) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307478 hdd_err("Invalid Number of channel received");
7479 return -EINVAL;
7480 }
7481
7482 hdd_debug("Number of channel to disable are: %d", temp_int);
7483
7484 if (!temp_int) {
Ashish Kumar Dhanotiya6176bef2019-07-25 15:51:35 +05307485 /*
7486 * Restore and Free the cache channels when the command is
7487 * received with num channels as 0
7488 */
7489 wlan_hdd_restore_channels(hdd_ctx, false);
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307490 return 0;
7491 }
7492
7493 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7494
7495 if (!hdd_ctx->original_channels) {
7496 if (hdd_alloc_chan_cache(hdd_ctx, temp_int)) {
7497 ret = -ENOMEM;
7498 goto mem_alloc_failed;
7499 }
7500 } else if (hdd_ctx->original_channels->num_channels != temp_int) {
7501 hdd_err("Invalid Number of channels");
7502 ret = -EINVAL;
7503 is_command_repeated = true;
7504 goto parse_failed;
7505 } else {
7506 is_command_repeated = true;
7507 }
7508 num_channels = temp_int;
7509 for (j = 0; j < num_channels; j++) {
7510 /*
7511 * param pointing to the beginning of first space
7512 * after number of channels
7513 */
7514 param = strpbrk(param, " ");
7515 /*no channel list after the number of channels argument*/
Jeff Johnsond36fa332019-03-18 13:42:25 -07007516 if (!param) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307517 hdd_err("Invalid No of channel provided in the list");
7518 ret = -EINVAL;
7519 goto parse_failed;
7520 }
7521
7522 param++;
7523
7524 /*removing empty space*/
7525 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7526 param++;
7527
7528 if ('\0' == *param) {
7529 hdd_err("No channel is provided in the list");
7530 ret = -EINVAL;
7531 goto parse_failed;
7532 }
7533
7534 if (sscanf(param, "%d ", &temp_int) != 1) {
7535 hdd_err("Cannot read channel number");
7536 ret = -EINVAL;
7537 goto parse_failed;
7538 }
7539
7540 if (!IS_CHANNEL_VALID(temp_int)) {
7541 hdd_err("Invalid channel number received");
7542 ret = -EINVAL;
7543 goto parse_failed;
7544 }
7545
7546 hdd_debug("channel[%d] = %d", j, temp_int);
7547 parsed_channels[j] = temp_int;
7548 }
7549
7550 /*extra arguments check*/
7551 param = strpbrk(param, " ");
Jeff Johnsond36fa332019-03-18 13:42:25 -07007552 if (param) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307553 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7554 param++;
7555
7556 if ('\0' != *param) {
7557 hdd_err("Invalid argument received");
7558 ret = -EINVAL;
7559 goto parse_failed;
7560 }
7561 }
7562
7563 /*
7564 * If command is received first time, cache the channels to
7565 * be disabled else compare the channels received in the
7566 * command with the cached channels, if channel list matches
7567 * return success otherewise return failure.
7568 */
7569 if (!is_command_repeated) {
7570 for (j = 0; j < num_channels; j++)
7571 hdd_ctx->original_channels->
7572 channel_info[j].channel_num =
7573 parsed_channels[j];
Dustin Brown3f0d7102018-08-02 12:01:52 -07007574
7575 /* Cache the channel list in regulatory also */
Dustin Brown07901ec2018-09-07 11:02:41 -07007576 ucfg_reg_cache_channel_state(hdd_ctx->pdev, parsed_channels,
Dustin Brown3f0d7102018-08-02 12:01:52 -07007577 num_channels);
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307578 } else {
7579 for (i = 0; i < num_channels; i++) {
7580 for (j = 0; j < num_channels; j++)
7581 if (hdd_ctx->original_channels->
7582 channel_info[i].channel_num ==
7583 parsed_channels[j])
7584 break;
7585 if (j == num_channels) {
7586 ret = -EINVAL;
7587 goto parse_failed;
7588 }
7589 }
7590 ret = 0;
7591 }
7592mem_alloc_failed:
7593
7594 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
Ashish Kumar Dhanotiyadd5f74c2019-03-14 16:50:41 +05307595 /* Disable the channels received in command SET_DISABLE_CHANNEL_LIST */
7596 if (!is_command_repeated && hdd_ctx->original_channels) {
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307597 ret = wlan_hdd_disable_channels(hdd_ctx);
7598 if (ret)
7599 return ret;
Srinivas Dasarie2495dc2020-02-13 09:49:24 +05307600 disconnect_sta_and_stop_sap(hdd_ctx,
7601 eSIR_MAC_OPER_CHANNEL_BAND_CHANGE);
Ashish Kumar Dhanotiyadd5f74c2019-03-14 16:50:41 +05307602 }
7603
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307604 hdd_exit();
7605
7606 return ret;
7607
7608parse_failed:
7609 if (!is_command_repeated)
7610 wlan_hdd_free_cache_channels(hdd_ctx);
Ashish Kumar Dhanotiyadd5f74c2019-03-14 16:50:41 +05307611
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307612 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7613 hdd_exit();
7614
7615 return ret;
7616}
7617
7618static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7619 struct hdd_context *hdd_ctx,
7620 uint8_t *command,
7621 uint8_t command_len,
7622 struct hdd_priv_data *priv_data)
7623{
7624 return hdd_parse_disable_chan_cmd(adapter, command);
7625}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307626
7627/**
7628 * hdd_get_disable_ch_list() - get disable channel list
7629 * @hdd_ctx: hdd context
7630 * @buf: buffer to hold disable channel list
7631 * @buf_len: buffer length
7632 *
7633 * Return: length of data copied to buf
7634 */
7635static int hdd_get_disable_ch_list(struct hdd_context *hdd_ctx, uint8_t *buf,
7636 uint32_t buf_len)
7637{
7638 struct hdd_cache_channel_info *ch_list;
7639 unsigned char i, num_ch;
7640 int len = 0;
7641
7642 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7643 if (hdd_ctx->original_channels &&
7644 hdd_ctx->original_channels->num_channels &&
7645 hdd_ctx->original_channels->channel_info) {
7646 num_ch = hdd_ctx->original_channels->num_channels;
7647
7648 len = scnprintf(buf, buf_len, "%s %hhu",
7649 "GET_DISABLE_CHANNEL_LIST", num_ch);
7650 ch_list = hdd_ctx->original_channels->channel_info;
7651 for (i = 0; (i < num_ch) && (len < buf_len - 1); i++) {
7652 len += scnprintf(buf + len, buf_len - len,
7653 " %d", ch_list[i].channel_num);
7654 }
7655 }
7656 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7657
7658 return len;
7659}
7660
7661static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7662 struct hdd_context *hdd_ctx,
7663 uint8_t *command,
7664 uint8_t command_len,
7665 struct hdd_priv_data *priv_data)
7666{
7667 char extra[512] = {0};
7668 int max_len, copied_length;
7669
7670 hdd_debug("Received Command to get disable Channels list");
7671
7672 max_len = QDF_MIN(priv_data->total_len, sizeof(extra));
7673 copied_length = hdd_get_disable_ch_list(hdd_ctx, extra, max_len);
7674 if (copied_length == 0) {
7675 hdd_err("disable channel list is not yet programmed");
7676 return -EINVAL;
7677 }
7678
7679 if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
7680 hdd_err("failed to copy data to user buffer");
7681 return -EFAULT;
7682 }
7683
7684 hdd_debug("data:%s", extra);
7685 return 0;
7686}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307687#else
7688
7689static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7690 struct hdd_context *hdd_ctx,
7691 uint8_t *command,
7692 uint8_t command_len,
7693 struct hdd_priv_data *priv_data)
7694{
7695 return 0;
7696}
7697
7698void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7699{
7700}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307701
7702static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7703 struct hdd_context *hdd_ctx,
7704 uint8_t *command,
7705 uint8_t command_len,
7706 struct hdd_priv_data *priv_data)
7707{
7708 return 0;
7709}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307710#endif
Sourav Mohapatra2a67b0e2019-10-15 17:59:59 +05307711
7712#ifdef FEATURE_ANI_LEVEL_REQUEST
7713static int drv_cmd_get_ani_level(struct hdd_adapter *adapter,
7714 struct hdd_context *hdd_ctx,
7715 uint8_t *command,
7716 uint8_t command_len,
7717 struct hdd_priv_data *priv_data)
7718{
7719 char *extra;
7720 int copied_length = 0, j, temp_int, ret = 0;
7721 uint8_t *param, num_freqs, num_recv_channels;
7722 uint32_t parsed_freqs[MAX_NUM_FREQS_FOR_ANI_LEVEL];
7723 struct wmi_host_ani_level_event ani[MAX_NUM_FREQS_FOR_ANI_LEVEL];
7724 size_t user_size = priv_data->total_len;
7725
7726 hdd_debug("Received Command to get ANI level");
7727
7728 param = strnchr(command, strlen(command), ' ');
7729
7730 /* No argument after the command */
7731 if (!param)
7732 return -EINVAL;
7733
7734 /* No space after the command */
7735 else if (SPACE_ASCII_VALUE != *param)
7736 return -EINVAL;
7737
7738 param++;
7739
7740 /* Removing empty spaces*/
7741 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7742 param++;
7743
7744 /*no argument followed by spaces */
7745 if ('\0' == *param)
7746 return -EINVAL;
7747
7748 /* Getting the first argument ie the number of channels */
7749 if (sscanf(param, "%d ", &temp_int) != 1) {
7750 hdd_err("Cannot get number of freq from input");
7751 return -EINVAL;
7752 }
7753
7754 if (temp_int < 0 || temp_int > MAX_NUM_FREQS_FOR_ANI_LEVEL) {
7755 hdd_err("Invalid Number of channel received");
7756 return -EINVAL;
7757 }
7758
7759 hdd_debug("Number of freq to fetch ANI level are: %d", temp_int);
7760
7761 if (!temp_int)
7762 return 0;
7763
7764 num_freqs = temp_int;
7765
7766 for (j = 0; j < num_freqs; j++) {
7767 /*
7768 * Param pointing to the beginning of first space
7769 * after number of channels.
7770 */
7771 param = strpbrk(param, " ");
7772 /*no channel list after the number of channels argument*/
7773 if (!param) {
7774 hdd_err("Invalid No of freq provided in the list");
7775 ret = -EINVAL;
7776 goto parse_failed;
7777 }
7778
7779 param++;
7780
7781 /* Removing empty space */
7782 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7783 param++;
7784
7785 if ('\0' == *param) {
7786 hdd_err("No freq is provided in the list");
7787 ret = -EINVAL;
7788 goto parse_failed;
7789 }
7790
7791 if (sscanf(param, "%d ", &temp_int) != 1) {
7792 hdd_err("Cannot read freq number");
7793 ret = -EINVAL;
7794 goto parse_failed;
7795 }
7796
7797 hdd_debug("channel_freq[%d] = %d", j, temp_int);
7798 parsed_freqs[j] = temp_int;
7799 }
7800
7801 /* Extra arguments check */
7802 param = strpbrk(param, " ");
7803 if (param) {
7804 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7805 param++;
7806
7807 if ('\0' != *param) {
7808 hdd_err("Invalid argument received");
7809 ret = -EINVAL;
7810 goto parse_failed;
7811 }
7812 }
7813
7814 qdf_mem_zero(ani, sizeof(ani));
7815 hdd_debug("num_freq: %d", num_freqs);
7816 if (QDF_IS_STATUS_ERROR(wlan_hdd_get_ani_level(adapter, ani,
7817 parsed_freqs,
7818 num_freqs))) {
7819 hdd_err("Unable to retrieve ani level");
7820 return -EINVAL;
7821 }
7822
7823 extra = qdf_mem_malloc(user_size);
7824 if (!extra) {
7825 hdd_err("memory allocation failed");
7826 ret = -ENOMEM;
7827 goto parse_failed;
7828 }
7829
7830 /*
7831 * Find the number of channels that are populated. If freq is not
7832 * filled then stop count there
7833 */
7834 for (num_recv_channels = 0;
7835 (num_recv_channels < num_freqs &&
7836 ani[num_recv_channels].chan_freq); num_recv_channels++)
7837 ;
7838
7839 for (j = 0; j < num_recv_channels; j++) {
7840 /* Sanity check for ANI level validity */
7841 if (ani[j].ani_level > MAX_ANI_LEVEL)
7842 continue;
7843
7844 copied_length += scnprintf(extra + copied_length,
7845 user_size - copied_length, "%d:%d\n",
7846 ani[j].chan_freq, ani[j].ani_level);
7847 }
7848
7849 if (copied_length == 0) {
7850 hdd_err("ANI level not fetched");
7851 ret = -EINVAL;
7852 goto free;
7853 }
7854
7855 hdd_debug("data: %s", extra);
7856
7857 if (copy_to_user(priv_data->buf, extra, copied_length + 1)) {
7858 hdd_err("failed to copy data to user buffer");
7859 ret = -EFAULT;
7860 goto free;
7861 }
7862
7863free:
7864 qdf_mem_free(extra);
7865
7866parse_failed:
7867 return ret;
7868}
7869
7870#else
7871static int drv_cmd_get_ani_level(struct hdd_adapter *adapter,
7872 struct hdd_context *hdd_ctx,
7873 uint8_t *command,
7874 uint8_t command_len,
7875 struct hdd_priv_data *priv_data)
7876{
7877 return 0;
7878}
7879#endif
Ashish Kumar Dhanotiya7efe26e2018-11-14 16:35:57 +05307880
7881#ifdef FUNC_CALL_MAP
7882static int drv_cmd_get_function_call_map(struct hdd_adapter *adapter,
7883 struct hdd_context *hdd_ctx,
7884 uint8_t *command,
7885 uint8_t command_len,
7886 struct hdd_priv_data *priv_data)
7887{
7888 char *cc_buf = qdf_mem_malloc(QDF_FUNCTION_CALL_MAP_BUF_LEN);
7889 uint8_t *param;
7890 int temp_int;
7891
7892 param = strnchr(command, strlen(command), ' ');
7893 /*no argument after the command*/
7894 if (NULL == param)
7895 return -EINVAL;
7896
7897 /*no space after the command*/
7898 else if (SPACE_ASCII_VALUE != *param)
7899 return -EINVAL;
7900
7901 param++;
7902
7903 /*removing empty spaces*/
7904 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7905 param++;
7906
7907 /*no argument followed by spaces*/
7908 if ('\0' == *param)
7909 return -EINVAL;
7910
7911 /*getting the first argument */
7912 if (sscanf(param, "%d ", &temp_int) != 1) {
7913 hdd_err("No option given");
7914 return -EINVAL;
7915 }
7916
7917 if (temp_int < 0 || temp_int > 1) {
7918 hdd_err("Invalid option given");
7919 return -EINVAL;
7920 }
7921
7922 /* Read the buffer */
7923 if (temp_int) {
7924 /*
7925 * These logs are required as these indicates the start and end of the
7926 * dump for the auto script to parse
7927 */
7928 hdd_info("Function call map dump start");
7929 qdf_get_func_call_map(cc_buf);
7930 qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
7931 cc_buf, QDF_FUNCTION_CALL_MAP_BUF_LEN);
7932 hdd_info("Function call map dump end");
7933 } else {
7934 qdf_clear_func_call_map();
7935 hdd_info("Function call map clear");
7936 }
7937 qdf_mem_free(cc_buf);
7938
7939 return 0;
7940}
7941#endif
7942
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007943/*
7944 * The following table contains all supported WLAN HDD
7945 * IOCTL driver commands and the handler for each of them.
7946 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07007947static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307948 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false},
7949 {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true},
7950 {"P2P_SET_PS", drv_cmd_p2p_set_ps, true},
7951 {"SETBAND", drv_cmd_set_band, true},
7952 {"SETWMMPS", drv_cmd_set_wmmps, true},
7953 {"COUNTRY", drv_cmd_country, true},
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +05307954 {"SETCOUNTRYREV", drv_cmd_country, true},
7955 {"GETCOUNTRYREV", drv_cmd_get_country, false},
Pragaspathi Thilagarajaa8320e2019-04-16 02:47:50 +05307956 {"SETSUSPENDMODE", drv_cmd_set_suspend_mode, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307957 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307958 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true},
7959 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false},
7960 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true},
7961 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false},
7962 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period,
7963 true},
7964 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period,
7965 false},
7966 {"SETROAMMODE", drv_cmd_set_roam_mode, true},
7967 {"GETROAMMODE", drv_cmd_get_roam_mode, false},
7968 {"SETROAMDELTA", drv_cmd_set_roam_delta, true},
7969 {"GETROAMDELTA", drv_cmd_get_roam_delta, false},
7970 {"GETBAND", drv_cmd_get_band, false},
7971 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels, true},
7972 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels, false},
7973 {"GETCCXMODE", drv_cmd_get_ccx_mode, false},
7974 {"GETOKCMODE", drv_cmd_get_okc_mode, false},
7975 {"GETFASTROAM", drv_cmd_get_fast_roam, false},
7976 {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false},
7977 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
7978 true},
7979 {"SENDACTIONFRAME", drv_cmd_send_action_frame, true},
7980 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
7981 false},
7982 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true},
7983 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false},
7984 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true},
7985 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false},
7986 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true},
7987 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false},
7988 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true},
7989 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false},
7990 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true},
7991 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false},
7992 {"REASSOC", drv_cmd_reassoc, true},
7993 {"SETWESMODE", drv_cmd_set_wes_mode, true},
7994 {"GETWESMODE", drv_cmd_get_wes_mode, false},
7995 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff,
7996 true},
7997 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff,
7998 false},
7999 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true},
8000 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false},
8001 {"SETFASTROAM", drv_cmd_set_fast_roam, true},
8002 {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true},
8003 {"FASTREASSOC", drv_cmd_fast_reassoc, true},
8004 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control, true},
8005 {"SETOKCMODE", drv_cmd_set_okc_mode, true},
8006 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control, false},
8007 {"BTCOEXMODE", drv_cmd_bt_coex_mode, true},
8008 {"SCAN-ACTIVE", drv_cmd_scan_active, false},
8009 {"SCAN-PASSIVE", drv_cmd_scan_passive, false},
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05308010 {"CONCSETDWELLTIME", drv_cmd_conc_set_dwell_time, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308011 {"GETDWELLTIME", drv_cmd_get_dwell_time, false},
8012 {"SETDWELLTIME", drv_cmd_set_dwell_time, true},
8013 {"MIRACAST", drv_cmd_miracast, true},
8014 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05308015#ifdef FEATURE_WLAN_RMC
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308016 {"SETRMCENABLE", drv_cmd_set_rmc_enable, true},
8017 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05308018 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate, true},
8019#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308020 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all, false},
8021 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308022 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08008023#ifdef FEATURE_WLAN_ESE
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308024 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true},
8025 {"GETTSMSTATS", drv_cmd_get_tsm_stats, true},
8026 {"SETCCKMIE", drv_cmd_set_cckm_ie, true},
8027 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true},
8028 {"CCXPLMREQ", drv_cmd_ccx_plm_req, true},
8029 {"SETCCXMODE", drv_cmd_set_ccx_mode, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08008030#endif /* FEATURE_WLAN_ESE */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308031 {"SETMCRATE", drv_cmd_set_mc_rate, true},
8032 {"MAXTXPOWER", drv_cmd_max_tx_power, true},
8033 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true},
8034 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false},
8035 {"GETLINKSTATUS", drv_cmd_get_link_status, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008036#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308037 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true},
8038 {"SETAPP1PARAMS", drv_cmd_set_app1_params, true},
8039 {"SETAPP2PARAMS", drv_cmd_set_app2_params, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008040#endif
8041#ifdef FEATURE_WLAN_TDLS
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308042 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
8043 true},
8044 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true},
8045 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true},
8046 {"TDLSSCAN", drv_cmd_tdls_scan, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008047#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308048 {"RSSI", drv_cmd_get_rssi, false},
8049 {"LINKSPEED", drv_cmd_get_linkspeed, false},
Qiwei Cai4505fc62018-05-17 18:35:19 +08008050#ifdef WLAN_FEATURE_PACKET_FILTERING
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308051 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true},
8052 {"RXFILTER-ADD", drv_cmd_rx_filter_add, true},
Qiwei Cai4505fc62018-05-17 18:35:19 +08008053#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308054 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true},
8055 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true},
8056 {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true},
8057 {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false},
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05308058 {"SET_DISABLE_CHANNEL_LIST", drv_cmd_set_disable_chan_list, true},
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05308059 {"GET_DISABLE_CHANNEL_LIST", drv_cmd_get_disable_chan_list, false},
Sourav Mohapatra2a67b0e2019-10-15 17:59:59 +05308060 {"GET_ANI_LEVEL", drv_cmd_get_ani_level, false},
Ashish Kumar Dhanotiya7efe26e2018-11-14 16:35:57 +05308061#ifdef FUNC_CALL_MAP
8062 {"GET_FUNCTION_CALL_MAP", drv_cmd_get_function_call_map, true},
8063#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308064 {"STOP", drv_cmd_dummy, false},
Srinivas Girigowda836475e2018-04-17 14:42:23 -07008065 /* Deprecated commands */
8066 {"RXFILTER-START", drv_cmd_dummy, false},
8067 {"RXFILTER-STOP", drv_cmd_dummy, false},
8068 {"BTCOEXSCAN-START", drv_cmd_dummy, false},
8069 {"BTCOEXSCAN-STOP", drv_cmd_dummy, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008070};
8071
8072/**
8073 * hdd_drv_cmd_process() - chooses and runs the proper
8074 * handler based on the input command
8075 * @adapter: Pointer to the hdd adapter
8076 * @cmd: Pointer to the driver command
8077 * @priv_data: Pointer to the data associated with the command
8078 *
8079 * This function parses the input hdd driver command and runs
8080 * the proper handler
8081 *
8082 * Return: 0 for success non-zero for failure
8083 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07008084static int hdd_drv_cmd_process(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008085 uint8_t *cmd,
Jeff Johnson353cd292017-08-17 06:47:26 -07008086 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008087{
Jeff Johnson621cf972017-08-28 11:58:44 -07008088 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008089 int i;
8090 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
8091 uint8_t *cmd_i = NULL;
8092 hdd_drv_cmd_handler_t handler = NULL;
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05308093 int len = 0, cmd_len = 0;
8094 uint8_t *ptr;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308095 bool args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008096
8097 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07008098 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008099 return -EINVAL;
8100 }
8101
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05308102 /* Calculate length of the first word */
8103 ptr = strchrnul(cmd, ' ');
8104 cmd_len = ptr - cmd;
8105
Jeff Johnson399c6272017-08-30 10:51:00 -07008106 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008107
8108 for (i = 0; i < cmd_num_total; i++) {
8109
8110 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
8111 handler = hdd_drv_cmds[i].handler;
8112 len = strlen(cmd_i);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308113 args = hdd_drv_cmds[i].args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008114
8115 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07008116 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008117 return -EINVAL;
8118 }
8119
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05308120 if (len == cmd_len && strncasecmp(cmd, cmd_i, len) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308121 if (args && drv_cmd_validate(cmd, len))
8122 return -EINVAL;
8123
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008124 return handler(adapter, hdd_ctx,
8125 cmd, len, priv_data);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05308126 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008127 }
8128
8129 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
8130}
8131
8132/**
8133 * hdd_driver_command() - top level wlan hdd driver command handler
8134 * @adapter: Pointer to the hdd adapter
8135 * @priv_data: Pointer to the raw command data
8136 *
8137 * This function is the top level wlan hdd driver command handler. It
8138 * handles the command with the help of hdd_drv_cmd_process()
8139 *
8140 * Return: 0 for success non-zero for failure
8141 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07008142static int hdd_driver_command(struct hdd_adapter *adapter,
Jeff Johnson353cd292017-08-17 06:47:26 -07008143 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008144{
8145 uint8_t *command = NULL;
8146 int ret = 0;
Jeff Johnson621cf972017-08-28 11:58:44 -07008147 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008148
Dustin Brown491d54b2018-03-14 12:39:11 -07008149 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05308150
Anurag Chouhan6d760662016-02-20 16:05:43 +05308151 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07008152 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008153 return -EINVAL;
8154 }
8155
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05308156 ret = wlan_hdd_validate_context(hdd_ctx);
8157 if (ret)
8158 return ret;
8159
8160 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
8161 hdd_err("Driver module is closed; command can not be processed");
8162 return -EINVAL;
8163 }
8164
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008165 /*
8166 * Note that valid pointers are provided by caller
8167 */
8168
8169 /* copy to local struct to avoid numerous changes to legacy code */
8170 if (priv_data->total_len <= 0 ||
8171 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08008172 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07008173 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008174 ret = -EINVAL;
8175 goto exit;
8176 }
8177
8178 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07008179 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008180 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07008181 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008182 ret = -ENOMEM;
8183 goto exit;
8184 }
8185
8186 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
8187 ret = -EFAULT;
8188 goto exit;
8189 }
8190
8191 /* Make sure the command is NUL-terminated */
8192 command[priv_data->total_len] = '\0';
8193
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08008194 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008195 ret = hdd_drv_cmd_process(adapter, command, priv_data);
8196
8197exit:
8198 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07008199 qdf_mem_free(command);
Dustin Browne74003f2018-03-14 12:51:58 -07008200 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008201 return ret;
8202}
8203
8204#ifdef CONFIG_COMPAT
Jeff Johnsone44b7012017-09-10 15:25:47 -07008205static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008206{
8207 struct {
8208 compat_uptr_t buf;
8209 int used_len;
8210 int total_len;
8211 } compat_priv_data;
Jeff Johnson353cd292017-08-17 06:47:26 -07008212 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008213 int ret = 0;
8214
8215 /*
8216 * Note that adapter and ifr have already been verified by caller,
8217 * and HDD context has also been validated
8218 */
8219 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
8220 sizeof(compat_priv_data))) {
8221 ret = -EFAULT;
8222 goto exit;
8223 }
8224 priv_data.buf = compat_ptr(compat_priv_data.buf);
8225 priv_data.used_len = compat_priv_data.used_len;
8226 priv_data.total_len = compat_priv_data.total_len;
8227 ret = hdd_driver_command(adapter, &priv_data);
8228exit:
8229 return ret;
8230}
8231#else /* CONFIG_COMPAT */
Jeff Johnsone44b7012017-09-10 15:25:47 -07008232static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008233{
8234 /* will never be invoked */
8235 return 0;
8236}
8237#endif /* CONFIG_COMPAT */
8238
Jeff Johnsone44b7012017-09-10 15:25:47 -07008239static int hdd_driver_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008240{
Jeff Johnson353cd292017-08-17 06:47:26 -07008241 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008242 int ret = 0;
8243
8244 /*
8245 * Note that adapter and ifr have already been verified by caller,
8246 * and HDD context has also been validated
8247 */
8248 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
8249 ret = -EFAULT;
8250 else
8251 ret = hdd_driver_command(adapter, &priv_data);
8252
8253 return ret;
8254}
8255
8256/**
8257 * __hdd_ioctl() - ioctl handler for wlan network interfaces
8258 * @dev: device upon which the ioctl was received
8259 * @ifr: ioctl request information
8260 * @cmd: ioctl command
8261 *
8262 * This function does initial processing of wlan device ioctls.
8263 * Currently two flavors of ioctls are supported. The primary ioctl
8264 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
8265 * for Android "DRIVER" commands. The other ioctl that is
8266 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
8267 * for FTM on some platforms. This function simply verifies that the
8268 * driver is in a sane state, and that the ioctl is one of the
8269 * supported flavors, in which case flavor-specific handlers are
8270 * dispatched.
8271 *
8272 * Return: 0 on success, non-zero on error
8273 */
8274static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
8275{
Jeff Johnsone44b7012017-09-10 15:25:47 -07008276 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson621cf972017-08-28 11:58:44 -07008277 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008278 int ret;
8279
Dustin Brownfdf17c12018-03-14 12:55:34 -07008280 hdd_enter_dev(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05308281
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008282 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08008283 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008284 ret = -ENODEV;
8285 goto exit;
8286 }
8287
8288 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08008289 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008290 ret = -EINVAL;
8291 goto exit;
8292 }
8293#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05308294 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008295 if (SIOCIOCTLTX99 == cmd) {
8296 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
8297 goto exit;
8298 }
8299 }
8300#endif
8301
8302 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8303 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05308304 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008305 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008306
8307 switch (cmd) {
8308 case (SIOCDEVPRIVATE + 1):
Mahesh Kumar Kalikot Veetil885a77b2018-03-26 14:46:59 -07008309 if (in_compat_syscall())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008310 ret = hdd_driver_compat_ioctl(adapter, ifr);
8311 else
8312 ret = hdd_driver_ioctl(adapter, ifr);
8313 break;
8314 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08008315 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008316 ret = -EINVAL;
8317 break;
8318 }
8319exit:
Dustin Browne74003f2018-03-14 12:51:58 -07008320 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008321 return ret;
8322}
8323
8324/**
8325 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
Dustin Brown98f7c822019-03-06 12:25:49 -08008326 * @net_dev: device upon which the ioctl was received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008327 * @ifr: ioctl request information
8328 * @cmd: ioctl command
8329 *
8330 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
8331 * which is where the ioctls are really handled.
8332 *
8333 * Return: 0 on success, non-zero on error
8334 */
Dustin Brown98f7c822019-03-06 12:25:49 -08008335int hdd_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008336{
Dustin Brown98f7c822019-03-06 12:25:49 -08008337 struct osif_vdev_sync *vdev_sync;
8338 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008339
Dustin Brown98f7c822019-03-06 12:25:49 -08008340 errno = osif_vdev_sync_op_start(net_dev, &vdev_sync);
8341 if (errno)
8342 return errno;
8343
8344 errno = __hdd_ioctl(net_dev, ifr, cmd);
8345
8346 osif_vdev_sync_op_stop(vdev_sync);
8347
8348 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008349}
Dustin Brown98f7c822019-03-06 12:25:49 -08008350