blob: f1e1c95ed2f468067248c7de70f934fe01b4d835 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jeff Johnson86bef3e2018-12-26 19:57:01 -08002 * Copyright (c) 2012-2019 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"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080048
49#if defined(LINUX_QCMBR)
50#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
51#endif
52
53/*
54 * Size of Driver command strings from upper layer
55 */
56#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
57#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
Pragaspathi Thilagarajaa8320e2019-04-16 02:47:50 +053058#define SIZE_OF_SETSUSPENDMODE 14
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080060/*
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +053061 * Size of GETCOUNTRYREV output = (sizeof("GETCOUNTRYREV") = 14) + one (space) +
62 * (sizeof("country_code") = 3) +
63 * one (NULL terminating character)
64 */
65#define SIZE_OF_GETCOUNTRYREV_OUTPUT 20
66
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080067#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080068#define TID_MIN_VALUE 0
69#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080070#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071
72/*
73 * Maximum buffer size used for returning the data back to user space
74 */
75#define WLAN_MAX_BUF_SIZE 1024
76#define WLAN_PRIV_DATA_MAX_LEN 8192
77
78/*
79 * Driver miracast parameters 0-Disabled
80 * 1-Source, 2-Sink
81 */
82#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
83#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
84
85/*
86 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
87 * we will split the printing.
88 */
89#define NUM_OF_STA_DATA_TO_PRINT 16
90
Dundi Raviteja53de6c32018-05-16 16:56:30 +053091#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
92/**
93 * struct enable_ext_wow_priv - Private data structure for ext wow
94 * @ext_wow_should_suspend: Suspend status of ext wow
95 */
96struct enable_ext_wow_priv {
97 bool ext_wow_should_suspend;
98};
99#endif
100
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800101/*
102 * Android DRIVER command structures
103 */
104struct android_wifi_reassoc_params {
105 unsigned char bssid[18];
106 int channel;
107};
108
109#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
110struct android_wifi_af_params {
111 unsigned char bssid[18];
112 int channel;
113 int dwell_time;
114 int len;
115 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
116};
117
118/*
119 * Define HDD driver command handling entry, each contains a command
120 * string and the handler.
121 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700122typedef int (*hdd_drv_cmd_handler_t)(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -0700123 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800124 uint8_t *cmd,
125 uint8_t cmd_name_len,
Jeff Johnson353cd292017-08-17 06:47:26 -0700126 struct hdd_priv_data *priv_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800127
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530128/**
129 * struct hdd_drv_cmd - Structure to store ioctl command handling info
130 * @cmd: Name of the command
131 * @handler: Command handler to be invoked
132 * @args: Set to true if command expects input parameters
133 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700134struct hdd_drv_cmd {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800135 const char *cmd;
136 hdd_drv_cmd_handler_t handler;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530137 bool args;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700138};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800139
140#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
141#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
142#define WLAN_HDD_MAX_TCP_PORT 65535
143#endif
144
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530145/**
146 * drv_cmd_validate() - Validates for space in hdd driver command
147 * @command: pointer to input data (its a NULL terminated string)
148 * @len: length of command name
149 *
150 * This function checks for space after command name and if no space
151 * is found returns error.
152 *
153 * Return: 0 for success non-zero for failure
154 */
155static int drv_cmd_validate(uint8_t *command, int len)
156{
157 if (command[len] != ' ')
158 return -EINVAL;
159
160 return 0;
161}
162
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800163#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800164struct tsm_priv {
165 tAniTrafStrmMetrics tsm_metrics;
166};
167
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800168static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
Sourav Mohapatradcd8f8d2019-07-03 15:43:15 +0530169 void *context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800170{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700171 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800172 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800173
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700174 request = osif_request_get(context);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800175 if (!request) {
176 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800177 return;
178 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700179 priv = osif_request_priv(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800180 priv->tsm_metrics = tsm_metrics;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700181 osif_request_complete(request);
182 osif_request_put(request);
Dustin Browne74003f2018-03-14 12:51:58 -0700183 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185}
186
Jeff Johnsone44b7012017-09-10 15:25:47 -0700187static int hdd_get_tsm_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800188 const uint8_t tid,
189 tAniTrafStrmMetrics *tsm_metrics)
190{
Jeff Johnson621cf972017-08-28 11:58:44 -0700191 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700192 struct hdd_station_ctx *hdd_sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800193 QDF_STATUS status;
194 int ret;
195 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700196 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800197 struct tsm_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700198 static const struct osif_request_params params = {
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800199 .priv_size = sizeof(*priv),
200 .timeout_ms = WLAN_WAIT_TIME_STATS,
201 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202
Jeff Johnsond36fa332019-03-18 13:42:25 -0700203 if (!adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700204 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800205 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800206 }
207
208 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
209 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
210
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700211 request = osif_request_alloc(&params);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800212 if (!request) {
213 hdd_err("Request allocation failure");
214 return -ENOMEM;
215 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700216 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800217
Jeff Johnsond549efa2018-06-13 20:27:47 -0700218 status = sme_get_tsm_stats(hdd_ctx->mac_handle, hdd_get_tsm_stats_cb,
Jeff Johnsone04b6992019-02-27 14:06:55 -0800219 hdd_sta_ctx->conn_info.bssid,
Jeff Johnson30f84552017-09-13 14:55:25 -0700220 cookie, tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800221 if (QDF_STATUS_SUCCESS != status) {
222 hdd_err("Unable to retrieve tsm statistics");
223 ret = qdf_status_to_os_return(status);
224 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800225 }
226
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700227 ret = osif_request_wait_for_response(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800228 if (ret) {
229 hdd_err("SME timed out while retrieving tsm statistics");
230 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800231 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800232
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700233 priv = osif_request_priv(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800234 *tsm_metrics = priv->tsm_metrics;
235
236 cleanup:
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700237 osif_request_put(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800238
239 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800240}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800241#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800242
Abhishek Ambure68677462019-09-13 12:44:26 +0530243#ifdef QCA_IBSS_SUPPORT
244/*
245 * Ibss prop IE from command will be of size:
246 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
247 * OUI_DATA should be at least 3 bytes long
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800248 */
Abhishek Ambure68677462019-09-13 12:44:26 +0530249#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
250static uint16_t cesium_pid;
251
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700252void
Jeff Johnsonafa022c2019-02-26 09:24:17 -0800253hdd_get_ibss_peer_info_cb(void *context,
Jeff Johnson52f19d52019-02-26 08:35:38 -0800254 tSirPeerInfoRspParams *peer_info)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800255{
Jeff Johnsonafa022c2019-02-26 09:24:17 -0800256 struct hdd_adapter *adapter = context;
Jeff Johnson93107ad2019-02-26 08:14:46 -0800257 struct hdd_station_ctx *sta_ctx;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800258 uint8_t i;
259
Jeff Johnsond36fa332019-03-18 13:42:25 -0700260 if ((!adapter) ||
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800261 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800262 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800263 return;
264 }
265
Jeff Johnson93107ad2019-02-26 08:14:46 -0800266 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsond36fa332019-03-18 13:42:25 -0700267 if (peer_info && QDF_STATUS_SUCCESS == peer_info->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700268 /* validate number of peers */
Jeff Johnson52f19d52019-02-26 08:35:38 -0800269 if (peer_info->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530270 hdd_warn("Limiting num_peers %u to %u",
Jeff Johnson52f19d52019-02-26 08:35:38 -0800271 peer_info->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
272 peer_info->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800273 }
Jeff Johnson52f19d52019-02-26 08:35:38 -0800274 sta_ctx->ibss_peer_info.status = peer_info->status;
275 sta_ctx->ibss_peer_info.numPeers = peer_info->numPeers;
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530276
Jeff Johnson52f19d52019-02-26 08:35:38 -0800277 for (i = 0; i < peer_info->numPeers; i++)
Jeff Johnson93107ad2019-02-26 08:14:46 -0800278 sta_ctx->ibss_peer_info.peerInfoParams[i] =
Jeff Johnson52f19d52019-02-26 08:35:38 -0800279 peer_info->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800280 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800281 hdd_debug("peerInfo %s: status %u, numPeers %u",
Jeff Johnson52f19d52019-02-26 08:35:38 -0800282 peer_info ? "valid" : "null",
283 peer_info ? peer_info->status : QDF_STATUS_E_FAILURE,
284 peer_info ? peer_info->numPeers : 0);
Jeff Johnson93107ad2019-02-26 08:14:46 -0800285 sta_ctx->ibss_peer_info.numPeers = 0;
286 sta_ctx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800287 }
288
289 complete(&adapter->ibss_peer_info_comp);
290}
291
292/**
293 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
294 * @adapter: Adapter context
295 *
296 * Request function to get IBSS peer info from lower layers
297 *
298 * Return: 0 for success non-zero for failure
299 */
300static
Jeff Johnsone44b7012017-09-10 15:25:47 -0700301QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(struct hdd_adapter *adapter)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800302{
Jeff Johnsond549efa2018-06-13 20:27:47 -0700303 QDF_STATUS status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800304 unsigned long rc;
Yeshwanth Sriram Guntuka3f262102019-07-16 15:41:08 +0530305 struct qdf_mac_addr bcast = QDF_MAC_ADDR_BCAST_INIT;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800306
307 INIT_COMPLETION(adapter->ibss_peer_info_comp);
308
Jeff Johnsond549efa2018-06-13 20:27:47 -0700309 status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle,
310 adapter,
311 hdd_get_ibss_peer_info_cb,
Yeshwanth Sriram Guntuka3f262102019-07-16 15:41:08 +0530312 true, bcast.bytes);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800313
Jeff Johnsond549efa2018-06-13 20:27:47 -0700314 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800315 rc = wait_for_completion_timeout
316 (&adapter->ibss_peer_info_comp,
317 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
318
319 /* status will be 0 if timed out */
320 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700321 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Jeff Johnsond549efa2018-06-13 20:27:47 -0700322 status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800323 }
324 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700325 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800326 }
327
Jeff Johnsond549efa2018-06-13 20:27:47 -0700328 return status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800329}
330
331/**
332 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
333 * @adapter: Adapter context
Jeff Johnson0a082d92019-03-04 12:25:49 -0800334 * @sta_id: Sta index for which the peer info is requested
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800335 *
336 * Request function to get IBSS peer info from lower layers
337 *
338 * Return: 0 for success non-zero for failure
339 */
340static QDF_STATUS
Sourav Mohapatraa3cf12a2019-08-19 15:40:49 +0530341hdd_cfg80211_get_ibss_peer_info(struct hdd_adapter *adapter, uint8_t *mac_addr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800342{
343 unsigned long rc;
Jeff Johnsond549efa2018-06-13 20:27:47 -0700344 QDF_STATUS status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800345
346 INIT_COMPLETION(adapter->ibss_peer_info_comp);
347
Jeff Johnsond549efa2018-06-13 20:27:47 -0700348 status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle,
349 adapter,
350 hdd_get_ibss_peer_info_cb,
Sourav Mohapatraa3cf12a2019-08-19 15:40:49 +0530351 false, mac_addr);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800352
Jeff Johnsond549efa2018-06-13 20:27:47 -0700353 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800354 rc = wait_for_completion_timeout(
355 &adapter->ibss_peer_info_comp,
356 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
357
358 /* status = 0 on timeout */
359 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700360 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Jeff Johnsond549efa2018-06-13 20:27:47 -0700361 status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800362 }
363 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700364 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800365 }
366
Jeff Johnsond549efa2018-06-13 20:27:47 -0700367 return status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800368}
369
370/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700371static QDF_STATUS
Jeff Johnson6636e622019-02-26 10:22:39 -0800372hdd_parse_get_ibss_peer_info(uint8_t *command,
Jeff Johnson64ba9af2019-02-26 12:57:35 -0800373 struct qdf_mac_addr *peer_macaddr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800374{
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800375 uint8_t *in_ptr = command;
Jeff Johnson6636e622019-02-26 10:22:39 -0800376 size_t in_ptr_len = strlen(command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700377
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800378 in_ptr = strnchr(command, in_ptr_len, SPACE_ASCII_VALUE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800379
Jeff Johnsond36fa332019-03-18 13:42:25 -0700380 if (!in_ptr)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700381 return QDF_STATUS_E_FAILURE;
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800382 else if (SPACE_ASCII_VALUE != *in_ptr)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700383 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800384
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800385 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
386 in_ptr++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800387
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800388 if ('\0' == *in_ptr)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700389 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800390
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800391 in_ptr_len -= (in_ptr - command);
Min Liu5359ab12018-03-29 14:30:24 +0800392 if (in_ptr_len < 17)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700393 return QDF_STATUS_E_FAILURE;
Min Liu5359ab12018-03-29 14:30:24 +0800394
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800395 if (in_ptr[2] != ':' || in_ptr[5] != ':' || in_ptr[8] != ':' ||
396 in_ptr[11] != ':' || in_ptr[14] != ':')
Min Liu5359ab12018-03-29 14:30:24 +0800397 return QDF_STATUS_E_FAILURE;
398
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800399 sscanf(in_ptr, "%2x:%2x:%2x:%2x:%2x:%2x",
Jeff Johnson64ba9af2019-02-26 12:57:35 -0800400 (unsigned int *)&peer_macaddr->bytes[0],
401 (unsigned int *)&peer_macaddr->bytes[1],
402 (unsigned int *)&peer_macaddr->bytes[2],
403 (unsigned int *)&peer_macaddr->bytes[3],
404 (unsigned int *)&peer_macaddr->bytes[4],
405 (unsigned int *)&peer_macaddr->bytes[5]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800406
407 return QDF_STATUS_SUCCESS;
408}
409
Abhishek Ambure68677462019-09-13 12:44:26 +0530410static void hdd_tx_fail_ind_callback(uint8_t *macaddr, uint8_t seq_no)
411{
412 int payload_len;
413 struct sk_buff *skb;
414 struct nlmsghdr *nlh;
415 uint8_t *data;
416
417 payload_len = ETH_ALEN;
418
419 if (0 == cesium_pid || !cesium_nl_srv_sock) {
420 hdd_err("cesium process not registered");
421 return;
422 }
423
424 skb = nlmsg_new(payload_len, GFP_ATOMIC);
425 if (!skb) {
426 hdd_err("nlmsg_new() failed for msg size[%d]",
427 NLMSG_SPACE(payload_len));
428 return;
429 }
430
431 nlh = nlmsg_put(skb, cesium_pid, seq_no, 0, payload_len, NLM_F_REQUEST);
432
433 if (!nlh) {
434 hdd_err("nlmsg_put() failed for msg size[%d]",
435 NLMSG_SPACE(payload_len));
436
437 kfree_skb(skb);
438 return;
439 }
440
441 data = nlmsg_data(nlh);
442 memcpy(data, macaddr, ETH_ALEN);
443
444 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
445 hdd_err("nlmsg_unicast() failed for msg size[%d]",
446 NLMSG_SPACE(payload_len));
447 }
448}
449
450/**
451 * hdd_parse_user_params() - return a pointer to the next argument
452 * @command: Input argument string
453 * @arg: Output pointer to the next argument
454 *
455 * This function parses argument stream and finds the pointer
456 * to the next argument
457 *
458 * Return: 0 if the next argument found; -EINVAL otherwise
459 */
460static int hdd_parse_user_params(uint8_t *command, uint8_t **arg)
461{
462 uint8_t *cursor;
463
464 cursor = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
465
466 /* no argument remains ? */
467 if (!cursor)
468 return -EINVAL;
469
470 /* no space after the current arg ? */
471 if (SPACE_ASCII_VALUE != *cursor)
472 return -EINVAL;
473
474 cursor++;
475
476 /* remove empty spaces */
477 while (SPACE_ASCII_VALUE == *cursor)
478 cursor++;
479
480 /* no argument after the spaces ? */
481 if ('\0' == *cursor)
482 return -EINVAL;
483
484 *arg = cursor;
485
486 return 0;
487}
488
489/**
490 * hdd_parse_ibsstx_fail_event_params - Parse params
491 * for SETIBSSTXFAILEVENT
492 * @command: Input ibss tx fail event argument
493 * @tx_fail_count: (Output parameter) Tx fail counter
494 * @pid: (Output parameter) PID
495 *
496 * Return: 0 if the parsing succeeds; -EINVAL otherwise
497 */
498static int hdd_parse_ibsstx_fail_event_params(uint8_t *command,
499 uint8_t *tx_fail_count,
500 uint16_t *pid)
501{
502 uint8_t *param = NULL;
503 int ret;
504
505 ret = hdd_parse_user_params(command, &param);
506
507 if (0 == ret && param) {
508 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
509 ret = -EINVAL;
510 goto done;
511 }
512 } else {
513 goto done;
514 }
515
516 if (0 == *tx_fail_count) {
517 *pid = 0;
518 goto done;
519 }
520
521 command = param;
522 command++;
523
524 ret = hdd_parse_user_params(command, &param);
525
526 if (0 == ret) {
527 if (1 != sscanf(param, "%hu", pid)) {
528 ret = -EINVAL;
529 goto done;
530 }
531 } else {
532 goto done;
533 }
534
535done:
536 return ret;
537}
538
539/* Function header is left blank intentionally */
540static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
541 int32_t *oui_length, int32_t limit)
542{
543 uint8_t len;
544 uint8_t data;
545
546 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
547 command++;
548 limit--;
549 }
550
551 len = 2;
552
553 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
554 (limit > 1)) {
555 sscanf(command, "%02x", (unsigned int *)&data);
556 ie[len++] = data;
557 command += 2;
558 limit -= 2;
559 }
560
561 *oui_length = len - 2;
562
563 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
564 command++;
565 limit--;
566 }
567
568 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
569 (limit > 1)) {
570 sscanf(command, "%02x", (unsigned int *)&data);
571 ie[len++] = data;
572 command += 2;
573 limit -= 2;
574 }
575
576 ie[0] = WLAN_ELEMID_VENDOR;
577 ie[1] = len - 2;
578
579 return len;
580}
581
582/**
583 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
584 * @adapter: Pointer to adapter
585 * @hdd_ctx: Pointer to HDD context
586 * @command: Pointer to command string
587 * @command_len : Command length
588 * @priv_data : Pointer to priv data
589 *
590 * Return:
591 * int status code
592 */
593static int drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *adapter,
594 struct hdd_context *hdd_ctx,
595 uint8_t *command,
596 uint8_t command_len,
597 struct hdd_priv_data *priv_data)
598{
599 int i = 0;
600 int status;
601 int ret = 0;
602 uint8_t *ibss_ie;
603 int32_t oui_length = 0;
604 uint32_t ibss_ie_length;
605 uint8_t *value = command;
606 tSirModifyIE modify_ie;
607 struct csr_roam_profile *roam_profile;
608 mac_handle_t mac_handle;
609
610 if (QDF_IBSS_MODE != adapter->device_mode) {
611 hdd_debug("Device_mode %s(%d) not IBSS",
612 qdf_opmode_str(adapter->device_mode),
613 adapter->device_mode);
614 return ret;
615 }
616
617 hdd_debug("received command %s", ((char *)value));
618
619 /* validate argument of command */
620 if (strlen(value) <= command_len) {
621 hdd_err("No arguments in command length %zu",
622 strlen(value));
623 ret = -EFAULT;
624 goto exit;
625 }
626
627 /* moving to arguments of commands */
628 value = value + command_len;
629 command_len = strlen(value);
630
631 /* oui_data can't be less than 3 bytes */
632 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
633 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
634 command_len);
635 ret = -EFAULT;
636 goto exit;
637 }
638
639 ibss_ie = qdf_mem_malloc(command_len);
640 if (!ibss_ie) {
641 hdd_err("Could not allocate memory for command length %d",
642 command_len);
643 ret = -ENOMEM;
644 goto exit;
645 }
646
647 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
648 &oui_length,
649 command_len);
650 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
651 hdd_err("Could not parse command %s return length %d",
652 value, ibss_ie_length);
653 ret = -EFAULT;
654 qdf_mem_free(ibss_ie);
655 goto exit;
656 }
657
658 roam_profile = hdd_roam_profile(adapter);
659
660 qdf_copy_macaddr(&modify_ie.bssid,
661 roam_profile->BSSIDs.bssid);
662
Abhishek Singh5a2c42f2019-11-19 11:39:23 +0530663 modify_ie.vdev_id = adapter->vdev_id;
Abhishek Ambure68677462019-09-13 12:44:26 +0530664 modify_ie.notify = true;
665 modify_ie.ieID = WLAN_ELEMID_VENDOR;
666 modify_ie.ieIDLen = ibss_ie_length;
667 modify_ie.ieBufferlength = ibss_ie_length;
668 modify_ie.pIEBuffer = ibss_ie;
669 modify_ie.oui_length = oui_length;
670
671 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
672 ibss_ie_length, oui_length);
673 while (i < modify_ie.ieBufferlength)
674 hdd_warn("0x%x", ibss_ie[i++]);
675
676 /* Probe Bcn modification */
677 mac_handle = hdd_ctx->mac_handle;
678 sme_modify_add_ie(mac_handle, &modify_ie, eUPDATE_IE_PROBE_BCN);
679
680 /* Populating probe resp frame */
681 sme_modify_add_ie(mac_handle, &modify_ie, eUPDATE_IE_PROBE_RESP);
682
683 qdf_mem_free(ibss_ie);
684
685 status = sme_send_cesium_enable_ind(mac_handle,
686 adapter->vdev_id);
687 if (QDF_STATUS_SUCCESS != status) {
688 hdd_err("Could not send cesium enable indication %d",
689 status);
690 ret = -EINVAL;
691 goto exit;
692 }
693
694exit:
695 return ret;
696}
697
698static int drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *adapter,
699 struct hdd_context *hdd_ctx,
700 uint8_t *command,
701 uint8_t command_len,
702 struct hdd_priv_data *priv_data)
703{
704 int ret = 0;
705 int status = QDF_STATUS_SUCCESS;
706 struct hdd_station_ctx *sta_ctx = NULL;
707 char *extra = NULL;
708 int idx = 0;
709 int length = 0;
710 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
711 uint32_t print_break_index = 0;
712
713 if (QDF_IBSS_MODE != adapter->device_mode) {
714 hdd_warn("Unsupported in mode %s(%d)",
715 qdf_opmode_str(adapter->device_mode),
716 adapter->device_mode);
717 return -EINVAL;
718 }
719
720 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
721 hdd_debug("Received GETIBSSPEERINFOALL Command");
722
723 /* Handle the command */
724 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
725 if (QDF_STATUS_SUCCESS == status) {
726 size_t user_size = qdf_min(WLAN_MAX_BUF_SIZE,
727 priv_data->total_len);
728
729 /*
730 * The variable extra needed to be allocated on the heap since
731 * amount of memory required to copy the data for 32 devices
732 * exceeds the size of 1024 bytes of default stack size. On
733 * 64 bit devices, the default max stack size of 2048 bytes
734 */
735 extra = qdf_mem_malloc(user_size);
736
737 if (!extra) {
738 hdd_err("memory allocation failed");
739 ret = -ENOMEM;
740 goto exit;
741 }
742
743 /* Copy number of stations */
744 length = scnprintf(extra, user_size, "%d ",
745 sta_ctx->ibss_peer_info.numPeers);
746 print_break_index = length;
747 for (idx = 0; idx < sta_ctx->ibss_peer_info.numPeers;
748 idx++) {
749 int8_t rssi;
750 uint32_t tx_rate;
751
752 qdf_mem_copy(mac_addr,
753 sta_ctx->ibss_peer_info.peerInfoParams[idx].
754 mac_addr, sizeof(mac_addr));
755
756 tx_rate =
757 sta_ctx->ibss_peer_info.peerInfoParams[idx].
758 txRate;
759 /*
760 * Only lower 3 bytes are rate info. Mask of the MSByte
761 */
762 tx_rate &= 0x00FFFFFF;
763
764 rssi = sta_ctx->ibss_peer_info.peerInfoParams[idx].
765 rssi;
766
767 length += scnprintf(extra + length,
768 user_size - length,
769 QDF_MAC_ADDR_STR" %d %d ",
770 QDF_MAC_ADDR_ARRAY(mac_addr),
771 tx_rate, rssi);
772 /*
773 * cdf_trace_msg has limitation of 512 bytes for the
774 * print buffer. Hence printing the data in two chunks.
775 * The first chunk will have the data for 16 devices
776 * and the second chunk will have the rest.
777 */
778 if (idx < NUM_OF_STA_DATA_TO_PRINT)
779 print_break_index = length;
780 }
781
782 /*
783 * Copy the data back into buffer, if the data to copy is
784 * more than 512 bytes than we will split the data and do
785 * it in two shots
786 */
787 if (copy_to_user(priv_data->buf, extra, print_break_index)) {
788 hdd_err("Copy into user data buffer failed");
789 ret = -EFAULT;
790 goto mem_free;
791 }
792
793 /* This overwrites the last space, which we already copied */
794 extra[print_break_index - 1] = '\0';
795 hdd_debug("%s", extra);
796
797 if (length > print_break_index) {
798 if (copy_to_user
799 (priv_data->buf + print_break_index,
800 extra + print_break_index,
801 length - print_break_index + 1)) {
802 hdd_err("Copy into user data buffer failed");
803 ret = -EFAULT;
804 goto mem_free;
805 }
806 hdd_debug("%s", &extra[print_break_index]);
807 }
808 } else {
809 /* Command failed, log error */
810 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
811 status);
812 ret = -EINVAL;
813 goto exit;
814 }
815 ret = 0;
816
817mem_free:
818 qdf_mem_free(extra);
819exit:
820 return ret;
821}
822
823/* Peer Info <Peer Addr> command */
824static int drv_cmd_get_ibss_peer_info(struct hdd_adapter *adapter,
825 struct hdd_context *hdd_ctx,
826 uint8_t *command,
827 uint8_t command_len,
828 struct hdd_priv_data *priv_data)
829{
830 int ret = 0;
831 uint8_t *value = command;
832 QDF_STATUS status;
833 struct hdd_station_ctx *sta_ctx = NULL;
834 char extra[128] = { 0 };
835 uint32_t length = 0;
Abhishek Ambure68677462019-09-13 12:44:26 +0530836 struct qdf_mac_addr peer_macaddr;
837
838 if (QDF_IBSS_MODE != adapter->device_mode) {
839 hdd_warn("Unsupported in mode %s(%d)",
840 qdf_opmode_str(adapter->device_mode),
841 adapter->device_mode);
842 return -EINVAL;
843 }
844
845 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
846
847 hdd_debug("Received GETIBSSPEERINFO Command");
848
849 /* if there are no peers, no need to continue with the command */
850 if (eConnectionState_IbssConnected !=
851 sta_ctx->conn_info.conn_state) {
852 hdd_err("No IBSS Peers coalesced");
853 ret = -EINVAL;
854 goto exit;
855 }
856
857 /* Parse the incoming command buffer */
858 status = hdd_parse_get_ibss_peer_info(value, &peer_macaddr);
859 if (QDF_STATUS_SUCCESS != status) {
860 hdd_err("Invalid GETIBSSPEERINFO command");
861 ret = -EINVAL;
862 goto exit;
863 }
864
Abhishek Ambure68677462019-09-13 12:44:26 +0530865 /* Handle the command */
Sourav Mohapatraa3cf12a2019-08-19 15:40:49 +0530866 status = hdd_cfg80211_get_ibss_peer_info(adapter, peer_macaddr.bytes);
Abhishek Ambure68677462019-09-13 12:44:26 +0530867 if (QDF_STATUS_SUCCESS == status) {
868 uint32_t tx_rate =
869 sta_ctx->ibss_peer_info.peerInfoParams[0].txRate;
870 /* Only lower 3 bytes are rate info. Mask of the MSByte */
871 tx_rate &= 0x00FFFFFF;
872
873 length = scnprintf(extra, sizeof(extra), "%d %d",
874 (int)tx_rate,
875 (int)sta_ctx->ibss_peer_info.
876 peerInfoParams[0].rssi);
877 length = QDF_MIN(priv_data->total_len, length + 1);
878
879 /* Copy the data back into buffer */
880 if (copy_to_user(priv_data->buf, &extra, length)) {
881 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
882 ret = -EFAULT;
883 goto exit;
884 }
885 } else {
886 /* Command failed, log error */
887 hdd_err("GETIBSSPEERINFO command failed with status code %d",
888 status);
889 ret = -EINVAL;
890 goto exit;
891 }
892
893 /* Success ! */
894 hdd_debug("%s", extra);
895 ret = 0;
896
897exit:
898 return ret;
899}
900
901static int drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *adapter,
902 struct hdd_context *hdd_ctx,
903 uint8_t *command,
904 uint8_t command_len,
905 struct hdd_priv_data *priv_data)
906{
907 int ret = 0;
908 char *value;
909 uint8_t tx_fail_count = 0;
910 uint16_t pid = 0;
911 mac_handle_t mac_handle;
912
913 value = command;
914
915 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
916
917 if (0 != ret) {
918 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
919 goto exit;
920 }
921
922 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
923 mac_handle = hdd_ctx->mac_handle;
924
925 if (0 == tx_fail_count) {
926 /* Disable TX Fail Indication */
927 if (QDF_STATUS_SUCCESS ==
928 sme_tx_fail_monitor_start_stop_ind(mac_handle,
929 tx_fail_count,
930 NULL)) {
931 cesium_pid = 0;
932 } else {
933 hdd_err("failed to disable TX Fail Event");
934 ret = -EINVAL;
935 }
936 } else {
937 if (QDF_STATUS_SUCCESS ==
938 sme_tx_fail_monitor_start_stop_ind(mac_handle,
939 tx_fail_count,
940 (void *)hdd_tx_fail_ind_callback)) {
941 cesium_pid = pid;
942 hdd_debug("Registered Cesium pid %u",
943 cesium_pid);
944 } else {
945 hdd_err("Failed to enable TX Fail Monitoring");
946 ret = -EINVAL;
947 }
948 }
949
950exit:
951 return ret;
952}
953#else
954/**
955 * drv_cmd_get_ibss_peer_info() - get ibss peer info all
956 * @adapter: Pointer to adapter
957 * @hdd_ctx: Pointer to HDD context
958 * @command: Pointer to command string
959 * @command_len : Command length
960 * @priv_data : Pointer to priv data
961 *
962 * This function is dummy
963 *
964 * Return: 0
965 */
966static inline int
967drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *adapter,
968 struct hdd_context *hdd_ctx,
969 uint8_t *command,
970 uint8_t command_len,
971 struct hdd_priv_data *priv_data)
972{
973 return 0;
974}
975
976/**
977 * drv_cmd_get_ibss_peer_info() - get ibss peer info
978 * @adapter: Pointer to adapter
979 * @hdd_ctx: Pointer to HDD context
980 * @command: Pointer to command string
981 * @command_len : Command length
982 * @priv_data : Pointer to priv data
983 *
984 * This function is dummy
985 *
986 * Return: 0
987 */
988static inline int
989drv_cmd_get_ibss_peer_info(struct hdd_adapter *adapter,
990 struct hdd_context *hdd_ctx,
991 uint8_t *command,
992 uint8_t command_len,
993 struct hdd_priv_data *priv_data)
994{
995 return 0;
996}
997
998/**
999 * drv_cmd_set_ibss_tx_fail_event() - set ibss tx fail event
1000 * @adapter: Pointer to adapter
1001 * @hdd_ctx: Pointer to HDD context
1002 * @command: Pointer to command string
1003 * @command_len : Command length
1004 * @priv_data : Pointer to priv data
1005 *
1006 * This function is dummy
1007 *
1008 * Return: 0
1009 */
1010static inline int
1011drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *adapter,
1012 struct hdd_context *hdd_ctx,
1013 uint8_t *command,
1014 uint8_t command_len,
1015 struct hdd_priv_data *priv_data)
1016{
1017 return 0;
1018}
1019
1020/**
1021 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
1022 * @adapter: Pointer to adapter
1023 * @hdd_ctx: Pointer to HDD context
1024 * @command: Pointer to command string
1025 * @command_len : Command length
1026 * @priv_data : Pointer to priv data
1027 *
1028 * This function is dummy
1029 *
1030 * Return: 0
1031 */
1032static inline int
1033drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *adapter,
1034 struct hdd_context *hdd_ctx,
1035 uint8_t *command,
1036 uint8_t command_len,
1037 struct hdd_priv_data *priv_data)
1038{
1039 return 0;
1040}
1041#endif
1042
Jeff Johnsond549efa2018-06-13 20:27:47 -07001043static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *ui_band)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044{
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -08001045 enum band_info band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001046
Harprit Chhabada5dff30e2019-03-12 17:56:45 -07001047 ucfg_reg_get_band(hdd_ctx->pdev, &band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001048 switch (band) {
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -08001049 case BAND_ALL:
Jeff Johnsond549efa2018-06-13 20:27:47 -07001050 *ui_band = WLAN_HDD_UI_BAND_AUTO;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001051 break;
1052
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -08001053 case BAND_2G:
Jeff Johnsond549efa2018-06-13 20:27:47 -07001054 *ui_band = WLAN_HDD_UI_BAND_2_4_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001055 break;
1056
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -08001057 case BAND_5G:
Jeff Johnsond549efa2018-06-13 20:27:47 -07001058 *ui_band = WLAN_HDD_UI_BAND_5_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001059 break;
1060
1061 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001062 hdd_warn("Invalid Band %d", band);
Jeff Johnsond549efa2018-06-13 20:27:47 -07001063 *ui_band = -1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001064 break;
1065 }
1066}
1067
1068/**
1069 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
1070 * @data: input data
1071 * @target_ap_bssid: pointer to bssid (output parameter)
1072 * @channel: pointer to channel (output parameter)
1073 *
1074 * Return: 0 if parsing is successful; -EINVAL otherwise
1075 */
1076static int _hdd_parse_bssid_and_chan(const uint8_t **data,
1077 uint8_t *bssid,
1078 uint8_t *channel)
1079{
1080 const uint8_t *in_ptr;
1081 int v = 0;
1082 int temp_int;
1083 uint8_t temp_buf[32];
1084
1085 /* 12 hexa decimal digits, 5 ':' and '\0' */
1086 uint8_t mac_addr[18];
1087
1088 if (!data || !*data)
1089 return -EINVAL;
1090
1091 in_ptr = *data;
1092
1093 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
1094 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001095 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096 goto error;
1097 /* no space after the command */
1098 else if (SPACE_ASCII_VALUE != *in_ptr)
1099 goto error;
1100
1101 /* remove empty spaces */
1102 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1103 in_ptr++;
1104
1105 /* no argument followed by spaces */
1106 if ('\0' == *in_ptr)
1107 goto error;
1108
1109 v = sscanf(in_ptr, "%17s", mac_addr);
1110 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001111 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
1112 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001113 goto error;
1114 }
1115
1116 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
1117 hex_to_bin(mac_addr[1]);
1118 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
1119 hex_to_bin(mac_addr[4]);
1120 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
1121 hex_to_bin(mac_addr[7]);
1122 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
1123 hex_to_bin(mac_addr[10]);
1124 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
1125 hex_to_bin(mac_addr[13]);
1126 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
1127 hex_to_bin(mac_addr[16]);
1128
1129 /* point to the next argument */
1130 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
1131 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001132 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133 goto error;
1134
1135 /* remove empty spaces */
1136 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1137 in_ptr++;
1138
1139 /* no argument followed by spaces */
1140 if ('\0' == *in_ptr)
1141 goto error;
1142
1143 /* get the next argument ie the channel number */
1144 v = sscanf(in_ptr, "%31s ", temp_buf);
1145 if (1 != v)
1146 goto error;
1147
1148 v = kstrtos32(temp_buf, 10, &temp_int);
1149 if ((v < 0) || (temp_int < 0) ||
1150 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
1151 return -EINVAL;
1152
1153 *channel = temp_int;
1154 *data = in_ptr;
1155 return 0;
1156error:
1157 *data = in_ptr;
1158 return -EINVAL;
1159}
1160
1161/**
1162 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
Jeff Johnson6636e622019-02-26 10:22:39 -08001163 * @command: Pointer to input data
Jeff Johnsonb7d52792019-02-26 12:42:08 -08001164 * @bssid: Pointer to target Ap bssid
Jeff Johnsond727cdc2019-02-26 12:47:05 -08001165 * @channel: Pointer to the Target AP channel
Jeff Johnson80d220a2019-02-26 12:27:24 -08001166 * @dwell_time: Pointer to the time to stay off-channel
Jeff Johnson6636e622019-02-26 10:22:39 -08001167 * after transmitting action frame
Jeff Johnson5f3a6122019-02-26 17:20:59 -08001168 * @buf: Pointer to data
Jeff Johnson103f67a2019-02-26 17:11:01 -08001169 * @buf_len: Pointer to data length
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170 *
1171 * This function parses the send action frame data passed in the format
1172 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
1173 *
1174 * Return: 0 for success non-zero for failure
1175 */
1176static int
Jeff Johnson6636e622019-02-26 10:22:39 -08001177hdd_parse_send_action_frame_v1_data(const uint8_t *command,
Jeff Johnsonb7d52792019-02-26 12:42:08 -08001178 uint8_t *bssid,
Jeff Johnsond727cdc2019-02-26 12:47:05 -08001179 uint8_t *channel, uint8_t *dwell_time,
Jeff Johnson5f3a6122019-02-26 17:20:59 -08001180 uint8_t **buf, uint8_t *buf_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001181{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001182 const uint8_t *in_ptr = command;
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08001183 const uint8_t *end_ptr;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001184 int temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001185 int j = 0;
1186 int i = 0;
1187 int v = 0;
Jeff Johnson72f498b2019-02-26 18:37:25 -08001188 uint8_t temp_buf[32];
1189 uint8_t temp_u8 = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001191 if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, channel))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001192 return -EINVAL;
1193
1194 /* point to the next argument */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001195 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001196 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001197 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001198 return -EINVAL;
1199 /* removing empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001200 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1201 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001202
1203 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001204 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001205 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001206
1207 /* getting the next argument ie the dwell time */
Jeff Johnson72f498b2019-02-26 18:37:25 -08001208 v = sscanf(in_ptr, "%31s ", temp_buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001209 if (1 != v)
1210 return -EINVAL;
1211
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001212 v = kstrtos32(temp_buf, 10, &temp_int);
1213 if (v < 0 || temp_int < 0)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001214 return -EINVAL;
1215
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001216 *dwell_time = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217
1218 /* point to the next argument */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001219 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001220 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001221 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001222 return -EINVAL;
1223 /* removing empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001224 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1225 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001226
1227 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001228 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230
1231 /* find the length of data */
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08001232 end_ptr = in_ptr;
1233 while (('\0' != *end_ptr))
1234 end_ptr++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001235
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08001236 *buf_len = end_ptr - in_ptr;
Jeff Johnson103f67a2019-02-26 17:11:01 -08001237 if (*buf_len <= 0)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001238 return -EINVAL;
1239
1240 /*
1241 * Allocate the number of bytes based on the number of input characters
1242 * whether it is even or odd.
1243 * if the number of input characters are even, then we need N/2 byte.
1244 * if the number of input characters are odd, then we need do (N+1)/2
1245 * to compensate rounding off.
1246 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
1247 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
1248 */
Jeff Johnson5f3a6122019-02-26 17:20:59 -08001249 *buf = qdf_mem_malloc((*buf_len + 1) / 2);
Jeff Johnsond36fa332019-03-18 13:42:25 -07001250 if (!*buf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001251 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001252 return -ENOMEM;
1253 }
1254
1255 /* the buffer received from the upper layer is character buffer,
1256 * we need to prepare the buffer taking 2 characters in to a U8 hex
1257 * decimal number for example 7f0000f0...form a buffer to contain 7f
1258 * in 0th location, 00 in 1st and f0 in 3rd location
1259 */
Jeff Johnson103f67a2019-02-26 17:11:01 -08001260 for (i = 0, j = 0; j < *buf_len; j += 2) {
1261 if (j + 1 == *buf_len) {
Jeff Johnson72f498b2019-02-26 18:37:25 -08001262 temp_u8 = hex_to_bin(in_ptr[j]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001263 } else {
Jeff Johnson72f498b2019-02-26 18:37:25 -08001264 temp_u8 =
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001265 (hex_to_bin(in_ptr[j]) << 4) |
1266 (hex_to_bin(in_ptr[j + 1]));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001267 }
Jeff Johnson72f498b2019-02-26 18:37:25 -08001268 (*buf)[i++] = temp_u8;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001269 }
Jeff Johnson103f67a2019-02-26 17:11:01 -08001270 *buf_len = i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001271 return 0;
1272}
1273
1274/**
1275 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
Jeff Johnson6636e622019-02-26 10:22:39 -08001276 * @command: Pointer to input data (its a NULL terminated string)
Jeff Johnsonb7d52792019-02-26 12:42:08 -08001277 * @bssid: Pointer to target Ap bssid
Jeff Johnsond727cdc2019-02-26 12:47:05 -08001278 * @channel: Pointer to the Target AP channel
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 *
1280 * This function parses the reasoc command data passed in the format
1281 * REASSOC<space><bssid><space><channel>
1282 *
1283 * Return: 0 for success non-zero for failure
1284 */
Jeff Johnson6636e622019-02-26 10:22:39 -08001285static int hdd_parse_reassoc_command_v1_data(const uint8_t *command,
Jeff Johnsonb7d52792019-02-26 12:42:08 -08001286 uint8_t *bssid,
Jeff Johnsond727cdc2019-02-26 12:47:05 -08001287 uint8_t *channel)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001288{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001289 const uint8_t *in_ptr = command;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001290
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001291 if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, channel))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001292 return -EINVAL;
1293
1294 return 0;
1295}
1296
Naveen Rawat05376ee2016-07-18 16:43:32 -07001297#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Abhinav Kumareab25932018-07-13 11:48:43 +05301298QDF_STATUS hdd_wma_send_fastreassoc_cmd(struct hdd_adapter *adapter,
1299 const tSirMacAddr bssid,
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001300 uint32_t ch_freq)
Naveen Rawat05376ee2016-07-18 16:43:32 -07001301{
Krunal Soni332f4af2017-06-01 14:36:17 -07001302 struct hdd_station_ctx *hdd_sta_ctx =
1303 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnson8313b9d2018-03-14 15:09:28 -07001304 struct csr_roam_profile *roam_profile;
Krunal Soni332f4af2017-06-01 14:36:17 -07001305 tSirMacAddr connected_bssid;
Naveen Rawat05376ee2016-07-18 16:43:32 -07001306
Jeff Johnson8313b9d2018-03-14 15:09:28 -07001307 roam_profile = hdd_roam_profile(adapter);
Jeff Johnsone04b6992019-02-27 14:06:55 -08001308 qdf_mem_copy(connected_bssid, hdd_sta_ctx->conn_info.bssid.bytes,
Krunal Soni332f4af2017-06-01 14:36:17 -07001309 ETH_ALEN);
Abhinav Kumareab25932018-07-13 11:48:43 +05301310 return sme_fast_reassoc(adapter->hdd_ctx->mac_handle,
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001311 roam_profile, bssid, ch_freq,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001312 adapter->vdev_id, connected_bssid);
Naveen Rawat05376ee2016-07-18 16:43:32 -07001313}
Naveen Rawat05376ee2016-07-18 16:43:32 -07001314#endif
1315
Jeff Johnsone44b7012017-09-10 15:25:47 -07001316int hdd_reassoc(struct hdd_adapter *adapter, const uint8_t *bssid,
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001317 uint32_t ch_freq, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001318{
Jeff Johnsond377dce2017-10-04 10:32:42 -07001319 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -07001320 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001321 int ret = 0;
Abhinav Kumareab25932018-07-13 11:48:43 +05301322 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001323
Jeff Johnsond36fa332019-03-18 13:42:25 -07001324 if (!hdd_ctx) {
Naveen Rawat05376ee2016-07-18 16:43:32 -07001325 hdd_err("Invalid hdd ctx");
1326 return -EINVAL;
1327 }
1328
Krunal Sonibe766b02016-03-10 13:00:44 -08001329 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001330 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07001331 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001332 adapter->device_mode);
1333 return -EINVAL;
1334 }
1335
Jeff Johnsond377dce2017-10-04 10:32:42 -07001336 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001337
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +05301338 /*
Jeff Johnsone7951512019-02-27 10:02:51 -08001339 * pHddStaCtx->conn_info.conn_state is set to disconnected only
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +05301340 * after the disconnect done indication from SME. If the SME is
1341 * in the process of disconnecting, the SME Connection state is
Jeff Johnsone7951512019-02-27 10:02:51 -08001342 * set to disconnected and the pHddStaCtx->conn_info.conn_state
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +05301343 * will still be associated till the disconnect is done.
1344 * So check both the HDD state and SME state here.
1345 * If not associated, no need to proceed with reassoc
1346 */
Jeff Johnsone7951512019-02-27 10:02:51 -08001347 if ((eConnectionState_Associated != sta_ctx->conn_info.conn_state) ||
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +05301348 (!sme_is_conn_state_connected(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001349 adapter->vdev_id))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001350 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001351 ret = -EINVAL;
1352 goto exit;
1353 }
1354
1355 /*
1356 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -08001357 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001358 */
Jeff Johnsone04b6992019-02-27 14:06:55 -08001359 if (!memcmp(bssid, sta_ctx->conn_info.bssid.bytes,
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001360 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001361 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001362 ch_freq = sta_ctx->conn_info.chan_freq;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001363 }
1364
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301365 if (QDF_STATUS_SUCCESS !=
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001366 wlan_hdd_validate_operation_channel(adapter, ch_freq)) {
1367 hdd_err("Invalid Ch freq: %d", ch_freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001368 ret = -EINVAL;
1369 goto exit;
1370 }
1371
1372 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -07001373 if (roaming_offload_enabled(hdd_ctx)) {
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001374 status = hdd_wma_send_fastreassoc_cmd(adapter, bssid, ch_freq);
Abhinav Kumareab25932018-07-13 11:48:43 +05301375 if (status != QDF_STATUS_SUCCESS) {
1376 hdd_err("Failed to send fast reassoc cmd");
1377 ret = -EINVAL;
1378 }
Naveen Rawat05376ee2016-07-18 16:43:32 -07001379 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07001380 tCsrHandoffRequest handoff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001381
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001382 handoff.ch_freq = ch_freq;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001383 handoff.src = src;
1384 qdf_mem_copy(handoff.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001385 sme_handoff_request(hdd_ctx->mac_handle, adapter->vdev_id,
Jeff Johnsond549efa2018-06-13 20:27:47 -07001386 &handoff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001387 }
1388exit:
1389 return ret;
1390}
1391
1392/**
1393 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
1394 * @adapter: Adapter upon which the command was received
1395 * @command: ASCII text command that was received
1396 *
1397 * This function parses the v1 REASSOC command with the format
1398 *
1399 * REASSOC xx:xx:xx:xx:xx:xx CH
1400 *
1401 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1402 * BSSID and CH is the ASCII representation of the channel. For
1403 * example
1404 *
1405 * REASSOC 00:0a:0b:11:22:33 48
1406 *
1407 * Return: 0 for success non-zero for failure
1408 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07001409static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001410{
1411 uint8_t channel = 0;
1412 tSirMacAddr bssid;
1413 int ret;
1414
1415 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001416 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001417 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001418 else
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001419 ret = hdd_reassoc(adapter, bssid,
1420 wlan_chan_to_freq(channel), REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001421
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001422 return ret;
1423}
1424
1425/**
1426 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
1427 * @adapter: Adapter upon which the command was received
1428 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001429 * followed by binary data
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301430 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001431 *
1432 * This function parses the v2 REASSOC command with the format
1433 *
1434 * REASSOC <android_wifi_reassoc_params>
1435 *
1436 * Return: 0 for success non-zero for failure
1437 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07001438static int hdd_parse_reassoc_v2(struct hdd_adapter *adapter,
1439 const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301440 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001441{
1442 struct android_wifi_reassoc_params params;
1443 tSirMacAddr bssid;
1444 int ret;
1445
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301446 if (total_len < sizeof(params) + 8) {
1447 hdd_err("Invalid command length");
1448 return -EINVAL;
1449 }
1450
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001451 /* The params are located after "REASSOC " */
1452 memcpy(&params, command + 8, sizeof(params));
1453
1454 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001455 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001456 ret = -EINVAL;
1457 } else {
Manikandan Mohan5c1e9ae2019-10-23 15:45:35 -07001458 ret = hdd_reassoc(adapter, bssid,
1459 wlan_chan_to_freq(params.channel), REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001460 }
1461 return ret;
1462}
1463
1464/**
1465 * hdd_parse_reassoc() - parse the REASSOC command
1466 * @adapter: Adapter upon which the command was received
1467 * @command: Command that was received
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301468 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001469 *
1470 * There are two different versions of the REASSOC command. Version 1
1471 * of the command contains a parameter list that is ASCII characters
1472 * whereas version 2 contains a combination of ASCII and binary
1473 * payload. Determine if a version 1 or a version 2 command is being
1474 * parsed by examining the parameters, and then dispatch the parser
1475 * that is appropriate for the command.
1476 *
1477 * Return: 0 for success non-zero for failure
1478 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07001479static int hdd_parse_reassoc(struct hdd_adapter *adapter, const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301480 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001481{
1482 int ret;
1483
1484 /* both versions start with "REASSOC "
1485 * v1 has a bssid and channel # as an ASCII string
1486 * REASSOC xx:xx:xx:xx:xx:xx CH
1487 * v2 has a C struct
1488 * REASSOC <binary c struct>
1489 *
1490 * The first field in the v2 struct is also the bssid in ASCII.
1491 * But in the case of a v2 message the BSSID is NUL-terminated.
1492 * Hence we can peek at that offset to see if this is V1 or V2
1493 * REASSOC xx:xx:xx:xx:xx:xx*
1494 * 1111111111222222
1495 * 01234567890123456789012345
1496 */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301497
1498 if (total_len < 26) {
1499 hdd_err("Invalid command, total_len = %d", total_len);
1500 return -EINVAL;
1501 }
1502
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001503 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001504 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001505 else
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301506 ret = hdd_parse_reassoc_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001507
1508 return ret;
1509}
1510
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001511/**
1512 * hdd_sendactionframe() - send a userspace-supplied action frame
1513 * @adapter: Adapter upon which the command was received
1514 * @bssid: BSSID target of the action frame
1515 * @channel: Channel upon which to send the frame
1516 * @dwell_time: Amount of time to dwell when the frame is sent
1517 * @payload_len:Length of the payload
1518 * @payload: Payload of the frame
1519 *
1520 * This function sends a userspace-supplied action frame
1521 *
1522 * Return: 0 for success non-zero for failure
1523 */
1524static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001525hdd_sendactionframe(struct hdd_adapter *adapter, const uint8_t *bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001526 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001527 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001528{
1529 struct ieee80211_channel chan;
Jingxiang Gece7c5472019-07-23 16:19:23 +08001530 uint8_t conn_info_channel;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001531 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001532 uint8_t *frame;
1533 struct ieee80211_hdr_3addr *hdr;
1534 u64 cookie;
Jeff Johnsond377dce2017-10-04 10:32:42 -07001535 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -07001536 struct hdd_context *hdd_ctx;
Jeff Johnsonecdf83b2019-02-26 18:33:56 -08001537 tpSirMacVendorSpecificFrameHdr vendor =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001538 (tpSirMacVendorSpecificFrameHdr) payload;
1539#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1540 struct cfg80211_mgmt_tx_params params;
1541#endif
1542
Krunal Sonibe766b02016-03-10 13:00:44 -08001543 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001544 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07001545 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001546 adapter->device_mode);
1547 return -EINVAL;
1548 }
1549
Jeff Johnsond377dce2017-10-04 10:32:42 -07001550 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001551 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1552
1553 /* if not associated, no need to send action frame */
Jeff Johnsone7951512019-02-27 10:02:51 -08001554 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001555 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001556 ret = -EINVAL;
1557 goto exit;
1558 }
1559
1560 /*
1561 * if the target bssid is different from currently associated AP,
1562 * then no need to send action frame
1563 */
Jeff Johnsone04b6992019-02-27 14:06:55 -08001564 if (memcmp(bssid, sta_ctx->conn_info.bssid.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301565 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001566 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001567 ret = -EINVAL;
1568 goto exit;
1569 }
1570
1571 chan.center_freq = sme_chn_to_freq(channel);
1572 /* Check if it is specific action frame */
Jeff Johnsonecdf83b2019-02-26 18:33:56 -08001573 if (vendor->category ==
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
Jeff Johnson2971e3a2019-02-26 18:31:54 -08001575 static const uint8_t oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001576
Jeff Johnsonecdf83b2019-02-26 18:33:56 -08001577 if (!qdf_mem_cmp(vendor->Oui, oui, 3)) {
Jingxiang Gece7c5472019-07-23 16:19:23 +08001578 conn_info_channel = wlan_reg_freq_to_chan(
1579 hdd_ctx->pdev,
Jingxiang Geae80dc62019-08-13 17:32:22 +08001580 sta_ctx->conn_info.chan_freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001581 /*
1582 * if the channel number is different from operating
1583 * channel then no need to send action frame
1584 */
1585 if (channel != 0) {
Jingxiang Gece7c5472019-07-23 16:19:23 +08001586 if (channel != conn_info_channel) {
1587 hdd_warn("channel(%u) is different from operating channel(%u)",
1588 channel,
1589 conn_info_channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001590 ret = -EINVAL;
1591 goto exit;
1592 }
1593 /*
1594 * If channel number is specified and same
1595 * as home channel, ensure that action frame
1596 * is sent immediately by cancelling
1597 * roaming scans. Otherwise large dwell times
1598 * may cause long delays in sending action
1599 * frames.
1600 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07001601 sme_abort_roam_scan(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001602 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603 } else {
1604 /*
1605 * 0 is accepted as current home channel,
1606 * delayed transmission of action frame is ok.
1607 */
Jingxiang Geae80dc62019-08-13 17:32:22 +08001608 chan.center_freq = sta_ctx->conn_info.chan_freq;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001609 }
1610 }
1611 }
1612 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001613 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614 ret = -EINVAL;
1615 goto exit;
1616 }
1617
1618 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301619 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001620 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001621 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622 ret = -ENOMEM;
1623 goto exit;
1624 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625
1626 hdr = (struct ieee80211_hdr_3addr *)frame;
1627 hdr->frame_control =
1628 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301629 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson1e851a12017-10-28 14:36:12 -07001630 qdf_mem_copy(hdr->addr2, adapter->mac_addr.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301631 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301632 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1633 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634
1635#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1636 params.chan = &chan;
1637 params.offchan = 0;
1638 params.wait = dwell_time;
1639 params.buf = frame;
1640 params.len = frame_len;
1641 params.no_cck = 1;
1642 params.dont_wait_for_ack = 1;
1643 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1644#else
1645 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001646 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001648
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001649 dwell_time, frame, frame_len, 1, 1, &cookie);
1650#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1651
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301652 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001653exit:
1654 return ret;
1655}
1656
1657/**
1658 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1659 * SENDACTIONFRAME command
1660 * @adapter: Adapter upon which the command was received
1661 * @command: ASCII text command that was received
1662 *
1663 * This function parses the v1 SENDACTIONFRAME command with the format
1664 *
1665 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1666 *
1667 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1668 * BSSID, CH is the ASCII representation of the channel, DW is the
1669 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1670 * payload. For example
1671 *
1672 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1673 *
1674 * Return: 0 for success non-zero for failure
1675 */
1676static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001677hdd_parse_sendactionframe_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001678{
1679 uint8_t channel = 0;
1680 uint8_t dwell_time = 0;
1681 uint8_t payload_len = 0;
1682 uint8_t *payload = NULL;
1683 tSirMacAddr bssid;
1684 int ret;
1685
1686 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1687 &dwell_time, &payload,
1688 &payload_len);
1689 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001690 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691 } else {
1692 ret = hdd_sendactionframe(adapter, bssid, channel,
1693 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301694 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695 }
1696
1697 return ret;
1698}
1699
1700/**
1701 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1702 * SENDACTIONFRAME command
1703 * @adapter: Adapter upon which the command was received
1704 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001705 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001706 *
1707 * This function parses the v2 SENDACTIONFRAME command with the format
1708 *
1709 * SENDACTIONFRAME <android_wifi_af_params>
1710 *
1711 * Return: 0 for success non-zero for failure
1712 */
1713static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001714hdd_parse_sendactionframe_v2(struct hdd_adapter *adapter,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001715 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716{
1717 struct android_wifi_af_params *params;
1718 tSirMacAddr bssid;
1719 int ret;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301720 int len_wo_payload = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001723 total_len -= 16;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301724 len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE;
1725 if (total_len <= len_wo_payload) {
1726 hdd_err("Invalid command len");
1727 return -EINVAL;
1728 }
1729
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001730 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001732 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301733 (params->len > (total_len - len_wo_payload))) {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001734 hdd_err("Invalid payload length: %d", params->len);
1735 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001737
1738 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1739 hdd_err("MAC address parsing failed");
1740 return -EINVAL;
1741 }
1742
1743 if (params->channel < 0 ||
1744 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1745 hdd_err("Invalid channel: %d", params->channel);
1746 return -EINVAL;
1747 }
1748
1749 if (params->dwell_time < 0) {
1750 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1751 return -EINVAL;
1752 }
1753
1754 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1755 params->dwell_time, params->len, params->data);
1756
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757 return ret;
1758}
1759
1760/**
1761 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1762 * @adapter: Adapter upon which the command was received
1763 * @command: Command that was received
1764 *
1765 * There are two different versions of the SENDACTIONFRAME command.
1766 * Version 1 of the command contains a parameter list that is ASCII
1767 * characters whereas version 2 contains a combination of ASCII and
1768 * binary payload. Determine if a version 1 or a version 2 command is
1769 * being parsed by examining the parameters, and then dispatch the
1770 * parser that is appropriate for the version of the command.
1771 *
1772 * Return: 0 for success non-zero for failure
1773 */
1774static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001775hdd_parse_sendactionframe(struct hdd_adapter *adapter, const char *command,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001776 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001777{
1778 int ret;
1779
1780 /*
1781 * both versions start with "SENDACTIONFRAME "
1782 * v1 has a bssid and other parameters as an ASCII string
1783 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1784 * v2 has a C struct
1785 * SENDACTIONFRAME <binary c struct>
1786 *
1787 * The first field in the v2 struct is also the bssid in ASCII.
1788 * But in the case of a v2 message the BSSID is NUL-terminated.
1789 * Hence we can peek at that offset to see if this is V1 or V2
1790 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1791 * 111111111122222222223333
1792 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001793 * For both the commands, a valid command must have atleast
1794 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001795 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001796 if (total_len < 34) {
1797 hdd_err("Invalid command (total_len=%d)", total_len);
1798 return -EINVAL;
1799 }
1800
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001801 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001803 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001804 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001805
1806 return ret;
1807}
1808
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001809/**
1810 * hdd_parse_channellist() - HDD Parse channel list
Liangwei Dong075afa72019-10-30 12:58:22 +08001811 * @hdd_ctx: hdd context
Jeff Johnson6636e622019-02-26 10:22:39 -08001812 * @command: Pointer to input channel list
Liangwei Dong075afa72019-10-30 12:58:22 +08001813 * @channel_freq_list: Pointer to local output array to record
Jeff Johnson6636e622019-02-26 10:22:39 -08001814 * channel list
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001815 * @num_channels: Pointer to number of roam scan channels
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001816 *
1817 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001818 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1819 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001820 * if the Number of channels (N) does not match with the actual number
1821 * of channels passed then take the minimum of N and count of
1822 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1823 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1824 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1825 * removing duplicate channels from the list
1826 *
1827 * Return: 0 for success non-zero for failure
1828 */
1829static int
Liangwei Dong075afa72019-10-30 12:58:22 +08001830hdd_parse_channellist(struct hdd_context *hdd_ctx,
1831 const uint8_t *command,
1832 uint32_t *channel_freq_list,
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001833 uint8_t *num_channels)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001834{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001835 const uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001836 int temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001837 int j = 0;
1838 int v = 0;
1839 char buf[32];
1840
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001841 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001842 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001843 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001845 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001847
1848 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001849 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1850 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001851
1852 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001853 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001855
1856 /* get the first argument ie the number of channels */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001857 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858 if (1 != v)
1859 return -EINVAL;
1860
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001861 v = kstrtos32(buf, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862 if ((v < 0) ||
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001863 (temp_int <= 0) || (temp_int > CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001864 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001865
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001866 *num_channels = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001867
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001868 hdd_debug("Number of channels are: %d", *num_channels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001869
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001870 for (j = 0; j < (*num_channels); j++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871 /*
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001872 * in_ptr pointing to the beginning of first space after number
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001873 * of channels
1874 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001875 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876 /* no channel list after the number of channels argument */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001877 if (!in_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878 if (0 != j) {
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001879 *num_channels = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001880 return 0;
1881 } else {
1882 return -EINVAL;
1883 }
1884 }
1885
1886 /* remove empty space */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001887 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1888 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001889
1890 /*
1891 * no channel list after the number of channels
1892 * argument and spaces
1893 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001894 if ('\0' == *in_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895 if (0 != j) {
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001896 *num_channels = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001897 return 0;
1898 } else {
1899 return -EINVAL;
1900 }
1901 }
1902
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001903 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001904 if (1 != v)
1905 return -EINVAL;
1906
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001907 v = kstrtos32(buf, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908 if ((v < 0) ||
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001909 (temp_int <= 0) ||
1910 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911 return -EINVAL;
1912 }
Liangwei Dong075afa72019-10-30 12:58:22 +08001913 channel_freq_list[j] =
1914 wlan_reg_chan_to_freq(hdd_ctx->pdev, temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001916 hdd_debug("Channel %d added to preferred channel list",
Liangwei Dong075afa72019-10-30 12:58:22 +08001917 channel_freq_list[j]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918 }
1919
1920 return 0;
1921}
1922
1923/**
1924 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1925 * SETROAMSCANCHANNELS command
1926 * @adapter: Adapter upon which the command was received
1927 * @command: ASCII text command that was received
1928 *
1929 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1930 *
1931 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1932 *
1933 * Where "N" is the ASCII representation of the number of channels and
1934 * C1 thru Cn is the ASCII representation of the channels. For example
1935 *
1936 * SETROAMSCANCHANNELS 4 36 40 44 48
1937 *
1938 * Return: 0 for success non-zero for failure
1939 */
1940static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001941hdd_parse_set_roam_scan_channels_v1(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001942 const char *command)
1943{
Liangwei Dong075afa72019-10-30 12:58:22 +08001944 uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301946 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001947 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948 int ret;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001949 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950
Liangwei Dong075afa72019-10-30 12:58:22 +08001951 if (!hdd_ctx) {
1952 hdd_err("invalid hdd ctx");
1953 ret = -EINVAL;
1954 goto exit;
1955 }
1956
1957 ret = hdd_parse_channellist(hdd_ctx, command, channel_freq_list,
1958 &num_chan);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001959 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001960 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001961 goto exit;
1962 }
1963
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05301964 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
1965 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001966 adapter->vdev_id, num_chan);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967
Wu Gao0821b0d2019-01-11 17:31:11 +08001968 if (num_chan > CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001969 hdd_err("number of channels (%d) supported exceeded max (%d)",
Wu Gao0821b0d2019-01-11 17:31:11 +08001970 num_chan, CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001971 ret = -EINVAL;
1972 goto exit;
1973 }
1974
Jeff Johnsond549efa2018-06-13 20:27:47 -07001975 mac_handle = hdd_ctx->mac_handle;
Liangwei Dong075afa72019-10-30 12:58:22 +08001976 if (!sme_validate_channel_list(mac_handle,
1977 channel_freq_list, num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301978 hdd_err("List contains invalid channel(s)");
1979 ret = -EINVAL;
1980 goto exit;
1981 }
1982
Jeff Johnsond549efa2018-06-13 20:27:47 -07001983 status = sme_change_roam_scan_channel_list(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001984 adapter->vdev_id,
Liangwei Dong075afa72019-10-30 12:58:22 +08001985 channel_freq_list,
1986 num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301987 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001988 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001989 ret = -EINVAL;
1990 goto exit;
1991 }
1992exit:
1993 return ret;
1994}
1995
1996/**
1997 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1998 * SETROAMSCANCHANNELS command
1999 * @adapter: Adapter upon which the command was received
2000 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07002001 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002002 *
2003 * This function parses the v2 SETROAMSCANCHANNELS command with the format
2004 *
2005 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
2006 *
2007 * The command begins with SETROAMSCANCHANNELS followed by a space, but
2008 * what follows the space is an array of u08 parameters. For example
2009 *
2010 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
2011 *
2012 * Return: 0 for success non-zero for failure
2013 */
2014static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07002015hdd_parse_set_roam_scan_channels_v2(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002016 const char *command)
2017{
2018 const uint8_t *value;
Liangwei Dong075afa72019-10-30 12:58:22 +08002019 uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020 uint8_t channel;
2021 uint8_t num_chan;
2022 int i;
Jeff Johnson621cf972017-08-28 11:58:44 -07002023 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302024 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002025 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002026 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002027
2028 /* array of values begins after "SETROAMSCANCHANNELS " */
2029 value = command + 20;
2030
2031 num_chan = *value++;
Wu Gao0821b0d2019-01-11 17:31:11 +08002032 if (num_chan > CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002033 hdd_err("number of channels (%d) supported exceeded max (%d)",
Wu Gao0821b0d2019-01-11 17:31:11 +08002034 num_chan, CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002035 ret = -EINVAL;
2036 goto exit;
2037 }
2038
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302039 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2040 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002041 adapter->vdev_id, num_chan);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302042
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043
2044 for (i = 0; i < num_chan; i++) {
2045 channel = *value++;
Nachiket Kukadecaa2e842018-05-09 17:56:12 +05302046 if (!channel) {
2047 hdd_err("Channels end at index %d, expected %d",
2048 i, num_chan);
2049 ret = -EINVAL;
2050 goto exit;
2051 }
2052
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002053 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002054 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 i, channel);
2056 ret = -EINVAL;
2057 goto exit;
2058 }
Liangwei Dong075afa72019-10-30 12:58:22 +08002059 channel_freq_list[i] = wlan_reg_chan_to_freq(hdd_ctx->pdev,
2060 channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002061 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05302062
Jeff Johnsond549efa2018-06-13 20:27:47 -07002063 mac_handle = hdd_ctx->mac_handle;
Liangwei Dong075afa72019-10-30 12:58:22 +08002064 if (!sme_validate_channel_list(mac_handle, channel_freq_list,
2065 num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05302066 hdd_err("List contains invalid channel(s)");
2067 ret = -EINVAL;
2068 goto exit;
2069 }
2070
Jeff Johnsond549efa2018-06-13 20:27:47 -07002071 status = sme_change_roam_scan_channel_list(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002072 adapter->vdev_id,
Liangwei Dong075afa72019-10-30 12:58:22 +08002073 channel_freq_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302074 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002075 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 ret = -EINVAL;
2077 goto exit;
2078 }
2079exit:
2080 return ret;
2081}
2082
2083/**
2084 * hdd_parse_set_roam_scan_channels() - parse the
2085 * SETROAMSCANCHANNELS command
2086 * @adapter: Adapter upon which the command was received
2087 * @command: Command that was received
2088 *
2089 * There are two different versions of the SETROAMSCANCHANNELS command.
2090 * Version 1 of the command contains a parameter list that is ASCII
2091 * characters whereas version 2 contains a binary payload. Determine
2092 * if a version 1 or a version 2 command is being parsed by examining
2093 * the parameters, and then dispatch the parser that is appropriate for
2094 * the command.
2095 *
2096 * Return: 0 for success non-zero for failure
2097 */
2098static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07002099hdd_parse_set_roam_scan_channels(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100{
2101 const char *cursor;
2102 char ch;
2103 bool v1;
2104 int ret;
2105
2106 /* start after "SETROAMSCANCHANNELS " */
2107 cursor = command + 20;
2108
2109 /* assume we have a version 1 command until proven otherwise */
2110 v1 = true;
2111
2112 /* v1 params will only contain ASCII digits and space */
2113 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002114 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002115 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002116 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002117
2118 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002119 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002120 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002121 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002122
2123 return ret;
2124}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002125
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002126#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002127/**
2128 * hdd_parse_plm_cmd() - HDD Parse Plm command
Jeff Johnson6636e622019-02-26 10:22:39 -08002129 * @command: Pointer to input data
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002130 * @req: Pointer to output struct plm_req
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002131 *
2132 * This function parses the plm command passed in the format
2133 * CCXPLMREQ<space><enable><space><dialog_token><space>
2134 * <meas_token><space><num_of_bursts><space><burst_int><space>
2135 * <measu duration><space><burst_len><space><desired_tx_pwr>
2136 * <space><multcast_addr><space><number_of_channels>
2137 * <space><channel_numbers>
2138 *
2139 * Return: 0 for success non-zero for failure
2140 */
Jeff Johnson6636e622019-02-26 10:22:39 -08002141static QDF_STATUS hdd_parse_plm_cmd(uint8_t *command,
Jeff Johnson36583f02019-02-26 08:02:11 -08002142 struct plm_req_params *req)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002143{
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002144 uint8_t *in_ptr = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145 int count, content = 0, ret = 0;
2146 char buf[32];
2147
2148 /* move to argument list */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002149 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Jeff Johnsond36fa332019-03-18 13:42:25 -07002150 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302151 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152
2153 /* no space after the command */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002154 if (SPACE_ASCII_VALUE != *in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302155 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002156
2157 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002158 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2159 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002160
2161 /* START/STOP PLM req */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002162 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002163 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302164 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002165
2166 ret = kstrtos32(buf, 10, &content);
2167 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302168 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002169
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002170 req->enable = content;
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002171 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002172
Jeff Johnsond36fa332019-03-18 13:42:25 -07002173 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302174 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002175
2176 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002177 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2178 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002179
2180 /* Dialog token of radio meas req containing meas reqIE */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002181 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002182 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302183 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002184
2185 ret = kstrtos32(buf, 10, &content);
2186 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302187 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002188
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002189 req->diag_token = content;
2190 hdd_debug("diag token %d", req->diag_token);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002191 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002192
Jeff Johnsond36fa332019-03-18 13:42:25 -07002193 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302194 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002195
2196 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002197 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2198 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002199
2200 /* measurement token of meas req IE */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002201 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002202 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302203 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002204
2205 ret = kstrtos32(buf, 10, &content);
2206 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302207 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002208
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002209 req->meas_token = content;
2210 hdd_debug("meas token %d", req->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002212 hdd_debug("PLM req %s", req->enable ? "START" : "STOP");
2213 if (req->enable) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002214
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002215 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002216
Jeff Johnsond36fa332019-03-18 13:42:25 -07002217 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302218 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002219
2220 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002221 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2222 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002223
2224 /* total number of bursts after which STA stops sending */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002225 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002226 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302227 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002228
2229 ret = kstrtos32(buf, 10, &content);
2230 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302231 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002232
2233 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302234 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002235
Jeff Johnson36583f02019-02-26 08:02:11 -08002236 req->num_bursts = content;
2237 hdd_debug("num bursts %d", req->num_bursts);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002238 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002239
Jeff Johnsond36fa332019-03-18 13:42:25 -07002240 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302241 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002242
2243 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002244 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2245 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002246
2247 /* burst interval in seconds */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002248 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002249 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302250 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002251
2252 ret = kstrtos32(buf, 10, &content);
2253 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302254 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002255
2256 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302257 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002258
Jeff Johnson36583f02019-02-26 08:02:11 -08002259 req->burst_int = content;
2260 hdd_debug("burst int %d", req->burst_int);
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 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
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->meas_duration = content;
2283 hdd_debug("meas duration %d", req->meas_duration);
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 length of PLM bursts */
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_len = content;
2306 hdd_debug("burst len %d", req->burst_len);
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 /* desired tx power for transmission of 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->desired_tx_pwr = content;
2329 hdd_debug("desired tx pwr %d", req->desired_tx_pwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002330
Anurag Chouhan6d760662016-02-20 16:05:43 +05302331 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002332 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002333
Jeff Johnsond36fa332019-03-18 13:42:25 -07002334 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302335 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002336
2337 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002338 while ((SPACE_ASCII_VALUE == *in_ptr)
2339 && ('\0' != *in_ptr))
2340 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002341
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002342 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002343 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302344 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002345
2346 ret = kstrtos32(buf, 16, &content);
2347 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302348 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002349
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08002350 req->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002351 }
2352
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -07002353 hdd_debug("MAC addr " QDF_MAC_ADDR_STR,
Srinivas Girigowda34fbba02019-04-08 12:07:44 -07002354 QDF_MAC_ADDR_ARRAY(req->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002355
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002356 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002357
Jeff Johnsond36fa332019-03-18 13:42:25 -07002358 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302359 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002360
2361 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002362 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2363 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002364
2365 /* number of channels */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002366 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002367 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302368 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002369
2370 ret = kstrtos32(buf, 10, &content);
2371 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302372 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373
2374 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302375 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002376
Wu Gao0821b0d2019-01-11 17:31:11 +08002377 content = QDF_MIN(content, CFG_VALID_CHANNEL_LIST_LEN);
Jeff Johnson36583f02019-02-26 08:02:11 -08002378 req->plm_num_ch = content;
2379 hdd_debug("num ch: %d", req->plm_num_ch);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002380
2381 /* Channel numbers */
Jeff Johnson36583f02019-02-26 08:02:11 -08002382 for (count = 0; count < req->plm_num_ch; count++) {
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002383 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002384
Jeff Johnsond36fa332019-03-18 13:42:25 -07002385 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302386 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002387
2388 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002389 while ((SPACE_ASCII_VALUE == *in_ptr)
2390 && ('\0' != *in_ptr))
2391 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002392
Jeff Johnson4fab64d2019-02-26 13:06:31 -08002393 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002394 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302395 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002396
2397 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07002398 if (ret < 0 || content <= 0 ||
2399 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302400 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002401
wadesong88aa89a2019-11-04 12:34:12 +08002402 req->plm_ch_freq_list[count] =
2403 cds_chan_to_freq(content);
2404 hdd_debug(" ch-freq- %d", req->plm_ch_freq_list[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002405 }
2406 }
2407 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302408 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002409}
2410#endif
2411
2412#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302413/**
2414 * wlan_hdd_ready_to_extwow() - Callback function for enable ext wow
2415 * @cookie: callback context
2416 * @is_success: suspend status of ext wow
2417 *
2418 * Return: none
2419 */
2420static void wlan_hdd_ready_to_extwow(void *cookie, bool is_success)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002421{
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302422 struct osif_request *request = NULL;
2423 struct enable_ext_wow_priv *priv = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002424
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302425 request = osif_request_get(cookie);
2426 if (!request) {
2427 hdd_err("Obselete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002428 return;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302429 }
2430 priv = osif_request_priv(request);
2431 priv->ext_wow_should_suspend = is_success;
2432
2433 osif_request_complete(request);
2434 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002435}
2436
Jeff Johnsone44b7012017-09-10 15:25:47 -07002437static int hdd_enable_ext_wow(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002438 tpSirExtWoWParams arg_params)
2439{
2440 tSirExtWoWParams params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002441 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07002442 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002443 int rc;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302444 struct enable_ext_wow_priv *priv = NULL;
2445 struct osif_request *request = NULL;
2446 void *cookie = NULL;
2447 struct osif_request_params hdd_params = {
2448 .priv_size = sizeof(*priv),
2449 .timeout_ms = WLAN_WAIT_TIME_READY_TO_EXTWOW,
2450 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002451
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302452 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002453
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302454 request = osif_request_alloc(&hdd_params);
2455 if (!request) {
2456 hdd_err("Request Allocation Failure");
2457 return -ENOMEM;
2458 }
2459 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002460
Jeff Johnsond549efa2018-06-13 20:27:47 -07002461 status = sme_configure_ext_wow(hdd_ctx->mac_handle, &params,
2462 &wlan_hdd_ready_to_extwow,
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302463 cookie);
Jeff Johnsond549efa2018-06-13 20:27:47 -07002464 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002465 hdd_err("sme_configure_ext_wow returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07002466 status);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302467 rc = -EPERM;
2468 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002469 }
2470
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302471 rc = osif_request_wait_for_response(request);
2472 if (rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002473 hdd_err("Failed to get ready to extwow");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302474 rc = -EPERM;
2475 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002476 }
2477
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302478 priv = osif_request_priv(request);
2479 if (!priv->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002480 hdd_err("Received ready to ExtWoW failure");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302481 rc = -EPERM;
2482 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002483 }
2484
Wu Gao66454f12018-09-26 19:55:41 +08002485 if (ucfg_pmo_extwow_is_goto_suspend_enabled(hdd_ctx->psoc)) {
Jeff Johnson17d62672017-03-27 08:00:11 -07002486 hdd_info("Received ready to ExtWoW. Going to suspend");
2487
2488 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
2489 if (rc < 0) {
2490 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
2491 rc);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302492 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07002493 }
2494 rc = wlan_hdd_bus_suspend();
2495 if (rc) {
2496 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
2497 rc);
2498 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302499 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07002500 }
2501 }
Wu Gao66454f12018-09-26 19:55:41 +08002502
Dundi Raviteja53de6c32018-05-16 16:56:30 +05302503exit:
2504 osif_request_put(request);
2505 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002506}
2507
Jeff Johnsone44b7012017-09-10 15:25:47 -07002508static int hdd_enable_ext_wow_parser(struct hdd_adapter *adapter, int vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002509 int value)
2510{
2511 tSirExtWoWParams params;
Jeff Johnson621cf972017-08-28 11:58:44 -07002512 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002513 int rc;
Wu Gao66454f12018-09-26 19:55:41 +08002514 uint8_t pin1, pin2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002515
2516 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302517 if (rc)
2518 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002519
2520 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
2521 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002522 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002523 return -EINVAL;
2524 }
2525
2526 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
2527 hdd_ctx->is_extwow_app_type1_param_set)
2528 params.type = value;
2529 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
2530 hdd_ctx->is_extwow_app_type2_param_set)
2531 params.type = value;
2532 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
2533 hdd_ctx->is_extwow_app_type1_param_set &&
2534 hdd_ctx->is_extwow_app_type2_param_set)
2535 params.type = value;
2536 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002537 hdd_err("Set app params before enable it value %d",
2538 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002539 return -EINVAL;
2540 }
2541
2542 params.vdev_id = vdev_id;
Wu Gao66454f12018-09-26 19:55:41 +08002543 pin1 = ucfg_pmo_extwow_app1_wakeup_pin_num(hdd_ctx->psoc);
2544 pin2 = ucfg_pmo_extwow_app2_wakeup_pin_num(hdd_ctx->psoc);
2545 params.wakeup_pin_num = pin1 | (pin2 << 8);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002546
2547 return hdd_enable_ext_wow(adapter, &params);
2548}
2549
Jeff Johnsond549efa2018-06-13 20:27:47 -07002550static int hdd_set_app_type1_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002551 tpSirAppType1Params arg_params)
2552{
2553 tSirAppType1Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002554 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002555
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302556 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002557
Jeff Johnsond549efa2018-06-13 20:27:47 -07002558 status = sme_configure_app_type1_params(mac_handle, &params);
2559 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002560 hdd_err("sme_configure_app_type1_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07002561 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002562 return -EPERM;
2563 }
2564
2565 return 0;
2566}
2567
Jeff Johnsone44b7012017-09-10 15:25:47 -07002568static int hdd_set_app_type1_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002569 char *arg, int len)
2570{
Jeff Johnson621cf972017-08-28 11:58:44 -07002571 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002572 char id[20], password[20];
2573 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002574 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002575
2576 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302577 if (rc)
2578 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002579
2580 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002581 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002582 return -EINVAL;
2583 }
2584
2585 memset(&params, 0, sizeof(tSirAppType1Params));
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002586 params.vdev_id = adapter->vdev_id;
Jeff Johnson1e851a12017-10-28 14:36:12 -07002587 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002588
2589 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302590 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002591 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302592 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002593
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002594 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002595 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002596 params.identification_id, params.id_length,
2597 params.password, params.pass_length);
2598
Jeff Johnsond549efa2018-06-13 20:27:47 -07002599 return hdd_set_app_type1_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002600}
2601
Jeff Johnsond549efa2018-06-13 20:27:47 -07002602static int hdd_set_app_type2_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002603 tpSirAppType2Params arg_params)
2604{
2605 tSirAppType2Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07002606 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002607
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302608 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002609
Jeff Johnsond549efa2018-06-13 20:27:47 -07002610 status = sme_configure_app_type2_params(mac_handle, &params);
2611 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002612 hdd_err("sme_configure_app_type2_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07002613 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002614 return -EPERM;
2615 }
2616
2617 return 0;
2618}
2619
Jeff Johnsone44b7012017-09-10 15:25:47 -07002620static int hdd_set_app_type2_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002621 char *arg, int len)
2622{
Jeff Johnson621cf972017-08-28 11:58:44 -07002623 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002624 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302625 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002626 tSirAppType2Params params;
2627 int ret;
2628
2629 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302630 if (ret)
2631 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002632
2633 memset(&params, 0, sizeof(tSirAppType2Params));
2634
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302635 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 -08002636 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2637 (unsigned int *)&params.ip_device_ip,
2638 (unsigned int *)&params.ip_server_ip,
2639 (unsigned int *)&params.tcp_seq,
2640 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302641 (uint16_t *)&params.tcp_src_port,
2642 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002643 (unsigned int *)&params.keepalive_init,
2644 (unsigned int *)&params.keepalive_min,
2645 (unsigned int *)&params.keepalive_max,
2646 (unsigned int *)&params.keepalive_inc,
2647 (unsigned int *)&params.tcp_tx_timeout_val,
2648 (unsigned int *)&params.tcp_rx_timeout_val);
2649
2650 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002651 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002652 return -EINVAL;
2653 }
2654
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -07002655 if (6 != sscanf(mac_addr, QDF_MAC_ADDR_STR,
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002656 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2657 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002658 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002659 return -EINVAL;
2660 }
2661
2662 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2663 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002664 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002665 return -EINVAL;
2666 }
2667
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302668 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302669 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002670
2671 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302672 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002673
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002674 params.vdev_id = adapter->vdev_id;
Wu Gao66454f12018-09-26 19:55:41 +08002675
2676 if (!params.tcp_src_port)
2677 params.tcp_src_port =
2678 ucfg_pmo_extwow_app2_tcp_src_port(hdd_ctx->psoc);
2679
2680 if (!params.tcp_dst_port)
2681 params.tcp_dst_port =
2682 ucfg_pmo_extwow_app2_tcp_dst_port(hdd_ctx->psoc);
2683
2684 if (!params.keepalive_init)
2685 params.keepalive_init =
2686 ucfg_pmo_extwow_app2_init_ping_interval(hdd_ctx->psoc);
2687
2688 if (!params.keepalive_min)
2689 params.keepalive_min =
2690 ucfg_pmo_extwow_app2_min_ping_interval(hdd_ctx->psoc);
2691
2692 if (!params.keepalive_max)
2693 params.keepalive_max =
2694 ucfg_pmo_extwow_app2_max_ping_interval(hdd_ctx->psoc);
2695
2696 if (!params.keepalive_inc)
2697 params.keepalive_inc =
2698 ucfg_pmo_extwow_app2_inc_ping_interval(hdd_ctx->psoc);
2699
2700 if (!params.tcp_tx_timeout_val)
2701 params.tcp_tx_timeout_val =
2702 ucfg_pmo_extwow_app2_tcp_tx_timeout(hdd_ctx->psoc);
2703
2704 if (!params.tcp_rx_timeout_val)
2705 params.tcp_rx_timeout_val =
2706 ucfg_pmo_extwow_app2_tcp_rx_timeout(hdd_ctx->psoc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002707
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002708 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002709 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002710 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2711 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2712 params.keepalive_init, params.keepalive_min,
2713 params.keepalive_max, params.keepalive_inc,
2714 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2715
Jeff Johnsond549efa2018-06-13 20:27:47 -07002716 return hdd_set_app_type2_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002717}
2718#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2719
2720/**
2721 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
Jeff Johnson6636e622019-02-26 10:22:39 -08002722 * @command: Pointer to MAXTXPOWER command
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002723 * @tx_power: Pointer to tx power
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002724 *
2725 * This function parses the MAXTXPOWER command passed in the format
2726 * MAXTXPOWER<space>X(Tx power in dbm)
2727 *
2728 * For example input commands:
2729 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2730 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2731 *
2732 * Return: 0 for success non-zero for failure
2733 */
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002734static int hdd_parse_setmaxtxpower_command(uint8_t *command, int *tx_power)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002735{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002736 uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002737 int temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002738 int v = 0;
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002739 *tx_power = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002740
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002741 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07002743 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002744 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002745 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002746 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002747
2748 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002749 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2750 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002751
2752 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002753 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002754 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002755
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002756 v = kstrtos32(in_ptr, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002757
2758 /* Range checking for passed parameter */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002759 if ((temp_int < HDD_MIN_TX_POWER) || (temp_int > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002760 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002761
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002762 *tx_power = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002763
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002764 hdd_debug("SETMAXTXPOWER: %d", *tx_power);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002765
2766 return 0;
2767} /* End of hdd_parse_setmaxtxpower_command */
2768
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302769static int hdd_get_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002770 char *extra, uint8_t n, uint8_t *len)
2771{
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302772 uint32_t val = 0;
2773
2774 if (!psoc || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002775 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002776 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002777 }
2778
2779 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302780 ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
2781 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n", val);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002782 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002783 }
Jeff Johnson68755312017-02-10 11:46:55 -08002784 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302785 ucfg_scan_cfg_get_passive_dwelltime(psoc, &val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002786 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302787 val);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002788 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002789 }
Jeff Johnson68755312017-02-10 11:46:55 -08002790 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302791 ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
2792 *len = scnprintf(extra, n, "GETDWELLTIME %u\n", val);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002793 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002794 }
2795
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002796 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002797}
2798
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302799static int hdd_set_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002800{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002801 uint8_t *value = command;
Srinivas Girigowdaa9ce5e62019-03-28 13:44:31 -07002802 int retval = 0, temp = 0;
2803 uint32_t val = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002804
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302805 if (!psoc) {
2806 hdd_err("psoc is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002807 return -EINVAL;
2808 }
2809
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002810 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302811 if (drv_cmd_validate(command, 23))
2812 return -EINVAL;
2813
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002814 value = value + 24;
2815 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302816 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002817 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302818 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002819 }
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302820 ucfg_scan_cfg_set_active_dwelltime(psoc, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002821 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302822 if (drv_cmd_validate(command, 24))
2823 return -EINVAL;
2824
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002825 value = value + 25;
2826 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302827 if (temp || !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002828 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302829 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002830 }
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302831 ucfg_scan_cfg_set_passive_dwelltime(psoc, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002832 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302833 if (drv_cmd_validate(command, 12))
2834 return -EINVAL;
2835
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836 value = value + 13;
2837 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302838 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002839 hdd_err("argument passed for SETDWELLTIME is incorrect");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302840 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002841 }
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302842 ucfg_scan_cfg_set_active_dwelltime(psoc, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002843 } else {
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302844 retval = -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002845 }
2846
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302847 return retval;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002848}
2849
Jeff Johnson253c0c22017-01-23 16:59:38 -08002850struct link_status_priv {
2851 uint8_t link_status;
2852};
2853
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302854/**
2855 * hdd_conc_set_dwell_time() - Set Concurrent dwell time parameters
2856 * @adapter: Adapter upon which the command was received
2857 * @command: ASCII text command that is received
2858 *
2859 * Driver commands:
2860 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MAX <value>
2861 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MIN <value>
2862 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MAX <value>
2863 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MIN <value>
2864 *
2865 * Return: 0 for success non-zero for failure
2866 */
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05302867static int hdd_conc_set_dwell_time(struct hdd_adapter *adapter,
2868 uint8_t *command)
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302869{
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302870 u8 *value = command;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302871 int val = 0, temp = 0;
2872 int retval = 0;
2873
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302874 if (strncmp(command, "CONCSETDWELLTIME ACTIVE MAX", 27) == 0) {
2875 if (drv_cmd_validate(command, 27)) {
2876 hdd_err("Invalid driver command");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302877 return -EINVAL;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302878 }
2879
2880 value = value + 28;
2881 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302882 if (temp ||
2883 !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC, val)) {
Harprit Chhabada4691a472018-12-07 11:22:48 -08002884 hdd_err("CONC ACTIVE MAX value %d incorrect", val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302885 return -EFAULT;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302886 }
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05302887 ucfg_scan_cfg_set_conc_active_dwelltime(
2888 (WLAN_HDD_GET_CTX(adapter))->psoc, val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302889 } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MAX", 28) == 0) {
2890 if (drv_cmd_validate(command, 28)) {
2891 hdd_err("Invalid driver command");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302892 return -EINVAL;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302893 }
2894
2895 value = value + 29;
2896 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302897 if (temp ||
2898 !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC, val)) {
Harprit Chhabada4691a472018-12-07 11:22:48 -08002899 hdd_err("CONC PASSIVE MAX val %d incorrect", val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302900 return -EFAULT;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302901 }
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05302902 ucfg_scan_cfg_set_conc_passive_dwelltime(
2903 (WLAN_HDD_GET_CTX(adapter))->psoc, val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302904 } else {
2905 retval = -EINVAL;
2906 }
2907
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302908 return retval;
2909}
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302910
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002911static void hdd_get_link_status_cb(uint8_t status, void *context)
2912{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002913 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002914 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002915
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002916 request = osif_request_get(context);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002917 if (!request) {
2918 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002919 return;
2920 }
2921
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002922 priv = osif_request_priv(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002923 priv->link_status = status;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002924 osif_request_complete(request);
2925 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002926}
2927
2928/**
2929 * wlan_hdd_get_link_status() - get link status
Jeff Johnson25c77342017-10-02 13:28:03 -07002930 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002931 *
2932 * This function sends a request to query the link status and waits
2933 * on a timer to invoke the callback. if the callback is invoked then
2934 * latest link status shall be returned or otherwise cached value
2935 * will be returned.
2936 *
2937 * Return: On success, link status shall be returned.
2938 * On error or not associated, link status 0 will be returned.
2939 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002940static int wlan_hdd_get_link_status(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002941{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002942 struct hdd_station_ctx *sta_ctx;
2943 QDF_STATUS status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002944 int ret;
2945 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002946 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002947 struct link_status_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002948 static const struct osif_request_params params = {
Jeff Johnson253c0c22017-01-23 16:59:38 -08002949 .priv_size = sizeof(*priv),
2950 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2951 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002952
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05302953 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002954 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2955 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002956 return 0;
2957 }
2958
Krunal Sonibe766b02016-03-10 13:00:44 -08002959 if ((QDF_STA_MODE != adapter->device_mode) &&
2960 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002961 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07002962 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002963 adapter->device_mode);
2964 return 0;
2965 }
2966
Jeff Johnsond377dce2017-10-04 10:32:42 -07002967 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsone7951512019-02-27 10:02:51 -08002968 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002969 /* If not associated, then expected link status return
2970 * value is 0
2971 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002972 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002973 return 0;
2974 }
2975
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002976 request = osif_request_alloc(&params);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002977 if (!request) {
2978 hdd_err("Request allocation failure");
2979 return 0;
2980 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002981 cookie = osif_request_cookie(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002982
Jeff Johnsond549efa2018-06-13 20:27:47 -07002983 status = sme_get_link_status(adapter->hdd_ctx->mac_handle,
2984 hdd_get_link_status_cb,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002985 cookie, adapter->vdev_id);
Jeff Johnsond549efa2018-06-13 20:27:47 -07002986 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002987 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002988 /* return a cached value */
2989 } else {
2990 /* request is sent -- wait for the response */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002991 ret = osif_request_wait_for_response(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002992 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002993 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002994 /* return a cached value */
2995 } else {
2996 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002997 priv = osif_request_priv(request);
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07002998 adapter->link_status = priv->link_status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002999 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003000 }
3001
Jeff Johnson253c0c22017-01-23 16:59:38 -08003002 /*
3003 * either we never sent a request, we sent a request and
3004 * received a response or we sent a request and timed out.
3005 * regardless we are done with the request.
3006 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07003007 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003008
3009 /* either callback updated adapter stats or it has cached data */
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07003010 return adapter->link_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003011}
3012
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08003013#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014/**
3015 * hdd_parse_ese_beacon_req() - Parse ese beacon request
Jeff Johnson6636e622019-02-26 10:22:39 -08003016 * @command: Pointer to data
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003017 * @req: Output pointer to store parsed ie information
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 *
3019 * This function parses the ese beacon request passed in the format
3020 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
3021 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
3022 * <space>Scan Mode N<space>Meas Duration N
3023 *
3024 * If the Number of bcn req fields (N) does not match with the
3025 * actual number of fields passed then take N.
3026 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
3027 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
3028 * This function does not take care of removing duplicate channels from the
3029 * list
3030 *
3031 * Return: 0 for success non-zero for failure
3032 */
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05303033static int hdd_parse_ese_beacon_req(struct wlan_objmgr_pdev *pdev,
3034 uint8_t *command,
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003035 tCsrEseBeaconReq *req)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003036{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003037 uint8_t *in_ptr = command;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003038 uint8_t input = 0;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003039 uint32_t temp_int = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003040 int j = 0, i = 0, v = 0;
3041 char buf[32];
3042
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003043 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Jeff Johnsond36fa332019-03-18 13:42:25 -07003044 if (!in_ptr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003045 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003046 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003047 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003048
3049 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003050 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
3051 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003052
3053 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003054 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055 return -EINVAL;
3056
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07003057 /* Getting the first argument ie Number of IE fields */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003058 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003059 if (1 != v)
3060 return -EINVAL;
3061
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003062 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003063 if (v < 0)
3064 return -EINVAL;
3065
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003066 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003067 req->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003068
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003069 hdd_debug("Number of Bcn Req Ie fields: %d", req->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003070
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003071 for (j = 0; j < (req->numBcnReqIe); j++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003072 for (i = 0; i < 4; i++) {
3073 /*
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003074 * in_ptr pointing to the beginning of 1st space
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003075 * after number of ie fields
3076 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003077 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003078 /* no ie data after the number of ie fields argument */
Jeff Johnsond36fa332019-03-18 13:42:25 -07003079 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003080 return -EINVAL;
3081
3082 /* remove empty space */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003083 while ((SPACE_ASCII_VALUE == *in_ptr)
3084 && ('\0' != *in_ptr))
3085 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003086
3087 /*
3088 * no ie data after the number of ie fields
3089 * argument and spaces
3090 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003091 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003092 return -EINVAL;
3093
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003094 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003095 if (1 != v)
3096 return -EINVAL;
3097
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003098 v = kstrtou32(buf, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003099 if (v < 0)
3100 return -EINVAL;
3101
3102 switch (i) {
3103 case 0: /* Measurement token */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003104 if (!temp_int) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003105 hdd_err("Invalid Measurement Token: %u",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003106 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003107 return -EINVAL;
3108 }
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003109 req->bcnReq[j].measurementToken =
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003110 temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003111 break;
3112
3113 case 1: /* Channel number */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003114 if (!temp_int ||
3115 (temp_int >
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003116 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003117 hdd_err("Invalid Channel Number: %u",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003118 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003119 return -EINVAL;
3120 }
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05303121 req->bcnReq[j].ch_freq =
3122 wlan_reg_chan_to_freq(pdev, temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003123 break;
3124
3125 case 2: /* Scan mode */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003126 if ((temp_int < eSIR_PASSIVE_SCAN)
3127 || (temp_int > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003128 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003129 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003130 return -EINVAL;
3131 }
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003132 req->bcnReq[j].scanMode = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003133 break;
3134
3135 case 3: /* Measurement duration */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003136 if ((!temp_int
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003137 && (req->bcnReq[j].scanMode !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003138 eSIR_BEACON_TABLE)) ||
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003139 (req->bcnReq[j].scanMode ==
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07003140 eSIR_BEACON_TABLE)) {
3141 hdd_err("Invalid Measurement Duration: %u",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003142 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003143 return -EINVAL;
3144 }
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003145 req->bcnReq[j].measurementDuration =
Jeff Johnsoncd361c92019-02-26 19:23:49 -08003146 temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003147 break;
3148 }
3149 }
3150 }
3151
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003152 for (j = 0; j < req->numBcnReqIe; j++) {
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05303153 hdd_debug("Index: %d Measurement Token: %u ch_freq: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003154 j,
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003155 req->bcnReq[j].measurementToken,
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05303156 req->bcnReq[j].ch_freq,
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08003157 req->bcnReq[j].scanMode,
3158 req->bcnReq[j].measurementDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003159 }
3160
3161 return 0;
3162}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003163
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003164/**
3165 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
Jeff Johnson6636e622019-02-26 10:22:39 -08003166 * @command: Pointer to input data
Jeff Johnson64c01b12019-02-26 13:12:50 -08003167 * @cckm_ie: Pointer to output cckm Ie
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003168 * @cckm_ie_len: Pointer to output cckm ie length
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003169 *
3170 * This function parses the SETCCKM IE command
3171 * SETCCKMIE<space><ie data>
3172 *
3173 * Return: 0 for success non-zero for failure
3174 */
Jeff Johnson64c01b12019-02-26 13:12:50 -08003175static int hdd_parse_get_cckm_ie(uint8_t *command, uint8_t **cckm_ie,
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003176 uint8_t *cckm_ie_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003177{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003178 uint8_t *in_ptr = command;
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08003179 uint8_t *end_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003180 int j = 0;
3181 int i = 0;
Jeff Johnson72f498b2019-02-26 18:37:25 -08003182 uint8_t temp_u8 = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07003183
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003184 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003185 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07003186 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003187 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003188 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003189 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07003190
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003191 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003192 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
3193 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003194 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003195 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003196 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07003197
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003198 /* find the length of data */
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08003199 end_ptr = in_ptr;
3200 while (('\0' != *end_ptr)) {
3201 end_ptr++;
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003202 ++(*cckm_ie_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003203 }
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003204 if (*cckm_ie_len <= 0)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003205 return -EINVAL;
3206 /*
3207 * Allocate the number of bytes based on the number of input characters
3208 * whether it is even or odd.
3209 * if the number of input characters are even, then we need N / 2 byte.
3210 * if the number of input characters are odd, then we need do
3211 * (N + 1) / 2 to compensate rounding off.
3212 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
3213 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
3214 */
Jeff Johnson64c01b12019-02-26 13:12:50 -08003215 *cckm_ie = qdf_mem_malloc((*cckm_ie_len + 1) / 2);
Jeff Johnsond36fa332019-03-18 13:42:25 -07003216 if (!*cckm_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003217 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003218 return -ENOMEM;
3219 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003220 /*
3221 * the buffer received from the upper layer is character buffer,
3222 * we need to prepare the buffer taking 2 characters in to a U8 hex
3223 * decimal number for example 7f0000f0...form a buffer to contain
3224 * 7f in 0th location, 00 in 1st and f0 in 3rd location
3225 */
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003226 for (i = 0, j = 0; j < *cckm_ie_len; j += 2) {
Jeff Johnson72f498b2019-02-26 18:37:25 -08003227 temp_u8 = (hex_to_bin(in_ptr[j]) << 4) |
Jeff Johnson4ff36b22019-02-26 13:01:07 -08003228 (hex_to_bin(in_ptr[j + 1]));
Jeff Johnson72f498b2019-02-26 18:37:25 -08003229 (*cckm_ie)[i++] = temp_u8;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003230 }
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08003231 *cckm_ie_len = i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003232 return 0;
3233}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08003234#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003235
Jeff Johnsonb3f80432019-02-26 20:25:38 -08003236int wlan_hdd_set_mc_rate(struct hdd_adapter *adapter, int target_rate)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003237{
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08003238 tSirRateUpdateInd rate_update = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303239 QDF_STATUS status;
Jeff Johnson25c77342017-10-02 13:28:03 -07003240 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05303241 bool bval = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003242
Jeff Johnsond36fa332019-03-18 13:42:25 -07003243 if (!hdd_ctx) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003244 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003245 return -EINVAL;
3246 }
Jeff Johnson25c77342017-10-02 13:28:03 -07003247 if ((QDF_IBSS_MODE != adapter->device_mode) &&
3248 (QDF_SAP_MODE != adapter->device_mode) &&
3249 (QDF_STA_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003250 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07003251 qdf_opmode_str(adapter->device_mode),
3252 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003253 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003254 return -EINVAL;
3255 }
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05303256
3257 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
3258 if (!QDF_IS_STATUS_SUCCESS(status)) {
3259 hdd_err("unable to get vht_enable2x2");
3260 return -EINVAL;
3261 }
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08003262 rate_update.nss = (bval == 0) ? 0 : 1;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05303263
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08003264 rate_update.dev_mode = adapter->device_mode;
3265 rate_update.mcastDataRate24GHz = target_rate;
3266 rate_update.mcastDataRate24GHzTxFlag = 1;
3267 rate_update.mcastDataRate5GHz = target_rate;
3268 rate_update.bcastDataRate = -1;
3269 qdf_copy_macaddr(&rate_update.bssid, &adapter->mac_addr);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003270 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08003271 rate_update.mcastDataRate24GHz, rate_update.bssid.bytes,
Dustin Brown458027c2018-10-19 12:26:27 -07003272 qdf_opmode_str(adapter->device_mode), adapter->device_mode);
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08003273 status = sme_send_rate_update_ind(hdd_ctx->mac_handle, &rate_update);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303274 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003275 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003276 return -EFAULT;
3277 }
3278 return 0;
3279}
3280
Jeff Johnsone44b7012017-09-10 15:25:47 -07003281static int drv_cmd_p2p_dev_addr(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003282 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003283 uint8_t *command,
3284 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003285 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003286{
Dustin Brownee220712018-04-19 16:24:23 -07003287 struct qdf_mac_addr *addr = &hdd_ctx->p2p_device_address;
3288 size_t user_size = qdf_min(sizeof(addr->bytes),
3289 (size_t)priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003290
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303291 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3292 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003293 adapter->vdev_id,
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303294 (unsigned int)(*(addr->bytes + 2) << 24 |
Dustin Brownee220712018-04-19 16:24:23 -07003295 *(addr->bytes + 3) << 16 |
3296 *(addr->bytes + 4) << 8 |
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303297 *(addr->bytes + 5)));
3298
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003299
Dustin Brownee220712018-04-19 16:24:23 -07003300 if (copy_to_user(priv_data->buf, addr->bytes, user_size)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003301 hdd_err("failed to copy data to user buffer");
Dustin Brownee220712018-04-19 16:24:23 -07003302 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003303 }
3304
Dustin Brownee220712018-04-19 16:24:23 -07003305 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003306}
3307
3308/**
3309 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
3310 * @adapter: Adapter on which the command was received
3311 * @hdd_ctx: HDD global context
3312 * @command: Entire driver command received from userspace
3313 * @command_len: Length of @command
3314 * @priv_data: Pointer to ioctl private data structure
3315 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07003316 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003317 * command to the actual command processor within the P2P module.
3318 *
3319 * Return: 0 on success, non-zero on failure
3320 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07003321static int drv_cmd_p2p_set_noa(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003322 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003323 uint8_t *command,
3324 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003325 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003326{
3327 return hdd_set_p2p_noa(adapter->dev, command);
3328}
3329
3330/**
3331 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
3332 * @adapter: Adapter on which the command was received
3333 * @hdd_ctx: HDD global context
3334 * @command: Entire driver command received from userspace
3335 * @command_len: Length of @command
3336 * @priv_data: Pointer to ioctl private data structure
3337 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07003338 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003339 * command to the actual command processor within the P2P module.
3340 *
3341 * Return: 0 on success, non-zero on failure
3342 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07003343static int drv_cmd_p2p_set_ps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003344 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003345 uint8_t *command,
3346 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003347 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003348{
3349 return hdd_set_p2p_opps(adapter->dev, command);
3350}
3351
Jeff Johnsone44b7012017-09-10 15:25:47 -07003352static int drv_cmd_set_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003353 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003354 uint8_t *command,
3355 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003356 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003357{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07003358 int err;
3359 uint8_t band;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003360
3361 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07003362 * Parse the band value passed from userspace. The first 8 bytes
3363 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07003365 err = kstrtou8(command + command_len + 1, 10, &band);
3366 if (err) {
3367 hdd_err("error %d parsing userspace band parameter", err);
3368 return err;
3369 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003370
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07003371 return hdd_reg_set_band(adapter->dev, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003372}
3373
Jeff Johnsone44b7012017-09-10 15:25:47 -07003374static int drv_cmd_set_wmmps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003375 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003376 uint8_t *command,
3377 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003378 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003379{
3380 return hdd_wmmps_helper(adapter, command);
3381}
3382
Jeff Johnsone44b7012017-09-10 15:25:47 -07003383static inline int drv_cmd_country(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003384 struct hdd_context *hdd_ctx,
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07003385 uint8_t *command,
3386 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003387 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003388{
Sourav Mohapatraa30c4572018-05-22 11:18:39 +05303389 char *country_code;
3390
3391 country_code = strnchr(command, strlen(command), ' ');
3392 /* no argument after the command */
3393 if (!country_code)
3394 return -EINVAL;
3395
3396 /* no space after the command */
3397 if (*country_code != SPACE_ASCII_VALUE)
3398 return -EINVAL;
3399
3400 country_code++;
3401
3402 /* removing empty spaces */
3403 while ((*country_code == SPACE_ASCII_VALUE) &&
3404 (*country_code != '\0'))
3405 country_code++;
3406
3407 /* no or less than 2 arguments followed by spaces */
3408 if (*country_code == '\0' || *(country_code + 1) == '\0')
3409 return -EINVAL;
3410
3411 return hdd_reg_set_country(hdd_ctx, country_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003412}
3413
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +05303414/**
3415 * drv_cmd_get_country() - Helper function to get current county code
3416 * @adapter: pointer to adapter on which request is received
3417 * @hdd_ctx: pointer to hdd context
3418 * @command: command name
3419 * @command_len: command buffer length
3420 * @priv_data: output pointer to hold current country code
3421 *
3422 * Return: On success 0, negative value on error.
3423 */
3424static int drv_cmd_get_country(struct hdd_adapter *adapter,
3425 struct hdd_context *hdd_ctx,
3426 uint8_t *command, uint8_t command_len,
3427 struct hdd_priv_data *priv_data)
3428{
3429 uint8_t buf[SIZE_OF_GETCOUNTRYREV_OUTPUT] = {0};
3430 uint8_t cc[REG_ALPHA2_LEN + 1];
3431 int ret = 0, len;
3432
3433 qdf_mem_copy(cc, hdd_ctx->reg.alpha2, REG_ALPHA2_LEN);
3434 cc[REG_ALPHA2_LEN] = '\0';
3435
3436 len = scnprintf(buf, sizeof(buf), "%s %s",
3437 "GETCOUNTRYREV", cc);
3438 hdd_debug("buf = %s", buf);
3439 len = QDF_MIN(priv_data->total_len, len + 1);
3440 if (copy_to_user(priv_data->buf, buf, len)) {
3441 hdd_err("failed to copy data to user buffer");
3442 ret = -EFAULT;
3443 }
3444
3445 return ret;
3446}
3447
Jeff Johnsone44b7012017-09-10 15:25:47 -07003448static int drv_cmd_set_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003449 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003450 uint8_t *command,
3451 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003452 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003453{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003454 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003455 uint8_t *value = command;
3456 int8_t rssi = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08003457 uint8_t lookup_threshold = cfg_default(
3458 CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303459 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003460
3461 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3462 value = value + command_len + 1;
3463
3464 /* Convert the value from ascii to integer */
3465 ret = kstrtos8(value, 10, &rssi);
3466 if (ret < 0) {
3467 /*
3468 * If the input value is greater than max value of datatype,
3469 * then also kstrtou8 fails
3470 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003471 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003472 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
3473 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003474 ret = -EINVAL;
3475 goto exit;
3476 }
3477
Wu Gao1ab05582018-11-08 16:22:49 +08003478 lookup_threshold = abs(rssi);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479
Wu Gao1ab05582018-11-08 16:22:49 +08003480 if (!cfg_in_range(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD,
3481 lookup_threshold)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003482 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003483 lookup_threshold,
3484 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
3485 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003486 ret = -EINVAL;
3487 goto exit;
3488 }
3489
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303490 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3491 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003492 adapter->vdev_id, lookup_threshold);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303493
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003494 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003495 lookup_threshold);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003496
Jeff Johnsond549efa2018-06-13 20:27:47 -07003497 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003498 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003499 lookup_threshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303500 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003501 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003502 ret = -EPERM;
3503 goto exit;
3504 }
3505
3506exit:
3507 return ret;
3508}
3509
Jeff Johnsone44b7012017-09-10 15:25:47 -07003510static int drv_cmd_get_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003511 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003512 uint8_t *command,
3513 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003514 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003515{
3516 int ret = 0;
Srinivas Dasari9249a982019-09-16 14:56:27 +05303517 uint8_t lookup_threshold;
3518 int rssi;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003519 char extra[32];
3520 uint8_t len = 0;
Srinivas Dasari9249a982019-09-16 14:56:27 +05303521 QDF_STATUS status;
3522
3523 status = sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle,
3524 adapter->vdev_id,
3525 &lookup_threshold);
3526 if (QDF_IS_STATUS_ERROR(status))
3527 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003528
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303529 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3530 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003531 adapter->vdev_id, lookup_threshold);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003532
Srinivas Dasari9249a982019-09-16 14:56:27 +05303533 hdd_debug("vdev_id: %u, lookup_threshold: %u",
3534 adapter->vdev_id, lookup_threshold);
3535
3536 rssi = (-1) * lookup_threshold;
3537
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003538 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303539 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003540 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003541 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003542 ret = -EFAULT;
3543 }
3544
3545 return ret;
3546}
3547
Jeff Johnsone44b7012017-09-10 15:25:47 -07003548static int drv_cmd_set_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003549 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003550 uint8_t *command,
3551 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003552 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003553{
3554 int ret = 0;
3555 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003556 uint8_t roam_scan_period = 0;
3557 uint16_t empty_scan_refresh_period =
3558 cfg_default(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003559
3560 /* input refresh period is in terms of seconds */
3561
3562 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3563 value = value + command_len + 1;
3564
3565 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003566 ret = kstrtou8(value, 10, &roam_scan_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003567 if (ret < 0) {
3568 /*
3569 * If the input value is greater than max value of datatype,
3570 * then also kstrtou8 fails
3571 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003572 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003573 (cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000),
3574 (cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003575 ret = -EINVAL;
3576 goto exit;
3577 }
3578
Srinivas Dasarib5d9f3e2019-08-22 01:43:42 +05303579 if (!ucfg_mlme_validate_scan_period(roam_scan_period * 1000)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003580 ret = -EINVAL;
3581 goto exit;
3582 }
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303583
3584 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3585 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003586 adapter->vdev_id, roam_scan_period);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303587
Wu Gao1ab05582018-11-08 16:22:49 +08003588 empty_scan_refresh_period = roam_scan_period * 1000;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003589
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003590 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003591 roam_scan_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003592
Jeff Johnsond549efa2018-06-13 20:27:47 -07003593 sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003594 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003595 empty_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003596
3597exit:
3598 return ret;
3599}
3600
Jeff Johnsone44b7012017-09-10 15:25:47 -07003601static int drv_cmd_get_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003602 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003603 uint8_t *command,
3604 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003605 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003606{
3607 int ret = 0;
Srinivas Dasari456aa702019-09-17 14:19:50 +05303608 uint16_t empty_scan_refresh_period;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003609 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003610 uint8_t len;
Srinivas Dasari456aa702019-09-17 14:19:50 +05303611 QDF_STATUS status;
3612
3613 status = sme_get_empty_scan_refresh_period(hdd_ctx->mac_handle,
3614 adapter->vdev_id,
3615 &empty_scan_refresh_period);
3616 if (QDF_IS_STATUS_ERROR(status))
3617 return qdf_status_to_os_return(status);
3618
3619 hdd_debug("vdev_id: %u, empty_scan_refresh_period: %u",
3620 adapter->vdev_id, empty_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003621
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303622 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3623 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003624 adapter->vdev_id,
Jeff Johnson96259452019-02-26 20:38:17 -08003625 empty_scan_refresh_period);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303626
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003627 len = scnprintf(extra, sizeof(extra), "%s %d",
3628 "GETROAMSCANPERIOD",
Jeff Johnson96259452019-02-26 20:38:17 -08003629 (empty_scan_refresh_period / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003630 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303631 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003632 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003633 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003634 ret = -EFAULT;
3635 }
3636
3637 return ret;
3638}
3639
Jeff Johnsone44b7012017-09-10 15:25:47 -07003640static int drv_cmd_set_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003641 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003642 uint8_t *command,
3643 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003644 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003645{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003646 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003647 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003648 uint8_t roam_scan_refresh_period = 0;
3649 uint16_t neighbor_scan_refresh_period =
3650 cfg_default(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003651
3652 /* input refresh period is in terms of seconds */
3653 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3654 value = value + command_len + 1;
3655
3656 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003657 ret = kstrtou8(value, 10, &roam_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658 if (ret < 0) {
3659 /*
3660 * If the input value is greater than max value of datatype,
3661 * then also kstrtou8 fails
3662 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003663 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003664 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003665 / 1000),
Wu Gao1ab05582018-11-08 16:22:49 +08003666 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003667 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003668 ret = -EINVAL;
3669 goto exit;
3670 }
Wu Gao1ab05582018-11-08 16:22:49 +08003671
3672 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD,
3673 roam_scan_refresh_period)) {
3674 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3675 roam_scan_refresh_period,
3676 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3677 / 1000),
3678 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3679 / 1000));
3680 ret = -EINVAL;
3681 goto exit;
3682 }
3683 neighbor_scan_refresh_period = roam_scan_refresh_period * 1000;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003685 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003686 neighbor_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003687
Jeff Johnsond549efa2018-06-13 20:27:47 -07003688 sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003689 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003690 neighbor_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003691
3692exit:
3693 return ret;
3694}
3695
Jeff Johnsone44b7012017-09-10 15:25:47 -07003696static int drv_cmd_get_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003697 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003698 uint8_t *command,
3699 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003700 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003701{
3702 int ret = 0;
3703 uint16_t value =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003704 sme_get_neighbor_scan_refresh_period(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003705 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003706 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707
3708 len = scnprintf(extra, sizeof(extra), "%s %d",
3709 "GETROAMSCANREFRESHPERIOD",
3710 (value / 1000));
3711 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303712 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003713 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003714 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003715 ret = -EFAULT;
3716 }
3717
3718 return ret;
3719}
3720
Jeff Johnsone44b7012017-09-10 15:25:47 -07003721static int drv_cmd_set_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003722 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003723 uint8_t *command,
3724 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003725 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003726{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003727 mac_handle_t mac_handle;
3728 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003729 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003730 uint8_t roam_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731
3732 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3733 value = value + SIZE_OF_SETROAMMODE + 1;
3734
3735 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003736 ret = kstrtou8(value, 10, &roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003737 if (ret < 0) {
3738 /*
3739 * If the input value is greater than max value of datatype,
3740 * then also kstrtou8 fails
3741 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003742 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003743 cfg_min(CFG_LFR_FEATURE_ENABLED),
3744 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745 ret = -EINVAL;
3746 goto exit;
3747 }
Wu Gao1ab05582018-11-08 16:22:49 +08003748
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003749 hdd_debug("Received Command to Set Roam Mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003750 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003751 /*
3752 * Note that
3753 * SETROAMMODE 0 is to enable LFR while
3754 * SETROAMMODE 1 is to disable LFR, but
3755 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3756 * enable/disable. So, we have to invert the value
3757 * to call sme_update_is_fast_roam_ini_feature_enabled.
3758 */
Wu Gao1ab05582018-11-08 16:22:49 +08003759 if (roam_mode) {
3760 /* Roam enable */
3761 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
3762 } else {
3763 /* Roam disable */
3764 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
3765 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003766
Wu Gao1ab05582018-11-08 16:22:49 +08003767 ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)roam_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07003768 mac_handle = hdd_ctx->mac_handle;
Wu Gao1ab05582018-11-08 16:22:49 +08003769 if (roam_mode) {
3770 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3771 (bool)roam_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07003772 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003773 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003774 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003775 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07003776 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003777 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003778 roam_mode);
3779 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3780 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003781 }
3782
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003783exit:
3784 return ret;
3785}
3786
Pragaspathi Thilagarajaa8320e2019-04-16 02:47:50 +05303787static int drv_cmd_set_suspend_mode(struct hdd_adapter *adapter,
3788 struct hdd_context *hdd_ctx,
3789 uint8_t *command,
3790 uint8_t command_len,
3791 struct hdd_priv_data *priv_data)
3792{
3793 int errno;
3794 uint8_t *value = command;
3795 QDF_STATUS status;
3796 uint8_t idle_monitor;
3797
3798 if (QDF_STA_MODE != adapter->device_mode) {
3799 hdd_debug("Non-STA interface");
3800 return 0;
3801 }
3802
3803 /* Move pointer to ahead of SETSUSPENDMODE<delimiter> */
3804 value = value + SIZE_OF_SETSUSPENDMODE + 1;
3805
3806 /* Convert the value from ascii to integer */
3807 errno = kstrtou8(value, 10, &idle_monitor);
3808 if (errno < 0) {
3809 /*
3810 * If the input value is greater than max value of datatype,
3811 * then also kstrtou8 fails
3812 */
3813 hdd_err("Range validation failed");
3814 return -EINVAL;
3815 }
3816
3817 hdd_debug("idle_monitor:%d", idle_monitor);
3818 status = ucfg_pmo_tgt_psoc_send_idle_roam_suspend_mode(hdd_ctx->psoc,
3819 idle_monitor);
3820 if (QDF_IS_STATUS_ERROR(status)) {
3821 hdd_debug("Send suspend mode to fw failed");
3822 return -EINVAL;
3823 }
3824 return 0;
3825}
3826
Jeff Johnsone44b7012017-09-10 15:25:47 -07003827static int drv_cmd_get_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003828 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003829 uint8_t *command,
3830 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003831 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003832{
3833 int ret = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08003834 bool roam_mode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003835 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003836 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003837
3838 /*
3839 * roamMode value shall be inverted because the sementics is different.
3840 */
Wu Gao1ab05582018-11-08 16:22:49 +08003841 if (roam_mode)
3842 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003843 else
Wu Gao1ab05582018-11-08 16:22:49 +08003844 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003845
Wu Gao1ab05582018-11-08 16:22:49 +08003846 len = scnprintf(extra, sizeof(extra), "%s %d", command, roam_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303847 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003848 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003849 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003850 ret = -EFAULT;
3851 }
3852
3853 return ret;
3854}
3855
Jeff Johnsone44b7012017-09-10 15:25:47 -07003856static int drv_cmd_set_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003857 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858 uint8_t *command,
3859 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003860 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003861{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003862 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003863 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003864 uint8_t roam_rssi_diff = cfg_default(CFG_LFR_ROAM_RSSI_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003865
3866 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3867 value = value + command_len + 1;
3868
3869 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003870 ret = kstrtou8(value, 10, &roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003871 if (ret < 0) {
3872 /*
3873 * If the input value is greater than max value of datatype,
3874 * then also kstrtou8 fails
3875 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003876 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003877 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3878 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003879 ret = -EINVAL;
3880 goto exit;
3881 }
3882
Wu Gao1ab05582018-11-08 16:22:49 +08003883 if (!cfg_in_range(CFG_LFR_ROAM_RSSI_DIFF, roam_rssi_diff)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003884 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003885 roam_rssi_diff,
3886 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3887 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003888 ret = -EINVAL;
3889 goto exit;
3890 }
3891
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003892 hdd_debug("Received Command to Set roam rssi diff = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003893 roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003894
Jeff Johnsond549efa2018-06-13 20:27:47 -07003895 sme_update_roam_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003896 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003897 roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003898
3899exit:
3900 return ret;
3901}
3902
Jeff Johnsone44b7012017-09-10 15:25:47 -07003903static int drv_cmd_get_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003904 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003905 uint8_t *command,
3906 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003907 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003908{
3909 int ret = 0;
Srinivas Dasari7f48ac02019-09-16 17:44:43 +05303910 uint8_t rssi_diff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003911 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003912 uint8_t len;
Srinivas Dasari7f48ac02019-09-16 17:44:43 +05303913 QDF_STATUS status;
3914
3915 status = sme_get_roam_rssi_diff(hdd_ctx->mac_handle, adapter->vdev_id,
3916 &rssi_diff);
3917 if (QDF_IS_STATUS_ERROR(status))
3918 return qdf_status_to_os_return(status);
3919
3920 hdd_debug("vdev_id: %u, rssi_diff: %u", adapter->vdev_id, rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003921
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303922 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3923 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
Jeff Johnson65003802019-02-26 20:50:49 -08003924 adapter->vdev_id, rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003925 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnson65003802019-02-26 20:50:49 -08003926 command, rssi_diff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303927 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003928
3929 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003930 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003931 ret = -EFAULT;
3932 }
3933
3934 return ret;
3935}
3936
Jeff Johnsone44b7012017-09-10 15:25:47 -07003937static int drv_cmd_get_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003938 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003939 uint8_t *command,
3940 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003941 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003942{
3943 int ret = 0;
3944 int band = -1;
3945 char extra[32];
3946 uint8_t len = 0;
3947
3948 hdd_get_band_helper(hdd_ctx, &band);
3949
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303950 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3951 TRACE_CODE_HDD_GETBAND_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003952 adapter->vdev_id, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003953
3954 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303955 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003956
3957 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003958 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003959 ret = -EFAULT;
3960 }
3961
3962 return ret;
3963}
3964
Jeff Johnsone44b7012017-09-10 15:25:47 -07003965static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003966 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967 uint8_t *command,
3968 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003969 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003970{
3971 return hdd_parse_set_roam_scan_channels(adapter, command);
3972}
3973
Jeff Johnsone44b7012017-09-10 15:25:47 -07003974static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003975 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003976 uint8_t *command,
3977 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003978 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003979{
3980 int ret = 0;
Jianmin Zhu203d7532019-10-28 17:17:05 +08003981 uint32_t freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08003982 uint8_t num_channels = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003983 uint8_t j = 0;
3984 char extra[128] = { 0 };
3985 int len;
Jianmin Zhu203d7532019-10-28 17:17:05 +08003986 uint8_t chan;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003987
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303988 if (QDF_STATUS_SUCCESS !=
Jeff Johnsond549efa2018-06-13 20:27:47 -07003989 sme_get_roam_scan_channel_list(hdd_ctx->mac_handle,
Jianmin Zhu203d7532019-10-28 17:17:05 +08003990 freq_list,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08003991 &num_channels,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003992 adapter->vdev_id)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003993 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003994 ret = -EFAULT;
3995 goto exit;
3996 }
3997
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303998 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3999 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08004000 adapter->vdev_id, num_channels);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304001
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004002 /*
4003 * output channel list is of the format
4004 * [Number of roam scan channels][Channel1][Channel2]...
4005 * copy the number of channels in the 0th index
4006 */
4007 len = scnprintf(extra, sizeof(extra), "%s %d", command,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08004008 num_channels);
Jianmin Zhu203d7532019-10-28 17:17:05 +08004009 for (j = 0; (j < num_channels) && len <= sizeof(extra); j++) {
4010 chan = wlan_reg_freq_to_chan(hdd_ctx->pdev, freq_list[j]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004011 len += scnprintf(extra + len, sizeof(extra) - len,
Jianmin Zhu203d7532019-10-28 17:17:05 +08004012 " %d", chan);
4013 }
Anurag Chouhan6d760662016-02-20 16:05:43 +05304014 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004015 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004016 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004017 ret = -EFAULT;
4018 goto exit;
4019 }
4020
4021exit:
4022 return ret;
4023}
4024
Jeff Johnsone44b7012017-09-10 15:25:47 -07004025static int drv_cmd_get_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004026 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004027 uint8_t *command,
4028 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004029 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004030{
4031 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004032 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Jeff Johnson22345e12019-02-26 21:33:02 -08004033 bool ese_mode = sme_get_is_ese_feature_enabled(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004034 char extra[32];
4035 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004036 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004037
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004038 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004039 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004040 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004041 * then this operation is not permitted (return FAILURE)
4042 */
Jeff Johnson22345e12019-02-26 21:33:02 -08004043 if (ese_mode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004044 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07004045 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004046 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004047 ret = -EPERM;
4048 goto exit;
4049 }
4050
4051 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnson22345e12019-02-26 21:33:02 -08004052 "GETCCXMODE", ese_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304053 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004054 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004055 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004056 ret = -EFAULT;
4057 goto exit;
4058 }
4059
4060exit:
4061 return ret;
4062}
4063
Jeff Johnsone44b7012017-09-10 15:25:47 -07004064static int drv_cmd_get_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004065 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004066 uint8_t *command,
4067 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004068 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004069{
4070 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004071 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004072 char extra[32];
4073 uint8_t len = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004074 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004075
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004076 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004077 /*
4078 * Check if the features OKC/ESE/11R are supported simultaneously,
4079 * then this operation is not permitted (return FAILURE)
4080 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004081 if (pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07004082 sme_get_is_ese_feature_enabled(mac_handle) &&
4083 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004084 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004085 ret = -EPERM;
4086 goto exit;
4087 }
4088
4089 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004090 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304091 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004092
4093 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004094 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004095 ret = -EFAULT;
4096 goto exit;
4097 }
4098
4099exit:
4100 return ret;
4101}
4102
Jeff Johnsone44b7012017-09-10 15:25:47 -07004103static int drv_cmd_get_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004104 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004105 uint8_t *command,
4106 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004107 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004108{
4109 int ret = 0;
Jeff Johnson22345e12019-02-26 21:33:02 -08004110 bool lfr_mode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004111 char extra[32];
4112 uint8_t len = 0;
4113
4114 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnson22345e12019-02-26 21:33:02 -08004115 "GETFASTROAM", lfr_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304116 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004117
4118 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004119 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004120 ret = -EFAULT;
4121 }
4122
4123 return ret;
4124}
4125
Jeff Johnsone44b7012017-09-10 15:25:47 -07004126static int drv_cmd_get_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004127 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004128 uint8_t *command,
4129 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004130 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004131{
4132 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004133 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004134 char extra[32];
4135 uint8_t len = 0;
4136
4137 len = scnprintf(extra, sizeof(extra), "%s %d",
4138 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304139 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004140
4141 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004142 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004143 ret = -EFAULT;
4144 }
4145
4146 return ret;
4147}
4148
Jeff Johnsone44b7012017-09-10 15:25:47 -07004149static int drv_cmd_set_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004150 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004151 uint8_t *command,
4152 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004153 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004154{
4155 int ret = 0;
4156 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004157 uint8_t min_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004158
4159 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
4160 value = value + command_len + 1;
4161
4162 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004163 ret = kstrtou8(value, 10, &min_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004164 if (ret < 0) {
4165 /*
4166 * If the input value is greater than max value of datatype,
4167 * then also kstrtou8 fails
4168 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004169 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004170 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
4171 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004172 ret = -EINVAL;
4173 goto exit;
4174 }
4175
Wu Gao1ab05582018-11-08 16:22:49 +08004176 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME, min_time)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004177 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08004178 min_time,
4179 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
4180 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004181 ret = -EINVAL;
4182 goto exit;
4183 }
4184
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304185 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
4186 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004187 adapter->vdev_id, min_time);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304188
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004189 hdd_debug("Received Command to change channel min time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004190 min_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004191
Jeff Johnsond549efa2018-06-13 20:27:47 -07004192 sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
Wu Gao1ab05582018-11-08 16:22:49 +08004193 min_time,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004194 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004195
4196exit:
4197 return ret;
4198}
4199
Jeff Johnsone44b7012017-09-10 15:25:47 -07004200static int drv_cmd_send_action_frame(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004201 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004202 uint8_t *command,
4203 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004204 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004205{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07004206 return hdd_parse_sendactionframe(adapter, command,
4207 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004208}
4209
Jeff Johnsone44b7012017-09-10 15:25:47 -07004210static int drv_cmd_get_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004211 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004212 uint8_t *command,
4213 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004214 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004215{
4216 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004217 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004218 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004219 char extra[32];
4220 uint8_t len = 0;
4221
4222 /* value is interms of msec */
4223 len = scnprintf(extra, sizeof(extra), "%s %d",
4224 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304225 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004226
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304227 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
4228 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004229 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004230
4231 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004232 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004233 ret = -EFAULT;
4234 }
4235
4236 return ret;
4237}
4238
Jeff Johnsone44b7012017-09-10 15:25:47 -07004239static int drv_cmd_set_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004240 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004241 uint8_t *command,
4242 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004243 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004244{
4245 int ret = 0;
4246 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004247 uint16_t max_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004248
4249 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
4250 value = value + command_len + 1;
4251
4252 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004253 ret = kstrtou16(value, 10, &max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 if (ret < 0) {
4255 /*
4256 * If the input value is greater than max value of datatype,
4257 * then also kstrtou8 fails
4258 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004259 hdd_err("kstrtou16 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004260 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
4261 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004262 ret = -EINVAL;
4263 goto exit;
4264 }
4265
Wu Gao1ab05582018-11-08 16:22:49 +08004266 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME, max_time)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004267 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08004268 max_time,
4269 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
4270 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004271 ret = -EINVAL;
4272 goto exit;
4273 }
4274
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004275 hdd_debug("Received Command to change channel max time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004276 max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004277
Jeff Johnsond549efa2018-06-13 20:27:47 -07004278 sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004279 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004280 max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004281
4282exit:
4283 return ret;
4284}
4285
Jeff Johnsone44b7012017-09-10 15:25:47 -07004286static int drv_cmd_get_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004287 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004288 uint8_t *command,
4289 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004290 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004291{
4292 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004293 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004294 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004295 char extra[32];
4296 uint8_t len = 0;
4297
4298 /* value is interms of msec */
4299 len = scnprintf(extra, sizeof(extra), "%s %d",
4300 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304301 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004302
4303 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004304 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004305 ret = -EFAULT;
4306 }
4307
4308 return ret;
4309}
4310
Jeff Johnsone44b7012017-09-10 15:25:47 -07004311static int drv_cmd_set_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004312 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004313 uint8_t *command,
4314 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004315 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004316{
4317 int ret = 0;
4318 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004319 uint16_t val = cfg_default(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004320
4321 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
4322 value = value + command_len + 1;
4323
4324 /* Convert the value from ascii to integer */
4325 ret = kstrtou16(value, 10, &val);
4326 if (ret < 0) {
4327 /*
4328 * If the input value is greater than max value of datatype,
4329 * then also kstrtou8 fails
4330 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004331 hdd_err("kstrtou16 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004332 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
4333 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334 ret = -EINVAL;
4335 goto exit;
4336 }
4337
Wu Gao1ab05582018-11-08 16:22:49 +08004338 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004339 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
4340 val,
Wu Gao1ab05582018-11-08 16:22:49 +08004341 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
4342 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004343 ret = -EINVAL;
4344 goto exit;
4345 }
4346
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004347 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004348 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004349
Jeff Johnsond549efa2018-06-13 20:27:47 -07004350 sme_set_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004351 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004352
4353exit:
4354 return ret;
4355}
4356
Jeff Johnsone44b7012017-09-10 15:25:47 -07004357static int drv_cmd_get_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004358 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004359 uint8_t *command,
4360 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004361 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004362{
4363 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004364 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004365 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004366 char extra[32];
4367 uint8_t len = 0;
4368
4369 /* value is interms of msec */
4370 len = scnprintf(extra, sizeof(extra), "%s %d",
4371 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304372 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004373
4374 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004375 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004376 ret = -EFAULT;
4377 }
4378
4379 return ret;
4380}
4381
Jeff Johnsone44b7012017-09-10 15:25:47 -07004382static int drv_cmd_set_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004383 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004384 uint8_t *command,
4385 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004386 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004387{
4388 int ret = 0;
4389 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004390 uint8_t val = cfg_default(CFG_LFR_ROAM_INTRA_BAND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004391
4392 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
4393 value = value + command_len + 1;
4394
4395 /* Convert the value from ascii to integer */
4396 ret = kstrtou8(value, 10, &val);
4397 if (ret < 0) {
4398 /*
4399 * If the input value is greater than max value of datatype,
4400 * then also kstrtou8 fails
4401 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004402 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004403 cfg_min(CFG_LFR_ROAM_INTRA_BAND),
4404 cfg_max(CFG_LFR_ROAM_INTRA_BAND));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004405 ret = -EINVAL;
4406 goto exit;
4407 }
4408
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004409 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004410 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004411
Wu Gao1ab05582018-11-08 16:22:49 +08004412 ucfg_mlme_set_roam_intra_band(hdd_ctx->psoc, (bool)val);
Jianmin Zhu0b505a62019-04-30 16:22:49 +08004413 policy_mgr_set_pcl_for_existing_combo(
4414 hdd_ctx->psoc,
4415 PM_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004416
4417exit:
4418 return ret;
4419}
4420
Jeff Johnsone44b7012017-09-10 15:25:47 -07004421static int drv_cmd_get_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004422 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423 uint8_t *command,
4424 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004425 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004426{
4427 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004428 uint16_t val = sme_get_roam_intra_band(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004429 char extra[32];
4430 uint8_t len = 0;
4431
4432 /* value is interms of msec */
4433 len = scnprintf(extra, sizeof(extra), "%s %d",
4434 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304435 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004436 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004437 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004438 ret = -EFAULT;
4439 }
4440
4441 return ret;
4442}
4443
Jeff Johnsone44b7012017-09-10 15:25:47 -07004444static int drv_cmd_set_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004445 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004446 uint8_t *command,
4447 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004448 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004449{
4450 int ret = 0;
4451 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004452 uint8_t nprobes = cfg_default(CFG_LFR_ROAM_SCAN_N_PROBES);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004453
4454 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
4455 value = value + command_len + 1;
4456
4457 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004458 ret = kstrtou8(value, 10, &nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004459 if (ret < 0) {
4460 /*
4461 * If the input value is greater than max value of datatype,
4462 * then also kstrtou8 fails
4463 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004464 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004465 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
4466 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004467 ret = -EINVAL;
4468 goto exit;
4469 }
4470
Wu Gao1ab05582018-11-08 16:22:49 +08004471 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_N_PROBES, nprobes)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004472 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08004473 nprobes,
4474 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
4475 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004476 ret = -EINVAL;
4477 goto exit;
4478 }
4479
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004480 hdd_debug("Received Command to Set nProbes = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004481 nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004482
Jeff Johnsond549efa2018-06-13 20:27:47 -07004483 sme_update_roam_scan_n_probes(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004484 adapter->vdev_id, nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004485
4486exit:
4487 return ret;
4488}
4489
Jeff Johnsone44b7012017-09-10 15:25:47 -07004490static int drv_cmd_get_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004491 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004492 uint8_t *command,
4493 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004494 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004495{
4496 int ret = 0;
Srinivas Dasaria5a42fa2019-09-20 12:47:15 +05304497 uint8_t val;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498 char extra[32];
4499 uint8_t len = 0;
Srinivas Dasaria5a42fa2019-09-20 12:47:15 +05304500 QDF_STATUS status;
4501
4502 status = sme_get_roam_scan_n_probes(hdd_ctx->mac_handle,
4503 adapter->vdev_id,
4504 &val);
4505 if (QDF_IS_STATUS_ERROR(status))
4506 return qdf_status_to_os_return(status);
4507
4508 hdd_debug("vdev_id: %u, scan_n_probes: %u",
4509 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004510
4511 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304512 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004513 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004514 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004515 ret = -EFAULT;
4516 }
4517
4518 return ret;
4519}
4520
Jeff Johnsone44b7012017-09-10 15:25:47 -07004521static int drv_cmd_set_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004522 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004523 uint8_t *command,
4524 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004525 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004526{
4527 int ret = 0;
4528 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004529 uint16_t home_away_time = cfg_default(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004530
4531 /* input value is in units of msec */
4532
4533 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4534 value = value + command_len + 1;
4535
4536 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004537 ret = kstrtou16(value, 10, &home_away_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004538 if (ret < 0) {
4539 /*
4540 * If the input value is greater than max value of datatype,
4541 * then also kstrtou8 fails
4542 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004543 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004544 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4545 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004546 ret = -EINVAL;
4547 goto exit;
4548 }
4549
Wu Gao1ab05582018-11-08 16:22:49 +08004550 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME, home_away_time)) {
4551 hdd_err("home_away_time value %d is out of range (min: %d max: %d)",
4552 home_away_time,
4553 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4554 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004555 ret = -EINVAL;
4556 goto exit;
4557 }
4558
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004559 hdd_debug("Received Command to Set scan away time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004560 home_away_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004561
Srinivas Dasari7bedcd12019-09-20 12:43:11 +05304562 sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle,
4563 adapter->vdev_id,
4564 home_away_time,
4565 true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004566
4567exit:
4568 return ret;
4569}
4570
Jeff Johnsone44b7012017-09-10 15:25:47 -07004571static int drv_cmd_get_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004572 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004573 uint8_t *command,
4574 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004575 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004576{
4577 int ret = 0;
Srinivas Dasari7bedcd12019-09-20 12:43:11 +05304578 uint16_t val;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004579 char extra[32];
4580 uint8_t len = 0;
Srinivas Dasari7bedcd12019-09-20 12:43:11 +05304581 QDF_STATUS status;
4582
4583 status = sme_get_roam_scan_home_away_time(hdd_ctx->mac_handle,
4584 adapter->vdev_id,
4585 &val);
4586 if (QDF_IS_STATUS_ERROR(status))
4587 return qdf_status_to_os_return(status);
4588
4589 hdd_debug("vdev_id: %u, scan home away time: %u",
4590 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004591
4592 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304593 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594
4595 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004596 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004597 ret = -EFAULT;
4598 }
4599
4600 return ret;
4601}
4602
Jeff Johnsone44b7012017-09-10 15:25:47 -07004603static int drv_cmd_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004604 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004605 uint8_t *command,
4606 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004607 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004608{
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05304609 return hdd_parse_reassoc(adapter, command, priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004610}
4611
Jeff Johnsone44b7012017-09-10 15:25:47 -07004612static int drv_cmd_set_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004613 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004614 uint8_t *command,
4615 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004616 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004617{
4618 int ret = 0;
4619 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004620 uint8_t wes_mode = cfg_default(CFG_LFR_ENABLE_WES_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004621
4622 /* Move pointer to ahead of SETWESMODE<delimiter> */
4623 value = value + command_len + 1;
4624
4625 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004626 ret = kstrtou8(value, 10, &wes_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004627 if (ret < 0) {
4628 /*
4629 * If the input value is greater than max value of datatype,
4630 * then also kstrtou8 fails
4631 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004632 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004633 cfg_min(CFG_LFR_ENABLE_WES_MODE),
4634 cfg_max(CFG_LFR_ENABLE_WES_MODE));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004635 ret = -EINVAL;
4636 goto exit;
4637 }
4638
Wu Gao1ab05582018-11-08 16:22:49 +08004639 hdd_debug("Received Command to Set WES Mode rssi diff = %d", wes_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004641 sme_update_wes_mode(hdd_ctx->mac_handle, wes_mode, adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004642
4643exit:
4644 return ret;
4645}
4646
Jeff Johnsone44b7012017-09-10 15:25:47 -07004647static int drv_cmd_get_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004648 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004649 uint8_t *command,
4650 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004651 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004652{
4653 int ret = 0;
Jeff Johnson22345e12019-02-26 21:33:02 -08004654 bool wes_mode = sme_get_wes_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004655 char extra[32];
4656 uint8_t len = 0;
4657
Jeff Johnson22345e12019-02-26 21:33:02 -08004658 len = scnprintf(extra, sizeof(extra), "%s %d", command, wes_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304659 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004660 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004661 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004662 ret = -EFAULT;
4663 }
4664
4665 return ret;
4666}
4667
Jeff Johnsone44b7012017-09-10 15:25:47 -07004668static int drv_cmd_set_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004669 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004670 uint8_t *command,
4671 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004672 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004673{
4674 int ret = 0;
4675 uint8_t *value = command;
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004676 uint8_t diff =
Wu Gao1ab05582018-11-08 16:22:49 +08004677 cfg_default(CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004678
4679 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4680 value = value + command_len + 1;
4681
4682 /* Convert the value from ascii to integer */
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004683 ret = kstrtou8(value, 10, &diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004684 if (ret < 0) {
4685 /*
4686 * If the input value is greater than max value of datatype,
4687 * then also kstrtou8 fails
4688 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004689 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004690 ret = -EINVAL;
4691 goto exit;
4692 }
4693
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004694 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004695 diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004696
Jeff Johnsond549efa2018-06-13 20:27:47 -07004697 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle,
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004698 adapter->vdev_id,
4699 diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004700
4701exit:
4702 return ret;
4703}
4704
Jeff Johnsone44b7012017-09-10 15:25:47 -07004705static int drv_cmd_get_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004706 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707 uint8_t *command,
4708 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004709 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004710{
4711 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004712 mac_handle_t mac_handle = hdd_ctx->mac_handle;
4713 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004714 char extra[32];
4715 uint8_t len = 0;
4716
4717 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304718 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004719 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004720 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004721 ret = -EFAULT;
4722 }
4723
4724 return ret;
4725}
4726
Jeff Johnsone44b7012017-09-10 15:25:47 -07004727static int drv_cmd_set_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004728 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004729 uint8_t *command,
4730 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004731 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004732{
4733 int ret = 0;
4734 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004735 uint8_t rescan_rssi_diff = cfg_default(CFG_LFR_ROAM_RESCAN_RSSI_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004736
4737 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4738 value = value + command_len + 1;
4739
4740 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004741 ret = kstrtou8(value, 10, &rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004742 if (ret < 0) {
4743 /*
4744 * If the input value is greater than max value of datatype,
4745 * then also kstrtou8 fails
4746 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004747 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004748 ret = -EINVAL;
4749 goto exit;
4750 }
4751
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004752 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004753 rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004754
Jeff Johnsond549efa2018-06-13 20:27:47 -07004755 sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004756 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004757 rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004758
4759exit:
4760 return ret;
4761}
4762
Jeff Johnsone44b7012017-09-10 15:25:47 -07004763static int drv_cmd_get_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004764 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004765 uint8_t *command,
4766 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004767 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004768{
4769 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004770 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004771 char extra[32];
4772 uint8_t len = 0;
4773
4774 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304775 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004776 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004777 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004778 ret = -EFAULT;
4779 }
4780
4781 return ret;
4782}
4783
Jeff Johnsone44b7012017-09-10 15:25:47 -07004784static int drv_cmd_set_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004785 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004786 uint8_t *command,
4787 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004788 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004789{
4790 int ret = 0;
4791 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004792 uint8_t lfr_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004793
4794 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4795 value = value + command_len + 1;
4796
4797 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004798 ret = kstrtou8(value, 10, &lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004799 if (ret < 0) {
4800 /*
4801 * If the input value is greater than max value of datatype,
4802 * then also kstrtou8 fails
4803 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004804 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004805 cfg_min(CFG_LFR_FEATURE_ENABLED),
4806 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004807 ret = -EINVAL;
4808 goto exit;
4809 }
4810
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004811 hdd_debug("Received Command to change lfr mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004812 lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004813
Wu Gao1ab05582018-11-08 16:22:49 +08004814 ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)lfr_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07004815 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004816 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004817 lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004818
4819exit:
4820 return ret;
4821}
4822
Jeff Johnsone44b7012017-09-10 15:25:47 -07004823static int drv_cmd_set_fast_transition(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{
4829 int ret = 0;
4830 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004831 uint8_t ft = cfg_default(CFG_LFR_FAST_TRANSITION_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004832
4833 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4834 value = value + command_len + 1;
4835
4836 /* Convert the value from ascii to integer */
4837 ret = kstrtou8(value, 10, &ft);
4838 if (ret < 0) {
4839 /*
4840 * If the input value is greater than max value of datatype,
4841 * then also kstrtou8 fails
4842 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004843 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004844 cfg_min(CFG_LFR_FAST_TRANSITION_ENABLED),
4845 cfg_max(CFG_LFR_FAST_TRANSITION_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004846 ret = -EINVAL;
4847 goto exit;
4848 }
4849
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004850 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004851
Wu Gao1ab05582018-11-08 16:22:49 +08004852 ucfg_mlme_set_fast_transition_enabled(hdd_ctx->psoc, (bool)ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004853
4854exit:
4855 return ret;
4856}
4857
Jeff Johnsone44b7012017-09-10 15:25:47 -07004858static int drv_cmd_fast_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004859 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004860 uint8_t *command,
4861 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004862 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004863{
4864 int ret = 0;
4865 uint8_t *value = command;
4866 uint8_t channel = 0;
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004867 tSirMacAddr bssid;
Jeff Johnson29c78672019-02-26 21:05:53 -08004868 uint32_t roam_id = INVALID_ROAM_ID;
Jeff Johnson9ff16952019-02-26 20:58:44 -08004869 tCsrRoamModifyProfileFields mod_fields;
Jeff Johnsondcaa8fc2019-02-26 21:26:31 -08004870 tCsrHandoffRequest req;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004871 struct hdd_station_ctx *sta_ctx;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004872 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004873
Krunal Sonibe766b02016-03-10 13:00:44 -08004874 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004875 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07004876 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004877 adapter->device_mode);
4878 return -EINVAL;
4879 }
4880
Jeff Johnsond377dce2017-10-04 10:32:42 -07004881 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jingxiang Gece7c5472019-07-23 16:19:23 +08004882 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004883
4884 /* if not associated, no need to proceed with reassoc */
Jeff Johnsone7951512019-02-27 10:02:51 -08004885 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004886 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004887 ret = -EINVAL;
4888 goto exit;
4889 }
4890
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004891 ret = hdd_parse_reassoc_command_v1_data(value, bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004892 &channel);
4893 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004894 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004895 goto exit;
4896 }
4897
Jeff Johnsond549efa2018-06-13 20:27:47 -07004898 mac_handle = hdd_ctx->mac_handle;
4899
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004900 /*
4901 * if the target bssid is same as currently associated AP,
4902 * issue reassoc to same AP
4903 */
Jeff Johnsone04b6992019-02-27 14:06:55 -08004904 if (!qdf_mem_cmp(bssid, sta_ctx->conn_info.bssid.bytes,
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004905 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004906 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304907 if (roaming_offload_enabled(hdd_ctx)) {
Jingxiang Gece7c5472019-07-23 16:19:23 +08004908 channel = wlan_reg_freq_to_chan(
4909 hdd_ctx->pdev,
Jingxiang Geae80dc62019-08-13 17:32:22 +08004910 sta_ctx->conn_info.chan_freq);
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004911 hdd_wma_send_fastreassoc_cmd(adapter, bssid,
4912 channel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304913 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07004914 sme_get_modify_profile_fields(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004915 adapter->vdev_id,
Jeff Johnson9ff16952019-02-26 20:58:44 -08004916 &mod_fields);
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004917 sme_roam_reassoc(mac_handle, adapter->vdev_id,
Jeff Johnson29c78672019-02-26 21:05:53 -08004918 NULL, mod_fields, &roam_id, 1);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304919 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004920 return 0;
4921 }
4922
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304923 /* Check channel number is a valid channel number */
Selvaraj, Sridhar64b0a9c2017-05-11 16:50:15 +05304924 if (channel && (QDF_STATUS_SUCCESS !=
4925 wlan_hdd_validate_operation_channel(adapter, channel))) {
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304926 hdd_err("Invalid Channel [%d]", channel);
4927 return -EINVAL;
4928 }
4929
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004930 if (roaming_offload_enabled(hdd_ctx)) {
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004931 hdd_wma_send_fastreassoc_cmd(adapter, bssid, (int)channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004932 goto exit;
4933 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004934 /* Proceed with reassoc */
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05304935 req.ch_freq = wlan_reg_chan_to_freq(hdd_ctx->pdev, channel);
Jeff Johnsondcaa8fc2019-02-26 21:26:31 -08004936 req.src = FASTREASSOC;
4937 qdf_mem_copy(req.bssid.bytes, bssid, sizeof(tSirMacAddr));
4938 sme_handoff_request(mac_handle, adapter->vdev_id, &req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004939exit:
4940 return ret;
4941}
4942
Jeff Johnsone44b7012017-09-10 15:25:47 -07004943static int drv_cmd_set_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004944 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004945 uint8_t *command,
4946 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004947 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004948{
4949 int ret = 0;
4950 uint8_t *value = command;
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004951 uint8_t roam_scan_control = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004952
4953 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4954 value = value + command_len + 1;
4955
4956 /* Convert the value from ascii to integer */
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004957 ret = kstrtou8(value, 10, &roam_scan_control);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004958 if (ret < 0) {
4959 /*
4960 * If the input value is greater than max value of datatype,
4961 * then also kstrtou8 fails
4962 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004963 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004964 ret = -EINVAL;
4965 goto exit;
4966 }
4967
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004968 hdd_debug("Received Command to Set roam scan control = %d",
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004969 roam_scan_control);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004970
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004971 if (0 != roam_scan_control) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004972 ret = 0; /* return success but ignore param value "true" */
4973 goto exit;
4974 }
4975
Jeff Johnsond549efa2018-06-13 20:27:47 -07004976 sme_set_roam_scan_control(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004977 adapter->vdev_id,
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004978 roam_scan_control);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004979
4980exit:
4981 return ret;
4982}
4983
Jeff Johnsone44b7012017-09-10 15:25:47 -07004984static int drv_cmd_set_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004985 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004986 uint8_t *command,
4987 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004988 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004989{
4990 int ret = 0;
4991 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004992 uint32_t okc_mode;
4993 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004994 mac_handle_t mac_handle;
Wu Gao93816212018-08-31 16:49:54 +08004995 uint32_t cur_pmkid_modes;
4996 QDF_STATUS status;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004997
4998 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999
5000 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005001 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005002 * then this operation is not permitted (return FAILURE)
5003 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005004 mac_handle = hdd_ctx->mac_handle;
5005 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005006 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07005007 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005008 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005009 ret = -EPERM;
5010 goto exit;
5011 }
5012
5013 /* Move pointer to ahead of SETOKCMODE<delimiter> */
5014 value = value + command_len + 1;
5015
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005016 /* get the current configured value */
Dustin Brown1dbefe62018-09-11 16:32:03 -07005017 status = ucfg_mlme_get_pmkid_modes(hdd_ctx->psoc,
Wu Gao93816212018-08-31 16:49:54 +08005018 &cur_pmkid_modes);
5019 if (status != QDF_STATUS_SUCCESS)
5020 hdd_err("get pmkid modes failed");
5021
5022 okc_mode = cur_pmkid_modes & CFG_PMKID_MODES_OKC;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005023
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005024 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005025 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005026 if (ret < 0) {
5027 /*
5028 * If the input value is greater than max value of datatype,
5029 * then also kstrtou8 fails
5030 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005031 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005032 ret = -EINVAL;
5033 goto exit;
5034 }
5035
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005036 if ((okc_mode < 0) ||
5037 (okc_mode > 1)) {
5038 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
5039 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005040 ret = -EINVAL;
5041 goto exit;
5042 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005043 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005044 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005045
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005046 if (okc_mode)
Wu Gao93816212018-08-31 16:49:54 +08005047 cur_pmkid_modes |= CFG_PMKID_MODES_OKC;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005048 else
Wu Gao93816212018-08-31 16:49:54 +08005049 cur_pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Dustin Brown1dbefe62018-09-11 16:32:03 -07005050 status = ucfg_mlme_set_pmkid_modes(hdd_ctx->psoc,
Wu Gao93816212018-08-31 16:49:54 +08005051 cur_pmkid_modes);
5052 if (status != QDF_STATUS_SUCCESS) {
5053 ret = -EPERM;
5054 hdd_err("set pmkid modes failed");
5055 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005056exit:
5057 return ret;
5058}
5059
Jeff Johnsone44b7012017-09-10 15:25:47 -07005060static int drv_cmd_get_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005061 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005062 uint8_t *command,
5063 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005064 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005065{
5066 int ret = 0;
Jeff Johnsond7ee4762019-02-26 21:01:00 -08005067 bool roam_scan_control = sme_get_roam_scan_control(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005068 char extra[32];
5069 uint8_t len = 0;
5070
5071 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnsond7ee4762019-02-26 21:01:00 -08005072 command, roam_scan_control);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305073 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005074 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005075 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005076 ret = -EFAULT;
5077 }
5078
5079 return ret;
5080}
5081
Jeff Johnsone44b7012017-09-10 15:25:47 -07005082static int drv_cmd_bt_coex_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005083 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005084 uint8_t *command,
5085 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005086 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005087{
5088 int ret = 0;
Jeff Johnson30192412019-02-26 20:32:52 -08005089 char *coex_mode;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005090
Jeff Johnson30192412019-02-26 20:32:52 -08005091 coex_mode = command + 11;
5092 if ('1' == *coex_mode) {
5093 hdd_debug("BTCOEXMODE %d", *coex_mode);
Jeff Johnson59b19312017-11-02 21:14:33 -07005094 hdd_ctx->bt_coex_mode_set = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005095 ret = wlan_hdd_scan_abort(adapter);
5096 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005097 hdd_err("Failed to abort existing scan status: %d",
5098 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005099 }
Jeff Johnson30192412019-02-26 20:32:52 -08005100 } else if ('2' == *coex_mode) {
5101 hdd_debug("BTCOEXMODE %d", *coex_mode);
Jeff Johnson59b19312017-11-02 21:14:33 -07005102 hdd_ctx->bt_coex_mode_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005103 }
5104
5105 return ret;
5106}
5107
Jeff Johnsone44b7012017-09-10 15:25:47 -07005108static int drv_cmd_scan_active(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005109 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005110 uint8_t *command,
5111 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005112 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005113{
5114 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
5115 return 0;
5116}
5117
Jeff Johnsone44b7012017-09-10 15:25:47 -07005118static int drv_cmd_scan_passive(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005119 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005120 uint8_t *command,
5121 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005122 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005123{
5124 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
5125 return 0;
5126}
5127
Jeff Johnsone44b7012017-09-10 15:25:47 -07005128static int drv_cmd_get_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005129 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005130 uint8_t *command,
5131 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005132 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005133{
5134 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005135 char extra[32];
5136 uint8_t len = 0;
5137
5138 memset(extra, 0, sizeof(extra));
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05305139 ret = hdd_get_dwell_time(hdd_ctx->psoc, command, extra,
5140 sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305141 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005142 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005143 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005144 ret = -EFAULT;
5145 goto exit;
5146 }
5147 ret = len;
5148exit:
5149 return ret;
5150}
5151
Jeff Johnsone44b7012017-09-10 15:25:47 -07005152static int drv_cmd_set_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005153 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005154 uint8_t *command,
5155 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005156 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005157{
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05305158 return hdd_set_dwell_time(hdd_ctx->psoc, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005159}
5160
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05305161static int drv_cmd_conc_set_dwell_time(struct hdd_adapter *adapter,
5162 struct hdd_context *hdd_ctx,
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05305163 u8 *command,
5164 u8 command_len,
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05305165 struct hdd_priv_data *priv_data)
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05305166{
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05305167 return hdd_conc_set_dwell_time(adapter, command);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05305168}
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05305169
Jeff Johnsone44b7012017-09-10 15:25:47 -07005170static int drv_cmd_miracast(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005171 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005172 uint8_t *command,
5173 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005174 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005175{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305176 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005177 int ret = 0;
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005178 uint8_t filter_type = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005179 uint8_t *value;
5180
Jeff Johnson6da2db12017-09-03 09:18:52 -07005181 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005182 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005183
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005184 value = command + 9;
5185
5186 /* Convert the value from ascii to integer */
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005187 ret = kstrtou8(value, 10, &filter_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005188 if (ret < 0) {
5189 /*
5190 * If the input value is greater than max value of datatype,
5191 * then also kstrtou8 fails
5192 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005193 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005194 ret = -EINVAL;
5195 goto exit;
5196 }
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005197 if ((filter_type < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL) ||
5198 (filter_type > WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005199 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005200 ret = -EINVAL;
5201 goto exit;
5202 }
5203 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005204 hdd_ctx->miracast_value = filter_type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005205
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005206 ret_status = sme_set_miracast(hdd_ctx->mac_handle, filter_type);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305207 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005208 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005209 return -EBUSY;
5210 }
Dustin Brown1dbefe62018-09-11 16:32:03 -07005211 ret_status = ucfg_scan_set_miracast(hdd_ctx->psoc,
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005212 filter_type ? true : false);
Abhishek Singhc87bb042018-01-30 17:10:42 +05305213 if (QDF_IS_STATUS_ERROR(ret_status)) {
5214 hdd_err("Failed to set miracastn scan");
5215 return -EBUSY;
5216 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005217
Dustin Brown1dbefe62018-09-11 16:32:03 -07005218 if (policy_mgr_is_mcc_in_24G(hdd_ctx->psoc))
Jeff Johnson3dd8a542019-02-26 21:38:14 -08005219 return wlan_hdd_set_mas(adapter, filter_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005220
5221exit:
5222 return ret;
5223}
5224
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305225#ifdef FEATURE_WLAN_RMC
5226/* Function header is left blank intentionally */
Jeff Johnson6636e622019-02-26 10:22:39 -08005227static int hdd_parse_setrmcenable_command(uint8_t *command,
Jeff Johnson259f3e92019-02-26 13:36:01 -08005228 uint8_t *rmc_enable)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305229{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005230 uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005231 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305232 int v = 0;
5233 char buf[32];
Jeff Johnson259f3e92019-02-26 13:36:01 -08005234 *rmc_enable = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305235
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005236 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305237
Jeff Johnsond36fa332019-03-18 13:42:25 -07005238 if (!in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305239 return 0;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005240 else if (SPACE_ASCII_VALUE != *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305241 return 0;
5242
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005243 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
5244 in_ptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305245
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005246 if ('\0' == *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305247 return 0;
5248
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005249 v = sscanf(in_ptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305250 if (1 != v)
5251 return -EINVAL;
5252
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005253 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305254 if (v < 0)
5255 return -EINVAL;
5256
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005257 *rmc_enable = temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305258
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005259 hdd_debug("rmc_enable: %d", *rmc_enable);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305260
5261 return 0;
5262}
5263
5264/* Function header is left blank intentionally */
Wu Gao1ab05582018-11-08 16:22:49 +08005265static int hdd_parse_setrmcactionperiod_command(uint8_t *pvalue,
5266 uint32_t *paction_period)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305267{
Wu Gao1ab05582018-11-08 16:22:49 +08005268 uint8_t *inptr = pvalue;
5269 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305270 int v = 0;
5271 char buf[32];
Wu Gao1ab05582018-11-08 16:22:49 +08005272 *paction_period = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305273
Wu Gao1ab05582018-11-08 16:22:49 +08005274 inptr = strnchr(pvalue, strlen(pvalue), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305275
Jeff Johnsond36fa332019-03-18 13:42:25 -07005276 if (!inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305277 return -EINVAL;
Wu Gao1ab05582018-11-08 16:22:49 +08005278 else if (SPACE_ASCII_VALUE != *inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305279 return -EINVAL;
5280
Wu Gao1ab05582018-11-08 16:22:49 +08005281 while ((SPACE_ASCII_VALUE == *inptr) && ('\0' != *inptr))
5282 inptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305283
Wu Gao1ab05582018-11-08 16:22:49 +08005284 if ('\0' == *inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305285 return 0;
5286
Wu Gao1ab05582018-11-08 16:22:49 +08005287 v = sscanf(inptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305288 if (1 != v)
5289 return -EINVAL;
5290
Wu Gao1ab05582018-11-08 16:22:49 +08005291 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305292 if (v < 0)
5293 return -EINVAL;
5294
Wu Gao1ab05582018-11-08 16:22:49 +08005295 if (!cfg_in_range(CFG_RMC_ACTION_PERIOD_FREQUENCY, temp_int))
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305296 return -EINVAL;
5297
Wu Gao1ab05582018-11-08 16:22:49 +08005298 *paction_period = temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305299
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005300 hdd_debug("action_period: %d", *paction_period);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305301
5302 return 0;
5303}
5304
5305/* Function header is left blank intentionally */
Jeff Johnson6636e622019-02-26 10:22:39 -08005306static int hdd_parse_setrmcrate_command(uint8_t *command,
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08005307 uint32_t *rate,
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005308 enum tx_rate_info *tx_flags)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305309{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005310 uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005311 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305312 int v = 0;
5313 char buf[32];
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08005314 *rate = 0;
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005315 *tx_flags = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305316
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005317 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305318
Jeff Johnsond36fa332019-03-18 13:42:25 -07005319 if (!in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305320 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005321 else if (SPACE_ASCII_VALUE != *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305322 return -EINVAL;
5323
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005324 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
5325 in_ptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305326
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005327 if ('\0' == *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305328 return 0;
5329
Jeff Johnson4ff36b22019-02-26 13:01:07 -08005330 v = sscanf(in_ptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305331 if (1 != v)
5332 return -EINVAL;
5333
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005334 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305335 if (v < 0)
5336 return -EINVAL;
5337
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005338 switch (temp_int) {
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305339 default:
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005340 hdd_warn("Unsupported rate: %d", temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305341 return -EINVAL;
5342 case 0:
5343 case 6:
5344 case 9:
5345 case 12:
5346 case 18:
5347 case 24:
5348 case 36:
5349 case 48:
5350 case 54:
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005351 *tx_flags = TX_RATE_LEGACY;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005352 *rate = temp_int * 10;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305353 break;
5354 case 65:
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005355 *tx_flags = TX_RATE_HT20;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08005356 *rate = temp_int * 10;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305357 break;
5358 case 72:
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005359 *tx_flags = TX_RATE_HT20 | TX_RATE_SGI;
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08005360 *rate = 722;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305361 break;
5362 }
5363
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08005364 hdd_debug("Rate: %d", *rate);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305365
5366 return 0;
5367}
5368
Jeff Johnsone44b7012017-09-10 15:25:47 -07005369static int drv_cmd_set_rmc_enable(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005370 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005371 uint8_t *command,
5372 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005373 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005374{
5375 int ret = 0;
5376 uint8_t *value = command;
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005377 uint8_t rmc_enable = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005378 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005379 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005380
Krunal Sonibe766b02016-03-10 13:00:44 -08005381 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5382 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005383 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005384 qdf_opmode_str(adapter->device_mode),
5385 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005386 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005387 ret = -EINVAL;
5388 goto exit;
5389 }
5390
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005391 status = hdd_parse_setrmcenable_command(value, &rmc_enable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005392 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005393 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005394 ret = -EINVAL;
5395 goto exit;
5396 }
5397
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005398 hdd_debug("rmc_enable %d", rmc_enable);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005399 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005400
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005401 if (true == rmc_enable) {
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005402 status = sme_enable_rmc(mac_handle, adapter->vdev_id);
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005403 } else if (false == rmc_enable) {
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005404 status = sme_disable_rmc(mac_handle, adapter->vdev_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005405 } else {
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005406 hdd_err("Invalid SETRMCENABLE command %d", rmc_enable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005407 ret = -EINVAL;
5408 goto exit;
5409 }
5410
5411 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005412 hdd_err("SETRMC %d failed status %d", rmc_enable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005413 ret = -EINVAL;
5414 goto exit;
5415 }
5416
5417exit:
5418 return ret;
5419}
5420
Jeff Johnsone44b7012017-09-10 15:25:47 -07005421static int drv_cmd_set_rmc_action_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005422 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005423 uint8_t *command,
5424 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005425 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005426{
5427 int ret = 0;
5428 uint8_t *value = command;
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005429 uint32_t action_period = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005430 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005431 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005432
Krunal Sonibe766b02016-03-10 13:00:44 -08005433 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5434 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005435 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005436 qdf_opmode_str(adapter->device_mode),
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005437 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005438 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005439 ret = -EINVAL;
5440 goto exit;
5441 }
5442
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005443 status = hdd_parse_setrmcactionperiod_command(value, &action_period);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005444 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005445 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005446 ret = -EINVAL;
5447 goto exit;
5448 }
5449
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005450 hdd_debug("action_period %d", action_period);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005451 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005452
Dustin Brown05d81302018-09-11 16:49:22 -07005453 if (ucfg_mlme_set_rmc_action_period_freq(hdd_ctx->psoc,
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005454 action_period) !=
Bala Venkatesh2fde2c62018-09-11 20:33:24 +05305455 QDF_STATUS_SUCCESS) {
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005456 hdd_err("Could not set SETRMCACTIONPERIOD %d", action_period);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005457 ret = -EINVAL;
5458 goto exit;
5459 }
5460
Jeff Johnsond549efa2018-06-13 20:27:47 -07005461 status = sme_send_rmc_action_period(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005462 adapter->vdev_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005463 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005464 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005465 status);
5466 ret = -EINVAL;
5467 goto exit;
5468 }
5469
5470exit:
5471 return ret;
5472}
5473
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305474static int drv_cmd_set_rmc_tx_rate(struct hdd_adapter *adapter,
5475 struct hdd_context *hdd_ctx,
5476 uint8_t *command,
5477 uint8_t command_len,
5478 struct hdd_priv_data *priv_data)
5479{
5480 int ret = 0;
5481 uint8_t *value = command;
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005482 uint32_t rate = 0;
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005483 enum tx_rate_info tx_flags = 0;
Jeff Johnson2370b852019-02-26 17:03:12 -08005484 tSirRateUpdateInd params = {0};
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305485 int status;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05305486 bool bval = false;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305487
5488 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5489 (QDF_SAP_MODE != adapter->device_mode)) {
5490 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005491 qdf_opmode_str(adapter->device_mode),
5492 adapter->device_mode);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305493 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
5494 ret = -EINVAL;
5495 goto exit;
5496 }
5497
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005498 status = hdd_parse_setrmcrate_command(value, &rate, &tx_flags);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305499 if (status) {
5500 hdd_err("Invalid SETRMCTXRATE command");
5501 ret = -EINVAL;
5502 goto exit;
5503 }
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005504 hdd_debug("rate %d", rate);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305505
5506 /*
5507 * Fill the user specifieed RMC rate param
5508 * and the derived tx flags.
5509 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05305510 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
5511 if (!QDF_IS_STATUS_SUCCESS(status)) {
5512 hdd_err("unable to get vht_enable2x2");
5513 ret = -EINVAL;
5514 goto exit;
5515 }
Jeff Johnson2370b852019-02-26 17:03:12 -08005516 params.nss = (bval == 0) ? 0 : 1;
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005517 params.reliableMcastDataRate = rate;
Jeff Johnson2370b852019-02-26 17:03:12 -08005518 params.reliableMcastDataRateTxFlag = tx_flags;
5519 params.dev_mode = adapter->device_mode;
5520 params.bcastDataRate = -1;
5521 memcpy(params.bssid.bytes,
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305522 adapter->mac_addr.bytes,
Jeff Johnson2370b852019-02-26 17:03:12 -08005523 sizeof(params.bssid));
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305524 status = sme_send_rate_update_ind(hdd_ctx->mac_handle,
Jeff Johnson2370b852019-02-26 17:03:12 -08005525 &params);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305526
5527exit:
5528 return ret;
5529}
5530#endif /* FEATURE_WLAN_RMC */
5531
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005532#ifdef FEATURE_WLAN_ESE
Jeff Johnsone44b7012017-09-10 15:25:47 -07005533static int drv_cmd_set_ccx_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005534 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005535 uint8_t *command,
5536 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005537 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005538{
5539 int ret = 0;
5540 uint8_t *value = command;
Liangwei Dong075afa72019-10-30 12:58:22 +08005541 uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005542 uint8_t num_channels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305543 QDF_STATUS status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005544 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005545
Liangwei Dong075afa72019-10-30 12:58:22 +08005546 if (!hdd_ctx) {
5547 hdd_err("invalid hdd ctx");
5548 ret = -EINVAL;
5549 goto exit;
5550 }
5551
5552 ret = hdd_parse_channellist(hdd_ctx, value, channel_freq_list,
5553 &num_channels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005554 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005555 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005556 goto exit;
5557 }
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005558 if (num_channels > CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005559 hdd_err("number of channels (%d) supported exceeded max (%d)",
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005560 num_channels,
5561 CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005562 ret = -EINVAL;
5563 goto exit;
5564 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305565
Jeff Johnsond549efa2018-06-13 20:27:47 -07005566 mac_handle = hdd_ctx->mac_handle;
Liangwei Dong075afa72019-10-30 12:58:22 +08005567 if (!sme_validate_channel_list(mac_handle, channel_freq_list,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005568 num_channels)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305569 hdd_err("List contains invalid channel(s)");
5570 ret = -EINVAL;
5571 goto exit;
5572 }
5573
Jeff Johnsond549efa2018-06-13 20:27:47 -07005574 status = sme_set_ese_roam_scan_channel_list(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005575 adapter->vdev_id,
Liangwei Dong075afa72019-10-30 12:58:22 +08005576 channel_freq_list,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005577 num_channels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305578 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005579 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005580 ret = -EINVAL;
5581 goto exit;
5582 }
5583
5584exit:
5585 return ret;
5586}
5587
Jeff Johnsone44b7012017-09-10 15:25:47 -07005588static int drv_cmd_get_tsm_stats(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005589 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005590 uint8_t *command,
5591 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005592 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005593{
5594 int ret = 0;
5595 uint8_t *value = command;
5596 char extra[128] = { 0 };
5597 int len = 0;
5598 uint8_t tid = 0;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005599 struct hdd_station_ctx *sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005600 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005601
Krunal Sonibe766b02016-03-10 13:00:44 -08005602 if ((QDF_STA_MODE != adapter->device_mode) &&
5603 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005604 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005605 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005606 adapter->device_mode);
5607 return -EINVAL;
5608 }
5609
Jeff Johnsond377dce2017-10-04 10:32:42 -07005610 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005611
5612 /* if not associated, return error */
Jeff Johnsone7951512019-02-27 10:02:51 -08005613 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005614 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005615 ret = -EINVAL;
5616 goto exit;
5617 }
5618
5619 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5620 value = value + command_len + 1;
5621
5622 /* Convert the value from ascii to integer */
5623 ret = kstrtou8(value, 10, &tid);
5624 if (ret < 0) {
5625 /*
5626 * If the input value is greater than max value of datatype,
5627 * then also kstrtou8 fails
5628 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005629 hdd_err("kstrtou8 failed range [%d - %d]",
5630 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005631 TID_MAX_VALUE);
5632 ret = -EINVAL;
5633 goto exit;
5634 }
5635 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005636 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005637 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5638 ret = -EINVAL;
5639 goto exit;
5640 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005641 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005642 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005643 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5644 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005645 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005646 goto exit;
5647 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005648 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005649 "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 -08005650 tsm_metrics.UplinkPktQueueDly,
5651 tsm_metrics.UplinkPktQueueDlyHist[0],
5652 tsm_metrics.UplinkPktQueueDlyHist[1],
5653 tsm_metrics.UplinkPktQueueDlyHist[2],
5654 tsm_metrics.UplinkPktQueueDlyHist[3],
5655 tsm_metrics.UplinkPktTxDly,
5656 tsm_metrics.UplinkPktLoss,
5657 tsm_metrics.UplinkPktCount,
5658 tsm_metrics.RoamingCount,
5659 tsm_metrics.RoamingDly);
5660 /*
5661 * Output TSM stats is of the format
5662 * GETTSMSTATS [PktQueueDly]
5663 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5664 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5665 */
5666 len = scnprintf(extra,
5667 sizeof(extra),
5668 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5669 command,
5670 tsm_metrics.UplinkPktQueueDly,
5671 tsm_metrics.UplinkPktQueueDlyHist[0],
5672 tsm_metrics.UplinkPktQueueDlyHist[1],
5673 tsm_metrics.UplinkPktQueueDlyHist[2],
5674 tsm_metrics.UplinkPktQueueDlyHist[3],
5675 tsm_metrics.UplinkPktTxDly,
5676 tsm_metrics.UplinkPktLoss,
5677 tsm_metrics.UplinkPktCount,
5678 tsm_metrics.RoamingCount,
5679 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305680 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005681 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005682 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005683 ret = -EFAULT;
5684 goto exit;
5685 }
5686
5687exit:
5688 return ret;
5689}
5690
Jeff Johnsone44b7012017-09-10 15:25:47 -07005691static int drv_cmd_set_cckm_ie(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005692 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005693 uint8_t *command,
5694 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005695 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005696{
5697 int ret;
5698 uint8_t *value = command;
Jeff Johnson264e2d32019-02-26 13:16:58 -08005699 uint8_t *cckm_ie = NULL;
Jeff Johnsonb9eeef32019-02-26 13:15:49 -08005700 uint8_t cckm_ie_len = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005701
Jeff Johnson264e2d32019-02-26 13:16:58 -08005702 ret = hdd_parse_get_cckm_ie(value, &cckm_ie, &cckm_ie_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005703 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005704 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005705 goto exit;
5706 }
5707
Jeff Johnsonb9eeef32019-02-26 13:15:49 -08005708 if (cckm_ie_len > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005709 hdd_err("CCKM Ie input length is more than max[%d]",
5710 DOT11F_IE_RSN_MAX_LEN);
Jeff Johnsond36fa332019-03-18 13:42:25 -07005711 if (cckm_ie) {
Jeff Johnson264e2d32019-02-26 13:16:58 -08005712 qdf_mem_free(cckm_ie);
5713 cckm_ie = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005714 }
5715 ret = -EINVAL;
5716 goto exit;
5717 }
5718
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005719 sme_set_cckm_ie(hdd_ctx->mac_handle, adapter->vdev_id,
Jeff Johnson264e2d32019-02-26 13:16:58 -08005720 cckm_ie, cckm_ie_len);
Jeff Johnsond36fa332019-03-18 13:42:25 -07005721 if (cckm_ie) {
Jeff Johnson264e2d32019-02-26 13:16:58 -08005722 qdf_mem_free(cckm_ie);
5723 cckm_ie = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005724 }
5725
5726exit:
5727 return ret;
5728}
5729
Jeff Johnsone44b7012017-09-10 15:25:47 -07005730static int drv_cmd_ccx_beacon_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005731 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005732 uint8_t *command,
5733 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005734 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005735{
5736 int ret;
5737 uint8_t *value = command;
Jeff Johnson210bc972019-02-26 19:55:01 -08005738 tCsrEseBeaconReq req = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305739 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005740
Krunal Sonibe766b02016-03-10 13:00:44 -08005741 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005742 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005743 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005744 adapter->device_mode);
5745 return -EINVAL;
5746 }
5747
gaurank kathpalia88f78ec2019-09-04 20:18:02 +05305748 ret = hdd_parse_ese_beacon_req(hdd_ctx->pdev, value, &req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005749 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005750 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005751 goto exit;
5752 }
5753
5754 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005755 hdd_debug("Not associated");
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305756
Jeff Johnson210bc972019-02-26 19:55:01 -08005757 if (!req.numBcnReqIe)
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305758 return -EINVAL;
5759
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005760 hdd_indicate_ese_bcn_report_no_results(adapter,
Jeff Johnson210bc972019-02-26 19:55:01 -08005761 req.bcnReq[0].measurementToken,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005762 0x02, /* BIT(1) set for measurement done */
5763 0); /* no BSS */
5764 goto exit;
5765 }
5766
Jeff Johnsond549efa2018-06-13 20:27:47 -07005767 status = sme_set_ese_beacon_request(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005768 adapter->vdev_id,
Jeff Johnson210bc972019-02-26 19:55:01 -08005769 &req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005770
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305771 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005772 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005773 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005774 ret = -EBUSY;
5775 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305776 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005777 hdd_err("sme_set_ese_beacon_request failed (%d)",
5778 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005779 ret = -EINVAL;
5780 goto exit;
5781 }
5782
5783exit:
5784 return ret;
5785}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005786
5787/**
5788 * drv_cmd_ccx_plm_req() - Set ESE PLM request
Jeff Johnson36583f02019-02-26 08:02:11 -08005789 * @adapter: Pointer to the HDD adapter
5790 * @hdd_ctx: Pointer to the HDD context
5791 * @command: Driver command string
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005792 * @command_len: Driver command string length
Jeff Johnson36583f02019-02-26 08:02:11 -08005793 * @priv_data: Private data coming with the driver command. Unused here
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005794 *
5795 * This function handles driver command that sets the ESE PLM request
5796 *
5797 * Return: 0 on success; negative errno otherwise
5798 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005799static int drv_cmd_ccx_plm_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005800 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005801 uint8_t *command,
5802 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005803 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005804{
Jeff Johnson36583f02019-02-26 08:02:11 -08005805 QDF_STATUS status;
5806 struct plm_req_params *req;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005807
Jeff Johnson36583f02019-02-26 08:02:11 -08005808 req = qdf_mem_malloc(sizeof(*req));
5809 if (!req)
5810 return -ENOMEM;
5811
5812 status = hdd_parse_plm_cmd(command, req);
5813 if (QDF_IS_STATUS_SUCCESS(status)) {
5814 req->vdev_id = adapter->vdev_id;
5815 status = sme_set_plm_request(hdd_ctx->mac_handle, req);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005816 }
Jeff Johnson36583f02019-02-26 08:02:11 -08005817 qdf_mem_free(req);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005818
Jeff Johnson36583f02019-02-26 08:02:11 -08005819 return qdf_status_to_os_return(status);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005820}
5821
5822/**
5823 * drv_cmd_set_ccx_mode() - Set ESE mode
5824 * @adapter: Pointer to the HDD adapter
5825 * @hdd_ctx: Pointer to the HDD context
5826 * @command: Driver command string
5827 * @command_len: Driver command string length
5828 * @priv_data: Private data coming with the driver command. Unused here
5829 *
5830 * This function handles driver command that sets ESE mode
5831 *
5832 * Return: 0 on success; negative errno otherwise
5833 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005834static int drv_cmd_set_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005835 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005836 uint8_t *command,
5837 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005838 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005839{
5840 int ret = 0;
5841 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08005842 uint8_t ese_mode = cfg_default(CFG_LFR_ESE_FEATURE_ENABLED);
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005843 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005844 mac_handle_t mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005845
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005846 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005847 mac_handle = hdd_ctx->mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005848 /*
5849 * Check if the features OKC/ESE/11R are supported simultaneously,
5850 * then this operation is not permitted (return FAILURE)
5851 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005852 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005853 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07005854 sme_get_is_ft_feature_enabled(mac_handle)) {
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005855 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5856 ret = -EPERM;
5857 goto exit;
5858 }
5859
5860 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5861 value = value + command_len + 1;
5862
5863 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08005864 ret = kstrtou8(value, 10, &ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005865 if (ret < 0) {
5866 /*
5867 * If the input value is greater than max value of datatype,
5868 * then also kstrtou8 fails
5869 */
5870 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08005871 cfg_min(CFG_LFR_ESE_FEATURE_ENABLED),
5872 cfg_max(CFG_LFR_ESE_FEATURE_ENABLED));
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005873 ret = -EINVAL;
5874 goto exit;
5875 }
5876
Wu Gao1ab05582018-11-08 16:22:49 +08005877 hdd_debug("Received Command to change ese mode = %d", ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005878
Jeff Johnsond549efa2018-06-13 20:27:47 -07005879 sme_update_is_ese_feature_enabled(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005880 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08005881 ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005882
5883exit:
5884 return ret;
5885}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005886#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005887
Jeff Johnsone44b7012017-09-10 15:25:47 -07005888static int drv_cmd_set_mc_rate(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005889 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005890 uint8_t *command,
5891 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005892 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005893{
5894 int ret = 0;
5895 uint8_t *value = command;
Srinivas Girigowda9d550152019-03-26 12:19:45 -07005896 uint32_t target_rate = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005897
5898 /* input value is in units of hundred kbps */
5899
5900 /* Move pointer to ahead of SETMCRATE<delimiter> */
5901 value = value + command_len + 1;
5902
5903 /* Convert the value from ascii to integer, decimal base */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005904 ret = kstrtouint(value, 10, &target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005905
Jeff Johnsond549efa2018-06-13 20:27:47 -07005906 ret = wlan_hdd_set_mc_rate(adapter, target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005907 return ret;
5908}
5909
Jeff Johnsone44b7012017-09-10 15:25:47 -07005910static int drv_cmd_max_tx_power(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005911 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005912 uint8_t *command,
5913 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005914 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005915{
Jeff Johnsond549efa2018-06-13 20:27:47 -07005916 int ret;
5917 int tx_power;
5918 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005919 uint8_t *value = command;
Dustin Brownce5b3d32018-01-17 15:07:38 -08005920 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005921 struct qdf_mac_addr selfmac = QDF_MAC_ADDR_BCAST_INIT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005922
Jeff Johnsond549efa2018-06-13 20:27:47 -07005923 ret = hdd_parse_setmaxtxpower_command(value, &tx_power);
5924 if (ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005925 hdd_err("Invalid MAXTXPOWER command");
Jeff Johnsond549efa2018-06-13 20:27:47 -07005926 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005927 }
5928
Dustin Brown920397d2017-12-13 16:27:50 -08005929 hdd_for_each_adapter(hdd_ctx, adapter) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005930 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305931 qdf_copy_macaddr(&bssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005932 &adapter->mac_addr);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005933 qdf_copy_macaddr(&selfmac,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005934 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005935
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005936 hdd_debug("Device mode %d max tx power %d selfMac: "
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -07005937 QDF_MAC_ADDR_STR " bssId: " QDF_MAC_ADDR_STR,
Jeff Johnsond549efa2018-06-13 20:27:47 -07005938 adapter->device_mode, tx_power,
Srinivas Girigowda34fbba02019-04-08 12:07:44 -07005939 QDF_MAC_ADDR_ARRAY(selfmac.bytes),
5940 QDF_MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005941
Jeff Johnsond549efa2018-06-13 20:27:47 -07005942 status = sme_set_max_tx_power(hdd_ctx->mac_handle,
5943 bssid, selfmac, tx_power);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305944 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005945 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005946 ret = -EINVAL;
5947 goto exit;
5948 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005949 hdd_debug("Set max tx power success");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005950 }
5951
5952exit:
5953 return ret;
5954}
5955
Jeff Johnsone44b7012017-09-10 15:25:47 -07005956static int drv_cmd_set_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005957 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005958 uint8_t *command,
5959 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005960 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005961{
5962 int ret = 0;
5963 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08005964 uint8_t dfs_scan_mode = cfg_default(CFG_LFR_ROAMING_DFS_CHANNEL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005965
5966 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5967 value = value + command_len + 1;
5968
5969 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08005970 ret = kstrtou8(value, 10, &dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005971 if (ret < 0) {
5972 /*
5973 * If the input value is greater than max value of datatype,
5974 * then also kstrtou8 fails
5975 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005976 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08005977 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5978 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005979 ret = -EINVAL;
5980 goto exit;
5981 }
5982
Wu Gao1ab05582018-11-08 16:22:49 +08005983 if (!cfg_in_range(CFG_LFR_ROAMING_DFS_CHANNEL, dfs_scan_mode)) {
Jeff Johnson68605512019-02-26 21:30:04 -08005984 hdd_err("dfs_scan_mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08005985 dfs_scan_mode,
5986 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5987 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005988 ret = -EINVAL;
5989 goto exit;
5990 }
5991
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005992 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08005993 dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005994
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005995 /* When DFS scanning is disabled, the DFS channels need to be
5996 * removed from the operation of device.
5997 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005998 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
Wu Gao1ab05582018-11-08 16:22:49 +08005999 dfs_scan_mode != ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08006000 if (ret < 0) {
6001 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006002 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08006003 goto exit;
6004 }
6005
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006006 sme_update_dfs_scan_mode(hdd_ctx->mac_handle, adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08006007 dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006008
6009exit:
6010 return ret;
6011}
6012
Jeff Johnsone44b7012017-09-10 15:25:47 -07006013static int drv_cmd_get_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006014 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006015 uint8_t *command,
6016 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006017 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006018{
6019 int ret = 0;
Jeff Johnson68605512019-02-26 21:30:04 -08006020 uint8_t dfs_scan_mode = sme_get_dfs_scan_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006021 char extra[32];
6022 uint8_t len = 0;
6023
Jeff Johnson68605512019-02-26 21:30:04 -08006024 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfs_scan_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306025 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006026 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006027 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006028 ret = -EFAULT;
6029 }
6030
6031 return ret;
6032}
6033
Jeff Johnsone44b7012017-09-10 15:25:47 -07006034static int drv_cmd_get_link_status(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006035 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006036 uint8_t *command,
6037 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006038 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006039{
6040 int ret = 0;
6041 int value = wlan_hdd_get_link_status(adapter);
6042 char extra[32];
6043 uint8_t len;
6044
6045 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306046 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006047 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006048 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006049 ret = -EFAULT;
6050 }
6051
6052 return ret;
6053}
6054
6055#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Jeff Johnsone44b7012017-09-10 15:25:47 -07006056static int drv_cmd_enable_ext_wow(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006057 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006058 uint8_t *command,
6059 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006060 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006061{
6062 uint8_t *value = command;
6063 int set_value;
6064
6065 /* Move pointer to ahead of ENABLEEXTWOW */
6066 value = value + command_len;
6067
Anurag Chouhan43e0c752016-09-03 16:17:02 +05306068 if (!(sscanf(value, "%d", &set_value))) {
Dustin Browna2868622018-03-20 11:38:14 -07006069 hdd_info("No input identified");
Anurag Chouhan43e0c752016-09-03 16:17:02 +05306070 return -EINVAL;
6071 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006072
6073 return hdd_enable_ext_wow_parser(adapter,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006074 adapter->vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006075 set_value);
6076}
6077
Jeff Johnsone44b7012017-09-10 15:25:47 -07006078static int drv_cmd_set_app1_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006079 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006080 uint8_t *command,
6081 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006082 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006083{
6084 int ret;
6085 uint8_t *value = command;
6086
6087 /* Move pointer to ahead of SETAPP1PARAMS */
6088 value = value + command_len;
6089
6090 ret = hdd_set_app_type1_parser(adapter,
6091 value, strlen(value));
6092 if (ret >= 0)
6093 hdd_ctx->is_extwow_app_type1_param_set = true;
6094
6095 return ret;
6096}
6097
Jeff Johnsone44b7012017-09-10 15:25:47 -07006098static int drv_cmd_set_app2_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006099 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006100 uint8_t *command,
6101 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006102 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006103{
6104 int ret;
6105 uint8_t *value = command;
6106
6107 /* Move pointer to ahead of SETAPP2PARAMS */
6108 value = value + command_len;
6109
6110 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
6111 if (ret >= 0)
6112 hdd_ctx->is_extwow_app_type2_param_set = true;
6113
6114 return ret;
6115}
6116#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
6117
6118#ifdef FEATURE_WLAN_TDLS
6119/**
6120 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
6121 * @adapter: Pointer to the HDD adapter
6122 * @hdd_ctx: Pointer to the HDD context
6123 * @command: Driver command string
6124 * @command_len: Driver command string length
6125 * @priv_data: Private data coming with the driver command. Unused here
6126 *
6127 * This function handles driver command that sets the secondary tdls off channel
6128 * offset
6129 *
6130 * Return: 0 on success; negative errno otherwise
6131 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006132static int drv_cmd_tdls_secondary_channel_offset(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006133 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006134 uint8_t *command,
6135 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006136 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006137{
6138 int ret;
6139 uint8_t *value = command;
6140 int set_value;
6141
6142 /* Move pointer to point the string */
6143 value += command_len;
6144
6145 ret = sscanf(value, "%d", &set_value);
6146 if (ret != 1)
6147 return -EINVAL;
6148
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006149 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006150
Bala Venkatesh113a9e62018-08-30 15:19:02 +05306151 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, adapter, set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006152
6153 return ret;
6154}
6155
6156/**
6157 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
6158 * @adapter: Pointer to the HDD adapter
6159 * @hdd_ctx: Pointer to the HDD context
6160 * @command: Driver command string
6161 * @command_len: Driver command string length
6162 * @priv_data: Private data coming with the driver command. Unused here
6163 *
6164 * This function handles driver command that sets tdls off channel mode
6165 *
6166 * Return: 0 on success; negative errno otherwise
6167 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006168static int drv_cmd_tdls_off_channel_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006169 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006170 uint8_t *command,
6171 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006172 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006173{
6174 int ret;
6175 uint8_t *value = command;
6176 int set_value;
6177
6178 /* Move pointer to point the string */
6179 value += command_len;
6180
6181 ret = sscanf(value, "%d", &set_value);
6182 if (ret != 1)
6183 return -EINVAL;
6184
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006185 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006186
Bala Venkatesh113a9e62018-08-30 15:19:02 +05306187 ret = hdd_set_tdls_offchannelmode(hdd_ctx, adapter, set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006188
6189 return ret;
6190}
6191
6192/**
6193 * drv_cmd_tdls_off_channel() - set tdls off channel number
6194 * @adapter: Pointer to the HDD adapter
6195 * @hdd_ctx: Pointer to the HDD context
6196 * @command: Driver command string
6197 * @command_len: Driver command string length
6198 * @priv_data: Private data coming with the driver command. Unused here
6199 *
6200 * This function handles driver command that sets tdls off channel number
6201 *
6202 * Return: 0 on success; negative errno otherwise
6203 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006204static int drv_cmd_tdls_off_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006205 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006206 uint8_t *command,
6207 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006208 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006209{
6210 int ret;
6211 uint8_t *value = command;
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306212 int channel;
6213 enum channel_state reg_state;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006214
6215 /* Move pointer to point the string */
6216 value += command_len;
6217
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306218 ret = sscanf(value, "%d", &channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006219 if (ret != 1)
6220 return -EINVAL;
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306221 reg_state = wlan_reg_get_channel_state(hdd_ctx->pdev, channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006222
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306223 if (reg_state == CHANNEL_STATE_DFS ||
6224 reg_state == CHANNEL_STATE_DISABLE ||
6225 reg_state == CHANNEL_STATE_INVALID) {
6226 hdd_err("reg state of the channel %d is %d and not supported",
6227 channel, reg_state);
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006228 return -EINVAL;
6229 }
6230
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306231 hdd_debug("Tdls offchannel num: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006232
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306233 ret = hdd_set_tdls_offchannel(hdd_ctx, adapter, channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006234
6235 return ret;
6236}
6237
6238/**
6239 * drv_cmd_tdls_scan() - set tdls scan type
6240 * @adapter: Pointer to the HDD adapter
6241 * @hdd_ctx: Pointer to the HDD context
6242 * @command: Driver command string
6243 * @command_len: Driver command string length
6244 * @priv_data: Private data coming with the driver command. Unused here
6245 *
6246 * This function handles driver command that sets tdls scan type
6247 *
6248 * Return: 0 on success; negative errno otherwise
6249 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006250static int drv_cmd_tdls_scan(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;
6257 uint8_t *value = command;
6258 int set_value;
6259
6260 /* Move pointer to point the string */
6261 value += command_len;
6262
6263 ret = sscanf(value, "%d", &set_value);
6264 if (ret != 1)
6265 return -EINVAL;
6266
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006267 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006268
6269 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6270
6271 return ret;
6272}
6273#endif
6274
Jeff Johnsone44b7012017-09-10 15:25:47 -07006275static int drv_cmd_get_rssi(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006276 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006277 uint8_t *command,
6278 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006279 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006280{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006281 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006282 int8_t rssi = 0;
6283 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006284
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006285 uint8_t len = 0;
6286
6287 wlan_hdd_get_rssi(adapter, &rssi);
6288
6289 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306290 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006291
6292 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006293 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006294 ret = -EFAULT;
6295 }
6296
6297 return ret;
6298}
6299
Jeff Johnsone44b7012017-09-10 15:25:47 -07006300static int drv_cmd_get_linkspeed(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006301 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006302 uint8_t *command,
6303 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006304 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006305{
6306 int ret;
6307 uint32_t link_speed = 0;
6308 char extra[32];
6309 uint8_t len = 0;
6310
6311 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6312 if (0 != ret)
6313 return ret;
6314
6315 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306316 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006317 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006318 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006319 ret = -EFAULT;
6320 }
6321
6322 return ret;
6323}
6324
Qiwei Cai4505fc62018-05-17 18:35:19 +08006325#ifdef WLAN_FEATURE_PACKET_FILTERING
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006326/**
6327 * hdd_set_rx_filter() - set RX filter
6328 * @adapter: Pointer to adapter
6329 * @action: Filter action
6330 * @pattern: Address pattern
6331 *
6332 * Address pattern is most significant byte of address for example
6333 * 0x01 for IPV4 multicast address
6334 * 0x33 for IPV6 multicast address
6335 * 0xFF for broadcast address
6336 *
6337 * Return: 0 for success, non-zero for failure
6338 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006339static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006340 uint8_t pattern)
6341{
6342 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006343 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006344 tSirRcvFltMcAddrList *filter;
Jeff Johnson621cf972017-08-28 11:58:44 -07006345 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006346 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006347
6348 ret = wlan_hdd_validate_context(hdd_ctx);
6349 if (0 != ret)
6350 return ret;
6351
Jeff Johnsond549efa2018-06-13 20:27:47 -07006352 mac_handle = hdd_ctx->mac_handle;
6353 if (!mac_handle) {
6354 hdd_err("MAC Handle is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006355 return -EINVAL;
6356 }
6357
Wu Gao66454f12018-09-26 19:55:41 +08006358 if (!ucfg_pmo_is_mc_addr_list_enabled(hdd_ctx->psoc)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006359 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306360 return -EINVAL;
6361 }
6362
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006363 /*
6364 * If action is false it means start dropping packets
6365 * Set addr_filter_pattern which will be used when sending
6366 * MC/BC address list to target
6367 */
6368 if (!action)
6369 adapter->addr_filter_pattern = pattern;
6370 else
6371 adapter->addr_filter_pattern = 0;
6372
Krunal Sonibe766b02016-03-10 13:00:44 -08006373 if (((adapter->device_mode == QDF_STA_MODE) ||
6374 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006375 adapter->mc_addr_list.mc_cnt &&
6376 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6377
6378
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306379 filter = qdf_mem_malloc(sizeof(*filter));
Jeff Johnsond36fa332019-03-18 13:42:25 -07006380 if (!filter) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006381 hdd_err("Could not allocate Memory");
6382 return -ENOMEM;
6383 }
6384 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006385 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006386 if (!memcmp(adapter->mc_addr_list.addr[i],
6387 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006388 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006389 adapter->mc_addr_list.addr[i],
6390 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006391
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006392 hdd_debug("%s RX filter : addr ="
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -07006393 QDF_MAC_ADDR_STR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006394 action ? "setting" : "clearing",
Srinivas Girigowda34fbba02019-04-08 12:07:44 -07006395 QDF_MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
Frank Liuf95e8132016-09-29 19:01:30 +08006396 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006397 }
SaidiReddy Yenuga0b2c9f42017-02-03 12:26:38 +05306398 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
6399 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006400 }
Frank Liuf95e8132016-09-29 19:01:30 +08006401 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006402 /* Set rx filter */
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006403 sme_8023_multicast_list(mac_handle, adapter->vdev_id,
Jeff Johnsond549efa2018-06-13 20:27:47 -07006404 filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306405 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006406 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006407 hdd_debug("mode %d mc_cnt %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07006408 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006409 }
6410
6411 return 0;
6412}
6413
6414/**
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006415 * hdd_driver_rxfilter_command_handler() - RXFILTER driver command handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006416 * @command: Pointer to input string driver command
6417 * @adapter: Pointer to adapter
6418 * @action: Action to enable/disable filtering
6419 *
6420 * If action == false
6421 * Start filtering out data packets based on type
6422 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6423 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6424 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6425 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6426 *
6427 * if action == true
6428 * Stop filtering data packets based on type
6429 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6430 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6431 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6432 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6433 *
6434 * Current implementation only supports IPV4 address filtering by
6435 * selectively allowing IPV4 multicast data packest based on
6436 * address list received in .ndo_set_rx_mode
6437 *
6438 * Return: 0 for success, non-zero for failure
6439 */
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006440static int hdd_driver_rxfilter_command_handler(uint8_t *command,
Jeff Johnsone44b7012017-09-10 15:25:47 -07006441 struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006442 bool action)
6443{
6444 int ret = 0;
6445 uint8_t *value;
6446 uint8_t type;
6447
6448 value = command;
6449 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6450 if (!action)
6451 value = command + 16;
6452 else
6453 value = command + 13;
6454 ret = kstrtou8(value, 10, &type);
6455 if (ret < 0) {
Dustin Brown933cd2a2018-04-18 11:28:15 -07006456 hdd_err("kstrtou8 failed invalid input value");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006457 return -EINVAL;
6458 }
6459
6460 switch (type) {
6461 case 2:
6462 /* Set rx filter for IPV4 multicast data packets */
6463 ret = hdd_set_rx_filter(adapter, action, 0x01);
6464 break;
6465 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006466 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006467 break;
6468 }
6469
6470 return ret;
6471}
6472
6473/**
6474 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6475 * @adapter: Pointer to network adapter
6476 * @hdd_ctx: Pointer to hdd context
6477 * @command: Pointer to input command
6478 * @command_len: Command length
6479 * @priv_data: Pointer to private data in command
6480 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006481static int drv_cmd_rx_filter_remove(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006482 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006483 uint8_t *command,
6484 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006485 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006486{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006487 return hdd_driver_rxfilter_command_handler(command, adapter, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006488}
6489
6490/**
6491 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6492 * @adapter: Pointer to network adapter
6493 * @hdd_ctx: Pointer to hdd context
6494 * @command: Pointer to input command
6495 * @command_len: Command length
6496 * @priv_data: Pointer to private data in command
6497 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006498static int drv_cmd_rx_filter_add(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006499 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006500 uint8_t *command,
6501 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006502 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006503{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006504 return hdd_driver_rxfilter_command_handler(command, adapter, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006505}
Qiwei Cai4505fc62018-05-17 18:35:19 +08006506#endif /* WLAN_FEATURE_PACKET_FILTERING */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006507
Archana Ramachandran393f3792015-11-13 17:13:21 -08006508/**
6509 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6510 * command
6511 * @value: Pointer to SETANTENNAMODE command
6512 * @mode: Pointer to antenna mode
6513 * @reason: Pointer to reason for set antenna mode
6514 *
6515 * This function parses the SETANTENNAMODE command passed in the format
6516 * SETANTENNAMODE<space>mode
6517 *
6518 * Return: 0 for success non-zero for failure
6519 */
6520static int hdd_parse_setantennamode_command(const uint8_t *value)
6521{
6522 const uint8_t *in_ptr = value;
6523 int tmp, v;
6524 char arg1[32];
6525
6526 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6527
6528 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07006529 if (!in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006530 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006531 return -EINVAL;
6532 }
6533
6534 /* no space after the command */
6535 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006536 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006537 return -EINVAL;
6538 }
6539
6540 /* remove empty spaces */
6541 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6542 in_ptr++;
6543
6544 /* no argument followed by spaces */
6545 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006546 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006547 return -EINVAL;
6548 }
6549
6550 /* get the argument i.e. antenna mode */
6551 v = sscanf(in_ptr, "%31s ", arg1);
6552 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006553 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006554 return -EINVAL;
6555 }
6556
6557 v = kstrtos32(arg1, 10, &tmp);
6558 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006559 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006560 return -EINVAL;
6561 }
6562
6563 return tmp;
6564}
6565
6566/**
6567 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6568 * mask is 2x2 mode
6569 * @hdd_ctx: Pointer to hdd contex
6570 *
6571 * Return: true if supported chain mask 2x2 else false
6572 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006573static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006574{
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306575 QDF_STATUS status;
6576 bool bval = false;
6577
6578/*
Archana Ramachandran393f3792015-11-13 17:13:21 -08006579 * Revisit and the update logic to determine the number
6580 * of TX/RX chains supported in the system when
6581 * antenna sharing per band chain mask support is
6582 * brought in
6583 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306584 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6585 if (!QDF_IS_STATUS_SUCCESS(status))
6586 hdd_err("unable to get vht_enable2x2");
6587
6588 return (bval == 0x01) ? true : false;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006589}
6590
6591/**
6592 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6593 * chain mask is 1x1
6594 * @hdd_ctx: Pointer to hdd contex
6595 *
6596 * Return: true if supported chain mask 1x1 else false
6597 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006598static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006599{
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306600 QDF_STATUS status;
6601 bool bval = false;
6602
Archana Ramachandran393f3792015-11-13 17:13:21 -08006603 /*
6604 * Revisit and update the logic to determine the number
6605 * of TX/RX chains supported in the system when
6606 * antenna sharing per band chain mask support is
6607 * brought in
6608 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306609 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6610 if (!QDF_IS_STATUS_SUCCESS(status))
6611 hdd_err("unable to get vht_enable2x2");
6612
6613 return (!bval) ? true : false;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006614}
6615
Jeff Johnson621cf972017-08-28 11:58:44 -07006616QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
Nitesh Shahe50711f2017-04-26 16:30:45 +05306617{
6618 QDF_STATUS status;
6619 uint8_t smps_mode;
6620 uint8_t smps_enable;
Jeff Johnsond549efa2018-06-13 20:27:47 -07006621 mac_handle_t mac_handle;
Nitesh Shahe50711f2017-04-26 16:30:45 +05306622
6623 /* Update SME SMPS config */
6624 if (HDD_ANTENNA_MODE_1X1 == mode) {
6625 smps_enable = true;
6626 smps_mode = HDD_SMPS_MODE_STATIC;
6627 } else {
6628 smps_enable = false;
6629 smps_mode = HDD_SMPS_MODE_DISABLED;
6630 }
6631
6632 hdd_debug("Update SME SMPS enable: %d mode: %d",
6633 smps_enable, smps_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006634 mac_handle = hdd_ctx->mac_handle;
6635 status = sme_update_mimo_power_save(mac_handle, smps_enable,
6636 smps_mode, false);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306637 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07006638 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
Nitesh Shahe50711f2017-04-26 16:30:45 +05306639 smps_enable, smps_mode, status);
6640 return QDF_STATUS_E_FAILURE;
6641 }
6642
6643 hdd_ctx->current_antenna_mode = mode;
6644 /*
6645 * Update the user requested nss in the mac context.
6646 * This will be used in tdls protocol engine to form tdls
6647 * Management frames.
6648 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07006649 sme_update_user_configured_nss(mac_handle,
6650 hdd_ctx->current_antenna_mode);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306651
6652 hdd_debug("Successfully switched to mode: %d x %d",
6653 hdd_ctx->current_antenna_mode,
6654 hdd_ctx->current_antenna_mode);
6655
6656 return QDF_STATUS_SUCCESS;
6657}
6658
Dundi Raviteja4016e932018-08-02 12:16:25 +05306659/**
6660 * wlan_hdd_soc_set_antenna_mode_cb() - Callback for set antenna mode
6661 * @status: Status of set antenna mode
6662 * @context: callback context
6663 *
6664 * Callback on setting antenna mode
6665 *
6666 * Return: None
6667 */
6668static void
6669wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status,
6670 void *context)
6671{
6672 struct osif_request *request = NULL;
6673
6674 hdd_debug("Status: %d", status);
6675
6676 request = osif_request_get(context);
6677 if (!request) {
6678 hdd_err("obselete request");
6679 return;
6680 }
6681
6682 /* Signal the completion of set dual mac config */
6683 osif_request_complete(request);
6684 osif_request_put(request);
6685}
6686
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306687static QDF_STATUS
6688hdd_populate_vdev_chains(struct wlan_mlme_nss_chains *nss_chains_cfg,
6689 uint8_t tx_chains,
6690 uint8_t rx_chains,
6691 enum nss_chains_band_info band,
6692 struct wlan_objmgr_vdev *vdev)
6693{
6694 struct wlan_mlme_nss_chains *dynamic_cfg;
6695
6696 nss_chains_cfg->num_rx_chains[band] = rx_chains;
6697 nss_chains_cfg->num_tx_chains[band] = tx_chains;
6698
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306699 dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306700 if (!dynamic_cfg) {
6701 hdd_err("nss chain dynamic config NULL");
6702 return QDF_STATUS_E_FAILURE;
6703 }
6704 /*
6705 * If user gives any nss value, then chains will be adjusted based on
6706 * nss (in SME func sme_validate_user_nss_chain_params).
6707 * If Chains are not suitable as per current NSS then, we need to
6708 * return, and the below logic is added for the same.
6709 */
6710
6711 if ((dynamic_cfg->rx_nss[band] > rx_chains) ||
6712 (dynamic_cfg->tx_nss[band] > tx_chains)) {
6713 hdd_err("Chains less than nss, configure correct nss first.");
6714 return QDF_STATUS_E_FAILURE;
6715 }
6716
6717 return QDF_STATUS_SUCCESS;
6718}
6719
6720static int
6721hdd_set_dynamic_antenna_mode(struct hdd_adapter *adapter,
6722 uint8_t num_rx_chains,
6723 uint8_t num_tx_chains)
6724{
6725 enum nss_chains_band_info band;
6726 struct wlan_mlme_nss_chains user_cfg;
6727 QDF_STATUS status;
6728 mac_handle_t mac_handle;
6729 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6730
6731 mac_handle = hdd_ctx->mac_handle;
6732 if (!mac_handle) {
6733 hdd_err("NULL MAC handle");
6734 return -EINVAL;
6735 }
6736
gaurank kathpalia6982d472018-10-31 21:54:15 +05306737 if (!hdd_is_vdev_in_conn_state(adapter)) {
6738 hdd_debug("Vdev (id %d) not in connected/started state, cannot accept command",
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006739 adapter->vdev_id);
gaurank kathpalia6982d472018-10-31 21:54:15 +05306740 return -EINVAL;
6741 }
6742
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306743 qdf_mem_zero(&user_cfg, sizeof(user_cfg));
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306744 for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) {
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306745 status = hdd_populate_vdev_chains(&user_cfg,
6746 num_rx_chains,
6747 num_tx_chains, band,
6748 adapter->vdev);
6749 if (QDF_IS_STATUS_ERROR(status))
6750 return -EINVAL;
6751 }
6752 status = sme_nss_chains_update(mac_handle,
6753 &user_cfg,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006754 adapter->vdev_id);
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306755 if (QDF_IS_STATUS_ERROR(status))
6756 return -EINVAL;
6757
6758 return 0;
6759}
Abhishek Singh1571ca72018-04-17 15:14:21 +05306760int hdd_set_antenna_mode(struct hdd_adapter *adapter,
6761 struct hdd_context *hdd_ctx, int mode)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006762{
6763 struct sir_antenna_mode_param params;
6764 QDF_STATUS status;
6765 int ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306766 struct osif_request *request = NULL;
6767 static const struct osif_request_params request_params = {
6768 .priv_size = 0,
Abhishek Singhd1f21c72019-01-21 15:16:34 +05306769 .timeout_ms = SME_POLICY_MGR_CMD_TIMEOUT,
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306770 };
Archana Ramachandran393f3792015-11-13 17:13:21 -08006771
Archana Ramachandran393f3792015-11-13 17:13:21 -08006772 switch (mode) {
6773 case HDD_ANTENNA_MODE_1X1:
6774 params.num_rx_chains = 1;
6775 params.num_tx_chains = 1;
6776 break;
6777 case HDD_ANTENNA_MODE_2X2:
6778 params.num_rx_chains = 2;
6779 params.num_tx_chains = 2;
6780 break;
6781 default:
6782 hdd_err("unsupported antenna mode");
6783 ret = -EINVAL;
6784 goto exit;
6785 }
6786
gaurank kathpalia1281b302018-11-05 21:10:37 +05306787 if (hdd_ctx->dynamic_nss_chains_support)
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306788 return hdd_set_dynamic_antenna_mode(adapter,
6789 params.num_rx_chains,
6790 params.num_tx_chains);
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306791
gaurank kathpaliaf95ae682018-11-05 21:13:07 +05306792 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6793 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6794 hdd_err("System does not support 2x2 mode");
6795 ret = -EPERM;
6796 goto exit;
6797 }
6798
6799 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6800 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6801 hdd_err("System only supports 1x1 mode");
6802 goto exit;
6803 }
6804
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006805 /* Check TDLS status and update antenna mode */
6806 if ((QDF_STA_MODE == adapter->device_mode) &&
Dustin Brown1dbefe62018-09-11 16:32:03 -07006807 policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07006808 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter, mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006809 if (0 != ret)
6810 goto exit;
6811 }
6812
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306813 request = osif_request_alloc(&request_params);
6814 if (!request) {
6815 hdd_err("Request Allocation Failure");
6816 ret = -ENOMEM;
6817 goto exit;
6818 }
6819
6820 params.set_antenna_mode_ctx = osif_request_cookie(request);
6821 params.set_antenna_mode_resp = (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006822 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006823 params.num_rx_chains,
6824 params.num_tx_chains);
6825
Jeff Johnsond549efa2018-06-13 20:27:47 -07006826 status = sme_soc_set_antenna_mode(hdd_ctx->mac_handle, &params);
Abhishek Singh1571ca72018-04-17 15:14:21 +05306827 if (QDF_IS_STATUS_ERROR(status)) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006828 hdd_err("set antenna mode failed status : %d", status);
6829 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306830 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006831 }
6832
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306833 ret = osif_request_wait_for_response(request);
6834 if (ret) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006835 hdd_err("send set antenna mode timed out");
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306836 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006837 }
6838
Nitesh Shahe50711f2017-04-26 16:30:45 +05306839 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006840 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006841 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306842 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006843 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006844 ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306845request_put:
6846 osif_request_put(request);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006847exit:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006848 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006849 ret, hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006850
Abhishek Singh1571ca72018-04-17 15:14:21 +05306851 return ret;
6852}
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306853
Abhishek Singh1571ca72018-04-17 15:14:21 +05306854/**
6855 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6856 * handler
6857 * @adapter: Pointer to network adapter
6858 * @hdd_ctx: Pointer to hdd context
6859 * @command: Pointer to input command
6860 * @command_len: Command length
6861 * @priv_data: Pointer to private data in command
6862 */
6863static int drv_cmd_set_antenna_mode(struct hdd_adapter *adapter,
6864 struct hdd_context *hdd_ctx,
6865 uint8_t *command,
6866 uint8_t command_len,
6867 struct hdd_priv_data *priv_data)
6868{
6869 int mode;
6870 uint8_t *value = command;
6871
6872 mode = hdd_parse_setantennamode_command(value);
6873 if (mode < 0) {
6874 hdd_err("Invalid SETANTENNA command");
6875 return mode;
6876 }
6877
6878 hdd_debug("Processing antenna mode switch to: %d", mode);
6879
6880 return hdd_set_antenna_mode(adapter, hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006881}
6882
6883/**
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306884 * hdd_get_dynamic_antenna_mode() -get the dynamic antenna mode for vdev
6885 * @antenna_mode: pointer to antenna mode of vdev
6886 * @dynamic_nss_chains_support: feature support for dynamic nss chains update
6887 * @vdev: Pointer to vdev
6888 *
6889 * This API will check for the num of chains configured for the vdev, and fill
6890 * that info in the antenna mode if the dynamic chains per vdev are supported.
6891 *
6892 * Return: None
6893 */
6894static void
6895hdd_get_dynamic_antenna_mode(uint32_t *antenna_mode,
6896 bool dynamic_nss_chains_support,
6897 struct wlan_objmgr_vdev *vdev)
6898{
6899 struct wlan_mlme_nss_chains *nss_chains_dynamic_cfg;
6900
6901 if (!dynamic_nss_chains_support)
6902 return;
6903
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306904 nss_chains_dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306905 if (!nss_chains_dynamic_cfg) {
6906 hdd_err("nss chain dynamic config NULL");
6907 return;
6908 }
6909 /*
6910 * At present, this command doesn't include band, so by default
6911 * it will return the band 2ghz present rf chains.
6912 */
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306913 *antenna_mode =
6914 nss_chains_dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306915}
6916
6917/**
Archana Ramachandran393f3792015-11-13 17:13:21 -08006918 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6919 * handler
6920 * @adapter: Pointer to hdd adapter
6921 * @hdd_ctx: Pointer to hdd context
6922 * @command: Pointer to input command
6923 * @command_len: length of the command
6924 * @priv_data: private data coming with the driver command
6925 *
6926 * Return: 0 for success non-zero for failure
6927 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006928static inline int drv_cmd_get_antenna_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006929 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006930 uint8_t *command,
6931 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006932 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006933{
6934 uint32_t antenna_mode = 0;
6935 char extra[32];
6936 uint8_t len = 0;
6937
6938 antenna_mode = hdd_ctx->current_antenna_mode;
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306939 /* Overwrite this antenna mode if dynamic vdev chains are supported */
6940 hdd_get_dynamic_antenna_mode(&antenna_mode,
6941 hdd_ctx->dynamic_nss_chains_support,
6942 adapter->vdev);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006943 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6944 antenna_mode);
6945 len = QDF_MIN(priv_data->total_len, len + 1);
6946 if (copy_to_user(priv_data->buf, &extra, len)) {
6947 hdd_err("Failed to copy data to user buffer");
6948 return -EFAULT;
6949 }
6950
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006951 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006952
6953 return 0;
6954}
6955
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006956/*
6957 * dummy (no-op) hdd driver command handler
6958 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006959static int drv_cmd_dummy(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006960 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006961 uint8_t *command,
6962 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006963 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006964{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006965 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006966 adapter->dev->name, command);
6967 return 0;
6968}
6969
6970/*
6971 * handler for any unsupported wlan hdd driver command
6972 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006973static int drv_cmd_invalid(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006974 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006975 uint8_t *command,
6976 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006977 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006978{
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05306979 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
6980 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006981 adapter->vdev_id, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006982
6983 hdd_warn("%s: Unsupported driver command \"%s\"",
6984 adapter->dev->name, command);
6985
6986 return -ENOTSUPP;
6987}
6988
6989/**
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306990 * drv_cmd_set_fcc_channel() - Handle fcc constraint request
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006991 * @adapter: HDD adapter
6992 * @hdd_ctx: HDD context
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306993 * @command: command ptr, SET_FCC_CHANNEL 0/-1 is the command
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006994 * @command_len: command len
6995 * @priv_data: private data
6996 *
6997 * Return: status
6998 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006999static int drv_cmd_set_fcc_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07007000 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007001 uint8_t *command,
7002 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07007003 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007004{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05307005 QDF_STATUS status;
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307006 int8_t input_value;
7007 bool fcc_constraint;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07007008 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007009
7010 /*
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307011 * This command would be called by user-space when it detects WLAN
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007012 * ON after airplane mode is set. When APM is set, WLAN turns off.
7013 * But it can be turned back on. Otherwise; when APM is turned back
7014 * off, WLAN would turn back on. So at that point the command is
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307015 * expected to come down. 0 means reduce power as per fcc constraint
7016 * and -1 means remove constraint.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007017 */
7018
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307019 err = kstrtos8(command + command_len + 1, 10, &input_value);
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07007020 if (err) {
7021 hdd_err("error %d parsing userspace fcc parameter", err);
7022 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007023 }
7024
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307025 fcc_constraint = input_value ? false : true;
7026 hdd_debug("input_value = %d && fcc_constraint = %u",
7027 input_value, fcc_constraint);
7028
Dustin Brown07901ec2018-09-07 11:02:41 -07007029 status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev, fcc_constraint);
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07007030
7031 if (QDF_IS_STATUS_ERROR(status))
7032 hdd_err("Failed to %s tx power for channels 12/13",
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05307033 fcc_constraint ? "restore" : "reduce");
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07007034
7035 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007036}
7037
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307038/**
7039 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
7040 * command
7041 * @value: Pointer to the command
7042 * @chan_number: Pointer to the channel number
7043 * @chan_bw: Pointer to the channel bandwidth
7044 *
7045 * Parses and provides the channel number and channel width from the input
7046 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
7047 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
7048 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
7049 *
7050 * Return: 0 for success, non-zero for failure
7051 */
7052static int hdd_parse_set_channel_switch_command(uint8_t *value,
7053 uint32_t *chan_number,
7054 uint32_t *chan_bw)
7055{
7056 const uint8_t *in_ptr = value;
7057 int ret;
7058
7059 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
7060
7061 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07007062 if (!in_ptr) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307063 hdd_err("No argument after the command");
7064 return -EINVAL;
7065 }
7066
7067 /* no space after the command */
7068 if (SPACE_ASCII_VALUE != *in_ptr) {
7069 hdd_err("No space after the command ");
7070 return -EINVAL;
7071 }
7072
7073 /* remove empty spaces and move the next argument */
7074 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
7075 in_ptr++;
7076
7077 /* no argument followed by spaces */
7078 if ('\0' == *in_ptr) {
7079 hdd_err("No argument followed by spaces");
7080 return -EINVAL;
7081 }
7082
7083 /* get the two arguments: channel number and bandwidth */
7084 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7085 if (ret != 2) {
7086 hdd_err("Arguments retrieval from cmd string failed");
7087 return -EINVAL;
7088 }
7089
7090 return 0;
7091}
7092
7093/**
7094 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7095 * @adapter: HDD adapter
7096 * @hdd_ctx: HDD context
7097 * @command: Pointer to the input command CHANNEL_SWITCH
7098 * @command_len: Command len
7099 * @priv_data: Private data
7100 *
7101 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7102 * of SAP/P2P-GO
7103 *
7104 * Return: 0 for success, non-zero for failure
7105 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007106static int drv_cmd_set_channel_switch(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07007107 struct hdd_context *hdd_ctx,
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307108 uint8_t *command,
7109 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07007110 struct hdd_priv_data *priv_data)
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307111{
7112 struct net_device *dev = adapter->dev;
7113 int status;
7114 uint32_t chan_number = 0, chan_bw = 0;
7115 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007116 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307117
Krunal Sonibe766b02016-03-10 13:00:44 -08007118 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7119 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307120 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7121 adapter->device_mode);
7122 return -EINVAL;
7123 }
7124
7125 status = hdd_parse_set_channel_switch_command(value,
7126 &chan_number, &chan_bw);
7127 if (status) {
7128 hdd_err("Invalid CHANNEL_SWITCH command");
7129 return status;
7130 }
7131
7132 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7133 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7134 return -EINVAL;
7135 }
7136
7137 if (chan_bw == 80)
7138 width = CH_WIDTH_80MHZ;
7139 else if (chan_bw == 40)
7140 width = CH_WIDTH_40MHZ;
7141 else
7142 width = CH_WIDTH_20MHZ;
7143
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007144 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307145
Bala Venkatesh8b9bbde2019-07-03 16:25:16 +05307146 wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, adapter->vdev_id,
7147 CSA_REASON_USER_INITIATED);
Tushnim Bhattacharyya6c40b112019-10-30 11:39:25 -07007148 status = hdd_softap_set_channel_change(dev,
7149 wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, chan_number),
7150 width, true);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307151 if (status) {
7152 hdd_err("Set channel change fail");
7153 return status;
7154 }
7155
7156 return 0;
7157}
7158
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307159#ifdef DISABLE_CHANNEL_LIST
7160void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7161{
7162 hdd_enter();
7163
7164 if (!hdd_ctx->original_channels)
7165 return;
7166
7167 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7168 hdd_ctx->original_channels->num_channels = 0;
7169 if (hdd_ctx->original_channels->channel_info) {
7170 qdf_mem_free(hdd_ctx->original_channels->channel_info);
7171 hdd_ctx->original_channels->channel_info = NULL;
7172 }
7173 qdf_mem_free(hdd_ctx->original_channels);
7174 hdd_ctx->original_channels = NULL;
7175 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7176
7177 hdd_exit();
7178}
7179
7180/**
7181 * hdd_alloc_chan_cache() - Allocate the memory to cache the channel
7182 * info for the channels received in command SET_DISABLE_CHANNEL_LIST
7183 * @hdd_ctx: Pointer to HDD context
7184 * @num_chan: Number of channels for which memory needs to
7185 * be allocated
7186 *
7187 * Return: 0 on success and error code on failure
7188 */
7189static int hdd_alloc_chan_cache(struct hdd_context *hdd_ctx, int num_chan)
7190{
7191 hdd_ctx->original_channels =
7192 qdf_mem_malloc(sizeof(struct hdd_cache_channels));
7193 if (!hdd_ctx->original_channels) {
7194 hdd_err("QDF_MALLOC_ERR");
7195 return -ENOMEM;
7196 }
7197 hdd_ctx->original_channels->num_channels = num_chan;
7198 hdd_ctx->original_channels->channel_info =
7199 qdf_mem_malloc(num_chan *
7200 sizeof(struct hdd_cache_channel_info));
7201 if (!hdd_ctx->original_channels->channel_info) {
7202 hdd_err("QDF_MALLOC_ERR");
7203 hdd_ctx->original_channels->num_channels = 0;
7204 qdf_mem_free(hdd_ctx->original_channels);
7205 hdd_ctx->original_channels = NULL;
7206 return -ENOMEM;
7207 }
7208 return 0;
7209}
7210
7211/**
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307212 * check_disable_channels() - Check for disable channel
7213 * @hdd_ctx: Pointer to hdd context
7214 * @operating_channel: Current operating channel of adapter
7215 *
7216 * This function checks original_channels array for a specific channel
7217 *
7218 * Return: 0 if channel not found, 1 if channel found
7219 */
7220static bool check_disable_channels(struct hdd_context *hdd_ctx,
7221 uint8_t operating_channel)
7222{
7223 uint32_t num_channels;
7224 uint8_t i;
7225
7226 if (!hdd_ctx || !hdd_ctx->original_channels ||
7227 !hdd_ctx->original_channels->channel_info)
7228 return false;
7229
7230 num_channels = hdd_ctx->original_channels->num_channels;
7231 for (i = 0; i < num_channels; i++)
7232 if (hdd_ctx->original_channels->channel_info[i].channel_num ==
7233 operating_channel)
7234 return true;
7235 return false;
7236}
7237
7238/**
7239 * disconnect_sta_and_stop_sap() - Disconnect STA and stop SAP
7240 *
7241 * @hdd_ctx: Pointer to hdd context
7242 *
7243 * Disable channels provided by user and disconnect STA if it is
7244 * connected to any AP, stop SAP and send deauthentication request
7245 * to STAs connected to SAP.
7246 *
7247 * Return: None
7248 */
7249static void disconnect_sta_and_stop_sap(struct hdd_context *hdd_ctx)
7250{
7251 struct hdd_adapter *adapter, *next = NULL;
7252 QDF_STATUS status;
Will Huang4b097f52019-08-29 10:51:56 -07007253 uint8_t ap_ch;
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307254
7255 if (!hdd_ctx)
7256 return;
7257
7258 hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx);
7259
7260 status = hdd_get_front_adapter(hdd_ctx, &adapter);
7261 while (adapter && (status == QDF_STATUS_SUCCESS)) {
7262 if (!hdd_validate_adapter(adapter) &&
Will Huang4b097f52019-08-29 10:51:56 -07007263 adapter->device_mode == QDF_SAP_MODE) {
7264 ap_ch = wlan_reg_freq_to_chan(
7265 hdd_ctx->pdev,
7266 adapter->session.ap.operating_chan_freq);
7267 if (check_disable_channels(hdd_ctx, ap_ch))
7268 wlan_hdd_stop_sap(adapter);
7269 }
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307270
7271 status = hdd_get_next_adapter(hdd_ctx, adapter, &next);
7272 adapter = next;
7273 }
7274}
7275
7276/**
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307277 * hdd_parse_disable_chan_cmd() - Parse the channel list received
7278 * in command.
7279 * @adapter: pointer to hdd adapter
7280 * @ptr: Pointer to the command string
7281 *
7282 * This function parses the channel list received in the command.
7283 * command should be a string having format
7284 * SET_DISABLE_CHANNEL_LIST <num of channels>
7285 * <channels separated by spaces>.
7286 * If the command comes multiple times than this function will compare
7287 * the channels received in the command with the channles cached in the
7288 * first command, if the channel list matches with the cached channles,
7289 * it returns success otherwise returns failure.
7290 *
7291 * Return: 0 on success, Error code on failure
7292 */
7293
7294static int hdd_parse_disable_chan_cmd(struct hdd_adapter *adapter, uint8_t *ptr)
7295{
7296 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7297 uint8_t *param;
7298 int j, i, temp_int, ret = 0, num_channels;
Liangwei Dong2eb654f2019-09-11 15:54:09 +08007299 uint32_t parsed_channels[NUM_CHANNELS];
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307300 bool is_command_repeated = false;
7301
Jeff Johnsond36fa332019-03-18 13:42:25 -07007302 if (!hdd_ctx) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307303 hdd_err("HDD Context is NULL");
7304 return -EINVAL;
7305 }
7306
7307 param = strnchr(ptr, strlen(ptr), ' ');
7308 /*no argument after the command*/
Jeff Johnsond36fa332019-03-18 13:42:25 -07007309 if (!param)
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307310 return -EINVAL;
7311
7312 /*no space after the command*/
7313 else if (SPACE_ASCII_VALUE != *param)
7314 return -EINVAL;
7315
7316 param++;
7317
7318 /*removing empty spaces*/
7319 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7320 param++;
7321
7322 /*no argument followed by spaces*/
7323 if ('\0' == *param)
7324 return -EINVAL;
7325
7326 /*getting the first argument ie the number of channels*/
7327 if (sscanf(param, "%d ", &temp_int) != 1) {
7328 hdd_err("Cannot get number of channels from input");
7329 return -EINVAL;
7330 }
7331
Liangwei Dong2eb654f2019-09-11 15:54:09 +08007332 if (temp_int < 0 || temp_int > NUM_CHANNELS) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307333 hdd_err("Invalid Number of channel received");
7334 return -EINVAL;
7335 }
7336
7337 hdd_debug("Number of channel to disable are: %d", temp_int);
7338
7339 if (!temp_int) {
Ashish Kumar Dhanotiya6176bef2019-07-25 15:51:35 +05307340 /*
7341 * Restore and Free the cache channels when the command is
7342 * received with num channels as 0
7343 */
7344 wlan_hdd_restore_channels(hdd_ctx, false);
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307345 return 0;
7346 }
7347
7348 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7349
7350 if (!hdd_ctx->original_channels) {
7351 if (hdd_alloc_chan_cache(hdd_ctx, temp_int)) {
7352 ret = -ENOMEM;
7353 goto mem_alloc_failed;
7354 }
7355 } else if (hdd_ctx->original_channels->num_channels != temp_int) {
7356 hdd_err("Invalid Number of channels");
7357 ret = -EINVAL;
7358 is_command_repeated = true;
7359 goto parse_failed;
7360 } else {
7361 is_command_repeated = true;
7362 }
7363 num_channels = temp_int;
7364 for (j = 0; j < num_channels; j++) {
7365 /*
7366 * param pointing to the beginning of first space
7367 * after number of channels
7368 */
7369 param = strpbrk(param, " ");
7370 /*no channel list after the number of channels argument*/
Jeff Johnsond36fa332019-03-18 13:42:25 -07007371 if (!param) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307372 hdd_err("Invalid No of channel provided in the list");
7373 ret = -EINVAL;
7374 goto parse_failed;
7375 }
7376
7377 param++;
7378
7379 /*removing empty space*/
7380 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7381 param++;
7382
7383 if ('\0' == *param) {
7384 hdd_err("No channel is provided in the list");
7385 ret = -EINVAL;
7386 goto parse_failed;
7387 }
7388
7389 if (sscanf(param, "%d ", &temp_int) != 1) {
7390 hdd_err("Cannot read channel number");
7391 ret = -EINVAL;
7392 goto parse_failed;
7393 }
7394
7395 if (!IS_CHANNEL_VALID(temp_int)) {
7396 hdd_err("Invalid channel number received");
7397 ret = -EINVAL;
7398 goto parse_failed;
7399 }
7400
7401 hdd_debug("channel[%d] = %d", j, temp_int);
7402 parsed_channels[j] = temp_int;
7403 }
7404
7405 /*extra arguments check*/
7406 param = strpbrk(param, " ");
Jeff Johnsond36fa332019-03-18 13:42:25 -07007407 if (param) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307408 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7409 param++;
7410
7411 if ('\0' != *param) {
7412 hdd_err("Invalid argument received");
7413 ret = -EINVAL;
7414 goto parse_failed;
7415 }
7416 }
7417
7418 /*
7419 * If command is received first time, cache the channels to
7420 * be disabled else compare the channels received in the
7421 * command with the cached channels, if channel list matches
7422 * return success otherewise return failure.
7423 */
7424 if (!is_command_repeated) {
7425 for (j = 0; j < num_channels; j++)
7426 hdd_ctx->original_channels->
7427 channel_info[j].channel_num =
7428 parsed_channels[j];
Dustin Brown3f0d7102018-08-02 12:01:52 -07007429
7430 /* Cache the channel list in regulatory also */
Dustin Brown07901ec2018-09-07 11:02:41 -07007431 ucfg_reg_cache_channel_state(hdd_ctx->pdev, parsed_channels,
Dustin Brown3f0d7102018-08-02 12:01:52 -07007432 num_channels);
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307433 } else {
7434 for (i = 0; i < num_channels; i++) {
7435 for (j = 0; j < num_channels; j++)
7436 if (hdd_ctx->original_channels->
7437 channel_info[i].channel_num ==
7438 parsed_channels[j])
7439 break;
7440 if (j == num_channels) {
7441 ret = -EINVAL;
7442 goto parse_failed;
7443 }
7444 }
7445 ret = 0;
7446 }
7447mem_alloc_failed:
7448
7449 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
Ashish Kumar Dhanotiyadd5f74c2019-03-14 16:50:41 +05307450 /* Disable the channels received in command SET_DISABLE_CHANNEL_LIST */
7451 if (!is_command_repeated && hdd_ctx->original_channels) {
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307452 ret = wlan_hdd_disable_channels(hdd_ctx);
7453 if (ret)
7454 return ret;
7455 disconnect_sta_and_stop_sap(hdd_ctx);
Ashish Kumar Dhanotiyadd5f74c2019-03-14 16:50:41 +05307456 }
7457
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307458 hdd_exit();
7459
7460 return ret;
7461
7462parse_failed:
7463 if (!is_command_repeated)
7464 wlan_hdd_free_cache_channels(hdd_ctx);
Ashish Kumar Dhanotiyadd5f74c2019-03-14 16:50:41 +05307465
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307466 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7467 hdd_exit();
7468
7469 return ret;
7470}
7471
7472static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7473 struct hdd_context *hdd_ctx,
7474 uint8_t *command,
7475 uint8_t command_len,
7476 struct hdd_priv_data *priv_data)
7477{
7478 return hdd_parse_disable_chan_cmd(adapter, command);
7479}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307480
7481/**
7482 * hdd_get_disable_ch_list() - get disable channel list
7483 * @hdd_ctx: hdd context
7484 * @buf: buffer to hold disable channel list
7485 * @buf_len: buffer length
7486 *
7487 * Return: length of data copied to buf
7488 */
7489static int hdd_get_disable_ch_list(struct hdd_context *hdd_ctx, uint8_t *buf,
7490 uint32_t buf_len)
7491{
7492 struct hdd_cache_channel_info *ch_list;
7493 unsigned char i, num_ch;
7494 int len = 0;
7495
7496 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7497 if (hdd_ctx->original_channels &&
7498 hdd_ctx->original_channels->num_channels &&
7499 hdd_ctx->original_channels->channel_info) {
7500 num_ch = hdd_ctx->original_channels->num_channels;
7501
7502 len = scnprintf(buf, buf_len, "%s %hhu",
7503 "GET_DISABLE_CHANNEL_LIST", num_ch);
7504 ch_list = hdd_ctx->original_channels->channel_info;
7505 for (i = 0; (i < num_ch) && (len < buf_len - 1); i++) {
7506 len += scnprintf(buf + len, buf_len - len,
7507 " %d", ch_list[i].channel_num);
7508 }
7509 }
7510 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7511
7512 return len;
7513}
7514
7515static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7516 struct hdd_context *hdd_ctx,
7517 uint8_t *command,
7518 uint8_t command_len,
7519 struct hdd_priv_data *priv_data)
7520{
7521 char extra[512] = {0};
7522 int max_len, copied_length;
7523
7524 hdd_debug("Received Command to get disable Channels list");
7525
7526 max_len = QDF_MIN(priv_data->total_len, sizeof(extra));
7527 copied_length = hdd_get_disable_ch_list(hdd_ctx, extra, max_len);
7528 if (copied_length == 0) {
7529 hdd_err("disable channel list is not yet programmed");
7530 return -EINVAL;
7531 }
7532
7533 if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
7534 hdd_err("failed to copy data to user buffer");
7535 return -EFAULT;
7536 }
7537
7538 hdd_debug("data:%s", extra);
7539 return 0;
7540}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307541#else
7542
7543static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7544 struct hdd_context *hdd_ctx,
7545 uint8_t *command,
7546 uint8_t command_len,
7547 struct hdd_priv_data *priv_data)
7548{
7549 return 0;
7550}
7551
7552void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7553{
7554}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307555
7556static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7557 struct hdd_context *hdd_ctx,
7558 uint8_t *command,
7559 uint8_t command_len,
7560 struct hdd_priv_data *priv_data)
7561{
7562 return 0;
7563}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307564#endif
Sourav Mohapatra2a67b0e2019-10-15 17:59:59 +05307565
7566#ifdef FEATURE_ANI_LEVEL_REQUEST
7567static int drv_cmd_get_ani_level(struct hdd_adapter *adapter,
7568 struct hdd_context *hdd_ctx,
7569 uint8_t *command,
7570 uint8_t command_len,
7571 struct hdd_priv_data *priv_data)
7572{
7573 char *extra;
7574 int copied_length = 0, j, temp_int, ret = 0;
7575 uint8_t *param, num_freqs, num_recv_channels;
7576 uint32_t parsed_freqs[MAX_NUM_FREQS_FOR_ANI_LEVEL];
7577 struct wmi_host_ani_level_event ani[MAX_NUM_FREQS_FOR_ANI_LEVEL];
7578 size_t user_size = priv_data->total_len;
7579
7580 hdd_debug("Received Command to get ANI level");
7581
7582 param = strnchr(command, strlen(command), ' ');
7583
7584 /* No argument after the command */
7585 if (!param)
7586 return -EINVAL;
7587
7588 /* No space after the command */
7589 else if (SPACE_ASCII_VALUE != *param)
7590 return -EINVAL;
7591
7592 param++;
7593
7594 /* Removing empty spaces*/
7595 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7596 param++;
7597
7598 /*no argument followed by spaces */
7599 if ('\0' == *param)
7600 return -EINVAL;
7601
7602 /* Getting the first argument ie the number of channels */
7603 if (sscanf(param, "%d ", &temp_int) != 1) {
7604 hdd_err("Cannot get number of freq from input");
7605 return -EINVAL;
7606 }
7607
7608 if (temp_int < 0 || temp_int > MAX_NUM_FREQS_FOR_ANI_LEVEL) {
7609 hdd_err("Invalid Number of channel received");
7610 return -EINVAL;
7611 }
7612
7613 hdd_debug("Number of freq to fetch ANI level are: %d", temp_int);
7614
7615 if (!temp_int)
7616 return 0;
7617
7618 num_freqs = temp_int;
7619
7620 for (j = 0; j < num_freqs; j++) {
7621 /*
7622 * Param pointing to the beginning of first space
7623 * after number of channels.
7624 */
7625 param = strpbrk(param, " ");
7626 /*no channel list after the number of channels argument*/
7627 if (!param) {
7628 hdd_err("Invalid No of freq provided in the list");
7629 ret = -EINVAL;
7630 goto parse_failed;
7631 }
7632
7633 param++;
7634
7635 /* Removing empty space */
7636 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7637 param++;
7638
7639 if ('\0' == *param) {
7640 hdd_err("No freq is provided in the list");
7641 ret = -EINVAL;
7642 goto parse_failed;
7643 }
7644
7645 if (sscanf(param, "%d ", &temp_int) != 1) {
7646 hdd_err("Cannot read freq number");
7647 ret = -EINVAL;
7648 goto parse_failed;
7649 }
7650
7651 hdd_debug("channel_freq[%d] = %d", j, temp_int);
7652 parsed_freqs[j] = temp_int;
7653 }
7654
7655 /* Extra arguments check */
7656 param = strpbrk(param, " ");
7657 if (param) {
7658 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7659 param++;
7660
7661 if ('\0' != *param) {
7662 hdd_err("Invalid argument received");
7663 ret = -EINVAL;
7664 goto parse_failed;
7665 }
7666 }
7667
7668 qdf_mem_zero(ani, sizeof(ani));
7669 hdd_debug("num_freq: %d", num_freqs);
7670 if (QDF_IS_STATUS_ERROR(wlan_hdd_get_ani_level(adapter, ani,
7671 parsed_freqs,
7672 num_freqs))) {
7673 hdd_err("Unable to retrieve ani level");
7674 return -EINVAL;
7675 }
7676
7677 extra = qdf_mem_malloc(user_size);
7678 if (!extra) {
7679 hdd_err("memory allocation failed");
7680 ret = -ENOMEM;
7681 goto parse_failed;
7682 }
7683
7684 /*
7685 * Find the number of channels that are populated. If freq is not
7686 * filled then stop count there
7687 */
7688 for (num_recv_channels = 0;
7689 (num_recv_channels < num_freqs &&
7690 ani[num_recv_channels].chan_freq); num_recv_channels++)
7691 ;
7692
7693 for (j = 0; j < num_recv_channels; j++) {
7694 /* Sanity check for ANI level validity */
7695 if (ani[j].ani_level > MAX_ANI_LEVEL)
7696 continue;
7697
7698 copied_length += scnprintf(extra + copied_length,
7699 user_size - copied_length, "%d:%d\n",
7700 ani[j].chan_freq, ani[j].ani_level);
7701 }
7702
7703 if (copied_length == 0) {
7704 hdd_err("ANI level not fetched");
7705 ret = -EINVAL;
7706 goto free;
7707 }
7708
7709 hdd_debug("data: %s", extra);
7710
7711 if (copy_to_user(priv_data->buf, extra, copied_length + 1)) {
7712 hdd_err("failed to copy data to user buffer");
7713 ret = -EFAULT;
7714 goto free;
7715 }
7716
7717free:
7718 qdf_mem_free(extra);
7719
7720parse_failed:
7721 return ret;
7722}
7723
7724#else
7725static int drv_cmd_get_ani_level(struct hdd_adapter *adapter,
7726 struct hdd_context *hdd_ctx,
7727 uint8_t *command,
7728 uint8_t command_len,
7729 struct hdd_priv_data *priv_data)
7730{
7731 return 0;
7732}
7733#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007734/*
7735 * The following table contains all supported WLAN HDD
7736 * IOCTL driver commands and the handler for each of them.
7737 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07007738static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307739 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false},
7740 {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true},
7741 {"P2P_SET_PS", drv_cmd_p2p_set_ps, true},
7742 {"SETBAND", drv_cmd_set_band, true},
7743 {"SETWMMPS", drv_cmd_set_wmmps, true},
7744 {"COUNTRY", drv_cmd_country, true},
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +05307745 {"SETCOUNTRYREV", drv_cmd_country, true},
7746 {"GETCOUNTRYREV", drv_cmd_get_country, false},
Pragaspathi Thilagarajaa8320e2019-04-16 02:47:50 +05307747 {"SETSUSPENDMODE", drv_cmd_set_suspend_mode, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307748 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307749 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true},
7750 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false},
7751 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true},
7752 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false},
7753 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period,
7754 true},
7755 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period,
7756 false},
7757 {"SETROAMMODE", drv_cmd_set_roam_mode, true},
7758 {"GETROAMMODE", drv_cmd_get_roam_mode, false},
7759 {"SETROAMDELTA", drv_cmd_set_roam_delta, true},
7760 {"GETROAMDELTA", drv_cmd_get_roam_delta, false},
7761 {"GETBAND", drv_cmd_get_band, false},
7762 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels, true},
7763 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels, false},
7764 {"GETCCXMODE", drv_cmd_get_ccx_mode, false},
7765 {"GETOKCMODE", drv_cmd_get_okc_mode, false},
7766 {"GETFASTROAM", drv_cmd_get_fast_roam, false},
7767 {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false},
7768 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
7769 true},
7770 {"SENDACTIONFRAME", drv_cmd_send_action_frame, true},
7771 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
7772 false},
7773 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true},
7774 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false},
7775 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true},
7776 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false},
7777 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true},
7778 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false},
7779 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true},
7780 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false},
7781 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true},
7782 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false},
7783 {"REASSOC", drv_cmd_reassoc, true},
7784 {"SETWESMODE", drv_cmd_set_wes_mode, true},
7785 {"GETWESMODE", drv_cmd_get_wes_mode, false},
7786 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff,
7787 true},
7788 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff,
7789 false},
7790 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true},
7791 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false},
7792 {"SETFASTROAM", drv_cmd_set_fast_roam, true},
7793 {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true},
7794 {"FASTREASSOC", drv_cmd_fast_reassoc, true},
7795 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control, true},
7796 {"SETOKCMODE", drv_cmd_set_okc_mode, true},
7797 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control, false},
7798 {"BTCOEXMODE", drv_cmd_bt_coex_mode, true},
7799 {"SCAN-ACTIVE", drv_cmd_scan_active, false},
7800 {"SCAN-PASSIVE", drv_cmd_scan_passive, false},
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05307801 {"CONCSETDWELLTIME", drv_cmd_conc_set_dwell_time, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307802 {"GETDWELLTIME", drv_cmd_get_dwell_time, false},
7803 {"SETDWELLTIME", drv_cmd_set_dwell_time, true},
7804 {"MIRACAST", drv_cmd_miracast, true},
7805 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05307806#ifdef FEATURE_WLAN_RMC
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307807 {"SETRMCENABLE", drv_cmd_set_rmc_enable, true},
7808 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05307809 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate, true},
7810#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307811 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all, false},
7812 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307813 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007814#ifdef FEATURE_WLAN_ESE
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307815 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true},
7816 {"GETTSMSTATS", drv_cmd_get_tsm_stats, true},
7817 {"SETCCKMIE", drv_cmd_set_cckm_ie, true},
7818 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true},
7819 {"CCXPLMREQ", drv_cmd_ccx_plm_req, true},
7820 {"SETCCXMODE", drv_cmd_set_ccx_mode, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007821#endif /* FEATURE_WLAN_ESE */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307822 {"SETMCRATE", drv_cmd_set_mc_rate, true},
7823 {"MAXTXPOWER", drv_cmd_max_tx_power, true},
7824 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true},
7825 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false},
7826 {"GETLINKSTATUS", drv_cmd_get_link_status, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007827#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307828 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true},
7829 {"SETAPP1PARAMS", drv_cmd_set_app1_params, true},
7830 {"SETAPP2PARAMS", drv_cmd_set_app2_params, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007831#endif
7832#ifdef FEATURE_WLAN_TDLS
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307833 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
7834 true},
7835 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true},
7836 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true},
7837 {"TDLSSCAN", drv_cmd_tdls_scan, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007838#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307839 {"RSSI", drv_cmd_get_rssi, false},
7840 {"LINKSPEED", drv_cmd_get_linkspeed, false},
Qiwei Cai4505fc62018-05-17 18:35:19 +08007841#ifdef WLAN_FEATURE_PACKET_FILTERING
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307842 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true},
7843 {"RXFILTER-ADD", drv_cmd_rx_filter_add, true},
Qiwei Cai4505fc62018-05-17 18:35:19 +08007844#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307845 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true},
7846 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true},
7847 {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true},
7848 {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false},
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307849 {"SET_DISABLE_CHANNEL_LIST", drv_cmd_set_disable_chan_list, true},
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307850 {"GET_DISABLE_CHANNEL_LIST", drv_cmd_get_disable_chan_list, false},
Sourav Mohapatra2a67b0e2019-10-15 17:59:59 +05307851 {"GET_ANI_LEVEL", drv_cmd_get_ani_level, false},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307852 {"STOP", drv_cmd_dummy, false},
Srinivas Girigowda836475e2018-04-17 14:42:23 -07007853 /* Deprecated commands */
7854 {"RXFILTER-START", drv_cmd_dummy, false},
7855 {"RXFILTER-STOP", drv_cmd_dummy, false},
7856 {"BTCOEXSCAN-START", drv_cmd_dummy, false},
7857 {"BTCOEXSCAN-STOP", drv_cmd_dummy, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007858};
7859
7860/**
7861 * hdd_drv_cmd_process() - chooses and runs the proper
7862 * handler based on the input command
7863 * @adapter: Pointer to the hdd adapter
7864 * @cmd: Pointer to the driver command
7865 * @priv_data: Pointer to the data associated with the command
7866 *
7867 * This function parses the input hdd driver command and runs
7868 * the proper handler
7869 *
7870 * Return: 0 for success non-zero for failure
7871 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007872static int hdd_drv_cmd_process(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007873 uint8_t *cmd,
Jeff Johnson353cd292017-08-17 06:47:26 -07007874 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007875{
Jeff Johnson621cf972017-08-28 11:58:44 -07007876 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007877 int i;
7878 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7879 uint8_t *cmd_i = NULL;
7880 hdd_drv_cmd_handler_t handler = NULL;
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307881 int len = 0, cmd_len = 0;
7882 uint8_t *ptr;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307883 bool args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007884
7885 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007886 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007887 return -EINVAL;
7888 }
7889
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307890 /* Calculate length of the first word */
7891 ptr = strchrnul(cmd, ' ');
7892 cmd_len = ptr - cmd;
7893
Jeff Johnson399c6272017-08-30 10:51:00 -07007894 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007895
7896 for (i = 0; i < cmd_num_total; i++) {
7897
7898 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7899 handler = hdd_drv_cmds[i].handler;
7900 len = strlen(cmd_i);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307901 args = hdd_drv_cmds[i].args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007902
7903 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007904 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007905 return -EINVAL;
7906 }
7907
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307908 if (len == cmd_len && strncasecmp(cmd, cmd_i, len) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307909 if (args && drv_cmd_validate(cmd, len))
7910 return -EINVAL;
7911
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007912 return handler(adapter, hdd_ctx,
7913 cmd, len, priv_data);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307914 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007915 }
7916
7917 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7918}
7919
7920/**
7921 * hdd_driver_command() - top level wlan hdd driver command handler
7922 * @adapter: Pointer to the hdd adapter
7923 * @priv_data: Pointer to the raw command data
7924 *
7925 * This function is the top level wlan hdd driver command handler. It
7926 * handles the command with the help of hdd_drv_cmd_process()
7927 *
7928 * Return: 0 for success non-zero for failure
7929 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007930static int hdd_driver_command(struct hdd_adapter *adapter,
Jeff Johnson353cd292017-08-17 06:47:26 -07007931 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007932{
7933 uint8_t *command = NULL;
7934 int ret = 0;
Jeff Johnson621cf972017-08-28 11:58:44 -07007935 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007936
Dustin Brown491d54b2018-03-14 12:39:11 -07007937 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307938
Anurag Chouhan6d760662016-02-20 16:05:43 +05307939 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007940 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007941 return -EINVAL;
7942 }
7943
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05307944 ret = wlan_hdd_validate_context(hdd_ctx);
7945 if (ret)
7946 return ret;
7947
7948 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
7949 hdd_err("Driver module is closed; command can not be processed");
7950 return -EINVAL;
7951 }
7952
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007953 /*
7954 * Note that valid pointers are provided by caller
7955 */
7956
7957 /* copy to local struct to avoid numerous changes to legacy code */
7958 if (priv_data->total_len <= 0 ||
7959 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007960 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007961 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007962 ret = -EINVAL;
7963 goto exit;
7964 }
7965
7966 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007967 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007968 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007969 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007970 ret = -ENOMEM;
7971 goto exit;
7972 }
7973
7974 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7975 ret = -EFAULT;
7976 goto exit;
7977 }
7978
7979 /* Make sure the command is NUL-terminated */
7980 command[priv_data->total_len] = '\0';
7981
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007982 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007983 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7984
7985exit:
7986 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007987 qdf_mem_free(command);
Dustin Browne74003f2018-03-14 12:51:58 -07007988 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007989 return ret;
7990}
7991
7992#ifdef CONFIG_COMPAT
Jeff Johnsone44b7012017-09-10 15:25:47 -07007993static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007994{
7995 struct {
7996 compat_uptr_t buf;
7997 int used_len;
7998 int total_len;
7999 } compat_priv_data;
Jeff Johnson353cd292017-08-17 06:47:26 -07008000 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008001 int ret = 0;
8002
8003 /*
8004 * Note that adapter and ifr have already been verified by caller,
8005 * and HDD context has also been validated
8006 */
8007 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
8008 sizeof(compat_priv_data))) {
8009 ret = -EFAULT;
8010 goto exit;
8011 }
8012 priv_data.buf = compat_ptr(compat_priv_data.buf);
8013 priv_data.used_len = compat_priv_data.used_len;
8014 priv_data.total_len = compat_priv_data.total_len;
8015 ret = hdd_driver_command(adapter, &priv_data);
8016exit:
8017 return ret;
8018}
8019#else /* CONFIG_COMPAT */
Jeff Johnsone44b7012017-09-10 15:25:47 -07008020static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008021{
8022 /* will never be invoked */
8023 return 0;
8024}
8025#endif /* CONFIG_COMPAT */
8026
Jeff Johnsone44b7012017-09-10 15:25:47 -07008027static int hdd_driver_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008028{
Jeff Johnson353cd292017-08-17 06:47:26 -07008029 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008030 int ret = 0;
8031
8032 /*
8033 * Note that adapter and ifr have already been verified by caller,
8034 * and HDD context has also been validated
8035 */
8036 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
8037 ret = -EFAULT;
8038 else
8039 ret = hdd_driver_command(adapter, &priv_data);
8040
8041 return ret;
8042}
8043
8044/**
8045 * __hdd_ioctl() - ioctl handler for wlan network interfaces
8046 * @dev: device upon which the ioctl was received
8047 * @ifr: ioctl request information
8048 * @cmd: ioctl command
8049 *
8050 * This function does initial processing of wlan device ioctls.
8051 * Currently two flavors of ioctls are supported. The primary ioctl
8052 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
8053 * for Android "DRIVER" commands. The other ioctl that is
8054 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
8055 * for FTM on some platforms. This function simply verifies that the
8056 * driver is in a sane state, and that the ioctl is one of the
8057 * supported flavors, in which case flavor-specific handlers are
8058 * dispatched.
8059 *
8060 * Return: 0 on success, non-zero on error
8061 */
8062static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
8063{
Jeff Johnsone44b7012017-09-10 15:25:47 -07008064 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson621cf972017-08-28 11:58:44 -07008065 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008066 int ret;
8067
Dustin Brownfdf17c12018-03-14 12:55:34 -07008068 hdd_enter_dev(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05308069
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008070 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08008071 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008072 ret = -ENODEV;
8073 goto exit;
8074 }
8075
8076 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08008077 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008078 ret = -EINVAL;
8079 goto exit;
8080 }
8081#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05308082 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008083 if (SIOCIOCTLTX99 == cmd) {
8084 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
8085 goto exit;
8086 }
8087 }
8088#endif
8089
8090 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8091 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05308092 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008093 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008094
8095 switch (cmd) {
8096 case (SIOCDEVPRIVATE + 1):
Mahesh Kumar Kalikot Veetil885a77b2018-03-26 14:46:59 -07008097 if (in_compat_syscall())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008098 ret = hdd_driver_compat_ioctl(adapter, ifr);
8099 else
8100 ret = hdd_driver_ioctl(adapter, ifr);
8101 break;
8102 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08008103 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008104 ret = -EINVAL;
8105 break;
8106 }
8107exit:
Dustin Browne74003f2018-03-14 12:51:58 -07008108 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008109 return ret;
8110}
8111
8112/**
8113 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
Dustin Brown98f7c822019-03-06 12:25:49 -08008114 * @net_dev: device upon which the ioctl was received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008115 * @ifr: ioctl request information
8116 * @cmd: ioctl command
8117 *
8118 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
8119 * which is where the ioctls are really handled.
8120 *
8121 * Return: 0 on success, non-zero on error
8122 */
Dustin Brown98f7c822019-03-06 12:25:49 -08008123int hdd_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008124{
Dustin Brown98f7c822019-03-06 12:25:49 -08008125 struct osif_vdev_sync *vdev_sync;
8126 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008127
Dustin Brown98f7c822019-03-06 12:25:49 -08008128 errno = osif_vdev_sync_op_start(net_dev, &vdev_sync);
8129 if (errno)
8130 return errno;
8131
8132 errno = __hdd_ioctl(net_dev, ifr, cmd);
8133
8134 osif_vdev_sync_op_stop(vdev_sync);
8135
8136 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008137}
Dustin Brown98f7c822019-03-06 12:25:49 -08008138