blob: 2ae86562314c7fc2428e8f0ab4822491503b3d53 [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
67/*
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080068 * Ibss prop IE from command will be of size:
69 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
70 * OUI_DATA should be at least 3 bytes long
71 */
72#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080073
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080074#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080075#define TID_MIN_VALUE 0
76#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080077#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080078
79/*
80 * Maximum buffer size used for returning the data back to user space
81 */
82#define WLAN_MAX_BUF_SIZE 1024
83#define WLAN_PRIV_DATA_MAX_LEN 8192
84
85/*
86 * Driver miracast parameters 0-Disabled
87 * 1-Source, 2-Sink
88 */
89#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
90#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
91
92/*
93 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
94 * we will split the printing.
95 */
96#define NUM_OF_STA_DATA_TO_PRINT 16
97
Dundi Raviteja53de6c32018-05-16 16:56:30 +053098#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
99/**
100 * struct enable_ext_wow_priv - Private data structure for ext wow
101 * @ext_wow_should_suspend: Suspend status of ext wow
102 */
103struct enable_ext_wow_priv {
104 bool ext_wow_should_suspend;
105};
106#endif
107
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800108/*
109 * Android DRIVER command structures
110 */
111struct android_wifi_reassoc_params {
112 unsigned char bssid[18];
113 int channel;
114};
115
116#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
117struct android_wifi_af_params {
118 unsigned char bssid[18];
119 int channel;
120 int dwell_time;
121 int len;
122 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
123};
124
125/*
126 * Define HDD driver command handling entry, each contains a command
127 * string and the handler.
128 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700129typedef int (*hdd_drv_cmd_handler_t)(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -0700130 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800131 uint8_t *cmd,
132 uint8_t cmd_name_len,
Jeff Johnson353cd292017-08-17 06:47:26 -0700133 struct hdd_priv_data *priv_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800134
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530135/**
136 * struct hdd_drv_cmd - Structure to store ioctl command handling info
137 * @cmd: Name of the command
138 * @handler: Command handler to be invoked
139 * @args: Set to true if command expects input parameters
140 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700141struct hdd_drv_cmd {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800142 const char *cmd;
143 hdd_drv_cmd_handler_t handler;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530144 bool args;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700145};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800146
147#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
148#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
149#define WLAN_HDD_MAX_TCP_PORT 65535
150#endif
151
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800152static uint16_t cesium_pid;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800153
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530154/**
155 * drv_cmd_validate() - Validates for space in hdd driver command
156 * @command: pointer to input data (its a NULL terminated string)
157 * @len: length of command name
158 *
159 * This function checks for space after command name and if no space
160 * is found returns error.
161 *
162 * Return: 0 for success non-zero for failure
163 */
164static int drv_cmd_validate(uint8_t *command, int len)
165{
166 if (command[len] != ' ')
167 return -EINVAL;
168
169 return 0;
170}
171
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800172#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800173struct tsm_priv {
174 tAniTrafStrmMetrics tsm_metrics;
175};
176
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800177static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
Sourav Mohapatradcd8f8d2019-07-03 15:43:15 +0530178 void *context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800179{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700180 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800181 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800182
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700183 request = osif_request_get(context);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800184 if (!request) {
185 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186 return;
187 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700188 priv = osif_request_priv(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800189 priv->tsm_metrics = tsm_metrics;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700190 osif_request_complete(request);
191 osif_request_put(request);
Dustin Browne74003f2018-03-14 12:51:58 -0700192 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800193
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194}
195
Jeff Johnsone44b7012017-09-10 15:25:47 -0700196static int hdd_get_tsm_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800197 const uint8_t tid,
198 tAniTrafStrmMetrics *tsm_metrics)
199{
Jeff Johnson621cf972017-08-28 11:58:44 -0700200 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700201 struct hdd_station_ctx *hdd_sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800202 QDF_STATUS status;
203 int ret;
204 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700205 struct osif_request *request;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800206 struct tsm_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700207 static const struct osif_request_params params = {
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800208 .priv_size = sizeof(*priv),
209 .timeout_ms = WLAN_WAIT_TIME_STATS,
210 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211
Jeff Johnsond36fa332019-03-18 13:42:25 -0700212 if (!adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700213 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800214 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800215 }
216
217 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
218 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
219
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700220 request = osif_request_alloc(&params);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800221 if (!request) {
222 hdd_err("Request allocation failure");
223 return -ENOMEM;
224 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700225 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800226
Jeff Johnsond549efa2018-06-13 20:27:47 -0700227 status = sme_get_tsm_stats(hdd_ctx->mac_handle, hdd_get_tsm_stats_cb,
Jeff Johnsone04b6992019-02-27 14:06:55 -0800228 hdd_sta_ctx->conn_info.bssid,
Jeff Johnson30f84552017-09-13 14:55:25 -0700229 cookie, tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800230 if (QDF_STATUS_SUCCESS != status) {
231 hdd_err("Unable to retrieve tsm statistics");
232 ret = qdf_status_to_os_return(status);
233 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800234 }
235
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700236 ret = osif_request_wait_for_response(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800237 if (ret) {
238 hdd_err("SME timed out while retrieving tsm statistics");
239 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800240 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800241
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700242 priv = osif_request_priv(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800243 *tsm_metrics = priv->tsm_metrics;
244
245 cleanup:
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -0700246 osif_request_put(request);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800247
248 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800249}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800250#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800251
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800252/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700253 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
Jeff Johnsonafa022c2019-02-26 09:24:17 -0800254 * @context: callback context (adapter supplied by caller)
Jeff Johnson52f19d52019-02-26 08:35:38 -0800255 * @peer_info: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800256 *
257 * This is an asynchronous callback function from SME when the peer info
258 * is received
259 *
260 * Return: 0 for success non-zero for failure
261 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700262void
Jeff Johnsonafa022c2019-02-26 09:24:17 -0800263hdd_get_ibss_peer_info_cb(void *context,
Jeff Johnson52f19d52019-02-26 08:35:38 -0800264 tSirPeerInfoRspParams *peer_info)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800265{
Jeff Johnsonafa022c2019-02-26 09:24:17 -0800266 struct hdd_adapter *adapter = context;
Jeff Johnson93107ad2019-02-26 08:14:46 -0800267 struct hdd_station_ctx *sta_ctx;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800268 uint8_t i;
269
Jeff Johnsond36fa332019-03-18 13:42:25 -0700270 if ((!adapter) ||
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800271 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800272 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800273 return;
274 }
275
Jeff Johnson93107ad2019-02-26 08:14:46 -0800276 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsond36fa332019-03-18 13:42:25 -0700277 if (peer_info && QDF_STATUS_SUCCESS == peer_info->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700278 /* validate number of peers */
Jeff Johnson52f19d52019-02-26 08:35:38 -0800279 if (peer_info->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530280 hdd_warn("Limiting num_peers %u to %u",
Jeff Johnson52f19d52019-02-26 08:35:38 -0800281 peer_info->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
282 peer_info->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800283 }
Jeff Johnson52f19d52019-02-26 08:35:38 -0800284 sta_ctx->ibss_peer_info.status = peer_info->status;
285 sta_ctx->ibss_peer_info.numPeers = peer_info->numPeers;
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530286
Jeff Johnson52f19d52019-02-26 08:35:38 -0800287 for (i = 0; i < peer_info->numPeers; i++)
Jeff Johnson93107ad2019-02-26 08:14:46 -0800288 sta_ctx->ibss_peer_info.peerInfoParams[i] =
Jeff Johnson52f19d52019-02-26 08:35:38 -0800289 peer_info->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800290 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800291 hdd_debug("peerInfo %s: status %u, numPeers %u",
Jeff Johnson52f19d52019-02-26 08:35:38 -0800292 peer_info ? "valid" : "null",
293 peer_info ? peer_info->status : QDF_STATUS_E_FAILURE,
294 peer_info ? peer_info->numPeers : 0);
Jeff Johnson93107ad2019-02-26 08:14:46 -0800295 sta_ctx->ibss_peer_info.numPeers = 0;
296 sta_ctx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800297 }
298
299 complete(&adapter->ibss_peer_info_comp);
300}
301
302/**
303 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
304 * @adapter: Adapter context
305 *
306 * Request function to get IBSS peer info from lower layers
307 *
308 * Return: 0 for success non-zero for failure
309 */
310static
Jeff Johnsone44b7012017-09-10 15:25:47 -0700311QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(struct hdd_adapter *adapter)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800312{
Jeff Johnsond549efa2018-06-13 20:27:47 -0700313 QDF_STATUS status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800314 unsigned long rc;
315
316 INIT_COMPLETION(adapter->ibss_peer_info_comp);
317
Jeff Johnsond549efa2018-06-13 20:27:47 -0700318 status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle,
319 adapter,
320 hdd_get_ibss_peer_info_cb,
321 true, 0xFF);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800322
Jeff Johnsond549efa2018-06-13 20:27:47 -0700323 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800324 rc = wait_for_completion_timeout
325 (&adapter->ibss_peer_info_comp,
326 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
327
328 /* status will be 0 if timed out */
329 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700330 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Jeff Johnsond549efa2018-06-13 20:27:47 -0700331 status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800332 }
333 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700334 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800335 }
336
Jeff Johnsond549efa2018-06-13 20:27:47 -0700337 return status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800338}
339
340/**
341 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
342 * @adapter: Adapter context
Jeff Johnson0a082d92019-03-04 12:25:49 -0800343 * @sta_id: Sta index for which the peer info is requested
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800344 *
345 * Request function to get IBSS peer info from lower layers
346 *
347 * Return: 0 for success non-zero for failure
348 */
349static QDF_STATUS
Jeff Johnson0a082d92019-03-04 12:25:49 -0800350hdd_cfg80211_get_ibss_peer_info(struct hdd_adapter *adapter, uint8_t sta_id)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800351{
352 unsigned long rc;
Jeff Johnsond549efa2018-06-13 20:27:47 -0700353 QDF_STATUS status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800354
355 INIT_COMPLETION(adapter->ibss_peer_info_comp);
356
Jeff Johnsond549efa2018-06-13 20:27:47 -0700357 status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle,
358 adapter,
359 hdd_get_ibss_peer_info_cb,
Jeff Johnson0a082d92019-03-04 12:25:49 -0800360 false, sta_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800361
Jeff Johnsond549efa2018-06-13 20:27:47 -0700362 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800363 rc = wait_for_completion_timeout(
364 &adapter->ibss_peer_info_comp,
365 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
366
367 /* status = 0 on timeout */
368 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700369 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Jeff Johnsond549efa2018-06-13 20:27:47 -0700370 status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800371 }
372 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700373 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800374 }
375
Jeff Johnsond549efa2018-06-13 20:27:47 -0700376 return status;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800377}
378
379/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700380static QDF_STATUS
Jeff Johnson6636e622019-02-26 10:22:39 -0800381hdd_parse_get_ibss_peer_info(uint8_t *command,
Jeff Johnson64ba9af2019-02-26 12:57:35 -0800382 struct qdf_mac_addr *peer_macaddr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800383{
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800384 uint8_t *in_ptr = command;
Jeff Johnson6636e622019-02-26 10:22:39 -0800385 size_t in_ptr_len = strlen(command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700386
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800387 in_ptr = strnchr(command, in_ptr_len, SPACE_ASCII_VALUE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800388
Jeff Johnsond36fa332019-03-18 13:42:25 -0700389 if (!in_ptr)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700390 return QDF_STATUS_E_FAILURE;
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800391 else if (SPACE_ASCII_VALUE != *in_ptr)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700392 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800393
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800394 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
395 in_ptr++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800396
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800397 if ('\0' == *in_ptr)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700398 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800399
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800400 in_ptr_len -= (in_ptr - command);
Min Liu5359ab12018-03-29 14:30:24 +0800401 if (in_ptr_len < 17)
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700402 return QDF_STATUS_E_FAILURE;
Min Liu5359ab12018-03-29 14:30:24 +0800403
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800404 if (in_ptr[2] != ':' || in_ptr[5] != ':' || in_ptr[8] != ':' ||
405 in_ptr[11] != ':' || in_ptr[14] != ':')
Min Liu5359ab12018-03-29 14:30:24 +0800406 return QDF_STATUS_E_FAILURE;
407
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800408 sscanf(in_ptr, "%2x:%2x:%2x:%2x:%2x:%2x",
Jeff Johnson64ba9af2019-02-26 12:57:35 -0800409 (unsigned int *)&peer_macaddr->bytes[0],
410 (unsigned int *)&peer_macaddr->bytes[1],
411 (unsigned int *)&peer_macaddr->bytes[2],
412 (unsigned int *)&peer_macaddr->bytes[3],
413 (unsigned int *)&peer_macaddr->bytes[4],
414 (unsigned int *)&peer_macaddr->bytes[5]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800415
416 return QDF_STATUS_SUCCESS;
417}
418
Jeff Johnsond549efa2018-06-13 20:27:47 -0700419static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *ui_band)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800420{
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800421 enum band_info band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700422
Harprit Chhabada5dff30e2019-03-12 17:56:45 -0700423 ucfg_reg_get_band(hdd_ctx->pdev, &band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800424 switch (band) {
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800425 case BAND_ALL:
Jeff Johnsond549efa2018-06-13 20:27:47 -0700426 *ui_band = WLAN_HDD_UI_BAND_AUTO;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800427 break;
428
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800429 case BAND_2G:
Jeff Johnsond549efa2018-06-13 20:27:47 -0700430 *ui_band = WLAN_HDD_UI_BAND_2_4_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431 break;
432
Varun Reddy Yeturua48bc412017-11-17 15:33:35 -0800433 case BAND_5G:
Jeff Johnsond549efa2018-06-13 20:27:47 -0700434 *ui_band = WLAN_HDD_UI_BAND_5_GHZ;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800435 break;
436
437 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700438 hdd_warn("Invalid Band %d", band);
Jeff Johnsond549efa2018-06-13 20:27:47 -0700439 *ui_band = -1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800440 break;
441 }
442}
443
444/**
445 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
446 * @data: input data
447 * @target_ap_bssid: pointer to bssid (output parameter)
448 * @channel: pointer to channel (output parameter)
449 *
450 * Return: 0 if parsing is successful; -EINVAL otherwise
451 */
452static int _hdd_parse_bssid_and_chan(const uint8_t **data,
453 uint8_t *bssid,
454 uint8_t *channel)
455{
456 const uint8_t *in_ptr;
457 int v = 0;
458 int temp_int;
459 uint8_t temp_buf[32];
460
461 /* 12 hexa decimal digits, 5 ':' and '\0' */
462 uint8_t mac_addr[18];
463
464 if (!data || !*data)
465 return -EINVAL;
466
467 in_ptr = *data;
468
469 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
470 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -0700471 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800472 goto error;
473 /* no space after the command */
474 else if (SPACE_ASCII_VALUE != *in_ptr)
475 goto error;
476
477 /* remove empty spaces */
478 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
479 in_ptr++;
480
481 /* no argument followed by spaces */
482 if ('\0' == *in_ptr)
483 goto error;
484
485 v = sscanf(in_ptr, "%17s", mac_addr);
486 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700487 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
488 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800489 goto error;
490 }
491
492 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
493 hex_to_bin(mac_addr[1]);
494 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
495 hex_to_bin(mac_addr[4]);
496 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
497 hex_to_bin(mac_addr[7]);
498 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
499 hex_to_bin(mac_addr[10]);
500 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
501 hex_to_bin(mac_addr[13]);
502 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
503 hex_to_bin(mac_addr[16]);
504
505 /* point to the next argument */
506 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
507 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -0700508 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800509 goto error;
510
511 /* remove empty spaces */
512 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
513 in_ptr++;
514
515 /* no argument followed by spaces */
516 if ('\0' == *in_ptr)
517 goto error;
518
519 /* get the next argument ie the channel number */
520 v = sscanf(in_ptr, "%31s ", temp_buf);
521 if (1 != v)
522 goto error;
523
524 v = kstrtos32(temp_buf, 10, &temp_int);
525 if ((v < 0) || (temp_int < 0) ||
526 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
527 return -EINVAL;
528
529 *channel = temp_int;
530 *data = in_ptr;
531 return 0;
532error:
533 *data = in_ptr;
534 return -EINVAL;
535}
536
537/**
538 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
Jeff Johnson6636e622019-02-26 10:22:39 -0800539 * @command: Pointer to input data
Jeff Johnsonb7d52792019-02-26 12:42:08 -0800540 * @bssid: Pointer to target Ap bssid
Jeff Johnsond727cdc2019-02-26 12:47:05 -0800541 * @channel: Pointer to the Target AP channel
Jeff Johnson80d220a2019-02-26 12:27:24 -0800542 * @dwell_time: Pointer to the time to stay off-channel
Jeff Johnson6636e622019-02-26 10:22:39 -0800543 * after transmitting action frame
Jeff Johnson5f3a6122019-02-26 17:20:59 -0800544 * @buf: Pointer to data
Jeff Johnson103f67a2019-02-26 17:11:01 -0800545 * @buf_len: Pointer to data length
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800546 *
547 * This function parses the send action frame data passed in the format
548 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
549 *
550 * Return: 0 for success non-zero for failure
551 */
552static int
Jeff Johnson6636e622019-02-26 10:22:39 -0800553hdd_parse_send_action_frame_v1_data(const uint8_t *command,
Jeff Johnsonb7d52792019-02-26 12:42:08 -0800554 uint8_t *bssid,
Jeff Johnsond727cdc2019-02-26 12:47:05 -0800555 uint8_t *channel, uint8_t *dwell_time,
Jeff Johnson5f3a6122019-02-26 17:20:59 -0800556 uint8_t **buf, uint8_t *buf_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800557{
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800558 const uint8_t *in_ptr = command;
Jeff Johnsonaae00ae2019-02-26 17:25:11 -0800559 const uint8_t *end_ptr;
Jeff Johnsoncd361c92019-02-26 19:23:49 -0800560 int temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800561 int j = 0;
562 int i = 0;
563 int v = 0;
Jeff Johnson72f498b2019-02-26 18:37:25 -0800564 uint8_t temp_buf[32];
565 uint8_t temp_u8 = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800566
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800567 if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, channel))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800568 return -EINVAL;
569
570 /* point to the next argument */
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800571 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800572 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -0700573 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800574 return -EINVAL;
575 /* removing empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800576 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
577 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800578
579 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800580 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800581 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800582
583 /* getting the next argument ie the dwell time */
Jeff Johnson72f498b2019-02-26 18:37:25 -0800584 v = sscanf(in_ptr, "%31s ", temp_buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800585 if (1 != v)
586 return -EINVAL;
587
Jeff Johnsoncd361c92019-02-26 19:23:49 -0800588 v = kstrtos32(temp_buf, 10, &temp_int);
589 if (v < 0 || temp_int < 0)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800590 return -EINVAL;
591
Jeff Johnsoncd361c92019-02-26 19:23:49 -0800592 *dwell_time = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800593
594 /* point to the next argument */
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800595 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800596 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -0700597 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800598 return -EINVAL;
599 /* removing empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800600 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
601 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800602
603 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800604 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800605 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800606
607 /* find the length of data */
Jeff Johnsonaae00ae2019-02-26 17:25:11 -0800608 end_ptr = in_ptr;
609 while (('\0' != *end_ptr))
610 end_ptr++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700611
Jeff Johnsonaae00ae2019-02-26 17:25:11 -0800612 *buf_len = end_ptr - in_ptr;
Jeff Johnson103f67a2019-02-26 17:11:01 -0800613 if (*buf_len <= 0)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800614 return -EINVAL;
615
616 /*
617 * Allocate the number of bytes based on the number of input characters
618 * whether it is even or odd.
619 * if the number of input characters are even, then we need N/2 byte.
620 * if the number of input characters are odd, then we need do (N+1)/2
621 * to compensate rounding off.
622 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
623 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
624 */
Jeff Johnson5f3a6122019-02-26 17:20:59 -0800625 *buf = qdf_mem_malloc((*buf_len + 1) / 2);
Jeff Johnsond36fa332019-03-18 13:42:25 -0700626 if (!*buf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700627 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800628 return -ENOMEM;
629 }
630
631 /* the buffer received from the upper layer is character buffer,
632 * we need to prepare the buffer taking 2 characters in to a U8 hex
633 * decimal number for example 7f0000f0...form a buffer to contain 7f
634 * in 0th location, 00 in 1st and f0 in 3rd location
635 */
Jeff Johnson103f67a2019-02-26 17:11:01 -0800636 for (i = 0, j = 0; j < *buf_len; j += 2) {
637 if (j + 1 == *buf_len) {
Jeff Johnson72f498b2019-02-26 18:37:25 -0800638 temp_u8 = hex_to_bin(in_ptr[j]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800639 } else {
Jeff Johnson72f498b2019-02-26 18:37:25 -0800640 temp_u8 =
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800641 (hex_to_bin(in_ptr[j]) << 4) |
642 (hex_to_bin(in_ptr[j + 1]));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800643 }
Jeff Johnson72f498b2019-02-26 18:37:25 -0800644 (*buf)[i++] = temp_u8;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800645 }
Jeff Johnson103f67a2019-02-26 17:11:01 -0800646 *buf_len = i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800647 return 0;
648}
649
650/**
651 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
Jeff Johnson6636e622019-02-26 10:22:39 -0800652 * @command: Pointer to input data (its a NULL terminated string)
Jeff Johnsonb7d52792019-02-26 12:42:08 -0800653 * @bssid: Pointer to target Ap bssid
Jeff Johnsond727cdc2019-02-26 12:47:05 -0800654 * @channel: Pointer to the Target AP channel
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800655 *
656 * This function parses the reasoc command data passed in the format
657 * REASSOC<space><bssid><space><channel>
658 *
659 * Return: 0 for success non-zero for failure
660 */
Jeff Johnson6636e622019-02-26 10:22:39 -0800661static int hdd_parse_reassoc_command_v1_data(const uint8_t *command,
Jeff Johnsonb7d52792019-02-26 12:42:08 -0800662 uint8_t *bssid,
Jeff Johnsond727cdc2019-02-26 12:47:05 -0800663 uint8_t *channel)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800664{
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800665 const uint8_t *in_ptr = command;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800666
Jeff Johnson4ff36b22019-02-26 13:01:07 -0800667 if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, channel))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800668 return -EINVAL;
669
670 return 0;
671}
672
Naveen Rawat05376ee2016-07-18 16:43:32 -0700673#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Abhinav Kumareab25932018-07-13 11:48:43 +0530674QDF_STATUS hdd_wma_send_fastreassoc_cmd(struct hdd_adapter *adapter,
675 const tSirMacAddr bssid,
676 int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700677{
Krunal Soni332f4af2017-06-01 14:36:17 -0700678 struct hdd_station_ctx *hdd_sta_ctx =
679 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnson8313b9d2018-03-14 15:09:28 -0700680 struct csr_roam_profile *roam_profile;
Krunal Soni332f4af2017-06-01 14:36:17 -0700681 tSirMacAddr connected_bssid;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700682
Jeff Johnson8313b9d2018-03-14 15:09:28 -0700683 roam_profile = hdd_roam_profile(adapter);
Jeff Johnsone04b6992019-02-27 14:06:55 -0800684 qdf_mem_copy(connected_bssid, hdd_sta_ctx->conn_info.bssid.bytes,
Krunal Soni332f4af2017-06-01 14:36:17 -0700685 ETH_ALEN);
Abhinav Kumareab25932018-07-13 11:48:43 +0530686 return sme_fast_reassoc(adapter->hdd_ctx->mac_handle,
687 roam_profile, bssid, channel,
Jeff Johnson5a6fc962019-02-04 14:20:25 -0800688 adapter->vdev_id, connected_bssid);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700689}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700690#endif
691
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800692/**
693 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800694 * @adapter: Adapter upon which the command was received
695 * @bssid: BSSID with which to reassociate
696 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700697 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800698 *
699 * This function performs a userspace-directed reassoc operation
700 *
701 * Return: 0 for success non-zero for failure
702 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700703int hdd_reassoc(struct hdd_adapter *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800704 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800705{
Jeff Johnsond377dce2017-10-04 10:32:42 -0700706 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -0700707 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708 int ret = 0;
Abhinav Kumareab25932018-07-13 11:48:43 +0530709 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800710
Jeff Johnsond36fa332019-03-18 13:42:25 -0700711 if (!hdd_ctx) {
Naveen Rawat05376ee2016-07-18 16:43:32 -0700712 hdd_err("Invalid hdd ctx");
713 return -EINVAL;
714 }
715
Krunal Sonibe766b02016-03-10 13:00:44 -0800716 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800717 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -0700718 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800719 adapter->device_mode);
720 return -EINVAL;
721 }
722
Jeff Johnsond377dce2017-10-04 10:32:42 -0700723 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800724
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +0530725 /*
Jeff Johnsone7951512019-02-27 10:02:51 -0800726 * pHddStaCtx->conn_info.conn_state is set to disconnected only
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +0530727 * after the disconnect done indication from SME. If the SME is
728 * in the process of disconnecting, the SME Connection state is
Jeff Johnsone7951512019-02-27 10:02:51 -0800729 * set to disconnected and the pHddStaCtx->conn_info.conn_state
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +0530730 * will still be associated till the disconnect is done.
731 * So check both the HDD state and SME state here.
732 * If not associated, no need to proceed with reassoc
733 */
Jeff Johnsone7951512019-02-27 10:02:51 -0800734 if ((eConnectionState_Associated != sta_ctx->conn_info.conn_state) ||
Vignesh Viswanathan7c43a7a2018-09-24 15:52:47 +0530735 (!sme_is_conn_state_connected(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -0800736 adapter->vdev_id))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800737 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800738 ret = -EINVAL;
739 goto exit;
740 }
741
742 /*
743 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800744 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745 */
Jeff Johnsone04b6992019-02-27 14:06:55 -0800746 if (!memcmp(bssid, sta_ctx->conn_info.bssid.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530747 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800748 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Jingxiang Gece7c5472019-07-23 16:19:23 +0800749 channel = wlan_reg_freq_to_chan(hdd_ctx->pdev,
Jingxiang Geae80dc62019-08-13 17:32:22 +0800750 sta_ctx->conn_info.chan_freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800751 }
752
753 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530754 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800755 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800756 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800757 ret = -EINVAL;
758 goto exit;
759 }
760
761 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700762 if (roaming_offload_enabled(hdd_ctx)) {
Abhinav Kumareab25932018-07-13 11:48:43 +0530763 status = hdd_wma_send_fastreassoc_cmd(adapter,
764 bssid, (int)channel);
765 if (status != QDF_STATUS_SUCCESS) {
766 hdd_err("Failed to send fast reassoc cmd");
767 ret = -EINVAL;
768 }
Naveen Rawat05376ee2016-07-18 16:43:32 -0700769 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -0700770 tCsrHandoffRequest handoff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800771
Jeff Johnsond549efa2018-06-13 20:27:47 -0700772 handoff.channel = channel;
773 handoff.src = src;
774 qdf_mem_copy(handoff.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson5a6fc962019-02-04 14:20:25 -0800775 sme_handoff_request(hdd_ctx->mac_handle, adapter->vdev_id,
Jeff Johnsond549efa2018-06-13 20:27:47 -0700776 &handoff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800777 }
778exit:
779 return ret;
780}
781
782/**
783 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
784 * @adapter: Adapter upon which the command was received
785 * @command: ASCII text command that was received
786 *
787 * This function parses the v1 REASSOC command with the format
788 *
789 * REASSOC xx:xx:xx:xx:xx:xx CH
790 *
791 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
792 * BSSID and CH is the ASCII representation of the channel. For
793 * example
794 *
795 * REASSOC 00:0a:0b:11:22:33 48
796 *
797 * Return: 0 for success non-zero for failure
798 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700799static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800800{
801 uint8_t channel = 0;
802 tSirMacAddr bssid;
803 int ret;
804
805 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700806 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700807 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700808 else
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700809 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700810
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800811 return ret;
812}
813
814/**
815 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
816 * @adapter: Adapter upon which the command was received
817 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700818 * followed by binary data
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530819 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820 *
821 * This function parses the v2 REASSOC command with the format
822 *
823 * REASSOC <android_wifi_reassoc_params>
824 *
825 * Return: 0 for success non-zero for failure
826 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700827static int hdd_parse_reassoc_v2(struct hdd_adapter *adapter,
828 const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530829 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800830{
831 struct android_wifi_reassoc_params params;
832 tSirMacAddr bssid;
833 int ret;
834
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530835 if (total_len < sizeof(params) + 8) {
836 hdd_err("Invalid command length");
837 return -EINVAL;
838 }
839
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840 /* The params are located after "REASSOC " */
841 memcpy(&params, command + 8, sizeof(params));
842
843 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700844 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800845 ret = -EINVAL;
846 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700847 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800848 }
849 return ret;
850}
851
852/**
853 * hdd_parse_reassoc() - parse the REASSOC command
854 * @adapter: Adapter upon which the command was received
855 * @command: Command that was received
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530856 * @total_len: Total length of the command received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800857 *
858 * There are two different versions of the REASSOC command. Version 1
859 * of the command contains a parameter list that is ASCII characters
860 * whereas version 2 contains a combination of ASCII and binary
861 * payload. Determine if a version 1 or a version 2 command is being
862 * parsed by examining the parameters, and then dispatch the parser
863 * that is appropriate for the command.
864 *
865 * Return: 0 for success non-zero for failure
866 */
Jeff Johnsone44b7012017-09-10 15:25:47 -0700867static int hdd_parse_reassoc(struct hdd_adapter *adapter, const char *command,
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530868 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800869{
870 int ret;
871
872 /* both versions start with "REASSOC "
873 * v1 has a bssid and channel # as an ASCII string
874 * REASSOC xx:xx:xx:xx:xx:xx CH
875 * v2 has a C struct
876 * REASSOC <binary c struct>
877 *
878 * The first field in the v2 struct is also the bssid in ASCII.
879 * But in the case of a v2 message the BSSID is NUL-terminated.
880 * Hence we can peek at that offset to see if this is V1 or V2
881 * REASSOC xx:xx:xx:xx:xx:xx*
882 * 1111111111222222
883 * 01234567890123456789012345
884 */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530885
886 if (total_len < 26) {
887 hdd_err("Invalid command, total_len = %d", total_len);
888 return -EINVAL;
889 }
890
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700891 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800892 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700893 else
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +0530894 ret = hdd_parse_reassoc_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800895
896 return ret;
897}
898
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899/**
900 * hdd_sendactionframe() - send a userspace-supplied action frame
901 * @adapter: Adapter upon which the command was received
902 * @bssid: BSSID target of the action frame
903 * @channel: Channel upon which to send the frame
904 * @dwell_time: Amount of time to dwell when the frame is sent
905 * @payload_len:Length of the payload
906 * @payload: Payload of the frame
907 *
908 * This function sends a userspace-supplied action frame
909 *
910 * Return: 0 for success non-zero for failure
911 */
912static int
Jeff Johnsone44b7012017-09-10 15:25:47 -0700913hdd_sendactionframe(struct hdd_adapter *adapter, const uint8_t *bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800914 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700915 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916{
917 struct ieee80211_channel chan;
Jingxiang Gece7c5472019-07-23 16:19:23 +0800918 uint8_t conn_info_channel;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -0700919 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800920 uint8_t *frame;
921 struct ieee80211_hdr_3addr *hdr;
922 u64 cookie;
Jeff Johnsond377dce2017-10-04 10:32:42 -0700923 struct hdd_station_ctx *sta_ctx;
Jeff Johnson621cf972017-08-28 11:58:44 -0700924 struct hdd_context *hdd_ctx;
Jeff Johnsonecdf83b2019-02-26 18:33:56 -0800925 tpSirMacVendorSpecificFrameHdr vendor =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800926 (tpSirMacVendorSpecificFrameHdr) payload;
927#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
928 struct cfg80211_mgmt_tx_params params;
929#endif
930
Krunal Sonibe766b02016-03-10 13:00:44 -0800931 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800932 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -0700933 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934 adapter->device_mode);
935 return -EINVAL;
936 }
937
Jeff Johnsond377dce2017-10-04 10:32:42 -0700938 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800939 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
940
941 /* if not associated, no need to send action frame */
Jeff Johnsone7951512019-02-27 10:02:51 -0800942 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800943 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 ret = -EINVAL;
945 goto exit;
946 }
947
948 /*
949 * if the target bssid is different from currently associated AP,
950 * then no need to send action frame
951 */
Jeff Johnsone04b6992019-02-27 14:06:55 -0800952 if (memcmp(bssid, sta_ctx->conn_info.bssid.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530953 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800954 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800955 ret = -EINVAL;
956 goto exit;
957 }
958
959 chan.center_freq = sme_chn_to_freq(channel);
960 /* Check if it is specific action frame */
Jeff Johnsonecdf83b2019-02-26 18:33:56 -0800961 if (vendor->category ==
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
Jeff Johnson2971e3a2019-02-26 18:31:54 -0800963 static const uint8_t oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700964
Jeff Johnsonecdf83b2019-02-26 18:33:56 -0800965 if (!qdf_mem_cmp(vendor->Oui, oui, 3)) {
Jingxiang Gece7c5472019-07-23 16:19:23 +0800966 conn_info_channel = wlan_reg_freq_to_chan(
967 hdd_ctx->pdev,
Jingxiang Geae80dc62019-08-13 17:32:22 +0800968 sta_ctx->conn_info.chan_freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800969 /*
970 * if the channel number is different from operating
971 * channel then no need to send action frame
972 */
973 if (channel != 0) {
Jingxiang Gece7c5472019-07-23 16:19:23 +0800974 if (channel != conn_info_channel) {
975 hdd_warn("channel(%u) is different from operating channel(%u)",
976 channel,
977 conn_info_channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800978 ret = -EINVAL;
979 goto exit;
980 }
981 /*
982 * If channel number is specified and same
983 * as home channel, ensure that action frame
984 * is sent immediately by cancelling
985 * roaming scans. Otherwise large dwell times
986 * may cause long delays in sending action
987 * frames.
988 */
Jeff Johnsond549efa2018-06-13 20:27:47 -0700989 sme_abort_roam_scan(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -0800990 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800991 } else {
992 /*
993 * 0 is accepted as current home channel,
994 * delayed transmission of action frame is ok.
995 */
Jingxiang Geae80dc62019-08-13 17:32:22 +0800996 chan.center_freq = sta_ctx->conn_info.chan_freq;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800997 }
998 }
999 }
1000 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001001 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001002 ret = -EINVAL;
1003 goto exit;
1004 }
1005
1006 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301007 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001008 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001009 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001010 ret = -ENOMEM;
1011 goto exit;
1012 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001013
1014 hdr = (struct ieee80211_hdr_3addr *)frame;
1015 hdr->frame_control =
1016 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301017 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
Jeff Johnson1e851a12017-10-28 14:36:12 -07001018 qdf_mem_copy(hdr->addr2, adapter->mac_addr.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301019 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301020 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1021 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001022
1023#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1024 params.chan = &chan;
1025 params.offchan = 0;
1026 params.wait = dwell_time;
1027 params.buf = frame;
1028 params.len = frame_len;
1029 params.no_cck = 1;
1030 params.dont_wait_for_ack = 1;
1031 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1032#else
1033 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001036
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001037 dwell_time, frame, frame_len, 1, 1, &cookie);
1038#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1039
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301040 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001041exit:
1042 return ret;
1043}
1044
1045/**
1046 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1047 * SENDACTIONFRAME command
1048 * @adapter: Adapter upon which the command was received
1049 * @command: ASCII text command that was received
1050 *
1051 * This function parses the v1 SENDACTIONFRAME command with the format
1052 *
1053 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1054 *
1055 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1056 * BSSID, CH is the ASCII representation of the channel, DW is the
1057 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1058 * payload. For example
1059 *
1060 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1061 *
1062 * Return: 0 for success non-zero for failure
1063 */
1064static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001065hdd_parse_sendactionframe_v1(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001066{
1067 uint8_t channel = 0;
1068 uint8_t dwell_time = 0;
1069 uint8_t payload_len = 0;
1070 uint8_t *payload = NULL;
1071 tSirMacAddr bssid;
1072 int ret;
1073
1074 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1075 &dwell_time, &payload,
1076 &payload_len);
1077 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001078 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001079 } else {
1080 ret = hdd_sendactionframe(adapter, bssid, channel,
1081 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301082 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001083 }
1084
1085 return ret;
1086}
1087
1088/**
1089 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1090 * SENDACTIONFRAME command
1091 * @adapter: Adapter upon which the command was received
1092 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001093 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001094 *
1095 * This function parses the v2 SENDACTIONFRAME command with the format
1096 *
1097 * SENDACTIONFRAME <android_wifi_af_params>
1098 *
1099 * Return: 0 for success non-zero for failure
1100 */
1101static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001102hdd_parse_sendactionframe_v2(struct hdd_adapter *adapter,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001103 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001104{
1105 struct android_wifi_af_params *params;
1106 tSirMacAddr bssid;
1107 int ret;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301108 int len_wo_payload = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001110 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001111 total_len -= 16;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301112 len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE;
1113 if (total_len <= len_wo_payload) {
1114 hdd_err("Invalid command len");
1115 return -EINVAL;
1116 }
1117
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001118 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001119
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001120 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05301121 (params->len > (total_len - len_wo_payload))) {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001122 hdd_err("Invalid payload length: %d", params->len);
1123 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001124 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001125
1126 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1127 hdd_err("MAC address parsing failed");
1128 return -EINVAL;
1129 }
1130
1131 if (params->channel < 0 ||
1132 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1133 hdd_err("Invalid channel: %d", params->channel);
1134 return -EINVAL;
1135 }
1136
1137 if (params->dwell_time < 0) {
1138 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1139 return -EINVAL;
1140 }
1141
1142 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1143 params->dwell_time, params->len, params->data);
1144
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145 return ret;
1146}
1147
1148/**
1149 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1150 * @adapter: Adapter upon which the command was received
1151 * @command: Command that was received
1152 *
1153 * There are two different versions of the SENDACTIONFRAME command.
1154 * Version 1 of the command contains a parameter list that is ASCII
1155 * characters whereas version 2 contains a combination of ASCII and
1156 * binary payload. Determine if a version 1 or a version 2 command is
1157 * being parsed by examining the parameters, and then dispatch the
1158 * parser that is appropriate for the version of the command.
1159 *
1160 * Return: 0 for success non-zero for failure
1161 */
1162static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001163hdd_parse_sendactionframe(struct hdd_adapter *adapter, const char *command,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001164 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001165{
1166 int ret;
1167
1168 /*
1169 * both versions start with "SENDACTIONFRAME "
1170 * v1 has a bssid and other parameters as an ASCII string
1171 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1172 * v2 has a C struct
1173 * SENDACTIONFRAME <binary c struct>
1174 *
1175 * The first field in the v2 struct is also the bssid in ASCII.
1176 * But in the case of a v2 message the BSSID is NUL-terminated.
1177 * Hence we can peek at that offset to see if this is V1 or V2
1178 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1179 * 111111111122222222223333
1180 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001181 * For both the commands, a valid command must have atleast
1182 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001183 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001184 if (total_len < 34) {
1185 hdd_err("Invalid command (total_len=%d)", total_len);
1186 return -EINVAL;
1187 }
1188
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001189 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001191 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001192 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001193
1194 return ret;
1195}
1196
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001197/**
1198 * hdd_parse_channellist() - HDD Parse channel list
Jeff Johnson6636e622019-02-26 10:22:39 -08001199 * @command: Pointer to input channel list
Jeff Johnson091cbb72019-02-26 12:49:38 -08001200 * @channel_list: Pointer to local output array to record
Jeff Johnson6636e622019-02-26 10:22:39 -08001201 * channel list
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001202 * @num_channels: Pointer to number of roam scan channels
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001203 *
1204 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001205 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1206 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001207 * if the Number of channels (N) does not match with the actual number
1208 * of channels passed then take the minimum of N and count of
1209 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1210 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1211 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1212 * removing duplicate channels from the list
1213 *
1214 * Return: 0 for success non-zero for failure
1215 */
1216static int
Jeff Johnson091cbb72019-02-26 12:49:38 -08001217hdd_parse_channellist(const uint8_t *command, uint8_t *channel_list,
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001218 uint8_t *num_channels)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001219{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001220 const uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001221 int temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001222 int j = 0;
1223 int v = 0;
1224 char buf[32];
1225
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001226 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001227 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001228 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001230 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001231 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232
1233 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001234 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1235 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236
1237 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001238 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001239 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240
1241 /* get the first argument ie the number of channels */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001242 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001243 if (1 != v)
1244 return -EINVAL;
1245
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001246 v = kstrtos32(buf, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001247 if ((v < 0) ||
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001248 (temp_int <= 0) || (temp_int > CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001250
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001251 *num_channels = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001252
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001253 hdd_debug("Number of channels are: %d", *num_channels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001255 for (j = 0; j < (*num_channels); j++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001256 /*
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001257 * in_ptr pointing to the beginning of first space after number
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001258 * of channels
1259 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001260 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001261 /* no channel list after the number of channels argument */
Jeff Johnsond36fa332019-03-18 13:42:25 -07001262 if (!in_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001263 if (0 != j) {
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001264 *num_channels = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265 return 0;
1266 } else {
1267 return -EINVAL;
1268 }
1269 }
1270
1271 /* remove empty space */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001272 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1273 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001274
1275 /*
1276 * no channel list after the number of channels
1277 * argument and spaces
1278 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001279 if ('\0' == *in_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001280 if (0 != j) {
Jeff Johnsonc3eac6c2019-02-26 18:09:53 -08001281 *num_channels = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001282 return 0;
1283 } else {
1284 return -EINVAL;
1285 }
1286 }
1287
Jeff Johnson4ff36b22019-02-26 13:01:07 -08001288 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001289 if (1 != v)
1290 return -EINVAL;
1291
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001292 v = kstrtos32(buf, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001293 if ((v < 0) ||
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001294 (temp_int <= 0) ||
1295 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001296 return -EINVAL;
1297 }
Jeff Johnsoncd361c92019-02-26 19:23:49 -08001298 channel_list[j] = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001299
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001300 hdd_debug("Channel %d added to preferred channel list",
Jeff Johnson091cbb72019-02-26 12:49:38 -08001301 channel_list[j]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001302 }
1303
1304 return 0;
1305}
1306
1307/**
1308 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1309 * SETROAMSCANCHANNELS command
1310 * @adapter: Adapter upon which the command was received
1311 * @command: ASCII text command that was received
1312 *
1313 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1314 *
1315 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1316 *
1317 * Where "N" is the ASCII representation of the number of channels and
1318 * C1 thru Cn is the ASCII representation of the channels. For example
1319 *
1320 * SETROAMSCANCHANNELS 4 36 40 44 48
1321 *
1322 * Return: 0 for success non-zero for failure
1323 */
1324static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001325hdd_parse_set_roam_scan_channels_v1(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001326 const char *command)
1327{
Wu Gao0821b0d2019-01-11 17:31:11 +08001328 uint8_t channel_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001329 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301330 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001331 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001332 int ret;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001333 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001334
1335 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1336 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001337 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001338 goto exit;
1339 }
1340
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05301341 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
1342 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001343 adapter->vdev_id, num_chan);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001344
Wu Gao0821b0d2019-01-11 17:31:11 +08001345 if (num_chan > CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001346 hdd_err("number of channels (%d) supported exceeded max (%d)",
Wu Gao0821b0d2019-01-11 17:31:11 +08001347 num_chan, CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001348 ret = -EINVAL;
1349 goto exit;
1350 }
1351
Jeff Johnsond549efa2018-06-13 20:27:47 -07001352 mac_handle = hdd_ctx->mac_handle;
1353 if (!sme_validate_channel_list(mac_handle, channel_list, num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301354 hdd_err("List contains invalid channel(s)");
1355 ret = -EINVAL;
1356 goto exit;
1357 }
1358
Jeff Johnsond549efa2018-06-13 20:27:47 -07001359 status = sme_change_roam_scan_channel_list(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001360 adapter->vdev_id,
Jeff Johnsond549efa2018-06-13 20:27:47 -07001361 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301362 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001363 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001364 ret = -EINVAL;
1365 goto exit;
1366 }
1367exit:
1368 return ret;
1369}
1370
1371/**
1372 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1373 * SETROAMSCANCHANNELS command
1374 * @adapter: Adapter upon which the command was received
1375 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001376 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377 *
1378 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1379 *
1380 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1381 *
1382 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1383 * what follows the space is an array of u08 parameters. For example
1384 *
1385 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1386 *
1387 * Return: 0 for success non-zero for failure
1388 */
1389static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001390hdd_parse_set_roam_scan_channels_v2(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001391 const char *command)
1392{
1393 const uint8_t *value;
Wu Gao0821b0d2019-01-11 17:31:11 +08001394 uint8_t channel_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001395 uint8_t channel;
1396 uint8_t num_chan;
1397 int i;
Jeff Johnson621cf972017-08-28 11:58:44 -07001398 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301399 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001400 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001401 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001402
1403 /* array of values begins after "SETROAMSCANCHANNELS " */
1404 value = command + 20;
1405
1406 num_chan = *value++;
Wu Gao0821b0d2019-01-11 17:31:11 +08001407 if (num_chan > CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001408 hdd_err("number of channels (%d) supported exceeded max (%d)",
Wu Gao0821b0d2019-01-11 17:31:11 +08001409 num_chan, CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001410 ret = -EINVAL;
1411 goto exit;
1412 }
1413
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05301414 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
1415 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001416 adapter->vdev_id, num_chan);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05301417
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001418
1419 for (i = 0; i < num_chan; i++) {
1420 channel = *value++;
Nachiket Kukadecaa2e842018-05-09 17:56:12 +05301421 if (!channel) {
1422 hdd_err("Channels end at index %d, expected %d",
1423 i, num_chan);
1424 ret = -EINVAL;
1425 goto exit;
1426 }
1427
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001428 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001429 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001430 i, channel);
1431 ret = -EINVAL;
1432 goto exit;
1433 }
1434 channel_list[i] = channel;
1435 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301436
Jeff Johnsond549efa2018-06-13 20:27:47 -07001437 mac_handle = hdd_ctx->mac_handle;
1438 if (!sme_validate_channel_list(mac_handle, channel_list, num_chan)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05301439 hdd_err("List contains invalid channel(s)");
1440 ret = -EINVAL;
1441 goto exit;
1442 }
1443
Jeff Johnsond549efa2018-06-13 20:27:47 -07001444 status = sme_change_roam_scan_channel_list(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001445 adapter->vdev_id,
Jeff Johnsond549efa2018-06-13 20:27:47 -07001446 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301447 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001448 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449 ret = -EINVAL;
1450 goto exit;
1451 }
1452exit:
1453 return ret;
1454}
1455
1456/**
1457 * hdd_parse_set_roam_scan_channels() - parse the
1458 * SETROAMSCANCHANNELS command
1459 * @adapter: Adapter upon which the command was received
1460 * @command: Command that was received
1461 *
1462 * There are two different versions of the SETROAMSCANCHANNELS command.
1463 * Version 1 of the command contains a parameter list that is ASCII
1464 * characters whereas version 2 contains a binary payload. Determine
1465 * if a version 1 or a version 2 command is being parsed by examining
1466 * the parameters, and then dispatch the parser that is appropriate for
1467 * the command.
1468 *
1469 * Return: 0 for success non-zero for failure
1470 */
1471static int
Jeff Johnsone44b7012017-09-10 15:25:47 -07001472hdd_parse_set_roam_scan_channels(struct hdd_adapter *adapter, const char *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001473{
1474 const char *cursor;
1475 char ch;
1476 bool v1;
1477 int ret;
1478
1479 /* start after "SETROAMSCANCHANNELS " */
1480 cursor = command + 20;
1481
1482 /* assume we have a version 1 command until proven otherwise */
1483 v1 = true;
1484
1485 /* v1 params will only contain ASCII digits and space */
1486 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001487 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001488 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001489 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001490
1491 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001492 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001493 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001494 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001495
1496 return ret;
1497}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001499#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001500/**
1501 * hdd_parse_plm_cmd() - HDD Parse Plm command
Jeff Johnson6636e622019-02-26 10:22:39 -08001502 * @command: Pointer to input data
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08001503 * @req: Pointer to output struct plm_req
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001504 *
1505 * This function parses the plm command passed in the format
1506 * CCXPLMREQ<space><enable><space><dialog_token><space>
1507 * <meas_token><space><num_of_bursts><space><burst_int><space>
1508 * <measu duration><space><burst_len><space><desired_tx_pwr>
1509 * <space><multcast_addr><space><number_of_channels>
1510 * <space><channel_numbers>
1511 *
1512 * Return: 0 for success non-zero for failure
1513 */
Jeff Johnson6636e622019-02-26 10:22:39 -08001514static QDF_STATUS hdd_parse_plm_cmd(uint8_t *command,
Jeff Johnson36583f02019-02-26 08:02:11 -08001515 struct plm_req_params *req)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001516{
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001517 uint8_t *in_ptr = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001518 int count, content = 0, ret = 0;
1519 char buf[32];
1520
1521 /* move to argument list */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001522 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Jeff Johnsond36fa332019-03-18 13:42:25 -07001523 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301524 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001525
1526 /* no space after the command */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001527 if (SPACE_ASCII_VALUE != *in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301528 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001529
1530 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001531 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1532 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001533
1534 /* START/STOP PLM req */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001535 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001536 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301537 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001538
1539 ret = kstrtos32(buf, 10, &content);
1540 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301541 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001542
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08001543 req->enable = content;
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001544 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001545
Jeff Johnsond36fa332019-03-18 13:42:25 -07001546 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301547 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001548
1549 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001550 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1551 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001552
1553 /* Dialog token of radio meas req containing meas reqIE */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001554 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301556 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001557
1558 ret = kstrtos32(buf, 10, &content);
1559 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301560 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001561
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08001562 req->diag_token = content;
1563 hdd_debug("diag token %d", req->diag_token);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001564 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001565
Jeff Johnsond36fa332019-03-18 13:42:25 -07001566 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301567 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001568
1569 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001570 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1571 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572
1573 /* measurement token of meas req IE */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001574 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001575 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301576 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001577
1578 ret = kstrtos32(buf, 10, &content);
1579 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301580 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001581
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08001582 req->meas_token = content;
1583 hdd_debug("meas token %d", req->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001584
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08001585 hdd_debug("PLM req %s", req->enable ? "START" : "STOP");
1586 if (req->enable) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001587
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001588 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001589
Jeff Johnsond36fa332019-03-18 13:42:25 -07001590 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301591 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001592
1593 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001594 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1595 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001596
1597 /* total number of bursts after which STA stops sending */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001598 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001599 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301600 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001601
1602 ret = kstrtos32(buf, 10, &content);
1603 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301604 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001605
1606 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301607 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608
Jeff Johnson36583f02019-02-26 08:02:11 -08001609 req->num_bursts = content;
1610 hdd_debug("num bursts %d", req->num_bursts);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001611 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001612
Jeff Johnsond36fa332019-03-18 13:42:25 -07001613 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301614 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001615
1616 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001617 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1618 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619
1620 /* burst interval in seconds */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001621 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301623 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001624
1625 ret = kstrtos32(buf, 10, &content);
1626 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301627 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628
1629 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301630 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001631
Jeff Johnson36583f02019-02-26 08:02:11 -08001632 req->burst_int = content;
1633 hdd_debug("burst int %d", req->burst_int);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001634 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001635
Jeff Johnsond36fa332019-03-18 13:42:25 -07001636 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301637 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638
1639 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001640 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1641 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001642
1643 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001644 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301646 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647
1648 ret = kstrtos32(buf, 10, &content);
1649 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301650 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001651
1652 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301653 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654
Jeff Johnson36583f02019-02-26 08:02:11 -08001655 req->meas_duration = content;
1656 hdd_debug("meas duration %d", req->meas_duration);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001657 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658
Jeff Johnsond36fa332019-03-18 13:42:25 -07001659 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301660 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001661
1662 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001663 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1664 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001665
1666 /* burst length of PLM bursts */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001667 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301669 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670
1671 ret = kstrtos32(buf, 10, &content);
1672 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301673 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001674
1675 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301676 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001677
Jeff Johnson36583f02019-02-26 08:02:11 -08001678 req->burst_len = content;
1679 hdd_debug("burst len %d", req->burst_len);
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001680 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001681
Jeff Johnsond36fa332019-03-18 13:42:25 -07001682 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301683 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001684
1685 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001686 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1687 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688
1689 /* desired tx power for transmission of PLM bursts */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001690 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301692 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693
1694 ret = kstrtos32(buf, 10, &content);
1695 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301696 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697
1698 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301699 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700
Jeff Johnson36583f02019-02-26 08:02:11 -08001701 req->desired_tx_pwr = content;
1702 hdd_debug("desired tx pwr %d", req->desired_tx_pwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001703
Anurag Chouhan6d760662016-02-20 16:05:43 +05301704 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001705 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001706
Jeff Johnsond36fa332019-03-18 13:42:25 -07001707 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301708 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709
1710 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001711 while ((SPACE_ASCII_VALUE == *in_ptr)
1712 && ('\0' != *in_ptr))
1713 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001714
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001715 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301717 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718
1719 ret = kstrtos32(buf, 16, &content);
1720 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301721 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722
Jeff Johnsona0b6c3c2019-02-26 11:04:52 -08001723 req->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001724 }
1725
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -07001726 hdd_debug("MAC addr " QDF_MAC_ADDR_STR,
Srinivas Girigowda34fbba02019-04-08 12:07:44 -07001727 QDF_MAC_ADDR_ARRAY(req->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001728
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001729 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730
Jeff Johnsond36fa332019-03-18 13:42:25 -07001731 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301732 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733
1734 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001735 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1736 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001737
1738 /* number of channels */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001739 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301741 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742
1743 ret = kstrtos32(buf, 10, &content);
1744 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301745 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001746
1747 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301748 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749
Wu Gao0821b0d2019-01-11 17:31:11 +08001750 content = QDF_MIN(content, CFG_VALID_CHANNEL_LIST_LEN);
Jeff Johnson36583f02019-02-26 08:02:11 -08001751 req->plm_num_ch = content;
1752 hdd_debug("num ch: %d", req->plm_num_ch);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753
1754 /* Channel numbers */
Jeff Johnson36583f02019-02-26 08:02:11 -08001755 for (count = 0; count < req->plm_num_ch; count++) {
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001756 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757
Jeff Johnsond36fa332019-03-18 13:42:25 -07001758 if (!in_ptr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301759 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001760
1761 /* remove empty spaces */
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001762 while ((SPACE_ASCII_VALUE == *in_ptr)
1763 && ('\0' != *in_ptr))
1764 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001765
Jeff Johnson4fab64d2019-02-26 13:06:31 -08001766 ret = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301768 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769
1770 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001771 if (ret < 0 || content <= 0 ||
1772 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301773 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774
Jeff Johnson36583f02019-02-26 08:02:11 -08001775 req->plm_ch_list[count] = content;
1776 hdd_debug(" ch- %d", req->plm_ch_list[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001777 }
1778 }
1779 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301780 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001781}
1782#endif
1783
1784#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301785/**
1786 * wlan_hdd_ready_to_extwow() - Callback function for enable ext wow
1787 * @cookie: callback context
1788 * @is_success: suspend status of ext wow
1789 *
1790 * Return: none
1791 */
1792static void wlan_hdd_ready_to_extwow(void *cookie, bool is_success)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001793{
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301794 struct osif_request *request = NULL;
1795 struct enable_ext_wow_priv *priv = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001796
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301797 request = osif_request_get(cookie);
1798 if (!request) {
1799 hdd_err("Obselete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001800 return;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301801 }
1802 priv = osif_request_priv(request);
1803 priv->ext_wow_should_suspend = is_success;
1804
1805 osif_request_complete(request);
1806 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807}
1808
Jeff Johnsone44b7012017-09-10 15:25:47 -07001809static int hdd_enable_ext_wow(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001810 tpSirExtWoWParams arg_params)
1811{
1812 tSirExtWoWParams params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001813 QDF_STATUS status;
Jeff Johnson621cf972017-08-28 11:58:44 -07001814 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001815 int rc;
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301816 struct enable_ext_wow_priv *priv = NULL;
1817 struct osif_request *request = NULL;
1818 void *cookie = NULL;
1819 struct osif_request_params hdd_params = {
1820 .priv_size = sizeof(*priv),
1821 .timeout_ms = WLAN_WAIT_TIME_READY_TO_EXTWOW,
1822 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001823
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301824 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301826 request = osif_request_alloc(&hdd_params);
1827 if (!request) {
1828 hdd_err("Request Allocation Failure");
1829 return -ENOMEM;
1830 }
1831 cookie = osif_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001832
Jeff Johnsond549efa2018-06-13 20:27:47 -07001833 status = sme_configure_ext_wow(hdd_ctx->mac_handle, &params,
1834 &wlan_hdd_ready_to_extwow,
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301835 cookie);
Jeff Johnsond549efa2018-06-13 20:27:47 -07001836 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001837 hdd_err("sme_configure_ext_wow returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07001838 status);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301839 rc = -EPERM;
1840 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001841 }
1842
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301843 rc = osif_request_wait_for_response(request);
1844 if (rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001845 hdd_err("Failed to get ready to extwow");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301846 rc = -EPERM;
1847 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848 }
1849
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301850 priv = osif_request_priv(request);
1851 if (!priv->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001852 hdd_err("Received ready to ExtWoW failure");
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301853 rc = -EPERM;
1854 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001855 }
1856
Wu Gao66454f12018-09-26 19:55:41 +08001857 if (ucfg_pmo_extwow_is_goto_suspend_enabled(hdd_ctx->psoc)) {
Jeff Johnson17d62672017-03-27 08:00:11 -07001858 hdd_info("Received ready to ExtWoW. Going to suspend");
1859
1860 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1861 if (rc < 0) {
1862 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1863 rc);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301864 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07001865 }
1866 rc = wlan_hdd_bus_suspend();
1867 if (rc) {
1868 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1869 rc);
1870 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301871 goto exit;
Jeff Johnson17d62672017-03-27 08:00:11 -07001872 }
1873 }
Wu Gao66454f12018-09-26 19:55:41 +08001874
Dundi Raviteja53de6c32018-05-16 16:56:30 +05301875exit:
1876 osif_request_put(request);
1877 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878}
1879
Jeff Johnsone44b7012017-09-10 15:25:47 -07001880static int hdd_enable_ext_wow_parser(struct hdd_adapter *adapter, int vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881 int value)
1882{
1883 tSirExtWoWParams params;
Jeff Johnson621cf972017-08-28 11:58:44 -07001884 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885 int rc;
Wu Gao66454f12018-09-26 19:55:41 +08001886 uint8_t pin1, pin2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887
1888 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301889 if (rc)
1890 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891
1892 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1893 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001894 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895 return -EINVAL;
1896 }
1897
1898 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1899 hdd_ctx->is_extwow_app_type1_param_set)
1900 params.type = value;
1901 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1902 hdd_ctx->is_extwow_app_type2_param_set)
1903 params.type = value;
1904 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1905 hdd_ctx->is_extwow_app_type1_param_set &&
1906 hdd_ctx->is_extwow_app_type2_param_set)
1907 params.type = value;
1908 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001909 hdd_err("Set app params before enable it value %d",
1910 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911 return -EINVAL;
1912 }
1913
1914 params.vdev_id = vdev_id;
Wu Gao66454f12018-09-26 19:55:41 +08001915 pin1 = ucfg_pmo_extwow_app1_wakeup_pin_num(hdd_ctx->psoc);
1916 pin2 = ucfg_pmo_extwow_app2_wakeup_pin_num(hdd_ctx->psoc);
1917 params.wakeup_pin_num = pin1 | (pin2 << 8);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918
1919 return hdd_enable_ext_wow(adapter, &params);
1920}
1921
Jeff Johnsond549efa2018-06-13 20:27:47 -07001922static int hdd_set_app_type1_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001923 tpSirAppType1Params arg_params)
1924{
1925 tSirAppType1Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001926 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301928 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001929
Jeff Johnsond549efa2018-06-13 20:27:47 -07001930 status = sme_configure_app_type1_params(mac_handle, &params);
1931 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001932 hdd_err("sme_configure_app_type1_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07001933 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001934 return -EPERM;
1935 }
1936
1937 return 0;
1938}
1939
Jeff Johnsone44b7012017-09-10 15:25:47 -07001940static int hdd_set_app_type1_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941 char *arg, int len)
1942{
Jeff Johnson621cf972017-08-28 11:58:44 -07001943 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001944 char id[20], password[20];
1945 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001946 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001947
1948 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301949 if (rc)
1950 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001951
1952 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001953 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 return -EINVAL;
1955 }
1956
1957 memset(&params, 0, sizeof(tSirAppType1Params));
Jeff Johnson5a6fc962019-02-04 14:20:25 -08001958 params.vdev_id = adapter->vdev_id;
Jeff Johnson1e851a12017-10-28 14:36:12 -07001959 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001960
1961 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301962 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001963 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301964 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001966 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001967 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001968 params.identification_id, params.id_length,
1969 params.password, params.pass_length);
1970
Jeff Johnsond549efa2018-06-13 20:27:47 -07001971 return hdd_set_app_type1_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972}
1973
Jeff Johnsond549efa2018-06-13 20:27:47 -07001974static int hdd_set_app_type2_params(mac_handle_t mac_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001975 tpSirAppType2Params arg_params)
1976{
1977 tSirAppType2Params params;
Jeff Johnsond549efa2018-06-13 20:27:47 -07001978 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001979
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301980 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001981
Jeff Johnsond549efa2018-06-13 20:27:47 -07001982 status = sme_configure_app_type2_params(mac_handle, &params);
1983 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001984 hdd_err("sme_configure_app_type2_params returned failure %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07001985 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986 return -EPERM;
1987 }
1988
1989 return 0;
1990}
1991
Jeff Johnsone44b7012017-09-10 15:25:47 -07001992static int hdd_set_app_type2_parser(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 char *arg, int len)
1994{
Jeff Johnson621cf972017-08-28 11:58:44 -07001995 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001996 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05301997 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998 tSirAppType2Params params;
1999 int ret;
2000
2001 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302002 if (ret)
2003 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004
2005 memset(&params, 0, sizeof(tSirAppType2Params));
2006
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302007 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 -08002008 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2009 (unsigned int *)&params.ip_device_ip,
2010 (unsigned int *)&params.ip_server_ip,
2011 (unsigned int *)&params.tcp_seq,
2012 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302013 (uint16_t *)&params.tcp_src_port,
2014 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015 (unsigned int *)&params.keepalive_init,
2016 (unsigned int *)&params.keepalive_min,
2017 (unsigned int *)&params.keepalive_max,
2018 (unsigned int *)&params.keepalive_inc,
2019 (unsigned int *)&params.tcp_tx_timeout_val,
2020 (unsigned int *)&params.tcp_rx_timeout_val);
2021
2022 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002023 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024 return -EINVAL;
2025 }
2026
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -07002027 if (6 != sscanf(mac_addr, QDF_MAC_ADDR_STR,
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002028 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2029 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002030 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031 return -EINVAL;
2032 }
2033
2034 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2035 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002036 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037 return -EINVAL;
2038 }
2039
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302040 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302041 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042
2043 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302044 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002045
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002046 params.vdev_id = adapter->vdev_id;
Wu Gao66454f12018-09-26 19:55:41 +08002047
2048 if (!params.tcp_src_port)
2049 params.tcp_src_port =
2050 ucfg_pmo_extwow_app2_tcp_src_port(hdd_ctx->psoc);
2051
2052 if (!params.tcp_dst_port)
2053 params.tcp_dst_port =
2054 ucfg_pmo_extwow_app2_tcp_dst_port(hdd_ctx->psoc);
2055
2056 if (!params.keepalive_init)
2057 params.keepalive_init =
2058 ucfg_pmo_extwow_app2_init_ping_interval(hdd_ctx->psoc);
2059
2060 if (!params.keepalive_min)
2061 params.keepalive_min =
2062 ucfg_pmo_extwow_app2_min_ping_interval(hdd_ctx->psoc);
2063
2064 if (!params.keepalive_max)
2065 params.keepalive_max =
2066 ucfg_pmo_extwow_app2_max_ping_interval(hdd_ctx->psoc);
2067
2068 if (!params.keepalive_inc)
2069 params.keepalive_inc =
2070 ucfg_pmo_extwow_app2_inc_ping_interval(hdd_ctx->psoc);
2071
2072 if (!params.tcp_tx_timeout_val)
2073 params.tcp_tx_timeout_val =
2074 ucfg_pmo_extwow_app2_tcp_tx_timeout(hdd_ctx->psoc);
2075
2076 if (!params.tcp_rx_timeout_val)
2077 params.tcp_rx_timeout_val =
2078 ucfg_pmo_extwow_app2_tcp_rx_timeout(hdd_ctx->psoc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002079
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002080 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002081 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002082 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2083 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2084 params.keepalive_init, params.keepalive_min,
2085 params.keepalive_max, params.keepalive_inc,
2086 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2087
Jeff Johnsond549efa2018-06-13 20:27:47 -07002088 return hdd_set_app_type2_params(hdd_ctx->mac_handle, &params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002089}
2090#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2091
2092/**
2093 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
Jeff Johnson6636e622019-02-26 10:22:39 -08002094 * @command: Pointer to MAXTXPOWER command
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002095 * @tx_power: Pointer to tx power
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002096 *
2097 * This function parses the MAXTXPOWER command passed in the format
2098 * MAXTXPOWER<space>X(Tx power in dbm)
2099 *
2100 * For example input commands:
2101 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2102 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2103 *
2104 * Return: 0 for success non-zero for failure
2105 */
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002106static int hdd_parse_setmaxtxpower_command(uint8_t *command, int *tx_power)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002107{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002108 uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002109 int temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002110 int v = 0;
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002111 *tx_power = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002112
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002113 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002114 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07002115 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002116 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002117 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002118 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002119
2120 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002121 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2122 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002123
2124 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002125 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002126 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002127
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002128 v = kstrtos32(in_ptr, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002129
2130 /* Range checking for passed parameter */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002131 if ((temp_int < HDD_MIN_TX_POWER) || (temp_int > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002132 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002133
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002134 *tx_power = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002135
Jeff Johnson93f47cf2019-02-26 13:08:48 -08002136 hdd_debug("SETMAXTXPOWER: %d", *tx_power);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002137
2138 return 0;
2139} /* End of hdd_parse_setmaxtxpower_command */
2140
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302141static int hdd_get_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002142 char *extra, uint8_t n, uint8_t *len)
2143{
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302144 uint32_t val = 0;
2145
2146 if (!psoc || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002147 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002148 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002149 }
2150
2151 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302152 ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
2153 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n", val);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002154 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002155 }
Jeff Johnson68755312017-02-10 11:46:55 -08002156 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302157 ucfg_scan_cfg_get_passive_dwelltime(psoc, &val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002158 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302159 val);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002160 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002161 }
Jeff Johnson68755312017-02-10 11:46:55 -08002162 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302163 ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
2164 *len = scnprintf(extra, n, "GETDWELLTIME %u\n", val);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002165 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 }
2167
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002168 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002169}
2170
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302171static int hdd_set_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002172{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002173 uint8_t *value = command;
Srinivas Girigowdaa9ce5e62019-03-28 13:44:31 -07002174 int retval = 0, temp = 0;
2175 uint32_t val = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002176
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302177 if (!psoc) {
2178 hdd_err("psoc is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002179 return -EINVAL;
2180 }
2181
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002182 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302183 if (drv_cmd_validate(command, 23))
2184 return -EINVAL;
2185
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002186 value = value + 24;
2187 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302188 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002189 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302190 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002191 }
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302192 ucfg_scan_cfg_set_active_dwelltime(psoc, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002193 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302194 if (drv_cmd_validate(command, 24))
2195 return -EINVAL;
2196
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002197 value = value + 25;
2198 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302199 if (temp || !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002200 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302201 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002202 }
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302203 ucfg_scan_cfg_set_passive_dwelltime(psoc, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002204 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05302205 if (drv_cmd_validate(command, 12))
2206 return -EINVAL;
2207
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002208 value = value + 13;
2209 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302210 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002211 hdd_err("argument passed for SETDWELLTIME is incorrect");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302212 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002213 }
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302214 ucfg_scan_cfg_set_active_dwelltime(psoc, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002215 } else {
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302216 retval = -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002217 }
2218
Sridhar Selvaraj48c47092017-07-31 18:18:14 +05302219 return retval;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002220}
2221
Jeff Johnson253c0c22017-01-23 16:59:38 -08002222struct link_status_priv {
2223 uint8_t link_status;
2224};
2225
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302226/**
2227 * hdd_conc_set_dwell_time() - Set Concurrent dwell time parameters
2228 * @adapter: Adapter upon which the command was received
2229 * @command: ASCII text command that is received
2230 *
2231 * Driver commands:
2232 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MAX <value>
2233 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MIN <value>
2234 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MAX <value>
2235 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MIN <value>
2236 *
2237 * Return: 0 for success non-zero for failure
2238 */
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05302239static int hdd_conc_set_dwell_time(struct hdd_adapter *adapter,
2240 uint8_t *command)
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302241{
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302242 u8 *value = command;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302243 int val = 0, temp = 0;
2244 int retval = 0;
2245
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302246 if (strncmp(command, "CONCSETDWELLTIME ACTIVE MAX", 27) == 0) {
2247 if (drv_cmd_validate(command, 27)) {
2248 hdd_err("Invalid driver command");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302249 return -EINVAL;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302250 }
2251
2252 value = value + 28;
2253 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302254 if (temp ||
2255 !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC, val)) {
Harprit Chhabada4691a472018-12-07 11:22:48 -08002256 hdd_err("CONC ACTIVE MAX value %d incorrect", val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302257 return -EFAULT;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302258 }
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05302259 ucfg_scan_cfg_set_conc_active_dwelltime(
2260 (WLAN_HDD_GET_CTX(adapter))->psoc, val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302261 } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MAX", 28) == 0) {
2262 if (drv_cmd_validate(command, 28)) {
2263 hdd_err("Invalid driver command");
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302264 return -EINVAL;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302265 }
2266
2267 value = value + 29;
2268 temp = kstrtou32(value, 10, &val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302269 if (temp ||
2270 !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC, val)) {
Harprit Chhabada4691a472018-12-07 11:22:48 -08002271 hdd_err("CONC PASSIVE MAX val %d incorrect", val);
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05302272 return -EFAULT;
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302273 }
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05302274 ucfg_scan_cfg_set_conc_passive_dwelltime(
2275 (WLAN_HDD_GET_CTX(adapter))->psoc, val);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302276 } else {
2277 retval = -EINVAL;
2278 }
2279
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302280 return retval;
2281}
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05302282
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002283static void hdd_get_link_status_cb(uint8_t status, void *context)
2284{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002285 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002286 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002287
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002288 request = osif_request_get(context);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002289 if (!request) {
2290 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002291 return;
2292 }
2293
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002294 priv = osif_request_priv(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002295 priv->link_status = status;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002296 osif_request_complete(request);
2297 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002298}
2299
2300/**
2301 * wlan_hdd_get_link_status() - get link status
Jeff Johnson25c77342017-10-02 13:28:03 -07002302 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002303 *
2304 * This function sends a request to query the link status and waits
2305 * on a timer to invoke the callback. if the callback is invoked then
2306 * latest link status shall be returned or otherwise cached value
2307 * will be returned.
2308 *
2309 * Return: On success, link status shall be returned.
2310 * On error or not associated, link status 0 will be returned.
2311 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002312static int wlan_hdd_get_link_status(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002313{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002314 struct hdd_station_ctx *sta_ctx;
2315 QDF_STATUS status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002316 int ret;
2317 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002318 struct osif_request *request;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002319 struct link_status_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002320 static const struct osif_request_params params = {
Jeff Johnson253c0c22017-01-23 16:59:38 -08002321 .priv_size = sizeof(*priv),
2322 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2323 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002324
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05302325 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002326 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2327 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002328 return 0;
2329 }
2330
Krunal Sonibe766b02016-03-10 13:00:44 -08002331 if ((QDF_STA_MODE != adapter->device_mode) &&
2332 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002333 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07002334 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002335 adapter->device_mode);
2336 return 0;
2337 }
2338
Jeff Johnsond377dce2017-10-04 10:32:42 -07002339 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsone7951512019-02-27 10:02:51 -08002340 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002341 /* If not associated, then expected link status return
2342 * value is 0
2343 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002344 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002345 return 0;
2346 }
2347
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002348 request = osif_request_alloc(&params);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002349 if (!request) {
2350 hdd_err("Request allocation failure");
2351 return 0;
2352 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002353 cookie = osif_request_cookie(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002354
Jeff Johnsond549efa2018-06-13 20:27:47 -07002355 status = sme_get_link_status(adapter->hdd_ctx->mac_handle,
2356 hdd_get_link_status_cb,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002357 cookie, adapter->vdev_id);
Jeff Johnsond549efa2018-06-13 20:27:47 -07002358 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002359 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002360 /* return a cached value */
2361 } else {
2362 /* request is sent -- wait for the response */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002363 ret = osif_request_wait_for_response(request);
Jeff Johnson253c0c22017-01-23 16:59:38 -08002364 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002365 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002366 /* return a cached value */
2367 } else {
2368 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002369 priv = osif_request_priv(request);
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07002370 adapter->link_status = priv->link_status;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002371 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002372 }
2373
Jeff Johnson253c0c22017-01-23 16:59:38 -08002374 /*
2375 * either we never sent a request, we sent a request and
2376 * received a response or we sent a request and timed out.
2377 * regardless we are done with the request.
2378 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07002379 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002380
2381 /* either callback updated adapter stats or it has cached data */
Jeff Johnsonbd4c4f02017-10-30 20:33:01 -07002382 return adapter->link_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002383}
2384
Jeff Johnson8f2016e2019-02-26 20:21:08 -08002385static void hdd_tx_fail_ind_callback(uint8_t *macaddr, uint8_t seq_no)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002386{
2387 int payload_len;
2388 struct sk_buff *skb;
2389 struct nlmsghdr *nlh;
2390 uint8_t *data;
2391
2392 payload_len = ETH_ALEN;
2393
Jeff Johnsond36fa332019-03-18 13:42:25 -07002394 if (0 == cesium_pid || !cesium_nl_srv_sock) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002395 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002396 return;
2397 }
2398
2399 skb = nlmsg_new(payload_len, GFP_ATOMIC);
Jeff Johnsond36fa332019-03-18 13:42:25 -07002400 if (!skb) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002401 hdd_err("nlmsg_new() failed for msg size[%d]",
2402 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002403 return;
2404 }
2405
Jeff Johnsond8a35462019-02-26 20:18:51 -08002406 nlh = nlmsg_put(skb, cesium_pid, seq_no, 0, payload_len, NLM_F_REQUEST);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002407
Jeff Johnsond36fa332019-03-18 13:42:25 -07002408 if (!nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002409 hdd_err("nlmsg_put() failed for msg size[%d]",
2410 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002411
2412 kfree_skb(skb);
2413 return;
2414 }
2415
2416 data = nlmsg_data(nlh);
Jeff Johnson8f2016e2019-02-26 20:21:08 -08002417 memcpy(data, macaddr, ETH_ALEN);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002418
2419 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002420 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2421 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002422 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002423}
2424
2425
2426/**
Jeff Johnson6636e622019-02-26 10:22:39 -08002427 * hdd_parse_user_params() - return a pointer to the next argument
2428 * @command: Input argument string
Jeff Johnson76e335b2019-02-26 17:41:17 -08002429 * @arg: Output pointer to the next argument
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002430 *
2431 * This function parses argument stream and finds the pointer
2432 * to the next argument
2433 *
2434 * Return: 0 if the next argument found; -EINVAL otherwise
2435 */
Jeff Johnson76e335b2019-02-26 17:41:17 -08002436static int hdd_parse_user_params(uint8_t *command, uint8_t **arg)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002437{
Jeff Johnson76e335b2019-02-26 17:41:17 -08002438 uint8_t *cursor;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002439
Jeff Johnson76e335b2019-02-26 17:41:17 -08002440 cursor = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002441
Jeff Johnson76e335b2019-02-26 17:41:17 -08002442 /* no argument remains ? */
2443 if (!cursor)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002444 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002445
Jeff Johnson76e335b2019-02-26 17:41:17 -08002446 /* no space after the current arg ? */
2447 if (SPACE_ASCII_VALUE != *cursor)
2448 return -EINVAL;
2449
2450 cursor++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002451
2452 /* remove empty spaces */
Jeff Johnson76e335b2019-02-26 17:41:17 -08002453 while (SPACE_ASCII_VALUE == *cursor)
2454 cursor++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002455
Jeff Johnson76e335b2019-02-26 17:41:17 -08002456 /* no argument after the spaces ? */
2457 if ('\0' == *cursor)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002458 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002459
Jeff Johnson76e335b2019-02-26 17:41:17 -08002460 *arg = cursor;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002461
2462 return 0;
2463}
2464
2465/**
2466 * hdd_parse_ibsstx_fail_event_params - Parse params
2467 * for SETIBSSTXFAILEVENT
Jeff Johnson6636e622019-02-26 10:22:39 -08002468 * @command: Input ibss tx fail event argument
2469 * @tx_fail_count: (Output parameter) Tx fail counter
2470 * @pid: (Output parameter) PID
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002471 *
2472 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2473 */
Jeff Johnson6636e622019-02-26 10:22:39 -08002474static int hdd_parse_ibsstx_fail_event_params(uint8_t *command,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002475 uint8_t *tx_fail_count,
2476 uint16_t *pid)
2477{
2478 uint8_t *param = NULL;
2479 int ret;
2480
Jeff Johnson6636e622019-02-26 10:22:39 -08002481 ret = hdd_parse_user_params(command, &param);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002482
Jeff Johnsond36fa332019-03-18 13:42:25 -07002483 if (0 == ret && param) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002484 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2485 ret = -EINVAL;
2486 goto done;
2487 }
2488 } else {
2489 goto done;
2490 }
2491
2492 if (0 == *tx_fail_count) {
2493 *pid = 0;
2494 goto done;
2495 }
2496
Jeff Johnson6636e622019-02-26 10:22:39 -08002497 command = param;
2498 command++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002499
Jeff Johnson6636e622019-02-26 10:22:39 -08002500 ret = hdd_parse_user_params(command, &param);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002501
2502 if (0 == ret) {
2503 if (1 != sscanf(param, "%hu", pid)) {
2504 ret = -EINVAL;
2505 goto done;
2506 }
2507 } else {
2508 goto done;
2509 }
2510
2511done:
2512 return ret;
2513}
2514
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002515#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002516/**
2517 * hdd_parse_ese_beacon_req() - Parse ese beacon request
Jeff Johnson6636e622019-02-26 10:22:39 -08002518 * @command: Pointer to data
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002519 * @req: Output pointer to store parsed ie information
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002520 *
2521 * This function parses the ese beacon request passed in the format
2522 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2523 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2524 * <space>Scan Mode N<space>Meas Duration N
2525 *
2526 * If the Number of bcn req fields (N) does not match with the
2527 * actual number of fields passed then take N.
2528 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2529 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2530 * This function does not take care of removing duplicate channels from the
2531 * list
2532 *
2533 * Return: 0 for success non-zero for failure
2534 */
Jeff Johnson6636e622019-02-26 10:22:39 -08002535static int hdd_parse_ese_beacon_req(uint8_t *command,
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002536 tCsrEseBeaconReq *req)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002537{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002538 uint8_t *in_ptr = command;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002539 uint8_t input = 0;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002540 uint32_t temp_int = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002541 int j = 0, i = 0, v = 0;
2542 char buf[32];
2543
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002544 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Jeff Johnsond36fa332019-03-18 13:42:25 -07002545 if (!in_ptr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002546 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002547 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002548 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002549
2550 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002551 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2552 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002553
2554 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002555 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002556 return -EINVAL;
2557
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002558 /* Getting the first argument ie Number of IE fields */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002559 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002560 if (1 != v)
2561 return -EINVAL;
2562
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002563 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002564 if (v < 0)
2565 return -EINVAL;
2566
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002567 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002568 req->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002569
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002570 hdd_debug("Number of Bcn Req Ie fields: %d", req->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002571
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002572 for (j = 0; j < (req->numBcnReqIe); j++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002573 for (i = 0; i < 4; i++) {
2574 /*
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002575 * in_ptr pointing to the beginning of 1st space
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002576 * after number of ie fields
2577 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002578 in_ptr = strpbrk(in_ptr, " ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002579 /* no ie data after the number of ie fields argument */
Jeff Johnsond36fa332019-03-18 13:42:25 -07002580 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002581 return -EINVAL;
2582
2583 /* remove empty space */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002584 while ((SPACE_ASCII_VALUE == *in_ptr)
2585 && ('\0' != *in_ptr))
2586 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002587
2588 /*
2589 * no ie data after the number of ie fields
2590 * argument and spaces
2591 */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002592 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002593 return -EINVAL;
2594
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002595 v = sscanf(in_ptr, "%31s ", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002596 if (1 != v)
2597 return -EINVAL;
2598
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002599 v = kstrtou32(buf, 10, &temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002600 if (v < 0)
2601 return -EINVAL;
2602
2603 switch (i) {
2604 case 0: /* Measurement token */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002605 if (!temp_int) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002606 hdd_err("Invalid Measurement Token: %u",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002607 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002608 return -EINVAL;
2609 }
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002610 req->bcnReq[j].measurementToken =
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002611 temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612 break;
2613
2614 case 1: /* Channel number */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002615 if (!temp_int ||
2616 (temp_int >
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002617 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002618 hdd_err("Invalid Channel Number: %u",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002619 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002620 return -EINVAL;
2621 }
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002622 req->bcnReq[j].channel = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002623 break;
2624
2625 case 2: /* Scan mode */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002626 if ((temp_int < eSIR_PASSIVE_SCAN)
2627 || (temp_int > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002628 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002629 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002630 return -EINVAL;
2631 }
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002632 req->bcnReq[j].scanMode = temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002633 break;
2634
2635 case 3: /* Measurement duration */
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002636 if ((!temp_int
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002637 && (req->bcnReq[j].scanMode !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002638 eSIR_BEACON_TABLE)) ||
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002639 (req->bcnReq[j].scanMode ==
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002640 eSIR_BEACON_TABLE)) {
2641 hdd_err("Invalid Measurement Duration: %u",
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002642 temp_int);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002643 return -EINVAL;
2644 }
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002645 req->bcnReq[j].measurementDuration =
Jeff Johnsoncd361c92019-02-26 19:23:49 -08002646 temp_int;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002647 break;
2648 }
2649 }
2650 }
2651
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002652 for (j = 0; j < req->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002653 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002654 j,
Jeff Johnsonb2c3d042019-02-26 12:23:26 -08002655 req->bcnReq[j].measurementToken,
2656 req->bcnReq[j].channel,
2657 req->bcnReq[j].scanMode,
2658 req->bcnReq[j].measurementDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002659 }
2660
2661 return 0;
2662}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002663
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002664/**
2665 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
Jeff Johnson6636e622019-02-26 10:22:39 -08002666 * @command: Pointer to input data
Jeff Johnson64c01b12019-02-26 13:12:50 -08002667 * @cckm_ie: Pointer to output cckm Ie
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08002668 * @cckm_ie_len: Pointer to output cckm ie length
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002669 *
2670 * This function parses the SETCCKM IE command
2671 * SETCCKMIE<space><ie data>
2672 *
2673 * Return: 0 for success non-zero for failure
2674 */
Jeff Johnson64c01b12019-02-26 13:12:50 -08002675static int hdd_parse_get_cckm_ie(uint8_t *command, uint8_t **cckm_ie,
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08002676 uint8_t *cckm_ie_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002677{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002678 uint8_t *in_ptr = command;
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08002679 uint8_t *end_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002680 int j = 0;
2681 int i = 0;
Jeff Johnson72f498b2019-02-26 18:37:25 -08002682 uint8_t temp_u8 = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002683
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002684 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002685 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07002686 if (!in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002687 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002688 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002689 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002690
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002691 /* remove empty spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002692 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2693 in_ptr++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002694 /* no argument followed by spaces */
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002695 if ('\0' == *in_ptr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002696 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002697
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002698 /* find the length of data */
Jeff Johnsonaae00ae2019-02-26 17:25:11 -08002699 end_ptr = in_ptr;
2700 while (('\0' != *end_ptr)) {
2701 end_ptr++;
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08002702 ++(*cckm_ie_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002703 }
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08002704 if (*cckm_ie_len <= 0)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002705 return -EINVAL;
2706 /*
2707 * Allocate the number of bytes based on the number of input characters
2708 * whether it is even or odd.
2709 * if the number of input characters are even, then we need N / 2 byte.
2710 * if the number of input characters are odd, then we need do
2711 * (N + 1) / 2 to compensate rounding off.
2712 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2713 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2714 */
Jeff Johnson64c01b12019-02-26 13:12:50 -08002715 *cckm_ie = qdf_mem_malloc((*cckm_ie_len + 1) / 2);
Jeff Johnsond36fa332019-03-18 13:42:25 -07002716 if (!*cckm_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002717 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002718 return -ENOMEM;
2719 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720 /*
2721 * the buffer received from the upper layer is character buffer,
2722 * we need to prepare the buffer taking 2 characters in to a U8 hex
2723 * decimal number for example 7f0000f0...form a buffer to contain
2724 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2725 */
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08002726 for (i = 0, j = 0; j < *cckm_ie_len; j += 2) {
Jeff Johnson72f498b2019-02-26 18:37:25 -08002727 temp_u8 = (hex_to_bin(in_ptr[j]) << 4) |
Jeff Johnson4ff36b22019-02-26 13:01:07 -08002728 (hex_to_bin(in_ptr[j + 1]));
Jeff Johnson72f498b2019-02-26 18:37:25 -08002729 (*cckm_ie)[i++] = temp_u8;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002730 }
Jeff Johnsonecbb79f2019-02-26 13:10:24 -08002731 *cckm_ie_len = i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732 return 0;
2733}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002734#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002735
Jeff Johnsonb3f80432019-02-26 20:25:38 -08002736int wlan_hdd_set_mc_rate(struct hdd_adapter *adapter, int target_rate)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002737{
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08002738 tSirRateUpdateInd rate_update = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302739 QDF_STATUS status;
Jeff Johnson25c77342017-10-02 13:28:03 -07002740 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05302741 bool bval = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742
Jeff Johnsond36fa332019-03-18 13:42:25 -07002743 if (!hdd_ctx) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002744 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002745 return -EINVAL;
2746 }
Jeff Johnson25c77342017-10-02 13:28:03 -07002747 if ((QDF_IBSS_MODE != adapter->device_mode) &&
2748 (QDF_SAP_MODE != adapter->device_mode) &&
2749 (QDF_STA_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002750 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07002751 qdf_opmode_str(adapter->device_mode),
2752 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002753 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002754 return -EINVAL;
2755 }
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05302756
2757 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
2758 if (!QDF_IS_STATUS_SUCCESS(status)) {
2759 hdd_err("unable to get vht_enable2x2");
2760 return -EINVAL;
2761 }
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08002762 rate_update.nss = (bval == 0) ? 0 : 1;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05302763
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08002764 rate_update.dev_mode = adapter->device_mode;
2765 rate_update.mcastDataRate24GHz = target_rate;
2766 rate_update.mcastDataRate24GHzTxFlag = 1;
2767 rate_update.mcastDataRate5GHz = target_rate;
2768 rate_update.bcastDataRate = -1;
2769 qdf_copy_macaddr(&rate_update.bssid, &adapter->mac_addr);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002770 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08002771 rate_update.mcastDataRate24GHz, rate_update.bssid.bytes,
Dustin Brown458027c2018-10-19 12:26:27 -07002772 qdf_opmode_str(adapter->device_mode), adapter->device_mode);
Jeff Johnson1a0c72b2019-02-26 20:29:43 -08002773 status = sme_send_rate_update_ind(hdd_ctx->mac_handle, &rate_update);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302774 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002775 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002776 return -EFAULT;
2777 }
2778 return 0;
2779}
2780
Jeff Johnsone44b7012017-09-10 15:25:47 -07002781static int drv_cmd_p2p_dev_addr(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002782 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002783 uint8_t *command,
2784 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002785 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002786{
Dustin Brownee220712018-04-19 16:24:23 -07002787 struct qdf_mac_addr *addr = &hdd_ctx->p2p_device_address;
2788 size_t user_size = qdf_min(sizeof(addr->bytes),
2789 (size_t)priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002790
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302791 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2792 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002793 adapter->vdev_id,
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302794 (unsigned int)(*(addr->bytes + 2) << 24 |
Dustin Brownee220712018-04-19 16:24:23 -07002795 *(addr->bytes + 3) << 16 |
2796 *(addr->bytes + 4) << 8 |
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302797 *(addr->bytes + 5)));
2798
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002799
Dustin Brownee220712018-04-19 16:24:23 -07002800 if (copy_to_user(priv_data->buf, addr->bytes, user_size)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002801 hdd_err("failed to copy data to user buffer");
Dustin Brownee220712018-04-19 16:24:23 -07002802 return -EFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002803 }
2804
Dustin Brownee220712018-04-19 16:24:23 -07002805 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002806}
2807
2808/**
2809 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2810 * @adapter: Adapter on which the command was received
2811 * @hdd_ctx: HDD global context
2812 * @command: Entire driver command received from userspace
2813 * @command_len: Length of @command
2814 * @priv_data: Pointer to ioctl private data structure
2815 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07002816 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002817 * command to the actual command processor within the P2P module.
2818 *
2819 * Return: 0 on success, non-zero on failure
2820 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002821static int drv_cmd_p2p_set_noa(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002822 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002823 uint8_t *command,
2824 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002825 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002826{
2827 return hdd_set_p2p_noa(adapter->dev, command);
2828}
2829
2830/**
2831 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2832 * @adapter: Adapter on which the command was received
2833 * @hdd_ctx: HDD global context
2834 * @command: Entire driver command received from userspace
2835 * @command_len: Length of @command
2836 * @priv_data: Pointer to ioctl private data structure
2837 *
Jeff Johnson78073fa2018-05-06 16:08:58 -07002838 * This is a trivial command handler function which simply forwards the
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002839 * command to the actual command processor within the P2P module.
2840 *
2841 * Return: 0 on success, non-zero on failure
2842 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07002843static int drv_cmd_p2p_set_ps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002844 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002845 uint8_t *command,
2846 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002847 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002848{
2849 return hdd_set_p2p_opps(adapter->dev, command);
2850}
2851
Jeff Johnsone44b7012017-09-10 15:25:47 -07002852static int drv_cmd_set_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002853 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002854 uint8_t *command,
2855 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002856 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002857{
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002858 int err;
2859 uint8_t band;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002860
2861 /*
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002862 * Parse the band value passed from userspace. The first 8 bytes
2863 * should be "SETBAND " and the 9th byte should be a UI band value
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002864 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002865 err = kstrtou8(command + command_len + 1, 10, &band);
2866 if (err) {
2867 hdd_err("error %d parsing userspace band parameter", err);
2868 return err;
2869 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002870
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002871 return hdd_reg_set_band(adapter->dev, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002872}
2873
Jeff Johnsone44b7012017-09-10 15:25:47 -07002874static int drv_cmd_set_wmmps(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002875 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002876 uint8_t *command,
2877 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002878 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002879{
2880 return hdd_wmmps_helper(adapter, command);
2881}
2882
Jeff Johnsone44b7012017-09-10 15:25:47 -07002883static inline int drv_cmd_country(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002884 struct hdd_context *hdd_ctx,
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07002885 uint8_t *command,
2886 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002887 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002888{
Sourav Mohapatraa30c4572018-05-22 11:18:39 +05302889 char *country_code;
2890
2891 country_code = strnchr(command, strlen(command), ' ');
2892 /* no argument after the command */
2893 if (!country_code)
2894 return -EINVAL;
2895
2896 /* no space after the command */
2897 if (*country_code != SPACE_ASCII_VALUE)
2898 return -EINVAL;
2899
2900 country_code++;
2901
2902 /* removing empty spaces */
2903 while ((*country_code == SPACE_ASCII_VALUE) &&
2904 (*country_code != '\0'))
2905 country_code++;
2906
2907 /* no or less than 2 arguments followed by spaces */
2908 if (*country_code == '\0' || *(country_code + 1) == '\0')
2909 return -EINVAL;
2910
2911 return hdd_reg_set_country(hdd_ctx, country_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002912}
2913
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +05302914/**
2915 * drv_cmd_get_country() - Helper function to get current county code
2916 * @adapter: pointer to adapter on which request is received
2917 * @hdd_ctx: pointer to hdd context
2918 * @command: command name
2919 * @command_len: command buffer length
2920 * @priv_data: output pointer to hold current country code
2921 *
2922 * Return: On success 0, negative value on error.
2923 */
2924static int drv_cmd_get_country(struct hdd_adapter *adapter,
2925 struct hdd_context *hdd_ctx,
2926 uint8_t *command, uint8_t command_len,
2927 struct hdd_priv_data *priv_data)
2928{
2929 uint8_t buf[SIZE_OF_GETCOUNTRYREV_OUTPUT] = {0};
2930 uint8_t cc[REG_ALPHA2_LEN + 1];
2931 int ret = 0, len;
2932
2933 qdf_mem_copy(cc, hdd_ctx->reg.alpha2, REG_ALPHA2_LEN);
2934 cc[REG_ALPHA2_LEN] = '\0';
2935
2936 len = scnprintf(buf, sizeof(buf), "%s %s",
2937 "GETCOUNTRYREV", cc);
2938 hdd_debug("buf = %s", buf);
2939 len = QDF_MIN(priv_data->total_len, len + 1);
2940 if (copy_to_user(priv_data->buf, buf, len)) {
2941 hdd_err("failed to copy data to user buffer");
2942 ret = -EFAULT;
2943 }
2944
2945 return ret;
2946}
2947
Jeff Johnsone44b7012017-09-10 15:25:47 -07002948static int drv_cmd_set_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07002949 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002950 uint8_t *command,
2951 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07002952 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002953{
Jeff Johnsond549efa2018-06-13 20:27:47 -07002954 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002955 uint8_t *value = command;
2956 int8_t rssi = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08002957 uint8_t lookup_threshold = cfg_default(
2958 CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302959 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002960
2961 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2962 value = value + command_len + 1;
2963
2964 /* Convert the value from ascii to integer */
2965 ret = kstrtos8(value, 10, &rssi);
2966 if (ret < 0) {
2967 /*
2968 * If the input value is greater than max value of datatype,
2969 * then also kstrtou8 fails
2970 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002971 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08002972 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
2973 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002974 ret = -EINVAL;
2975 goto exit;
2976 }
2977
Wu Gao1ab05582018-11-08 16:22:49 +08002978 lookup_threshold = abs(rssi);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002979
Wu Gao1ab05582018-11-08 16:22:49 +08002980 if (!cfg_in_range(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD,
2981 lookup_threshold)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002982 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08002983 lookup_threshold,
2984 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
2985 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002986 ret = -EINVAL;
2987 goto exit;
2988 }
2989
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302990 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2991 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002992 adapter->vdev_id, lookup_threshold);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05302993
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002994 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08002995 lookup_threshold);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002996
Jeff Johnsond549efa2018-06-13 20:27:47 -07002997 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08002998 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08002999 lookup_threshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303000 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003001 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003002 ret = -EPERM;
3003 goto exit;
3004 }
3005
3006exit:
3007 return ret;
3008}
3009
Jeff Johnsone44b7012017-09-10 15:25:47 -07003010static int drv_cmd_get_roam_trigger(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003011 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003012 uint8_t *command,
3013 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003014 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003015{
3016 int ret = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08003017 uint8_t lookup_threshold =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003018 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle);
Wu Gao1ab05582018-11-08 16:22:49 +08003019 int rssi = (-1) * lookup_threshold;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003020 char extra[32];
3021 uint8_t len = 0;
3022
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303023 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3024 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003025 adapter->vdev_id, lookup_threshold);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003026
3027 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303028 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003029 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003030 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003031 ret = -EFAULT;
3032 }
3033
3034 return ret;
3035}
3036
Jeff Johnsone44b7012017-09-10 15:25:47 -07003037static int drv_cmd_set_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003038 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003039 uint8_t *command,
3040 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003041 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003042{
3043 int ret = 0;
3044 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003045 uint8_t roam_scan_period = 0;
3046 uint16_t empty_scan_refresh_period =
3047 cfg_default(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003048
3049 /* input refresh period is in terms of seconds */
3050
3051 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3052 value = value + command_len + 1;
3053
3054 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003055 ret = kstrtou8(value, 10, &roam_scan_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003056 if (ret < 0) {
3057 /*
3058 * If the input value is greater than max value of datatype,
3059 * then also kstrtou8 fails
3060 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003061 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003062 (cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000),
3063 (cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003064 ret = -EINVAL;
3065 goto exit;
3066 }
3067
Wu Gao1ab05582018-11-08 16:22:49 +08003068 if (!cfg_in_range(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD,
3069 roam_scan_period)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003070 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003071 roam_scan_period,
3072 (cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000),
3073 (cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003074 ret = -EINVAL;
3075 goto exit;
3076 }
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303077
3078 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3079 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003080 adapter->vdev_id, roam_scan_period);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303081
Wu Gao1ab05582018-11-08 16:22:49 +08003082 empty_scan_refresh_period = roam_scan_period * 1000;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003083
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003084 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003085 roam_scan_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003086
Jeff Johnsond549efa2018-06-13 20:27:47 -07003087 sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003088 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003089 empty_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003090
3091exit:
3092 return ret;
3093}
3094
Jeff Johnsone44b7012017-09-10 15:25:47 -07003095static int drv_cmd_get_roam_scan_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003096 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003097 uint8_t *command,
3098 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003099 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003100{
3101 int ret = 0;
Jeff Johnson96259452019-02-26 20:38:17 -08003102 uint16_t empty_scan_refresh_period =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003103 sme_get_empty_scan_refresh_period(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003104 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003105 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003106
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303107 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3108 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003109 adapter->vdev_id,
Jeff Johnson96259452019-02-26 20:38:17 -08003110 empty_scan_refresh_period);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303111
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003112 len = scnprintf(extra, sizeof(extra), "%s %d",
3113 "GETROAMSCANPERIOD",
Jeff Johnson96259452019-02-26 20:38:17 -08003114 (empty_scan_refresh_period / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003115 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303116 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003117 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003118 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003119 ret = -EFAULT;
3120 }
3121
3122 return ret;
3123}
3124
Jeff Johnsone44b7012017-09-10 15:25:47 -07003125static int drv_cmd_set_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003126 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003127 uint8_t *command,
3128 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003129 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003130{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003131 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003132 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003133 uint8_t roam_scan_refresh_period = 0;
3134 uint16_t neighbor_scan_refresh_period =
3135 cfg_default(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003136
3137 /* input refresh period is in terms of seconds */
3138 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3139 value = value + command_len + 1;
3140
3141 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003142 ret = kstrtou8(value, 10, &roam_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003143 if (ret < 0) {
3144 /*
3145 * If the input value is greater than max value of datatype,
3146 * then also kstrtou8 fails
3147 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003148 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003149 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003150 / 1000),
Wu Gao1ab05582018-11-08 16:22:49 +08003151 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003152 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003153 ret = -EINVAL;
3154 goto exit;
3155 }
Wu Gao1ab05582018-11-08 16:22:49 +08003156
3157 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD,
3158 roam_scan_refresh_period)) {
3159 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3160 roam_scan_refresh_period,
3161 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3162 / 1000),
3163 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3164 / 1000));
3165 ret = -EINVAL;
3166 goto exit;
3167 }
3168 neighbor_scan_refresh_period = roam_scan_refresh_period * 1000;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003169
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003170 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003171 neighbor_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003172
Jeff Johnsond549efa2018-06-13 20:27:47 -07003173 sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003174 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003175 neighbor_scan_refresh_period);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003176
3177exit:
3178 return ret;
3179}
3180
Jeff Johnsone44b7012017-09-10 15:25:47 -07003181static int drv_cmd_get_roam_scan_refresh_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003182 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003183 uint8_t *command,
3184 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003185 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003186{
3187 int ret = 0;
3188 uint16_t value =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003189 sme_get_neighbor_scan_refresh_period(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003190 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003191 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003192
3193 len = scnprintf(extra, sizeof(extra), "%s %d",
3194 "GETROAMSCANREFRESHPERIOD",
3195 (value / 1000));
3196 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303197 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003198 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003199 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003200 ret = -EFAULT;
3201 }
3202
3203 return ret;
3204}
3205
Jeff Johnsone44b7012017-09-10 15:25:47 -07003206static int drv_cmd_set_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003207 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003208 uint8_t *command,
3209 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003210 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003211{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003212 mac_handle_t mac_handle;
3213 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003214 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003215 uint8_t roam_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003216
3217 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3218 value = value + SIZE_OF_SETROAMMODE + 1;
3219
3220 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003221 ret = kstrtou8(value, 10, &roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003222 if (ret < 0) {
3223 /*
3224 * If the input value is greater than max value of datatype,
3225 * then also kstrtou8 fails
3226 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003227 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003228 cfg_min(CFG_LFR_FEATURE_ENABLED),
3229 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003230 ret = -EINVAL;
3231 goto exit;
3232 }
Wu Gao1ab05582018-11-08 16:22:49 +08003233
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003234 hdd_debug("Received Command to Set Roam Mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003235 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003236 /*
3237 * Note that
3238 * SETROAMMODE 0 is to enable LFR while
3239 * SETROAMMODE 1 is to disable LFR, but
3240 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3241 * enable/disable. So, we have to invert the value
3242 * to call sme_update_is_fast_roam_ini_feature_enabled.
3243 */
Wu Gao1ab05582018-11-08 16:22:49 +08003244 if (roam_mode) {
3245 /* Roam enable */
3246 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
3247 } else {
3248 /* Roam disable */
3249 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
3250 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003251
Wu Gao1ab05582018-11-08 16:22:49 +08003252 ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)roam_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07003253 mac_handle = hdd_ctx->mac_handle;
Wu Gao1ab05582018-11-08 16:22:49 +08003254 if (roam_mode) {
3255 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3256 (bool)roam_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07003257 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003258 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003259 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003260 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07003261 sme_update_is_fast_roam_ini_feature_enabled(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003262 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003263 roam_mode);
3264 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3265 roam_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003266 }
3267
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003268exit:
3269 return ret;
3270}
3271
Pragaspathi Thilagarajaa8320e2019-04-16 02:47:50 +05303272static int drv_cmd_set_suspend_mode(struct hdd_adapter *adapter,
3273 struct hdd_context *hdd_ctx,
3274 uint8_t *command,
3275 uint8_t command_len,
3276 struct hdd_priv_data *priv_data)
3277{
3278 int errno;
3279 uint8_t *value = command;
3280 QDF_STATUS status;
3281 uint8_t idle_monitor;
3282
3283 if (QDF_STA_MODE != adapter->device_mode) {
3284 hdd_debug("Non-STA interface");
3285 return 0;
3286 }
3287
3288 /* Move pointer to ahead of SETSUSPENDMODE<delimiter> */
3289 value = value + SIZE_OF_SETSUSPENDMODE + 1;
3290
3291 /* Convert the value from ascii to integer */
3292 errno = kstrtou8(value, 10, &idle_monitor);
3293 if (errno < 0) {
3294 /*
3295 * If the input value is greater than max value of datatype,
3296 * then also kstrtou8 fails
3297 */
3298 hdd_err("Range validation failed");
3299 return -EINVAL;
3300 }
3301
3302 hdd_debug("idle_monitor:%d", idle_monitor);
3303 status = ucfg_pmo_tgt_psoc_send_idle_roam_suspend_mode(hdd_ctx->psoc,
3304 idle_monitor);
3305 if (QDF_IS_STATUS_ERROR(status)) {
3306 hdd_debug("Send suspend mode to fw failed");
3307 return -EINVAL;
3308 }
3309 return 0;
3310}
3311
Jeff Johnsone44b7012017-09-10 15:25:47 -07003312static int drv_cmd_get_roam_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003313 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003314 uint8_t *command,
3315 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003316 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003317{
3318 int ret = 0;
Wu Gao1ab05582018-11-08 16:22:49 +08003319 bool roam_mode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003320 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003321 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003322
3323 /*
3324 * roamMode value shall be inverted because the sementics is different.
3325 */
Wu Gao1ab05582018-11-08 16:22:49 +08003326 if (roam_mode)
3327 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003328 else
Wu Gao1ab05582018-11-08 16:22:49 +08003329 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003330
Wu Gao1ab05582018-11-08 16:22:49 +08003331 len = scnprintf(extra, sizeof(extra), "%s %d", command, roam_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303332 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003333 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003334 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003335 ret = -EFAULT;
3336 }
3337
3338 return ret;
3339}
3340
Jeff Johnsone44b7012017-09-10 15:25:47 -07003341static int drv_cmd_set_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003342 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003343 uint8_t *command,
3344 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003345 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003346{
Jeff Johnsond549efa2018-06-13 20:27:47 -07003347 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003348 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003349 uint8_t roam_rssi_diff = cfg_default(CFG_LFR_ROAM_RSSI_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003350
3351 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3352 value = value + command_len + 1;
3353
3354 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003355 ret = kstrtou8(value, 10, &roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003356 if (ret < 0) {
3357 /*
3358 * If the input value is greater than max value of datatype,
3359 * then also kstrtou8 fails
3360 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003361 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003362 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3363 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364 ret = -EINVAL;
3365 goto exit;
3366 }
3367
Wu Gao1ab05582018-11-08 16:22:49 +08003368 if (!cfg_in_range(CFG_LFR_ROAM_RSSI_DIFF, roam_rssi_diff)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003369 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003370 roam_rssi_diff,
3371 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3372 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003373 ret = -EINVAL;
3374 goto exit;
3375 }
3376
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003377 hdd_debug("Received Command to Set roam rssi diff = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003378 roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003379
Jeff Johnsond549efa2018-06-13 20:27:47 -07003380 sme_update_roam_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003381 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003382 roam_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003383
3384exit:
3385 return ret;
3386}
3387
Jeff Johnsone44b7012017-09-10 15:25:47 -07003388static int drv_cmd_get_roam_delta(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003389 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003390 uint8_t *command,
3391 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003392 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003393{
3394 int ret = 0;
Jeff Johnson65003802019-02-26 20:50:49 -08003395 uint8_t rssi_diff =
Jeff Johnsond549efa2018-06-13 20:27:47 -07003396 sme_get_roam_rssi_diff(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003397 char extra[32];
Jeff Johnsond549efa2018-06-13 20:27:47 -07003398 uint8_t len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003399
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303400 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3401 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
Jeff Johnson65003802019-02-26 20:50:49 -08003402 adapter->vdev_id, rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403
3404 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnson65003802019-02-26 20:50:49 -08003405 command, rssi_diff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303406 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003407
3408 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003409 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410 ret = -EFAULT;
3411 }
3412
3413 return ret;
3414}
3415
Jeff Johnsone44b7012017-09-10 15:25:47 -07003416static int drv_cmd_get_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003417 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418 uint8_t *command,
3419 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003420 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421{
3422 int ret = 0;
3423 int band = -1;
3424 char extra[32];
3425 uint8_t len = 0;
3426
3427 hdd_get_band_helper(hdd_ctx, &band);
3428
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303429 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3430 TRACE_CODE_HDD_GETBAND_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003431 adapter->vdev_id, band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003432
3433 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303434 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003435
3436 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003437 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003438 ret = -EFAULT;
3439 }
3440
3441 return ret;
3442}
3443
Jeff Johnsone44b7012017-09-10 15:25:47 -07003444static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003445 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003446 uint8_t *command,
3447 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003448 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003449{
3450 return hdd_parse_set_roam_scan_channels(adapter, command);
3451}
3452
Jeff Johnsone44b7012017-09-10 15:25:47 -07003453static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003454 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003455 uint8_t *command,
3456 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003457 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003458{
3459 int ret = 0;
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08003460 uint8_t channel_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3461 uint8_t num_channels = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003462 uint8_t j = 0;
3463 char extra[128] = { 0 };
3464 int len;
3465
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303466 if (QDF_STATUS_SUCCESS !=
Jeff Johnsond549efa2018-06-13 20:27:47 -07003467 sme_get_roam_scan_channel_list(hdd_ctx->mac_handle,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08003468 channel_list,
3469 &num_channels,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003470 adapter->vdev_id)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003471 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003472 ret = -EFAULT;
3473 goto exit;
3474 }
3475
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303476 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3477 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08003478 adapter->vdev_id, num_channels);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303479
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003480 /*
3481 * output channel list is of the format
3482 * [Number of roam scan channels][Channel1][Channel2]...
3483 * copy the number of channels in the 0th index
3484 */
3485 len = scnprintf(extra, sizeof(extra), "%s %d", command,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08003486 num_channels);
3487 for (j = 0; (j < num_channels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003488 len += scnprintf(extra + len, sizeof(extra) - len,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08003489 " %d", channel_list[j]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003490
Anurag Chouhan6d760662016-02-20 16:05:43 +05303491 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003492 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003493 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003494 ret = -EFAULT;
3495 goto exit;
3496 }
3497
3498exit:
3499 return ret;
3500}
3501
Jeff Johnsone44b7012017-09-10 15:25:47 -07003502static int drv_cmd_get_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003503 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003504 uint8_t *command,
3505 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003506 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003507{
3508 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003509 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Jeff Johnson22345e12019-02-26 21:33:02 -08003510 bool ese_mode = sme_get_is_ese_feature_enabled(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003511 char extra[32];
3512 uint8_t len = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003513 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003514
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003515 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003516 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003517 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003518 * then this operation is not permitted (return FAILURE)
3519 */
Jeff Johnson22345e12019-02-26 21:33:02 -08003520 if (ese_mode &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003521 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07003522 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003523 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524 ret = -EPERM;
3525 goto exit;
3526 }
3527
3528 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnson22345e12019-02-26 21:33:02 -08003529 "GETCCXMODE", ese_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303530 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003531 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003532 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003533 ret = -EFAULT;
3534 goto exit;
3535 }
3536
3537exit:
3538 return ret;
3539}
3540
Jeff Johnsone44b7012017-09-10 15:25:47 -07003541static int drv_cmd_get_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003542 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003543 uint8_t *command,
3544 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003545 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003546{
3547 int ret = 0;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003548 struct pmkid_mode_bits pmkid_modes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003549 char extra[32];
3550 uint8_t len = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003551 mac_handle_t mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003552
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003553 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003554 /*
3555 * Check if the features OKC/ESE/11R are supported simultaneously,
3556 * then this operation is not permitted (return FAILURE)
3557 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003558 if (pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07003559 sme_get_is_ese_feature_enabled(mac_handle) &&
3560 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003561 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003562 ret = -EPERM;
3563 goto exit;
3564 }
3565
3566 len = scnprintf(extra, sizeof(extra), "%s %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08003567 "GETOKCMODE", pmkid_modes.fw_okc);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303568 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003569
3570 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003571 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003572 ret = -EFAULT;
3573 goto exit;
3574 }
3575
3576exit:
3577 return ret;
3578}
3579
Jeff Johnsone44b7012017-09-10 15:25:47 -07003580static int drv_cmd_get_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003581 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003582 uint8_t *command,
3583 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003584 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003585{
3586 int ret = 0;
Jeff Johnson22345e12019-02-26 21:33:02 -08003587 bool lfr_mode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003588 char extra[32];
3589 uint8_t len = 0;
3590
3591 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnson22345e12019-02-26 21:33:02 -08003592 "GETFASTROAM", lfr_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303593 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003594
3595 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003596 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003597 ret = -EFAULT;
3598 }
3599
3600 return ret;
3601}
3602
Jeff Johnsone44b7012017-09-10 15:25:47 -07003603static int drv_cmd_get_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003604 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003605 uint8_t *command,
3606 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003607 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003608{
3609 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003610 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003611 char extra[32];
3612 uint8_t len = 0;
3613
3614 len = scnprintf(extra, sizeof(extra), "%s %d",
3615 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303616 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003617
3618 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003619 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003620 ret = -EFAULT;
3621 }
3622
3623 return ret;
3624}
3625
Jeff Johnsone44b7012017-09-10 15:25:47 -07003626static int drv_cmd_set_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003627 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003628 uint8_t *command,
3629 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003630 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003631{
3632 int ret = 0;
3633 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003634 uint8_t min_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003635
3636 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3637 value = value + command_len + 1;
3638
3639 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003640 ret = kstrtou8(value, 10, &min_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003641 if (ret < 0) {
3642 /*
3643 * If the input value is greater than max value of datatype,
3644 * then also kstrtou8 fails
3645 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003646 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003647 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
3648 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003649 ret = -EINVAL;
3650 goto exit;
3651 }
3652
Wu Gao1ab05582018-11-08 16:22:49 +08003653 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME, min_time)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003654 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003655 min_time,
3656 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
3657 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658 ret = -EINVAL;
3659 goto exit;
3660 }
3661
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303662 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3663 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003664 adapter->vdev_id, min_time);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303665
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003666 hdd_debug("Received Command to change channel min time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003667 min_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003668
Jeff Johnsond549efa2018-06-13 20:27:47 -07003669 sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
Wu Gao1ab05582018-11-08 16:22:49 +08003670 min_time,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003671 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003672
3673exit:
3674 return ret;
3675}
3676
Jeff Johnsone44b7012017-09-10 15:25:47 -07003677static int drv_cmd_send_action_frame(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003678 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003679 uint8_t *command,
3680 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003681 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003682{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003683 return hdd_parse_sendactionframe(adapter, command,
3684 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003685}
3686
Jeff Johnsone44b7012017-09-10 15:25:47 -07003687static int drv_cmd_get_roam_scan_channel_min_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003688 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003689 uint8_t *command,
3690 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003691 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003692{
3693 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003694 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003695 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003696 char extra[32];
3697 uint8_t len = 0;
3698
3699 /* value is interms of msec */
3700 len = scnprintf(extra, sizeof(extra), "%s %d",
3701 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303702 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003703
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05303704 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3705 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003706 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707
3708 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003709 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003710 ret = -EFAULT;
3711 }
3712
3713 return ret;
3714}
3715
Jeff Johnsone44b7012017-09-10 15:25:47 -07003716static int drv_cmd_set_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003717 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003718 uint8_t *command,
3719 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003720 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003721{
3722 int ret = 0;
3723 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003724 uint16_t max_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003725
3726 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3727 value = value + command_len + 1;
3728
3729 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003730 ret = kstrtou16(value, 10, &max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731 if (ret < 0) {
3732 /*
3733 * If the input value is greater than max value of datatype,
3734 * then also kstrtou8 fails
3735 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003736 hdd_err("kstrtou16 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003737 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
3738 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003739 ret = -EINVAL;
3740 goto exit;
3741 }
3742
Wu Gao1ab05582018-11-08 16:22:49 +08003743 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME, max_time)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003744 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003745 max_time,
3746 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
3747 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003748 ret = -EINVAL;
3749 goto exit;
3750 }
3751
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003752 hdd_debug("Received Command to change channel max time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003753 max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003754
Jeff Johnsond549efa2018-06-13 20:27:47 -07003755 sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003756 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08003757 max_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003758
3759exit:
3760 return ret;
3761}
3762
Jeff Johnsone44b7012017-09-10 15:25:47 -07003763static int drv_cmd_get_scan_channel_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003764 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003765 uint8_t *command,
3766 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003767 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003768{
3769 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003770 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003771 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003772 char extra[32];
3773 uint8_t len = 0;
3774
3775 /* value is interms of msec */
3776 len = scnprintf(extra, sizeof(extra), "%s %d",
3777 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303778 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003779
3780 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003781 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003782 ret = -EFAULT;
3783 }
3784
3785 return ret;
3786}
3787
Jeff Johnsone44b7012017-09-10 15:25:47 -07003788static int drv_cmd_set_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003789 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003790 uint8_t *command,
3791 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003792 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003793{
3794 int ret = 0;
3795 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003796 uint16_t val = cfg_default(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003797
3798 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3799 value = value + command_len + 1;
3800
3801 /* Convert the value from ascii to integer */
3802 ret = kstrtou16(value, 10, &val);
3803 if (ret < 0) {
3804 /*
3805 * If the input value is greater than max value of datatype,
3806 * then also kstrtou8 fails
3807 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003808 hdd_err("kstrtou16 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003809 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
3810 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003811 ret = -EINVAL;
3812 goto exit;
3813 }
3814
Wu Gao1ab05582018-11-08 16:22:49 +08003815 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD, val)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003816 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3817 val,
Wu Gao1ab05582018-11-08 16:22:49 +08003818 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
3819 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003820 ret = -EINVAL;
3821 goto exit;
3822 }
3823
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003824 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003825 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826
Jeff Johnsond549efa2018-06-13 20:27:47 -07003827 sme_set_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003828 adapter->vdev_id, val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003829
3830exit:
3831 return ret;
3832}
3833
Jeff Johnsone44b7012017-09-10 15:25:47 -07003834static int drv_cmd_get_scan_home_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003835 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003836 uint8_t *command,
3837 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003838 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003839{
3840 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003841 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003842 adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003843 char extra[32];
3844 uint8_t len = 0;
3845
3846 /* value is interms of msec */
3847 len = scnprintf(extra, sizeof(extra), "%s %d",
3848 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303849 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003850
3851 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003852 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003853 ret = -EFAULT;
3854 }
3855
3856 return ret;
3857}
3858
Jeff Johnsone44b7012017-09-10 15:25:47 -07003859static int drv_cmd_set_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003860 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003861 uint8_t *command,
3862 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003863 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003864{
3865 int ret = 0;
3866 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003867 uint8_t val = cfg_default(CFG_LFR_ROAM_INTRA_BAND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003868
3869 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3870 value = value + command_len + 1;
3871
3872 /* Convert the value from ascii to integer */
3873 ret = kstrtou8(value, 10, &val);
3874 if (ret < 0) {
3875 /*
3876 * If the input value is greater than max value of datatype,
3877 * then also kstrtou8 fails
3878 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003879 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003880 cfg_min(CFG_LFR_ROAM_INTRA_BAND),
3881 cfg_max(CFG_LFR_ROAM_INTRA_BAND));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003882 ret = -EINVAL;
3883 goto exit;
3884 }
3885
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003886 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003887 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003888
Wu Gao1ab05582018-11-08 16:22:49 +08003889 ucfg_mlme_set_roam_intra_band(hdd_ctx->psoc, (bool)val);
Jianmin Zhu0b505a62019-04-30 16:22:49 +08003890 policy_mgr_set_pcl_for_existing_combo(
3891 hdd_ctx->psoc,
3892 PM_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003893
3894exit:
3895 return ret;
3896}
3897
Jeff Johnsone44b7012017-09-10 15:25:47 -07003898static int drv_cmd_get_roam_intra_band(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003899 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003900 uint8_t *command,
3901 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003902 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903{
3904 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003905 uint16_t val = sme_get_roam_intra_band(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003906 char extra[32];
3907 uint8_t len = 0;
3908
3909 /* value is interms of msec */
3910 len = scnprintf(extra, sizeof(extra), "%s %d",
3911 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303912 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003913 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003914 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003915 ret = -EFAULT;
3916 }
3917
3918 return ret;
3919}
3920
Jeff Johnsone44b7012017-09-10 15:25:47 -07003921static int drv_cmd_set_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003922 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923 uint8_t *command,
3924 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003925 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003926{
3927 int ret = 0;
3928 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003929 uint8_t nprobes = cfg_default(CFG_LFR_ROAM_SCAN_N_PROBES);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003930
3931 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3932 value = value + command_len + 1;
3933
3934 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08003935 ret = kstrtou8(value, 10, &nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003936 if (ret < 0) {
3937 /*
3938 * If the input value is greater than max value of datatype,
3939 * then also kstrtou8 fails
3940 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003941 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08003942 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
3943 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003944 ret = -EINVAL;
3945 goto exit;
3946 }
3947
Wu Gao1ab05582018-11-08 16:22:49 +08003948 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_N_PROBES, nprobes)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003949 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08003950 nprobes,
3951 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
3952 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003953 ret = -EINVAL;
3954 goto exit;
3955 }
3956
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003957 hdd_debug("Received Command to Set nProbes = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08003958 nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003959
Jeff Johnsond549efa2018-06-13 20:27:47 -07003960 sme_update_roam_scan_n_probes(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08003961 adapter->vdev_id, nprobes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003962
3963exit:
3964 return ret;
3965}
3966
Jeff Johnsone44b7012017-09-10 15:25:47 -07003967static int drv_cmd_get_scan_n_probes(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003968 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003969 uint8_t *command,
3970 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003971 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003972{
3973 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07003974 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003975 char extra[32];
3976 uint8_t len = 0;
3977
3978 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303979 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003980 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003981 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982 ret = -EFAULT;
3983 }
3984
3985 return ret;
3986}
3987
Jeff Johnsone44b7012017-09-10 15:25:47 -07003988static int drv_cmd_set_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07003989 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003990 uint8_t *command,
3991 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07003992 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003993{
3994 int ret = 0;
3995 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08003996 uint16_t home_away_time = cfg_default(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME);
3997 uint16_t current_home_away_time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003998
3999 /* input value is in units of msec */
4000
4001 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4002 value = value + command_len + 1;
4003
4004 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004005 ret = kstrtou16(value, 10, &home_away_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004006 if (ret < 0) {
4007 /*
4008 * If the input value is greater than max value of datatype,
4009 * then also kstrtou8 fails
4010 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004011 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004012 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4013 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004014 ret = -EINVAL;
4015 goto exit;
4016 }
4017
Wu Gao1ab05582018-11-08 16:22:49 +08004018 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME, home_away_time)) {
4019 hdd_err("home_away_time value %d is out of range (min: %d max: %d)",
4020 home_away_time,
4021 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4022 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004023 ret = -EINVAL;
4024 goto exit;
4025 }
4026
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004027 hdd_debug("Received Command to Set scan away time = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004028 home_away_time);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004029
Wu Gao1ab05582018-11-08 16:22:49 +08004030 ucfg_mlme_get_home_away_time(hdd_ctx->psoc, &current_home_away_time);
4031 if (current_home_away_time != home_away_time) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07004032 sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004033 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004034 home_away_time,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004035 true);
4036 }
4037
4038exit:
4039 return ret;
4040}
4041
Jeff Johnsone44b7012017-09-10 15:25:47 -07004042static int drv_cmd_get_scan_home_away_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004043 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004044 uint8_t *command,
4045 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004046 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004047{
4048 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004049 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004050 char extra[32];
4051 uint8_t len = 0;
4052
4053 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304054 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004055
4056 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004057 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004058 ret = -EFAULT;
4059 }
4060
4061 return ret;
4062}
4063
Jeff Johnsone44b7012017-09-10 15:25:47 -07004064static int drv_cmd_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004065 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004066 uint8_t *command,
4067 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004068 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004069{
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05304070 return hdd_parse_reassoc(adapter, command, priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071}
4072
Jeff Johnsone44b7012017-09-10 15:25:47 -07004073static int drv_cmd_set_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004074 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004075 uint8_t *command,
4076 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004077 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004078{
4079 int ret = 0;
4080 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004081 uint8_t wes_mode = cfg_default(CFG_LFR_ENABLE_WES_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004082
4083 /* Move pointer to ahead of SETWESMODE<delimiter> */
4084 value = value + command_len + 1;
4085
4086 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004087 ret = kstrtou8(value, 10, &wes_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004088 if (ret < 0) {
4089 /*
4090 * If the input value is greater than max value of datatype,
4091 * then also kstrtou8 fails
4092 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004093 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004094 cfg_min(CFG_LFR_ENABLE_WES_MODE),
4095 cfg_max(CFG_LFR_ENABLE_WES_MODE));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004096 ret = -EINVAL;
4097 goto exit;
4098 }
4099
Wu Gao1ab05582018-11-08 16:22:49 +08004100 hdd_debug("Received Command to Set WES Mode rssi diff = %d", wes_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004101
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004102 sme_update_wes_mode(hdd_ctx->mac_handle, wes_mode, adapter->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004103
4104exit:
4105 return ret;
4106}
4107
Jeff Johnsone44b7012017-09-10 15:25:47 -07004108static int drv_cmd_get_wes_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004109 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004110 uint8_t *command,
4111 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004112 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004113{
4114 int ret = 0;
Jeff Johnson22345e12019-02-26 21:33:02 -08004115 bool wes_mode = sme_get_wes_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004116 char extra[32];
4117 uint8_t len = 0;
4118
Jeff Johnson22345e12019-02-26 21:33:02 -08004119 len = scnprintf(extra, sizeof(extra), "%s %d", command, wes_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304120 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004121 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004122 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004123 ret = -EFAULT;
4124 }
4125
4126 return ret;
4127}
4128
Jeff Johnsone44b7012017-09-10 15:25:47 -07004129static int drv_cmd_set_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004130 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004131 uint8_t *command,
4132 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004133 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004134{
4135 int ret = 0;
4136 uint8_t *value = command;
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004137 uint8_t diff =
Wu Gao1ab05582018-11-08 16:22:49 +08004138 cfg_default(CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004139
4140 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4141 value = value + command_len + 1;
4142
4143 /* Convert the value from ascii to integer */
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004144 ret = kstrtou8(value, 10, &diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004145 if (ret < 0) {
4146 /*
4147 * If the input value is greater than max value of datatype,
4148 * then also kstrtou8 fails
4149 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004150 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004151 ret = -EINVAL;
4152 goto exit;
4153 }
4154
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004155 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004156 diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004157
Jeff Johnsond549efa2018-06-13 20:27:47 -07004158 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle,
Jeff Johnson8e3ca4c2019-02-26 20:42:24 -08004159 adapter->vdev_id,
4160 diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004161
4162exit:
4163 return ret;
4164}
4165
Jeff Johnsone44b7012017-09-10 15:25:47 -07004166static int drv_cmd_get_opportunistic_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004167 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004168 uint8_t *command,
4169 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004170 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004171{
4172 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004173 mac_handle_t mac_handle = hdd_ctx->mac_handle;
4174 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004175 char extra[32];
4176 uint8_t len = 0;
4177
4178 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304179 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004180 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004181 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004182 ret = -EFAULT;
4183 }
4184
4185 return ret;
4186}
4187
Jeff Johnsone44b7012017-09-10 15:25:47 -07004188static int drv_cmd_set_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004189 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190 uint8_t *command,
4191 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004192 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004193{
4194 int ret = 0;
4195 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004196 uint8_t rescan_rssi_diff = cfg_default(CFG_LFR_ROAM_RESCAN_RSSI_DIFF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004197
4198 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4199 value = value + command_len + 1;
4200
4201 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004202 ret = kstrtou8(value, 10, &rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004203 if (ret < 0) {
4204 /*
4205 * If the input value is greater than max value of datatype,
4206 * then also kstrtou8 fails
4207 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004208 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004209 ret = -EINVAL;
4210 goto exit;
4211 }
4212
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004213 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004214 rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004215
Jeff Johnsond549efa2018-06-13 20:27:47 -07004216 sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004217 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004218 rescan_rssi_diff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004219
4220exit:
4221 return ret;
4222}
4223
Jeff Johnsone44b7012017-09-10 15:25:47 -07004224static int drv_cmd_get_roam_rescan_rssi_diff(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004225 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004226 uint8_t *command,
4227 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004228 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004229{
4230 int ret = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004231 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004232 char extra[32];
4233 uint8_t len = 0;
4234
4235 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304236 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004237 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004238 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004239 ret = -EFAULT;
4240 }
4241
4242 return ret;
4243}
4244
Jeff Johnsone44b7012017-09-10 15:25:47 -07004245static int drv_cmd_set_fast_roam(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004246 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004247 uint8_t *command,
4248 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004249 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004250{
4251 int ret = 0;
4252 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004253 uint8_t lfr_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254
4255 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4256 value = value + command_len + 1;
4257
4258 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08004259 ret = kstrtou8(value, 10, &lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004260 if (ret < 0) {
4261 /*
4262 * If the input value is greater than max value of datatype,
4263 * then also kstrtou8 fails
4264 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004265 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004266 cfg_min(CFG_LFR_FEATURE_ENABLED),
4267 cfg_max(CFG_LFR_FEATURE_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004268 ret = -EINVAL;
4269 goto exit;
4270 }
4271
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004272 hdd_debug("Received Command to change lfr mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08004273 lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004274
Wu Gao1ab05582018-11-08 16:22:49 +08004275 ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)lfr_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07004276 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004277 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08004278 lfr_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004279
4280exit:
4281 return ret;
4282}
4283
Jeff Johnsone44b7012017-09-10 15:25:47 -07004284static int drv_cmd_set_fast_transition(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004285 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004286 uint8_t *command,
4287 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004288 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004289{
4290 int ret = 0;
4291 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08004292 uint8_t ft = cfg_default(CFG_LFR_FAST_TRANSITION_ENABLED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293
4294 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4295 value = value + command_len + 1;
4296
4297 /* Convert the value from ascii to integer */
4298 ret = kstrtou8(value, 10, &ft);
4299 if (ret < 0) {
4300 /*
4301 * If the input value is greater than max value of datatype,
4302 * then also kstrtou8 fails
4303 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004304 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08004305 cfg_min(CFG_LFR_FAST_TRANSITION_ENABLED),
4306 cfg_max(CFG_LFR_FAST_TRANSITION_ENABLED));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004307 ret = -EINVAL;
4308 goto exit;
4309 }
4310
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004311 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004312
Wu Gao1ab05582018-11-08 16:22:49 +08004313 ucfg_mlme_set_fast_transition_enabled(hdd_ctx->psoc, (bool)ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004314
4315exit:
4316 return ret;
4317}
4318
Jeff Johnsone44b7012017-09-10 15:25:47 -07004319static int drv_cmd_fast_reassoc(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004320 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004321 uint8_t *command,
4322 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004323 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004324{
4325 int ret = 0;
4326 uint8_t *value = command;
4327 uint8_t channel = 0;
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004328 tSirMacAddr bssid;
Jeff Johnson29c78672019-02-26 21:05:53 -08004329 uint32_t roam_id = INVALID_ROAM_ID;
Jeff Johnson9ff16952019-02-26 20:58:44 -08004330 tCsrRoamModifyProfileFields mod_fields;
Jeff Johnsondcaa8fc2019-02-26 21:26:31 -08004331 tCsrHandoffRequest req;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004332 struct hdd_station_ctx *sta_ctx;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004333 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334
Krunal Sonibe766b02016-03-10 13:00:44 -08004335 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07004337 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004338 adapter->device_mode);
4339 return -EINVAL;
4340 }
4341
Jeff Johnsond377dce2017-10-04 10:32:42 -07004342 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jingxiang Gece7c5472019-07-23 16:19:23 +08004343 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344
4345 /* if not associated, no need to proceed with reassoc */
Jeff Johnsone7951512019-02-27 10:02:51 -08004346 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004347 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004348 ret = -EINVAL;
4349 goto exit;
4350 }
4351
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004352 ret = hdd_parse_reassoc_command_v1_data(value, bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004353 &channel);
4354 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004355 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004356 goto exit;
4357 }
4358
Jeff Johnsond549efa2018-06-13 20:27:47 -07004359 mac_handle = hdd_ctx->mac_handle;
4360
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004361 /*
4362 * if the target bssid is same as currently associated AP,
4363 * issue reassoc to same AP
4364 */
Jeff Johnsone04b6992019-02-27 14:06:55 -08004365 if (!qdf_mem_cmp(bssid, sta_ctx->conn_info.bssid.bytes,
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004366 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004367 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304368 if (roaming_offload_enabled(hdd_ctx)) {
Jingxiang Gece7c5472019-07-23 16:19:23 +08004369 channel = wlan_reg_freq_to_chan(
4370 hdd_ctx->pdev,
Jingxiang Geae80dc62019-08-13 17:32:22 +08004371 sta_ctx->conn_info.chan_freq);
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004372 hdd_wma_send_fastreassoc_cmd(adapter, bssid,
4373 channel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304374 } else {
Jeff Johnsond549efa2018-06-13 20:27:47 -07004375 sme_get_modify_profile_fields(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004376 adapter->vdev_id,
Jeff Johnson9ff16952019-02-26 20:58:44 -08004377 &mod_fields);
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004378 sme_roam_reassoc(mac_handle, adapter->vdev_id,
Jeff Johnson29c78672019-02-26 21:05:53 -08004379 NULL, mod_fields, &roam_id, 1);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304380 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004381 return 0;
4382 }
4383
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304384 /* Check channel number is a valid channel number */
Selvaraj, Sridhar64b0a9c2017-05-11 16:50:15 +05304385 if (channel && (QDF_STATUS_SUCCESS !=
4386 wlan_hdd_validate_operation_channel(adapter, channel))) {
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304387 hdd_err("Invalid Channel [%d]", channel);
4388 return -EINVAL;
4389 }
4390
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004391 if (roaming_offload_enabled(hdd_ctx)) {
Jeff Johnson8ff3ffe2019-02-26 13:21:07 -08004392 hdd_wma_send_fastreassoc_cmd(adapter, bssid, (int)channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004393 goto exit;
4394 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004395 /* Proceed with reassoc */
Jeff Johnsondcaa8fc2019-02-26 21:26:31 -08004396 req.channel = channel;
4397 req.src = FASTREASSOC;
4398 qdf_mem_copy(req.bssid.bytes, bssid, sizeof(tSirMacAddr));
4399 sme_handoff_request(mac_handle, adapter->vdev_id, &req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004400exit:
4401 return ret;
4402}
4403
Jeff Johnsone44b7012017-09-10 15:25:47 -07004404static int drv_cmd_set_roam_scan_control(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004405 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004406 uint8_t *command,
4407 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004408 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004409{
4410 int ret = 0;
4411 uint8_t *value = command;
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004412 uint8_t roam_scan_control = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004413
4414 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4415 value = value + command_len + 1;
4416
4417 /* Convert the value from ascii to integer */
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004418 ret = kstrtou8(value, 10, &roam_scan_control);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004419 if (ret < 0) {
4420 /*
4421 * If the input value is greater than max value of datatype,
4422 * then also kstrtou8 fails
4423 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004424 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004425 ret = -EINVAL;
4426 goto exit;
4427 }
4428
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004429 hdd_debug("Received Command to Set roam scan control = %d",
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004430 roam_scan_control);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004432 if (0 != roam_scan_control) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004433 ret = 0; /* return success but ignore param value "true" */
4434 goto exit;
4435 }
4436
Jeff Johnsond549efa2018-06-13 20:27:47 -07004437 sme_set_roam_scan_control(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004438 adapter->vdev_id,
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004439 roam_scan_control);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004440
4441exit:
4442 return ret;
4443}
4444
Jeff Johnsone44b7012017-09-10 15:25:47 -07004445static int drv_cmd_set_okc_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004446 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004447 uint8_t *command,
4448 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004449 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004450{
4451 int ret = 0;
4452 uint8_t *value = command;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004453 uint32_t okc_mode;
4454 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004455 mac_handle_t mac_handle;
Wu Gao93816212018-08-31 16:49:54 +08004456 uint32_t cur_pmkid_modes;
4457 QDF_STATUS status;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004458
4459 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004460
4461 /*
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004462 * Check if the features PMKID/ESE/11R are supported simultaneously,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004463 * then this operation is not permitted (return FAILURE)
4464 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07004465 mac_handle = hdd_ctx->mac_handle;
4466 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004467 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07004468 sme_get_is_ft_feature_enabled(mac_handle)) {
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004469 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004470 ret = -EPERM;
4471 goto exit;
4472 }
4473
4474 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4475 value = value + command_len + 1;
4476
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004477 /* get the current configured value */
Dustin Brown1dbefe62018-09-11 16:32:03 -07004478 status = ucfg_mlme_get_pmkid_modes(hdd_ctx->psoc,
Wu Gao93816212018-08-31 16:49:54 +08004479 &cur_pmkid_modes);
4480 if (status != QDF_STATUS_SUCCESS)
4481 hdd_err("get pmkid modes failed");
4482
4483 okc_mode = cur_pmkid_modes & CFG_PMKID_MODES_OKC;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004484
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004485 /* Convert the value from ascii to integer */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004486 ret = kstrtou32(value, 10, &okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004487 if (ret < 0) {
4488 /*
4489 * If the input value is greater than max value of datatype,
4490 * then also kstrtou8 fails
4491 */
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004492 hdd_err("value out of range [0 - 1]");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004493 ret = -EINVAL;
4494 goto exit;
4495 }
4496
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004497 if ((okc_mode < 0) ||
4498 (okc_mode > 1)) {
4499 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4500 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004501 ret = -EINVAL;
4502 goto exit;
4503 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004504 hdd_debug("Received Command to change okc mode = %d",
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004505 okc_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004506
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004507 if (okc_mode)
Wu Gao93816212018-08-31 16:49:54 +08004508 cur_pmkid_modes |= CFG_PMKID_MODES_OKC;
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08004509 else
Wu Gao93816212018-08-31 16:49:54 +08004510 cur_pmkid_modes &= ~CFG_PMKID_MODES_OKC;
Dustin Brown1dbefe62018-09-11 16:32:03 -07004511 status = ucfg_mlme_set_pmkid_modes(hdd_ctx->psoc,
Wu Gao93816212018-08-31 16:49:54 +08004512 cur_pmkid_modes);
4513 if (status != QDF_STATUS_SUCCESS) {
4514 ret = -EPERM;
4515 hdd_err("set pmkid modes failed");
4516 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004517exit:
4518 return ret;
4519}
4520
Jeff Johnsone44b7012017-09-10 15:25:47 -07004521static int drv_cmd_get_roam_scan_control(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;
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004528 bool roam_scan_control = sme_get_roam_scan_control(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004529 char extra[32];
4530 uint8_t len = 0;
4531
4532 len = scnprintf(extra, sizeof(extra), "%s %d",
Jeff Johnsond7ee4762019-02-26 21:01:00 -08004533 command, roam_scan_control);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304534 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004535 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004536 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004537 ret = -EFAULT;
4538 }
4539
4540 return ret;
4541}
4542
Jeff Johnsone44b7012017-09-10 15:25:47 -07004543static int drv_cmd_bt_coex_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004544 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004545 uint8_t *command,
4546 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004547 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004548{
4549 int ret = 0;
Jeff Johnson30192412019-02-26 20:32:52 -08004550 char *coex_mode;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004551
Jeff Johnson30192412019-02-26 20:32:52 -08004552 coex_mode = command + 11;
4553 if ('1' == *coex_mode) {
4554 hdd_debug("BTCOEXMODE %d", *coex_mode);
Jeff Johnson59b19312017-11-02 21:14:33 -07004555 hdd_ctx->bt_coex_mode_set = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004556 ret = wlan_hdd_scan_abort(adapter);
4557 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004558 hdd_err("Failed to abort existing scan status: %d",
4559 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004560 }
Jeff Johnson30192412019-02-26 20:32:52 -08004561 } else if ('2' == *coex_mode) {
4562 hdd_debug("BTCOEXMODE %d", *coex_mode);
Jeff Johnson59b19312017-11-02 21:14:33 -07004563 hdd_ctx->bt_coex_mode_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004564 }
4565
4566 return ret;
4567}
4568
Jeff Johnsone44b7012017-09-10 15:25:47 -07004569static int drv_cmd_scan_active(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004570 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004571 uint8_t *command,
4572 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004573 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004574{
4575 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4576 return 0;
4577}
4578
Jeff Johnsone44b7012017-09-10 15:25:47 -07004579static int drv_cmd_scan_passive(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004580 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004581 uint8_t *command,
4582 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004583 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004584{
4585 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4586 return 0;
4587}
4588
Jeff Johnsone44b7012017-09-10 15:25:47 -07004589static int drv_cmd_get_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004590 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004591 uint8_t *command,
4592 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004593 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594{
4595 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004596 char extra[32];
4597 uint8_t len = 0;
4598
4599 memset(extra, 0, sizeof(extra));
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05304600 ret = hdd_get_dwell_time(hdd_ctx->psoc, command, extra,
4601 sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304602 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004603 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004604 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004605 ret = -EFAULT;
4606 goto exit;
4607 }
4608 ret = len;
4609exit:
4610 return ret;
4611}
4612
Jeff Johnsone44b7012017-09-10 15:25:47 -07004613static int drv_cmd_set_dwell_time(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004614 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615 uint8_t *command,
4616 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004617 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004618{
Abhishek Singh8ebda9db2018-12-18 15:15:01 +05304619 return hdd_set_dwell_time(hdd_ctx->psoc, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004620}
4621
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05304622static int drv_cmd_conc_set_dwell_time(struct hdd_adapter *adapter,
4623 struct hdd_context *hdd_ctx,
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05304624 u8 *command,
4625 u8 command_len,
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05304626 struct hdd_priv_data *priv_data)
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05304627{
Ashish Kumar Dhanotiya652c2332018-12-11 17:33:17 +05304628 return hdd_conc_set_dwell_time(adapter, command);
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05304629}
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05304630
Jeff Johnsone44b7012017-09-10 15:25:47 -07004631static int drv_cmd_miracast(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004632 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004633 uint8_t *command,
4634 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004635 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004636{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304637 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 int ret = 0;
Jeff Johnson3dd8a542019-02-26 21:38:14 -08004639 uint8_t filter_type = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 uint8_t *value;
4641
Jeff Johnson6da2db12017-09-03 09:18:52 -07004642 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004643 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004645 value = command + 9;
4646
4647 /* Convert the value from ascii to integer */
Jeff Johnson3dd8a542019-02-26 21:38:14 -08004648 ret = kstrtou8(value, 10, &filter_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004649 if (ret < 0) {
4650 /*
4651 * If the input value is greater than max value of datatype,
4652 * then also kstrtou8 fails
4653 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004654 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004655 ret = -EINVAL;
4656 goto exit;
4657 }
Jeff Johnson3dd8a542019-02-26 21:38:14 -08004658 if ((filter_type < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL) ||
4659 (filter_type > WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004660 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004661 ret = -EINVAL;
4662 goto exit;
4663 }
4664 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
Jeff Johnson3dd8a542019-02-26 21:38:14 -08004665 hdd_ctx->miracast_value = filter_type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004666
Jeff Johnson3dd8a542019-02-26 21:38:14 -08004667 ret_status = sme_set_miracast(hdd_ctx->mac_handle, filter_type);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304668 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004669 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004670 return -EBUSY;
4671 }
Dustin Brown1dbefe62018-09-11 16:32:03 -07004672 ret_status = ucfg_scan_set_miracast(hdd_ctx->psoc,
Jeff Johnson3dd8a542019-02-26 21:38:14 -08004673 filter_type ? true : false);
Abhishek Singhc87bb042018-01-30 17:10:42 +05304674 if (QDF_IS_STATUS_ERROR(ret_status)) {
4675 hdd_err("Failed to set miracastn scan");
4676 return -EBUSY;
4677 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004678
Dustin Brown1dbefe62018-09-11 16:32:03 -07004679 if (policy_mgr_is_mcc_in_24G(hdd_ctx->psoc))
Jeff Johnson3dd8a542019-02-26 21:38:14 -08004680 return wlan_hdd_set_mas(adapter, filter_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004681
4682exit:
4683 return ret;
4684}
4685
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004686/* Function header is left blank intentionally */
4687static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4688 int32_t *oui_length, int32_t limit)
4689{
4690 uint8_t len;
4691 uint8_t data;
4692
4693 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4694 command++;
4695 limit--;
4696 }
4697
4698 len = 2;
4699
4700 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4701 (limit > 1)) {
4702 sscanf(command, "%02x", (unsigned int *)&data);
4703 ie[len++] = data;
4704 command += 2;
4705 limit -= 2;
4706 }
4707
4708 *oui_length = len - 2;
4709
4710 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4711 command++;
4712 limit--;
4713 }
4714
4715 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4716 (limit > 1)) {
4717 sscanf(command, "%02x", (unsigned int *)&data);
4718 ie[len++] = data;
4719 command += 2;
4720 limit -= 2;
4721 }
4722
Srinivas Girigowda8e7ecab2019-05-16 11:31:19 -07004723 ie[0] = WLAN_ELEMID_VENDOR;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004724 ie[1] = len - 2;
4725
4726 return len;
4727}
4728
4729/**
4730 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4731 * @adapter: Pointer to adapter
4732 * @hdd_ctx: Pointer to HDD context
4733 * @command: Pointer to command string
4734 * @command_len : Command length
4735 * @priv_data : Pointer to priv data
4736 *
4737 * Return:
4738 * int status code
4739 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07004740static int drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004741 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004742 uint8_t *command,
4743 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004744 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004745{
4746 int i = 0;
4747 int status;
4748 int ret = 0;
4749 uint8_t *ibss_ie;
4750 int32_t oui_length = 0;
4751 uint32_t ibss_ie_length;
4752 uint8_t *value = command;
Jeff Johnson7964a112019-02-26 18:24:12 -08004753 tSirModifyIE modify_ie;
Jeff Johnson61b5e982018-03-15 11:33:31 -07004754 struct csr_roam_profile *roam_profile;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004755 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004756
Krunal Sonibe766b02016-03-10 13:00:44 -08004757 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004758 hdd_debug("Device_mode %s(%d) not IBSS",
Dustin Brown458027c2018-10-19 12:26:27 -07004759 qdf_opmode_str(adapter->device_mode),
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004760 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004761 return ret;
4762 }
4763
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004764 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004765
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004766 /* validate argument of command */
4767 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004768 hdd_err("No arguments in command length %zu",
4769 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004770 ret = -EFAULT;
4771 goto exit;
4772 }
4773
4774 /* moving to arguments of commands */
4775 value = value + command_len;
4776 command_len = strlen(value);
4777
4778 /* oui_data can't be less than 3 bytes */
4779 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004780 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4781 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004782 ret = -EFAULT;
4783 goto exit;
4784 }
4785
4786 ibss_ie = qdf_mem_malloc(command_len);
4787 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004788 hdd_err("Could not allocate memory for command length %d",
4789 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004790 ret = -ENOMEM;
4791 goto exit;
4792 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004793
4794 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4795 &oui_length,
4796 command_len);
4797 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004798 hdd_err("Could not parse command %s return length %d",
4799 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004800 ret = -EFAULT;
4801 qdf_mem_free(ibss_ie);
4802 goto exit;
4803 }
4804
Jeff Johnson8313b9d2018-03-14 15:09:28 -07004805 roam_profile = hdd_roam_profile(adapter);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004806
Jeff Johnson7964a112019-02-26 18:24:12 -08004807 qdf_copy_macaddr(&modify_ie.bssid,
Jeff Johnson5b34fce2017-10-13 13:24:51 -07004808 roam_profile->BSSIDs.bssid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004809
Jeff Johnson7964a112019-02-26 18:24:12 -08004810 modify_ie.smeSessionId = adapter->vdev_id;
4811 modify_ie.notify = true;
Srinivas Girigowda8e7ecab2019-05-16 11:31:19 -07004812 modify_ie.ieID = WLAN_ELEMID_VENDOR;
Jeff Johnson7964a112019-02-26 18:24:12 -08004813 modify_ie.ieIDLen = ibss_ie_length;
4814 modify_ie.ieBufferlength = ibss_ie_length;
4815 modify_ie.pIEBuffer = ibss_ie;
4816 modify_ie.oui_length = oui_length;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004817
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004818 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4819 ibss_ie_length, oui_length);
Jeff Johnson7964a112019-02-26 18:24:12 -08004820 while (i < modify_ie.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004821 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004822
4823 /* Probe Bcn modification */
Jeff Johnsond549efa2018-06-13 20:27:47 -07004824 mac_handle = hdd_ctx->mac_handle;
Jeff Johnson7964a112019-02-26 18:24:12 -08004825 sme_modify_add_ie(mac_handle, &modify_ie, eUPDATE_IE_PROBE_BCN);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004826
4827 /* Populating probe resp frame */
Jeff Johnson7964a112019-02-26 18:24:12 -08004828 sme_modify_add_ie(mac_handle, &modify_ie, eUPDATE_IE_PROBE_RESP);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004829
4830 qdf_mem_free(ibss_ie);
4831
Jeff Johnsond549efa2018-06-13 20:27:47 -07004832 status = sme_send_cesium_enable_ind(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08004833 adapter->vdev_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004834 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004835 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004836 status);
4837 ret = -EINVAL;
4838 goto exit;
4839 }
4840
4841exit:
4842 return ret;
4843}
4844
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304845#ifdef FEATURE_WLAN_RMC
4846/* Function header is left blank intentionally */
Jeff Johnson6636e622019-02-26 10:22:39 -08004847static int hdd_parse_setrmcenable_command(uint8_t *command,
Jeff Johnson259f3e92019-02-26 13:36:01 -08004848 uint8_t *rmc_enable)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304849{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004850 uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08004851 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304852 int v = 0;
4853 char buf[32];
Jeff Johnson259f3e92019-02-26 13:36:01 -08004854 *rmc_enable = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304855
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004856 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304857
Jeff Johnsond36fa332019-03-18 13:42:25 -07004858 if (!in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304859 return 0;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004860 else if (SPACE_ASCII_VALUE != *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304861 return 0;
4862
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004863 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
4864 in_ptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304865
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004866 if ('\0' == *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304867 return 0;
4868
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004869 v = sscanf(in_ptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304870 if (1 != v)
4871 return -EINVAL;
4872
Jeff Johnsoncd361c92019-02-26 19:23:49 -08004873 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304874 if (v < 0)
4875 return -EINVAL;
4876
Jeff Johnsoncd361c92019-02-26 19:23:49 -08004877 *rmc_enable = temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304878
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08004879 hdd_debug("rmc_enable: %d", *rmc_enable);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304880
4881 return 0;
4882}
4883
4884/* Function header is left blank intentionally */
Wu Gao1ab05582018-11-08 16:22:49 +08004885static int hdd_parse_setrmcactionperiod_command(uint8_t *pvalue,
4886 uint32_t *paction_period)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304887{
Wu Gao1ab05582018-11-08 16:22:49 +08004888 uint8_t *inptr = pvalue;
4889 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304890 int v = 0;
4891 char buf[32];
Wu Gao1ab05582018-11-08 16:22:49 +08004892 *paction_period = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304893
Wu Gao1ab05582018-11-08 16:22:49 +08004894 inptr = strnchr(pvalue, strlen(pvalue), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304895
Jeff Johnsond36fa332019-03-18 13:42:25 -07004896 if (!inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304897 return -EINVAL;
Wu Gao1ab05582018-11-08 16:22:49 +08004898 else if (SPACE_ASCII_VALUE != *inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304899 return -EINVAL;
4900
Wu Gao1ab05582018-11-08 16:22:49 +08004901 while ((SPACE_ASCII_VALUE == *inptr) && ('\0' != *inptr))
4902 inptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304903
Wu Gao1ab05582018-11-08 16:22:49 +08004904 if ('\0' == *inptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304905 return 0;
4906
Wu Gao1ab05582018-11-08 16:22:49 +08004907 v = sscanf(inptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304908 if (1 != v)
4909 return -EINVAL;
4910
Wu Gao1ab05582018-11-08 16:22:49 +08004911 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304912 if (v < 0)
4913 return -EINVAL;
4914
Wu Gao1ab05582018-11-08 16:22:49 +08004915 if (!cfg_in_range(CFG_RMC_ACTION_PERIOD_FREQUENCY, temp_int))
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304916 return -EINVAL;
4917
Wu Gao1ab05582018-11-08 16:22:49 +08004918 *paction_period = temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304919
Jeff Johnson3972e0d2019-02-26 19:42:35 -08004920 hdd_debug("action_period: %d", *paction_period);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304921
4922 return 0;
4923}
4924
4925/* Function header is left blank intentionally */
Jeff Johnson6636e622019-02-26 10:22:39 -08004926static int hdd_parse_setrmcrate_command(uint8_t *command,
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08004927 uint32_t *rate,
Jeff Johnson269d7fb2019-02-26 10:47:33 -08004928 enum tx_rate_info *tx_flags)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304929{
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004930 uint8_t *in_ptr = command;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08004931 int temp_int;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304932 int v = 0;
4933 char buf[32];
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08004934 *rate = 0;
Jeff Johnson269d7fb2019-02-26 10:47:33 -08004935 *tx_flags = 0;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304936
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004937 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304938
Jeff Johnsond36fa332019-03-18 13:42:25 -07004939 if (!in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304940 return -EINVAL;
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004941 else if (SPACE_ASCII_VALUE != *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304942 return -EINVAL;
4943
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004944 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
4945 in_ptr++;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304946
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004947 if ('\0' == *in_ptr)
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304948 return 0;
4949
Jeff Johnson4ff36b22019-02-26 13:01:07 -08004950 v = sscanf(in_ptr, "%31s ", buf);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304951 if (1 != v)
4952 return -EINVAL;
4953
Jeff Johnsoncd361c92019-02-26 19:23:49 -08004954 v = kstrtos32(buf, 10, &temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304955 if (v < 0)
4956 return -EINVAL;
4957
Jeff Johnsoncd361c92019-02-26 19:23:49 -08004958 switch (temp_int) {
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304959 default:
Jeff Johnsoncd361c92019-02-26 19:23:49 -08004960 hdd_warn("Unsupported rate: %d", temp_int);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304961 return -EINVAL;
4962 case 0:
4963 case 6:
4964 case 9:
4965 case 12:
4966 case 18:
4967 case 24:
4968 case 36:
4969 case 48:
4970 case 54:
Jeff Johnson269d7fb2019-02-26 10:47:33 -08004971 *tx_flags = TX_RATE_LEGACY;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08004972 *rate = temp_int * 10;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304973 break;
4974 case 65:
Jeff Johnson269d7fb2019-02-26 10:47:33 -08004975 *tx_flags = TX_RATE_HT20;
Jeff Johnsoncd361c92019-02-26 19:23:49 -08004976 *rate = temp_int * 10;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304977 break;
4978 case 72:
Jeff Johnson269d7fb2019-02-26 10:47:33 -08004979 *tx_flags = TX_RATE_HT20 | TX_RATE_SGI;
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08004980 *rate = 722;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304981 break;
4982 }
4983
Jeff Johnsonb9f9b282019-02-26 13:40:32 -08004984 hdd_debug("Rate: %d", *rate);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05304985
4986 return 0;
4987}
4988
Jeff Johnsone44b7012017-09-10 15:25:47 -07004989static int drv_cmd_set_rmc_enable(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07004990 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004991 uint8_t *command,
4992 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07004993 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004994{
4995 int ret = 0;
4996 uint8_t *value = command;
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08004997 uint8_t rmc_enable = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004998 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07004999 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005000
Krunal Sonibe766b02016-03-10 13:00:44 -08005001 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5002 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005003 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005004 qdf_opmode_str(adapter->device_mode),
5005 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005006 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005007 ret = -EINVAL;
5008 goto exit;
5009 }
5010
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005011 status = hdd_parse_setrmcenable_command(value, &rmc_enable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005012 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005013 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005014 ret = -EINVAL;
5015 goto exit;
5016 }
5017
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005018 hdd_debug("rmc_enable %d", rmc_enable);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005019 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005020
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005021 if (true == rmc_enable) {
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005022 status = sme_enable_rmc(mac_handle, adapter->vdev_id);
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005023 } else if (false == rmc_enable) {
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005024 status = sme_disable_rmc(mac_handle, adapter->vdev_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005025 } else {
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005026 hdd_err("Invalid SETRMCENABLE command %d", rmc_enable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005027 ret = -EINVAL;
5028 goto exit;
5029 }
5030
5031 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsonf8a0b8f2019-02-26 19:26:31 -08005032 hdd_err("SETRMC %d failed status %d", rmc_enable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005033 ret = -EINVAL;
5034 goto exit;
5035 }
5036
5037exit:
5038 return ret;
5039}
5040
Jeff Johnsone44b7012017-09-10 15:25:47 -07005041static int drv_cmd_set_rmc_action_period(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005042 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005043 uint8_t *command,
5044 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005045 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005046{
5047 int ret = 0;
5048 uint8_t *value = command;
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005049 uint32_t action_period = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005050 int status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005051 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005052
Krunal Sonibe766b02016-03-10 13:00:44 -08005053 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5054 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005055 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005056 qdf_opmode_str(adapter->device_mode),
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005057 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005058 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005059 ret = -EINVAL;
5060 goto exit;
5061 }
5062
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005063 status = hdd_parse_setrmcactionperiod_command(value, &action_period);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005064 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005065 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005066 ret = -EINVAL;
5067 goto exit;
5068 }
5069
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005070 hdd_debug("action_period %d", action_period);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005071 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005072
Dustin Brown05d81302018-09-11 16:49:22 -07005073 if (ucfg_mlme_set_rmc_action_period_freq(hdd_ctx->psoc,
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005074 action_period) !=
Bala Venkatesh2fde2c62018-09-11 20:33:24 +05305075 QDF_STATUS_SUCCESS) {
Jeff Johnson3972e0d2019-02-26 19:42:35 -08005076 hdd_err("Could not set SETRMCACTIONPERIOD %d", action_period);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005077 ret = -EINVAL;
5078 goto exit;
5079 }
5080
Jeff Johnsond549efa2018-06-13 20:27:47 -07005081 status = sme_send_rmc_action_period(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005082 adapter->vdev_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005083 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005084 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005085 status);
5086 ret = -EINVAL;
5087 goto exit;
5088 }
5089
5090exit:
5091 return ret;
5092}
5093
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305094static int drv_cmd_set_rmc_tx_rate(struct hdd_adapter *adapter,
5095 struct hdd_context *hdd_ctx,
5096 uint8_t *command,
5097 uint8_t command_len,
5098 struct hdd_priv_data *priv_data)
5099{
5100 int ret = 0;
5101 uint8_t *value = command;
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005102 uint32_t rate = 0;
Jeff Johnson269d7fb2019-02-26 10:47:33 -08005103 enum tx_rate_info tx_flags = 0;
Jeff Johnson2370b852019-02-26 17:03:12 -08005104 tSirRateUpdateInd params = {0};
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305105 int status;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05305106 bool bval = false;
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305107
5108 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5109 (QDF_SAP_MODE != adapter->device_mode)) {
5110 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005111 qdf_opmode_str(adapter->device_mode),
5112 adapter->device_mode);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305113 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
5114 ret = -EINVAL;
5115 goto exit;
5116 }
5117
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005118 status = hdd_parse_setrmcrate_command(value, &rate, &tx_flags);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305119 if (status) {
5120 hdd_err("Invalid SETRMCTXRATE command");
5121 ret = -EINVAL;
5122 goto exit;
5123 }
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005124 hdd_debug("rate %d", rate);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305125
5126 /*
5127 * Fill the user specifieed RMC rate param
5128 * and the derived tx flags.
5129 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05305130 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
5131 if (!QDF_IS_STATUS_SUCCESS(status)) {
5132 hdd_err("unable to get vht_enable2x2");
5133 ret = -EINVAL;
5134 goto exit;
5135 }
Jeff Johnson2370b852019-02-26 17:03:12 -08005136 params.nss = (bval == 0) ? 0 : 1;
Jeff Johnsonaf5283f2019-02-26 19:31:48 -08005137 params.reliableMcastDataRate = rate;
Jeff Johnson2370b852019-02-26 17:03:12 -08005138 params.reliableMcastDataRateTxFlag = tx_flags;
5139 params.dev_mode = adapter->device_mode;
5140 params.bcastDataRate = -1;
5141 memcpy(params.bssid.bytes,
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305142 adapter->mac_addr.bytes,
Jeff Johnson2370b852019-02-26 17:03:12 -08005143 sizeof(params.bssid));
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305144 status = sme_send_rate_update_ind(hdd_ctx->mac_handle,
Jeff Johnson2370b852019-02-26 17:03:12 -08005145 &params);
Rachit Kankaneee1735c2018-08-02 13:19:34 +05305146
5147exit:
5148 return ret;
5149}
5150#endif /* FEATURE_WLAN_RMC */
5151
Jeff Johnsone44b7012017-09-10 15:25:47 -07005152static int drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005153 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005154 uint8_t *command,
5155 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005156 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005157{
5158 int ret = 0;
5159 int status = QDF_STATUS_SUCCESS;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005160 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005161 char *extra = NULL;
5162 int idx = 0;
5163 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005164 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Jeff Johnson0e5369e2019-02-26 21:54:26 -08005165 uint32_t print_break_index = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005166
Krunal Sonibe766b02016-03-10 13:00:44 -08005167 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005168 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005169 qdf_opmode_str(adapter->device_mode),
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005170 adapter->device_mode);
5171 return -EINVAL;
5172 }
5173
Jeff Johnsond377dce2017-10-04 10:32:42 -07005174 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005175 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005176
5177 /* Handle the command */
5178 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5179 if (QDF_STATUS_SUCCESS == status) {
Dustin Brownc8e96f12018-04-19 09:27:42 -07005180 size_t user_size = qdf_min(WLAN_MAX_BUF_SIZE,
5181 priv_data->total_len);
5182
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005183 /*
5184 * The variable extra needed to be allocated on the heap since
5185 * amount of memory required to copy the data for 32 devices
5186 * exceeds the size of 1024 bytes of default stack size. On
5187 * 64 bit devices, the default max stack size of 2048 bytes
5188 */
Dustin Brownc8e96f12018-04-19 09:27:42 -07005189 extra = qdf_mem_malloc(user_size);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005190
Jeff Johnsond36fa332019-03-18 13:42:25 -07005191 if (!extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005192 hdd_err("memory allocation failed");
5193 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005194 goto exit;
5195 }
5196
5197 /* Copy number of stations */
Dustin Brownc8e96f12018-04-19 09:27:42 -07005198 length = scnprintf(extra, user_size, "%d ",
Jeff Johnsond377dce2017-10-04 10:32:42 -07005199 sta_ctx->ibss_peer_info.numPeers);
Jeff Johnson0e5369e2019-02-26 21:54:26 -08005200 print_break_index = length;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005201 for (idx = 0; idx < sta_ctx->ibss_peer_info.numPeers;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005202 idx++) {
5203 int8_t rssi;
5204 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005205
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005206 qdf_mem_copy(mac_addr,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005207 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005208 mac_addr, sizeof(mac_addr));
5209
5210 tx_rate =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005211 sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005212 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305213 /*
5214 * Only lower 3 bytes are rate info. Mask of the MSByte
5215 */
5216 tx_rate &= 0x00FFFFFF;
5217
Jeff Johnsond377dce2017-10-04 10:32:42 -07005218 rssi = sta_ctx->ibss_peer_info.peerInfoParams[idx].
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005219 rssi;
5220
Dustin Brownc8e96f12018-04-19 09:27:42 -07005221 length += scnprintf(extra + length,
5222 user_size - length,
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -07005223 QDF_MAC_ADDR_STR" %d %d ",
5224 QDF_MAC_ADDR_ARRAY(mac_addr),
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005225 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005226 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005227 * cdf_trace_msg has limitation of 512 bytes for the
5228 * print buffer. Hence printing the data in two chunks.
5229 * The first chunk will have the data for 16 devices
5230 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005231 */
5232 if (idx < NUM_OF_STA_DATA_TO_PRINT)
Jeff Johnson0e5369e2019-02-26 21:54:26 -08005233 print_break_index = length;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005234 }
5235
5236 /*
5237 * Copy the data back into buffer, if the data to copy is
5238 * more than 512 bytes than we will split the data and do
5239 * it in two shots
5240 */
Jeff Johnson0e5369e2019-02-26 21:54:26 -08005241 if (copy_to_user(priv_data->buf, extra, print_break_index)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005242 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005243 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305244 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005245 }
5246
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005247 /* This overwrites the last space, which we already copied */
Jeff Johnson0e5369e2019-02-26 21:54:26 -08005248 extra[print_break_index - 1] = '\0';
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005249 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005250
Jeff Johnson0e5369e2019-02-26 21:54:26 -08005251 if (length > print_break_index) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005252 if (copy_to_user
Jeff Johnson0e5369e2019-02-26 21:54:26 -08005253 (priv_data->buf + print_break_index,
5254 extra + print_break_index,
5255 length - print_break_index + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005256 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005257 ret = -EFAULT;
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305258 goto mem_free;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005259 }
Jeff Johnson0e5369e2019-02-26 21:54:26 -08005260 hdd_debug("%s", &extra[print_break_index]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005261 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005262 } else {
5263 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005264 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5265 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005266 ret = -EINVAL;
5267 goto exit;
5268 }
5269 ret = 0;
5270
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +05305271mem_free:
5272 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005273exit:
5274 return ret;
5275}
5276
5277/* Peer Info <Peer Addr> command */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005278static int drv_cmd_get_ibss_peer_info(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005279 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005280 uint8_t *command,
5281 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005282 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005283{
5284 int ret = 0;
5285 uint8_t *value = command;
5286 QDF_STATUS status;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005287 struct hdd_station_ctx *sta_ctx = NULL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005288 char extra[128] = { 0 };
5289 uint32_t length = 0;
Jeff Johnson0a082d92019-03-04 12:25:49 -08005290 uint8_t sta_id = 0;
Jeff Johnson2d044612019-02-26 20:08:43 -08005291 struct qdf_mac_addr peer_macaddr;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005292
Krunal Sonibe766b02016-03-10 13:00:44 -08005293 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005294 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005295 qdf_opmode_str(adapter->device_mode),
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005296 adapter->device_mode);
5297 return -EINVAL;
5298 }
5299
Jeff Johnsond377dce2017-10-04 10:32:42 -07005300 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005301
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005302 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005303
5304 /* if there are no peers, no need to continue with the command */
5305 if (eConnectionState_IbssConnected !=
Jeff Johnsone7951512019-02-27 10:02:51 -08005306 sta_ctx->conn_info.conn_state) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005307 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005308 ret = -EINVAL;
5309 goto exit;
5310 }
5311
5312 /* Parse the incoming command buffer */
Jeff Johnson2d044612019-02-26 20:08:43 -08005313 status = hdd_parse_get_ibss_peer_info(value, &peer_macaddr);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005314 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005315 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005316 ret = -EINVAL;
5317 goto exit;
5318 }
5319
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005320 /* Get station index for the peer mac address and sanitize it */
Jeff Johnson0a082d92019-03-04 12:25:49 -08005321 hdd_get_peer_sta_id(sta_ctx, &peer_macaddr, &sta_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005322
Jeff Johnson0a082d92019-03-04 12:25:49 -08005323 if (sta_id > MAX_PEERS) {
5324 hdd_err("Invalid StaIdx %d returned", sta_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005325 ret = -EINVAL;
5326 goto exit;
5327 }
5328
5329 /* Handle the command */
Jeff Johnson0a082d92019-03-04 12:25:49 -08005330 status = hdd_cfg80211_get_ibss_peer_info(adapter, sta_id);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005331 if (QDF_STATUS_SUCCESS == status) {
Jeff Johnsona464bf22019-02-26 21:41:48 -08005332 uint32_t tx_rate =
Jeff Johnsond377dce2017-10-04 10:32:42 -07005333 sta_ctx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305334 /* Only lower 3 bytes are rate info. Mask of the MSByte */
Jeff Johnsona464bf22019-02-26 21:41:48 -08005335 tx_rate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005336
5337 length = scnprintf(extra, sizeof(extra), "%d %d",
Jeff Johnsona464bf22019-02-26 21:41:48 -08005338 (int)tx_rate,
Jeff Johnsond377dce2017-10-04 10:32:42 -07005339 (int)sta_ctx->ibss_peer_info.
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005340 peerInfoParams[0].rssi);
Jingxiang Ge03e2b592019-01-23 17:15:53 +08005341 length = QDF_MIN(priv_data->total_len, length + 1);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005342
5343 /* Copy the data back into buffer */
Jingxiang Ge03e2b592019-01-23 17:15:53 +08005344 if (copy_to_user(priv_data->buf, &extra, length)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005345 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005346 ret = -EFAULT;
5347 goto exit;
5348 }
5349 } else {
5350 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005351 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5352 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005353 ret = -EINVAL;
5354 goto exit;
5355 }
5356
5357 /* Success ! */
Rajeev Kumar Sirasanagandla92ec9d92018-04-24 21:33:06 +05305358 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005359 ret = 0;
5360
5361exit:
5362 return ret;
5363}
5364
Jeff Johnsone44b7012017-09-10 15:25:47 -07005365static int drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005366 struct hdd_context *hdd_ctx,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005367 uint8_t *command,
5368 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005369 struct hdd_priv_data *priv_data)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005370{
5371 int ret = 0;
5372 char *value;
5373 uint8_t tx_fail_count = 0;
5374 uint16_t pid = 0;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005375 mac_handle_t mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005376
5377 value = command;
5378
5379 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5380
5381 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005382 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005383 goto exit;
5384 }
5385
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005386 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005387 mac_handle = hdd_ctx->mac_handle;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005388
5389 if (0 == tx_fail_count) {
5390 /* Disable TX Fail Indication */
5391 if (QDF_STATUS_SUCCESS ==
Jeff Johnsond549efa2018-06-13 20:27:47 -07005392 sme_tx_fail_monitor_start_stop_ind(mac_handle,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005393 tx_fail_count,
5394 NULL)) {
5395 cesium_pid = 0;
5396 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005397 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005398 ret = -EINVAL;
5399 }
5400 } else {
5401 if (QDF_STATUS_SUCCESS ==
Jeff Johnsond549efa2018-06-13 20:27:47 -07005402 sme_tx_fail_monitor_start_stop_ind(mac_handle,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005403 tx_fail_count,
5404 (void *)hdd_tx_fail_ind_callback)) {
5405 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005406 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005407 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005408 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005409 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005410 ret = -EINVAL;
5411 }
5412 }
5413
5414exit:
5415 return ret;
5416}
5417
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005418#ifdef FEATURE_WLAN_ESE
Jeff Johnsone44b7012017-09-10 15:25:47 -07005419static int drv_cmd_set_ccx_roam_scan_channels(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005420 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005421 uint8_t *command,
5422 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005423 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005424{
5425 int ret = 0;
5426 uint8_t *value = command;
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005427 uint8_t channel_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5428 uint8_t num_channels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305429 QDF_STATUS status;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005430 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005431
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005432 ret = hdd_parse_channellist(value, channel_list, &num_channels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005433 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005434 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005435 goto exit;
5436 }
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005437 if (num_channels > CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005438 hdd_err("number of channels (%d) supported exceeded max (%d)",
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005439 num_channels,
5440 CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005441 ret = -EINVAL;
5442 goto exit;
5443 }
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305444
Jeff Johnsond549efa2018-06-13 20:27:47 -07005445 mac_handle = hdd_ctx->mac_handle;
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005446 if (!sme_validate_channel_list(mac_handle, channel_list,
5447 num_channels)) {
Vignesh Viswanathana2f5ce582018-05-09 20:38:39 +05305448 hdd_err("List contains invalid channel(s)");
5449 ret = -EINVAL;
5450 goto exit;
5451 }
5452
Jeff Johnsond549efa2018-06-13 20:27:47 -07005453 status = sme_set_ese_roam_scan_channel_list(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005454 adapter->vdev_id,
Jeff Johnson8a2e1da2019-02-26 17:56:24 -08005455 channel_list,
5456 num_channels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305457 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005458 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005459 ret = -EINVAL;
5460 goto exit;
5461 }
5462
5463exit:
5464 return ret;
5465}
5466
Jeff Johnsone44b7012017-09-10 15:25:47 -07005467static int drv_cmd_get_tsm_stats(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005468 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005469 uint8_t *command,
5470 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005471 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005472{
5473 int ret = 0;
5474 uint8_t *value = command;
5475 char extra[128] = { 0 };
5476 int len = 0;
5477 uint8_t tid = 0;
Jeff Johnsond377dce2017-10-04 10:32:42 -07005478 struct hdd_station_ctx *sta_ctx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005479 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005480
Krunal Sonibe766b02016-03-10 13:00:44 -08005481 if ((QDF_STA_MODE != adapter->device_mode) &&
5482 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005483 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005484 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005485 adapter->device_mode);
5486 return -EINVAL;
5487 }
5488
Jeff Johnsond377dce2017-10-04 10:32:42 -07005489 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005490
5491 /* if not associated, return error */
Jeff Johnsone7951512019-02-27 10:02:51 -08005492 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005493 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005494 ret = -EINVAL;
5495 goto exit;
5496 }
5497
5498 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5499 value = value + command_len + 1;
5500
5501 /* Convert the value from ascii to integer */
5502 ret = kstrtou8(value, 10, &tid);
5503 if (ret < 0) {
5504 /*
5505 * If the input value is greater than max value of datatype,
5506 * then also kstrtou8 fails
5507 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005508 hdd_err("kstrtou8 failed range [%d - %d]",
5509 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005510 TID_MAX_VALUE);
5511 ret = -EINVAL;
5512 goto exit;
5513 }
5514 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005515 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005516 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5517 ret = -EINVAL;
5518 goto exit;
5519 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005520 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005521 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005522 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5523 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005524 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005525 goto exit;
5526 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005527 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005528 "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 -08005529 tsm_metrics.UplinkPktQueueDly,
5530 tsm_metrics.UplinkPktQueueDlyHist[0],
5531 tsm_metrics.UplinkPktQueueDlyHist[1],
5532 tsm_metrics.UplinkPktQueueDlyHist[2],
5533 tsm_metrics.UplinkPktQueueDlyHist[3],
5534 tsm_metrics.UplinkPktTxDly,
5535 tsm_metrics.UplinkPktLoss,
5536 tsm_metrics.UplinkPktCount,
5537 tsm_metrics.RoamingCount,
5538 tsm_metrics.RoamingDly);
5539 /*
5540 * Output TSM stats is of the format
5541 * GETTSMSTATS [PktQueueDly]
5542 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5543 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5544 */
5545 len = scnprintf(extra,
5546 sizeof(extra),
5547 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5548 command,
5549 tsm_metrics.UplinkPktQueueDly,
5550 tsm_metrics.UplinkPktQueueDlyHist[0],
5551 tsm_metrics.UplinkPktQueueDlyHist[1],
5552 tsm_metrics.UplinkPktQueueDlyHist[2],
5553 tsm_metrics.UplinkPktQueueDlyHist[3],
5554 tsm_metrics.UplinkPktTxDly,
5555 tsm_metrics.UplinkPktLoss,
5556 tsm_metrics.UplinkPktCount,
5557 tsm_metrics.RoamingCount,
5558 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305559 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005560 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005561 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005562 ret = -EFAULT;
5563 goto exit;
5564 }
5565
5566exit:
5567 return ret;
5568}
5569
Jeff Johnsone44b7012017-09-10 15:25:47 -07005570static int drv_cmd_set_cckm_ie(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005571 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005572 uint8_t *command,
5573 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005574 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005575{
5576 int ret;
5577 uint8_t *value = command;
Jeff Johnson264e2d32019-02-26 13:16:58 -08005578 uint8_t *cckm_ie = NULL;
Jeff Johnsonb9eeef32019-02-26 13:15:49 -08005579 uint8_t cckm_ie_len = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005580
Jeff Johnson264e2d32019-02-26 13:16:58 -08005581 ret = hdd_parse_get_cckm_ie(value, &cckm_ie, &cckm_ie_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005582 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005583 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005584 goto exit;
5585 }
5586
Jeff Johnsonb9eeef32019-02-26 13:15:49 -08005587 if (cckm_ie_len > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005588 hdd_err("CCKM Ie input length is more than max[%d]",
5589 DOT11F_IE_RSN_MAX_LEN);
Jeff Johnsond36fa332019-03-18 13:42:25 -07005590 if (cckm_ie) {
Jeff Johnson264e2d32019-02-26 13:16:58 -08005591 qdf_mem_free(cckm_ie);
5592 cckm_ie = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005593 }
5594 ret = -EINVAL;
5595 goto exit;
5596 }
5597
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005598 sme_set_cckm_ie(hdd_ctx->mac_handle, adapter->vdev_id,
Jeff Johnson264e2d32019-02-26 13:16:58 -08005599 cckm_ie, cckm_ie_len);
Jeff Johnsond36fa332019-03-18 13:42:25 -07005600 if (cckm_ie) {
Jeff Johnson264e2d32019-02-26 13:16:58 -08005601 qdf_mem_free(cckm_ie);
5602 cckm_ie = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005603 }
5604
5605exit:
5606 return ret;
5607}
5608
Jeff Johnsone44b7012017-09-10 15:25:47 -07005609static int drv_cmd_ccx_beacon_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005610 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005611 uint8_t *command,
5612 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005613 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005614{
5615 int ret;
5616 uint8_t *value = command;
Jeff Johnson210bc972019-02-26 19:55:01 -08005617 tCsrEseBeaconReq req = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305618 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005619
Krunal Sonibe766b02016-03-10 13:00:44 -08005620 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005621 hdd_warn("Unsupported in mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005622 qdf_opmode_str(adapter->device_mode),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005623 adapter->device_mode);
5624 return -EINVAL;
5625 }
5626
Jeff Johnson210bc972019-02-26 19:55:01 -08005627 ret = hdd_parse_ese_beacon_req(value, &req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005628 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005629 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005630 goto exit;
5631 }
5632
5633 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005634 hdd_debug("Not associated");
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305635
Jeff Johnson210bc972019-02-26 19:55:01 -08005636 if (!req.numBcnReqIe)
Rajeev Kumar Sirasanagandla8413a482018-04-19 18:02:45 +05305637 return -EINVAL;
5638
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005639 hdd_indicate_ese_bcn_report_no_results(adapter,
Jeff Johnson210bc972019-02-26 19:55:01 -08005640 req.bcnReq[0].measurementToken,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005641 0x02, /* BIT(1) set for measurement done */
5642 0); /* no BSS */
5643 goto exit;
5644 }
5645
Jeff Johnsond549efa2018-06-13 20:27:47 -07005646 status = sme_set_ese_beacon_request(hdd_ctx->mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005647 adapter->vdev_id,
Jeff Johnson210bc972019-02-26 19:55:01 -08005648 &req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005649
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305650 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005651 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005652 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005653 ret = -EBUSY;
5654 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305655 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005656 hdd_err("sme_set_ese_beacon_request failed (%d)",
5657 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005658 ret = -EINVAL;
5659 goto exit;
5660 }
5661
5662exit:
5663 return ret;
5664}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005665
5666/**
5667 * drv_cmd_ccx_plm_req() - Set ESE PLM request
Jeff Johnson36583f02019-02-26 08:02:11 -08005668 * @adapter: Pointer to the HDD adapter
5669 * @hdd_ctx: Pointer to the HDD context
5670 * @command: Driver command string
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005671 * @command_len: Driver command string length
Jeff Johnson36583f02019-02-26 08:02:11 -08005672 * @priv_data: Private data coming with the driver command. Unused here
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005673 *
5674 * This function handles driver command that sets the ESE PLM request
5675 *
5676 * Return: 0 on success; negative errno otherwise
5677 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005678static int drv_cmd_ccx_plm_req(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005679 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005680 uint8_t *command,
5681 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005682 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005683{
Jeff Johnson36583f02019-02-26 08:02:11 -08005684 QDF_STATUS status;
5685 struct plm_req_params *req;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005686
Jeff Johnson36583f02019-02-26 08:02:11 -08005687 req = qdf_mem_malloc(sizeof(*req));
5688 if (!req)
5689 return -ENOMEM;
5690
5691 status = hdd_parse_plm_cmd(command, req);
5692 if (QDF_IS_STATUS_SUCCESS(status)) {
5693 req->vdev_id = adapter->vdev_id;
5694 status = sme_set_plm_request(hdd_ctx->mac_handle, req);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005695 }
Jeff Johnson36583f02019-02-26 08:02:11 -08005696 qdf_mem_free(req);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005697
Jeff Johnson36583f02019-02-26 08:02:11 -08005698 return qdf_status_to_os_return(status);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005699}
5700
5701/**
5702 * drv_cmd_set_ccx_mode() - Set ESE mode
5703 * @adapter: Pointer to the HDD adapter
5704 * @hdd_ctx: Pointer to the HDD context
5705 * @command: Driver command string
5706 * @command_len: Driver command string length
5707 * @priv_data: Private data coming with the driver command. Unused here
5708 *
5709 * This function handles driver command that sets ESE mode
5710 *
5711 * Return: 0 on success; negative errno otherwise
5712 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07005713static int drv_cmd_set_ccx_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005714 struct hdd_context *hdd_ctx,
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005715 uint8_t *command,
5716 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005717 struct hdd_priv_data *priv_data)
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005718{
5719 int ret = 0;
5720 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08005721 uint8_t ese_mode = cfg_default(CFG_LFR_ESE_FEATURE_ENABLED);
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005722 struct pmkid_mode_bits pmkid_modes;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005723 mac_handle_t mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005724
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005725 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005726 mac_handle = hdd_ctx->mac_handle;
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005727 /*
5728 * Check if the features OKC/ESE/11R are supported simultaneously,
5729 * then this operation is not permitted (return FAILURE)
5730 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005731 if (sme_get_is_ese_feature_enabled(mac_handle) &&
Deepak Dhamdhere828f1892017-02-09 11:51:19 -08005732 pmkid_modes.fw_okc &&
Jeff Johnsond549efa2018-06-13 20:27:47 -07005733 sme_get_is_ft_feature_enabled(mac_handle)) {
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005734 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5735 ret = -EPERM;
5736 goto exit;
5737 }
5738
5739 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5740 value = value + command_len + 1;
5741
5742 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08005743 ret = kstrtou8(value, 10, &ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005744 if (ret < 0) {
5745 /*
5746 * If the input value is greater than max value of datatype,
5747 * then also kstrtou8 fails
5748 */
5749 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08005750 cfg_min(CFG_LFR_ESE_FEATURE_ENABLED),
5751 cfg_max(CFG_LFR_ESE_FEATURE_ENABLED));
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005752 ret = -EINVAL;
5753 goto exit;
5754 }
5755
Wu Gao1ab05582018-11-08 16:22:49 +08005756 hdd_debug("Received Command to change ese mode = %d", ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005757
Jeff Johnsond549efa2018-06-13 20:27:47 -07005758 sme_update_is_ese_feature_enabled(mac_handle,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005759 adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08005760 ese_mode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005761
5762exit:
5763 return ret;
5764}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005765#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005766
Jeff Johnsone44b7012017-09-10 15:25:47 -07005767static int drv_cmd_set_mc_rate(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005768 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005769 uint8_t *command,
5770 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005771 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005772{
5773 int ret = 0;
5774 uint8_t *value = command;
Srinivas Girigowda9d550152019-03-26 12:19:45 -07005775 uint32_t target_rate = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005776
5777 /* input value is in units of hundred kbps */
5778
5779 /* Move pointer to ahead of SETMCRATE<delimiter> */
5780 value = value + command_len + 1;
5781
5782 /* Convert the value from ascii to integer, decimal base */
Jeff Johnsond549efa2018-06-13 20:27:47 -07005783 ret = kstrtouint(value, 10, &target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005784
Jeff Johnsond549efa2018-06-13 20:27:47 -07005785 ret = wlan_hdd_set_mc_rate(adapter, target_rate);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005786 return ret;
5787}
5788
Jeff Johnsone44b7012017-09-10 15:25:47 -07005789static int drv_cmd_max_tx_power(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005790 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005791 uint8_t *command,
5792 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005793 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005794{
Jeff Johnsond549efa2018-06-13 20:27:47 -07005795 int ret;
5796 int tx_power;
5797 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005798 uint8_t *value = command;
Dustin Brownce5b3d32018-01-17 15:07:38 -08005799 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
Jeff Johnsond549efa2018-06-13 20:27:47 -07005800 struct qdf_mac_addr selfmac = QDF_MAC_ADDR_BCAST_INIT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005801
Jeff Johnsond549efa2018-06-13 20:27:47 -07005802 ret = hdd_parse_setmaxtxpower_command(value, &tx_power);
5803 if (ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005804 hdd_err("Invalid MAXTXPOWER command");
Jeff Johnsond549efa2018-06-13 20:27:47 -07005805 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005806 }
5807
Dustin Brown920397d2017-12-13 16:27:50 -08005808 hdd_for_each_adapter(hdd_ctx, adapter) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005809 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305810 qdf_copy_macaddr(&bssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005811 &adapter->mac_addr);
Jeff Johnsond549efa2018-06-13 20:27:47 -07005812 qdf_copy_macaddr(&selfmac,
Jeff Johnson1e851a12017-10-28 14:36:12 -07005813 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005814
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005815 hdd_debug("Device mode %d max tx power %d selfMac: "
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -07005816 QDF_MAC_ADDR_STR " bssId: " QDF_MAC_ADDR_STR,
Jeff Johnsond549efa2018-06-13 20:27:47 -07005817 adapter->device_mode, tx_power,
Srinivas Girigowda34fbba02019-04-08 12:07:44 -07005818 QDF_MAC_ADDR_ARRAY(selfmac.bytes),
5819 QDF_MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005820
Jeff Johnsond549efa2018-06-13 20:27:47 -07005821 status = sme_set_max_tx_power(hdd_ctx->mac_handle,
5822 bssid, selfmac, tx_power);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305823 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005824 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005825 ret = -EINVAL;
5826 goto exit;
5827 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005828 hdd_debug("Set max tx power success");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005829 }
5830
5831exit:
5832 return ret;
5833}
5834
Jeff Johnsone44b7012017-09-10 15:25:47 -07005835static int drv_cmd_set_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005836 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005837 uint8_t *command,
5838 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005839 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005840{
5841 int ret = 0;
5842 uint8_t *value = command;
Wu Gao1ab05582018-11-08 16:22:49 +08005843 uint8_t dfs_scan_mode = cfg_default(CFG_LFR_ROAMING_DFS_CHANNEL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005844
5845 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5846 value = value + command_len + 1;
5847
5848 /* Convert the value from ascii to integer */
Wu Gao1ab05582018-11-08 16:22:49 +08005849 ret = kstrtou8(value, 10, &dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005850 if (ret < 0) {
5851 /*
5852 * If the input value is greater than max value of datatype,
5853 * then also kstrtou8 fails
5854 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005855 hdd_err("kstrtou8 failed range [%d - %d]",
Wu Gao1ab05582018-11-08 16:22:49 +08005856 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5857 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005858 ret = -EINVAL;
5859 goto exit;
5860 }
5861
Wu Gao1ab05582018-11-08 16:22:49 +08005862 if (!cfg_in_range(CFG_LFR_ROAMING_DFS_CHANNEL, dfs_scan_mode)) {
Jeff Johnson68605512019-02-26 21:30:04 -08005863 hdd_err("dfs_scan_mode value %d is out of range (Min: %d Max: %d)",
Wu Gao1ab05582018-11-08 16:22:49 +08005864 dfs_scan_mode,
5865 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5866 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005867 ret = -EINVAL;
5868 goto exit;
5869 }
5870
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005871 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Wu Gao1ab05582018-11-08 16:22:49 +08005872 dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005873
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005874 /* When DFS scanning is disabled, the DFS channels need to be
5875 * removed from the operation of device.
5876 */
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07005877 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
Wu Gao1ab05582018-11-08 16:22:49 +08005878 dfs_scan_mode != ROAMING_DFS_CHANNEL_DISABLED);
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005879 if (ret < 0) {
5880 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005881 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005882 goto exit;
5883 }
5884
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005885 sme_update_dfs_scan_mode(hdd_ctx->mac_handle, adapter->vdev_id,
Wu Gao1ab05582018-11-08 16:22:49 +08005886 dfs_scan_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005887
5888exit:
5889 return ret;
5890}
5891
Jeff Johnsone44b7012017-09-10 15:25:47 -07005892static int drv_cmd_get_dfs_scan_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005893 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005894 uint8_t *command,
5895 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005896 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005897{
5898 int ret = 0;
Jeff Johnson68605512019-02-26 21:30:04 -08005899 uint8_t dfs_scan_mode = sme_get_dfs_scan_mode(hdd_ctx->mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005900 char extra[32];
5901 uint8_t len = 0;
5902
Jeff Johnson68605512019-02-26 21:30:04 -08005903 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfs_scan_mode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305904 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005905 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005906 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005907 ret = -EFAULT;
5908 }
5909
5910 return ret;
5911}
5912
Jeff Johnsone44b7012017-09-10 15:25:47 -07005913static int drv_cmd_get_link_status(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005914 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005915 uint8_t *command,
5916 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005917 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005918{
5919 int ret = 0;
5920 int value = wlan_hdd_get_link_status(adapter);
5921 char extra[32];
5922 uint8_t len;
5923
5924 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305925 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005926 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005927 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005928 ret = -EFAULT;
5929 }
5930
5931 return ret;
5932}
5933
5934#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Jeff Johnsone44b7012017-09-10 15:25:47 -07005935static int drv_cmd_enable_ext_wow(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005936 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005937 uint8_t *command,
5938 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005939 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005940{
5941 uint8_t *value = command;
5942 int set_value;
5943
5944 /* Move pointer to ahead of ENABLEEXTWOW */
5945 value = value + command_len;
5946
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305947 if (!(sscanf(value, "%d", &set_value))) {
Dustin Browna2868622018-03-20 11:38:14 -07005948 hdd_info("No input identified");
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305949 return -EINVAL;
5950 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005951
5952 return hdd_enable_ext_wow_parser(adapter,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08005953 adapter->vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005954 set_value);
5955}
5956
Jeff Johnsone44b7012017-09-10 15:25:47 -07005957static int drv_cmd_set_app1_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005958 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005959 uint8_t *command,
5960 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005961 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005962{
5963 int ret;
5964 uint8_t *value = command;
5965
5966 /* Move pointer to ahead of SETAPP1PARAMS */
5967 value = value + command_len;
5968
5969 ret = hdd_set_app_type1_parser(adapter,
5970 value, strlen(value));
5971 if (ret >= 0)
5972 hdd_ctx->is_extwow_app_type1_param_set = true;
5973
5974 return ret;
5975}
5976
Jeff Johnsone44b7012017-09-10 15:25:47 -07005977static int drv_cmd_set_app2_params(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07005978 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005979 uint8_t *command,
5980 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07005981 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005982{
5983 int ret;
5984 uint8_t *value = command;
5985
5986 /* Move pointer to ahead of SETAPP2PARAMS */
5987 value = value + command_len;
5988
5989 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5990 if (ret >= 0)
5991 hdd_ctx->is_extwow_app_type2_param_set = true;
5992
5993 return ret;
5994}
5995#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5996
5997#ifdef FEATURE_WLAN_TDLS
5998/**
5999 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
6000 * @adapter: Pointer to the HDD adapter
6001 * @hdd_ctx: Pointer to the HDD context
6002 * @command: Driver command string
6003 * @command_len: Driver command string length
6004 * @priv_data: Private data coming with the driver command. Unused here
6005 *
6006 * This function handles driver command that sets the secondary tdls off channel
6007 * offset
6008 *
6009 * Return: 0 on success; negative errno otherwise
6010 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006011static int drv_cmd_tdls_secondary_channel_offset(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006012 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006013 uint8_t *command,
6014 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006015 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006016{
6017 int ret;
6018 uint8_t *value = command;
6019 int set_value;
6020
6021 /* Move pointer to point the string */
6022 value += command_len;
6023
6024 ret = sscanf(value, "%d", &set_value);
6025 if (ret != 1)
6026 return -EINVAL;
6027
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006028 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006029
Bala Venkatesh113a9e62018-08-30 15:19:02 +05306030 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, adapter, set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006031
6032 return ret;
6033}
6034
6035/**
6036 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
6037 * @adapter: Pointer to the HDD adapter
6038 * @hdd_ctx: Pointer to the HDD context
6039 * @command: Driver command string
6040 * @command_len: Driver command string length
6041 * @priv_data: Private data coming with the driver command. Unused here
6042 *
6043 * This function handles driver command that sets tdls off channel mode
6044 *
6045 * Return: 0 on success; negative errno otherwise
6046 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006047static int drv_cmd_tdls_off_channel_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006048 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006049 uint8_t *command,
6050 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006051 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006052{
6053 int ret;
6054 uint8_t *value = command;
6055 int set_value;
6056
6057 /* Move pointer to point the string */
6058 value += command_len;
6059
6060 ret = sscanf(value, "%d", &set_value);
6061 if (ret != 1)
6062 return -EINVAL;
6063
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006064 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006065
Bala Venkatesh113a9e62018-08-30 15:19:02 +05306066 ret = hdd_set_tdls_offchannelmode(hdd_ctx, adapter, set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006067
6068 return ret;
6069}
6070
6071/**
6072 * drv_cmd_tdls_off_channel() - set tdls off channel number
6073 * @adapter: Pointer to the HDD adapter
6074 * @hdd_ctx: Pointer to the HDD context
6075 * @command: Driver command string
6076 * @command_len: Driver command string length
6077 * @priv_data: Private data coming with the driver command. Unused here
6078 *
6079 * This function handles driver command that sets tdls off channel number
6080 *
6081 * Return: 0 on success; negative errno otherwise
6082 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006083static int drv_cmd_tdls_off_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006084 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006085 uint8_t *command,
6086 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006087 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006088{
6089 int ret;
6090 uint8_t *value = command;
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306091 int channel;
6092 enum channel_state reg_state;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006093
6094 /* Move pointer to point the string */
6095 value += command_len;
6096
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306097 ret = sscanf(value, "%d", &channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006098 if (ret != 1)
6099 return -EINVAL;
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306100 reg_state = wlan_reg_get_channel_state(hdd_ctx->pdev, channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006101
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306102 if (reg_state == CHANNEL_STATE_DFS ||
6103 reg_state == CHANNEL_STATE_DISABLE ||
6104 reg_state == CHANNEL_STATE_INVALID) {
6105 hdd_err("reg state of the channel %d is %d and not supported",
6106 channel, reg_state);
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006107 return -EINVAL;
6108 }
6109
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306110 hdd_debug("Tdls offchannel num: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006111
Bala Venkatesh07546fb2019-07-08 18:29:28 +05306112 ret = hdd_set_tdls_offchannel(hdd_ctx, adapter, channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006113
6114 return ret;
6115}
6116
6117/**
6118 * drv_cmd_tdls_scan() - set tdls scan type
6119 * @adapter: Pointer to the HDD adapter
6120 * @hdd_ctx: Pointer to the HDD context
6121 * @command: Driver command string
6122 * @command_len: Driver command string length
6123 * @priv_data: Private data coming with the driver command. Unused here
6124 *
6125 * This function handles driver command that sets tdls scan type
6126 *
6127 * Return: 0 on success; negative errno otherwise
6128 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006129static int drv_cmd_tdls_scan(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006130 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006131 uint8_t *command,
6132 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006133 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006134{
6135 int ret;
6136 uint8_t *value = command;
6137 int set_value;
6138
6139 /* Move pointer to point the string */
6140 value += command_len;
6141
6142 ret = sscanf(value, "%d", &set_value);
6143 if (ret != 1)
6144 return -EINVAL;
6145
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006146 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006147
6148 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6149
6150 return ret;
6151}
6152#endif
6153
Jeff Johnsone44b7012017-09-10 15:25:47 -07006154static int drv_cmd_get_rssi(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006155 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006156 uint8_t *command,
6157 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006158 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006159{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006160 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006161 int8_t rssi = 0;
6162 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006163
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006164 uint8_t len = 0;
6165
6166 wlan_hdd_get_rssi(adapter, &rssi);
6167
6168 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306169 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006170
6171 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006172 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006173 ret = -EFAULT;
6174 }
6175
6176 return ret;
6177}
6178
Jeff Johnsone44b7012017-09-10 15:25:47 -07006179static int drv_cmd_get_linkspeed(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006180 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006181 uint8_t *command,
6182 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006183 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006184{
6185 int ret;
6186 uint32_t link_speed = 0;
6187 char extra[32];
6188 uint8_t len = 0;
6189
6190 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6191 if (0 != ret)
6192 return ret;
6193
6194 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306195 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006196 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006197 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006198 ret = -EFAULT;
6199 }
6200
6201 return ret;
6202}
6203
Qiwei Cai4505fc62018-05-17 18:35:19 +08006204#ifdef WLAN_FEATURE_PACKET_FILTERING
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006205/**
6206 * hdd_set_rx_filter() - set RX filter
6207 * @adapter: Pointer to adapter
6208 * @action: Filter action
6209 * @pattern: Address pattern
6210 *
6211 * Address pattern is most significant byte of address for example
6212 * 0x01 for IPV4 multicast address
6213 * 0x33 for IPV6 multicast address
6214 * 0xFF for broadcast address
6215 *
6216 * Return: 0 for success, non-zero for failure
6217 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006218static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006219 uint8_t pattern)
6220{
6221 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006222 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006223 tSirRcvFltMcAddrList *filter;
Jeff Johnson621cf972017-08-28 11:58:44 -07006224 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006225 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006226
6227 ret = wlan_hdd_validate_context(hdd_ctx);
6228 if (0 != ret)
6229 return ret;
6230
Jeff Johnsond549efa2018-06-13 20:27:47 -07006231 mac_handle = hdd_ctx->mac_handle;
6232 if (!mac_handle) {
6233 hdd_err("MAC Handle is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006234 return -EINVAL;
6235 }
6236
Wu Gao66454f12018-09-26 19:55:41 +08006237 if (!ucfg_pmo_is_mc_addr_list_enabled(hdd_ctx->psoc)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006238 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306239 return -EINVAL;
6240 }
6241
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006242 /*
6243 * If action is false it means start dropping packets
6244 * Set addr_filter_pattern which will be used when sending
6245 * MC/BC address list to target
6246 */
6247 if (!action)
6248 adapter->addr_filter_pattern = pattern;
6249 else
6250 adapter->addr_filter_pattern = 0;
6251
Krunal Sonibe766b02016-03-10 13:00:44 -08006252 if (((adapter->device_mode == QDF_STA_MODE) ||
6253 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006254 adapter->mc_addr_list.mc_cnt &&
6255 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6256
6257
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306258 filter = qdf_mem_malloc(sizeof(*filter));
Jeff Johnsond36fa332019-03-18 13:42:25 -07006259 if (!filter) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006260 hdd_err("Could not allocate Memory");
6261 return -ENOMEM;
6262 }
6263 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006264 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006265 if (!memcmp(adapter->mc_addr_list.addr[i],
6266 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006267 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006268 adapter->mc_addr_list.addr[i],
6269 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006270
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006271 hdd_debug("%s RX filter : addr ="
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -07006272 QDF_MAC_ADDR_STR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006273 action ? "setting" : "clearing",
Srinivas Girigowda34fbba02019-04-08 12:07:44 -07006274 QDF_MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
Frank Liuf95e8132016-09-29 19:01:30 +08006275 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006276 }
SaidiReddy Yenuga0b2c9f42017-02-03 12:26:38 +05306277 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
6278 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006279 }
Frank Liuf95e8132016-09-29 19:01:30 +08006280 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006281 /* Set rx filter */
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006282 sme_8023_multicast_list(mac_handle, adapter->vdev_id,
Jeff Johnsond549efa2018-06-13 20:27:47 -07006283 filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306284 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006285 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006286 hdd_debug("mode %d mc_cnt %d",
Jeff Johnsond549efa2018-06-13 20:27:47 -07006287 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006288 }
6289
6290 return 0;
6291}
6292
6293/**
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006294 * hdd_driver_rxfilter_command_handler() - RXFILTER driver command handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006295 * @command: Pointer to input string driver command
6296 * @adapter: Pointer to adapter
6297 * @action: Action to enable/disable filtering
6298 *
6299 * If action == false
6300 * Start filtering out data packets based on type
6301 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6302 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6303 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6304 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6305 *
6306 * if action == true
6307 * Stop filtering data packets based on type
6308 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6309 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6310 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6311 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6312 *
6313 * Current implementation only supports IPV4 address filtering by
6314 * selectively allowing IPV4 multicast data packest based on
6315 * address list received in .ndo_set_rx_mode
6316 *
6317 * Return: 0 for success, non-zero for failure
6318 */
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006319static int hdd_driver_rxfilter_command_handler(uint8_t *command,
Jeff Johnsone44b7012017-09-10 15:25:47 -07006320 struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006321 bool action)
6322{
6323 int ret = 0;
6324 uint8_t *value;
6325 uint8_t type;
6326
6327 value = command;
6328 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6329 if (!action)
6330 value = command + 16;
6331 else
6332 value = command + 13;
6333 ret = kstrtou8(value, 10, &type);
6334 if (ret < 0) {
Dustin Brown933cd2a2018-04-18 11:28:15 -07006335 hdd_err("kstrtou8 failed invalid input value");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006336 return -EINVAL;
6337 }
6338
6339 switch (type) {
6340 case 2:
6341 /* Set rx filter for IPV4 multicast data packets */
6342 ret = hdd_set_rx_filter(adapter, action, 0x01);
6343 break;
6344 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006345 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006346 break;
6347 }
6348
6349 return ret;
6350}
6351
6352/**
6353 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6354 * @adapter: Pointer to network adapter
6355 * @hdd_ctx: Pointer to hdd context
6356 * @command: Pointer to input command
6357 * @command_len: Command length
6358 * @priv_data: Pointer to private data in command
6359 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006360static int drv_cmd_rx_filter_remove(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006361 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006362 uint8_t *command,
6363 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006364 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006365{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006366 return hdd_driver_rxfilter_command_handler(command, adapter, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006367}
6368
6369/**
6370 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6371 * @adapter: Pointer to network adapter
6372 * @hdd_ctx: Pointer to hdd context
6373 * @command: Pointer to input command
6374 * @command_len: Command length
6375 * @priv_data: Pointer to private data in command
6376 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006377static int drv_cmd_rx_filter_add(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006378 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006379 uint8_t *command,
6380 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006381 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006382{
Jeff Johnson0f7440e2018-05-06 16:12:39 -07006383 return hdd_driver_rxfilter_command_handler(command, adapter, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006384}
Qiwei Cai4505fc62018-05-17 18:35:19 +08006385#endif /* WLAN_FEATURE_PACKET_FILTERING */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006386
Archana Ramachandran393f3792015-11-13 17:13:21 -08006387/**
6388 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6389 * command
6390 * @value: Pointer to SETANTENNAMODE command
6391 * @mode: Pointer to antenna mode
6392 * @reason: Pointer to reason for set antenna mode
6393 *
6394 * This function parses the SETANTENNAMODE command passed in the format
6395 * SETANTENNAMODE<space>mode
6396 *
6397 * Return: 0 for success non-zero for failure
6398 */
6399static int hdd_parse_setantennamode_command(const uint8_t *value)
6400{
6401 const uint8_t *in_ptr = value;
6402 int tmp, v;
6403 char arg1[32];
6404
6405 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6406
6407 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07006408 if (!in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006409 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006410 return -EINVAL;
6411 }
6412
6413 /* no space after the command */
6414 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006415 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006416 return -EINVAL;
6417 }
6418
6419 /* remove empty spaces */
6420 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6421 in_ptr++;
6422
6423 /* no argument followed by spaces */
6424 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006425 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006426 return -EINVAL;
6427 }
6428
6429 /* get the argument i.e. antenna mode */
6430 v = sscanf(in_ptr, "%31s ", arg1);
6431 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006432 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006433 return -EINVAL;
6434 }
6435
6436 v = kstrtos32(arg1, 10, &tmp);
6437 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006438 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006439 return -EINVAL;
6440 }
6441
6442 return tmp;
6443}
6444
6445/**
6446 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6447 * mask is 2x2 mode
6448 * @hdd_ctx: Pointer to hdd contex
6449 *
6450 * Return: true if supported chain mask 2x2 else false
6451 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006452static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006453{
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306454 QDF_STATUS status;
6455 bool bval = false;
6456
6457/*
Archana Ramachandran393f3792015-11-13 17:13:21 -08006458 * Revisit and the update logic to determine the number
6459 * of TX/RX chains supported in the system when
6460 * antenna sharing per band chain mask support is
6461 * brought in
6462 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306463 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6464 if (!QDF_IS_STATUS_SUCCESS(status))
6465 hdd_err("unable to get vht_enable2x2");
6466
6467 return (bval == 0x01) ? true : false;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006468}
6469
6470/**
6471 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6472 * chain mask is 1x1
6473 * @hdd_ctx: Pointer to hdd contex
6474 *
6475 * Return: true if supported chain mask 1x1 else false
6476 */
Jeff Johnson621cf972017-08-28 11:58:44 -07006477static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006478{
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306479 QDF_STATUS status;
6480 bool bval = false;
6481
Archana Ramachandran393f3792015-11-13 17:13:21 -08006482 /*
6483 * Revisit and update the logic to determine the number
6484 * of TX/RX chains supported in the system when
6485 * antenna sharing per band chain mask support is
6486 * brought in
6487 */
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05306488 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6489 if (!QDF_IS_STATUS_SUCCESS(status))
6490 hdd_err("unable to get vht_enable2x2");
6491
6492 return (!bval) ? true : false;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006493}
6494
Jeff Johnson621cf972017-08-28 11:58:44 -07006495QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
Nitesh Shahe50711f2017-04-26 16:30:45 +05306496{
6497 QDF_STATUS status;
6498 uint8_t smps_mode;
6499 uint8_t smps_enable;
Jeff Johnsond549efa2018-06-13 20:27:47 -07006500 mac_handle_t mac_handle;
Nitesh Shahe50711f2017-04-26 16:30:45 +05306501
6502 /* Update SME SMPS config */
6503 if (HDD_ANTENNA_MODE_1X1 == mode) {
6504 smps_enable = true;
6505 smps_mode = HDD_SMPS_MODE_STATIC;
6506 } else {
6507 smps_enable = false;
6508 smps_mode = HDD_SMPS_MODE_DISABLED;
6509 }
6510
6511 hdd_debug("Update SME SMPS enable: %d mode: %d",
6512 smps_enable, smps_mode);
Jeff Johnsond549efa2018-06-13 20:27:47 -07006513 mac_handle = hdd_ctx->mac_handle;
6514 status = sme_update_mimo_power_save(mac_handle, smps_enable,
6515 smps_mode, false);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306516 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07006517 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
Nitesh Shahe50711f2017-04-26 16:30:45 +05306518 smps_enable, smps_mode, status);
6519 return QDF_STATUS_E_FAILURE;
6520 }
6521
6522 hdd_ctx->current_antenna_mode = mode;
6523 /*
6524 * Update the user requested nss in the mac context.
6525 * This will be used in tdls protocol engine to form tdls
6526 * Management frames.
6527 */
Jeff Johnsond549efa2018-06-13 20:27:47 -07006528 sme_update_user_configured_nss(mac_handle,
6529 hdd_ctx->current_antenna_mode);
Nitesh Shahe50711f2017-04-26 16:30:45 +05306530
6531 hdd_debug("Successfully switched to mode: %d x %d",
6532 hdd_ctx->current_antenna_mode,
6533 hdd_ctx->current_antenna_mode);
6534
6535 return QDF_STATUS_SUCCESS;
6536}
6537
Dundi Raviteja4016e932018-08-02 12:16:25 +05306538/**
6539 * wlan_hdd_soc_set_antenna_mode_cb() - Callback for set antenna mode
6540 * @status: Status of set antenna mode
6541 * @context: callback context
6542 *
6543 * Callback on setting antenna mode
6544 *
6545 * Return: None
6546 */
6547static void
6548wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status,
6549 void *context)
6550{
6551 struct osif_request *request = NULL;
6552
6553 hdd_debug("Status: %d", status);
6554
6555 request = osif_request_get(context);
6556 if (!request) {
6557 hdd_err("obselete request");
6558 return;
6559 }
6560
6561 /* Signal the completion of set dual mac config */
6562 osif_request_complete(request);
6563 osif_request_put(request);
6564}
6565
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306566static QDF_STATUS
6567hdd_populate_vdev_chains(struct wlan_mlme_nss_chains *nss_chains_cfg,
6568 uint8_t tx_chains,
6569 uint8_t rx_chains,
6570 enum nss_chains_band_info band,
6571 struct wlan_objmgr_vdev *vdev)
6572{
6573 struct wlan_mlme_nss_chains *dynamic_cfg;
6574
6575 nss_chains_cfg->num_rx_chains[band] = rx_chains;
6576 nss_chains_cfg->num_tx_chains[band] = tx_chains;
6577
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306578 dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306579 if (!dynamic_cfg) {
6580 hdd_err("nss chain dynamic config NULL");
6581 return QDF_STATUS_E_FAILURE;
6582 }
6583 /*
6584 * If user gives any nss value, then chains will be adjusted based on
6585 * nss (in SME func sme_validate_user_nss_chain_params).
6586 * If Chains are not suitable as per current NSS then, we need to
6587 * return, and the below logic is added for the same.
6588 */
6589
6590 if ((dynamic_cfg->rx_nss[band] > rx_chains) ||
6591 (dynamic_cfg->tx_nss[band] > tx_chains)) {
6592 hdd_err("Chains less than nss, configure correct nss first.");
6593 return QDF_STATUS_E_FAILURE;
6594 }
6595
6596 return QDF_STATUS_SUCCESS;
6597}
6598
6599static int
6600hdd_set_dynamic_antenna_mode(struct hdd_adapter *adapter,
6601 uint8_t num_rx_chains,
6602 uint8_t num_tx_chains)
6603{
6604 enum nss_chains_band_info band;
6605 struct wlan_mlme_nss_chains user_cfg;
6606 QDF_STATUS status;
6607 mac_handle_t mac_handle;
6608 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6609
6610 mac_handle = hdd_ctx->mac_handle;
6611 if (!mac_handle) {
6612 hdd_err("NULL MAC handle");
6613 return -EINVAL;
6614 }
6615
gaurank kathpalia6982d472018-10-31 21:54:15 +05306616 if (!hdd_is_vdev_in_conn_state(adapter)) {
6617 hdd_debug("Vdev (id %d) not in connected/started state, cannot accept command",
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006618 adapter->vdev_id);
gaurank kathpalia6982d472018-10-31 21:54:15 +05306619 return -EINVAL;
6620 }
6621
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306622 qdf_mem_zero(&user_cfg, sizeof(user_cfg));
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306623 for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) {
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306624 status = hdd_populate_vdev_chains(&user_cfg,
6625 num_rx_chains,
6626 num_tx_chains, band,
6627 adapter->vdev);
6628 if (QDF_IS_STATUS_ERROR(status))
6629 return -EINVAL;
6630 }
6631 status = sme_nss_chains_update(mac_handle,
6632 &user_cfg,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006633 adapter->vdev_id);
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306634 if (QDF_IS_STATUS_ERROR(status))
6635 return -EINVAL;
6636
6637 return 0;
6638}
Abhishek Singh1571ca72018-04-17 15:14:21 +05306639int hdd_set_antenna_mode(struct hdd_adapter *adapter,
6640 struct hdd_context *hdd_ctx, int mode)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006641{
6642 struct sir_antenna_mode_param params;
6643 QDF_STATUS status;
6644 int ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306645 struct osif_request *request = NULL;
6646 static const struct osif_request_params request_params = {
6647 .priv_size = 0,
Abhishek Singhd1f21c72019-01-21 15:16:34 +05306648 .timeout_ms = SME_POLICY_MGR_CMD_TIMEOUT,
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306649 };
Archana Ramachandran393f3792015-11-13 17:13:21 -08006650
Archana Ramachandran393f3792015-11-13 17:13:21 -08006651 switch (mode) {
6652 case HDD_ANTENNA_MODE_1X1:
6653 params.num_rx_chains = 1;
6654 params.num_tx_chains = 1;
6655 break;
6656 case HDD_ANTENNA_MODE_2X2:
6657 params.num_rx_chains = 2;
6658 params.num_tx_chains = 2;
6659 break;
6660 default:
6661 hdd_err("unsupported antenna mode");
6662 ret = -EINVAL;
6663 goto exit;
6664 }
6665
gaurank kathpalia1281b302018-11-05 21:10:37 +05306666 if (hdd_ctx->dynamic_nss_chains_support)
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306667 return hdd_set_dynamic_antenna_mode(adapter,
6668 params.num_rx_chains,
6669 params.num_tx_chains);
gaurank kathpalia7cb6a322018-10-24 19:50:34 +05306670
gaurank kathpaliaf95ae682018-11-05 21:13:07 +05306671 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6672 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6673 hdd_err("System does not support 2x2 mode");
6674 ret = -EPERM;
6675 goto exit;
6676 }
6677
6678 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6679 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6680 hdd_err("System only supports 1x1 mode");
6681 goto exit;
6682 }
6683
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006684 /* Check TDLS status and update antenna mode */
6685 if ((QDF_STA_MODE == adapter->device_mode) &&
Dustin Brown1dbefe62018-09-11 16:32:03 -07006686 policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) {
Jeff Johnsond549efa2018-06-13 20:27:47 -07006687 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter, mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006688 if (0 != ret)
6689 goto exit;
6690 }
6691
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306692 request = osif_request_alloc(&request_params);
6693 if (!request) {
6694 hdd_err("Request Allocation Failure");
6695 ret = -ENOMEM;
6696 goto exit;
6697 }
6698
6699 params.set_antenna_mode_ctx = osif_request_cookie(request);
6700 params.set_antenna_mode_resp = (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006701 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006702 params.num_rx_chains,
6703 params.num_tx_chains);
6704
Jeff Johnsond549efa2018-06-13 20:27:47 -07006705 status = sme_soc_set_antenna_mode(hdd_ctx->mac_handle, &params);
Abhishek Singh1571ca72018-04-17 15:14:21 +05306706 if (QDF_IS_STATUS_ERROR(status)) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006707 hdd_err("set antenna mode failed status : %d", status);
6708 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306709 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006710 }
6711
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306712 ret = osif_request_wait_for_response(request);
6713 if (ret) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006714 hdd_err("send set antenna mode timed out");
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306715 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006716 }
6717
Nitesh Shahe50711f2017-04-26 16:30:45 +05306718 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006719 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran393f3792015-11-13 17:13:21 -08006720 ret = -EFAULT;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306721 goto request_put;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006722 }
Archana Ramachandran5041b252016-04-25 14:29:25 -07006723 ret = 0;
Dundi Raviteja6bb9e322018-05-16 17:04:41 +05306724request_put:
6725 osif_request_put(request);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006726exit:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006727 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006728 ret, hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006729
Abhishek Singh1571ca72018-04-17 15:14:21 +05306730 return ret;
6731}
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306732
Abhishek Singh1571ca72018-04-17 15:14:21 +05306733/**
6734 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6735 * handler
6736 * @adapter: Pointer to network adapter
6737 * @hdd_ctx: Pointer to hdd context
6738 * @command: Pointer to input command
6739 * @command_len: Command length
6740 * @priv_data: Pointer to private data in command
6741 */
6742static int drv_cmd_set_antenna_mode(struct hdd_adapter *adapter,
6743 struct hdd_context *hdd_ctx,
6744 uint8_t *command,
6745 uint8_t command_len,
6746 struct hdd_priv_data *priv_data)
6747{
6748 int mode;
6749 uint8_t *value = command;
6750
6751 mode = hdd_parse_setantennamode_command(value);
6752 if (mode < 0) {
6753 hdd_err("Invalid SETANTENNA command");
6754 return mode;
6755 }
6756
6757 hdd_debug("Processing antenna mode switch to: %d", mode);
6758
6759 return hdd_set_antenna_mode(adapter, hdd_ctx, mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006760}
6761
6762/**
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306763 * hdd_get_dynamic_antenna_mode() -get the dynamic antenna mode for vdev
6764 * @antenna_mode: pointer to antenna mode of vdev
6765 * @dynamic_nss_chains_support: feature support for dynamic nss chains update
6766 * @vdev: Pointer to vdev
6767 *
6768 * This API will check for the num of chains configured for the vdev, and fill
6769 * that info in the antenna mode if the dynamic chains per vdev are supported.
6770 *
6771 * Return: None
6772 */
6773static void
6774hdd_get_dynamic_antenna_mode(uint32_t *antenna_mode,
6775 bool dynamic_nss_chains_support,
6776 struct wlan_objmgr_vdev *vdev)
6777{
6778 struct wlan_mlme_nss_chains *nss_chains_dynamic_cfg;
6779
6780 if (!dynamic_nss_chains_support)
6781 return;
6782
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306783 nss_chains_dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306784 if (!nss_chains_dynamic_cfg) {
6785 hdd_err("nss chain dynamic config NULL");
6786 return;
6787 }
6788 /*
6789 * At present, this command doesn't include band, so by default
6790 * it will return the band 2ghz present rf chains.
6791 */
gaurank kathpaliab414bce2018-11-09 18:44:46 +05306792 *antenna_mode =
6793 nss_chains_dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306794}
6795
6796/**
Archana Ramachandran393f3792015-11-13 17:13:21 -08006797 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6798 * handler
6799 * @adapter: Pointer to hdd adapter
6800 * @hdd_ctx: Pointer to hdd context
6801 * @command: Pointer to input command
6802 * @command_len: length of the command
6803 * @priv_data: private data coming with the driver command
6804 *
6805 * Return: 0 for success non-zero for failure
6806 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006807static inline int drv_cmd_get_antenna_mode(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006808 struct hdd_context *hdd_ctx,
Archana Ramachandran393f3792015-11-13 17:13:21 -08006809 uint8_t *command,
6810 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006811 struct hdd_priv_data *priv_data)
Archana Ramachandran393f3792015-11-13 17:13:21 -08006812{
6813 uint32_t antenna_mode = 0;
6814 char extra[32];
6815 uint8_t len = 0;
6816
6817 antenna_mode = hdd_ctx->current_antenna_mode;
gaurank kathpalia2472fb92018-10-31 17:40:18 +05306818 /* Overwrite this antenna mode if dynamic vdev chains are supported */
6819 hdd_get_dynamic_antenna_mode(&antenna_mode,
6820 hdd_ctx->dynamic_nss_chains_support,
6821 adapter->vdev);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006822 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6823 antenna_mode);
6824 len = QDF_MIN(priv_data->total_len, len + 1);
6825 if (copy_to_user(priv_data->buf, &extra, len)) {
6826 hdd_err("Failed to copy data to user buffer");
6827 return -EFAULT;
6828 }
6829
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006830 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006831
6832 return 0;
6833}
6834
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006835/*
6836 * dummy (no-op) hdd driver command handler
6837 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006838static int drv_cmd_dummy(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006839 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006840 uint8_t *command,
6841 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006842 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006843{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006844 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006845 adapter->dev->name, command);
6846 return 0;
6847}
6848
6849/*
6850 * handler for any unsupported wlan hdd driver command
6851 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006852static int drv_cmd_invalid(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006853 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006854 uint8_t *command,
6855 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006856 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006857{
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05306858 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
6859 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
Jeff Johnson5a6fc962019-02-04 14:20:25 -08006860 adapter->vdev_id, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006861
6862 hdd_warn("%s: Unsupported driver command \"%s\"",
6863 adapter->dev->name, command);
6864
6865 return -ENOTSUPP;
6866}
6867
6868/**
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306869 * drv_cmd_set_fcc_channel() - Handle fcc constraint request
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006870 * @adapter: HDD adapter
6871 * @hdd_ctx: HDD context
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306872 * @command: command ptr, SET_FCC_CHANNEL 0/-1 is the command
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006873 * @command_len: command len
6874 * @priv_data: private data
6875 *
6876 * Return: status
6877 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006878static int drv_cmd_set_fcc_channel(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006879 struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006880 uint8_t *command,
6881 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006882 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006883{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306884 QDF_STATUS status;
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306885 int8_t input_value;
6886 bool fcc_constraint;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006887 int err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006888
6889 /*
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306890 * This command would be called by user-space when it detects WLAN
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006891 * ON after airplane mode is set. When APM is set, WLAN turns off.
6892 * But it can be turned back on. Otherwise; when APM is turned back
6893 * off, WLAN would turn back on. So at that point the command is
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306894 * expected to come down. 0 means reduce power as per fcc constraint
6895 * and -1 means remove constraint.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006896 */
6897
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306898 err = kstrtos8(command + command_len + 1, 10, &input_value);
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006899 if (err) {
6900 hdd_err("error %d parsing userspace fcc parameter", err);
6901 return err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006902 }
6903
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306904 fcc_constraint = input_value ? false : true;
6905 hdd_debug("input_value = %d && fcc_constraint = %u",
6906 input_value, fcc_constraint);
6907
Dustin Brown07901ec2018-09-07 11:02:41 -07006908 status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev, fcc_constraint);
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006909
6910 if (QDF_IS_STATUS_ERROR(status))
6911 hdd_err("Failed to %s tx power for channels 12/13",
Rajeev Kumar Sirasanagandla1a21bf62019-04-08 15:28:57 +05306912 fcc_constraint ? "restore" : "reduce");
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -07006913
6914 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006915}
6916
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306917/**
6918 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6919 * command
6920 * @value: Pointer to the command
6921 * @chan_number: Pointer to the channel number
6922 * @chan_bw: Pointer to the channel bandwidth
6923 *
6924 * Parses and provides the channel number and channel width from the input
6925 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6926 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6927 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6928 *
6929 * Return: 0 for success, non-zero for failure
6930 */
6931static int hdd_parse_set_channel_switch_command(uint8_t *value,
6932 uint32_t *chan_number,
6933 uint32_t *chan_bw)
6934{
6935 const uint8_t *in_ptr = value;
6936 int ret;
6937
6938 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6939
6940 /* no argument after the command */
Jeff Johnsond36fa332019-03-18 13:42:25 -07006941 if (!in_ptr) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306942 hdd_err("No argument after the command");
6943 return -EINVAL;
6944 }
6945
6946 /* no space after the command */
6947 if (SPACE_ASCII_VALUE != *in_ptr) {
6948 hdd_err("No space after the command ");
6949 return -EINVAL;
6950 }
6951
6952 /* remove empty spaces and move the next argument */
6953 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6954 in_ptr++;
6955
6956 /* no argument followed by spaces */
6957 if ('\0' == *in_ptr) {
6958 hdd_err("No argument followed by spaces");
6959 return -EINVAL;
6960 }
6961
6962 /* get the two arguments: channel number and bandwidth */
6963 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6964 if (ret != 2) {
6965 hdd_err("Arguments retrieval from cmd string failed");
6966 return -EINVAL;
6967 }
6968
6969 return 0;
6970}
6971
6972/**
6973 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6974 * @adapter: HDD adapter
6975 * @hdd_ctx: HDD context
6976 * @command: Pointer to the input command CHANNEL_SWITCH
6977 * @command_len: Command len
6978 * @priv_data: Private data
6979 *
6980 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6981 * of SAP/P2P-GO
6982 *
6983 * Return: 0 for success, non-zero for failure
6984 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07006985static int drv_cmd_set_channel_switch(struct hdd_adapter *adapter,
Jeff Johnson621cf972017-08-28 11:58:44 -07006986 struct hdd_context *hdd_ctx,
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306987 uint8_t *command,
6988 uint8_t command_len,
Jeff Johnson353cd292017-08-17 06:47:26 -07006989 struct hdd_priv_data *priv_data)
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306990{
6991 struct net_device *dev = adapter->dev;
6992 int status;
6993 uint32_t chan_number = 0, chan_bw = 0;
6994 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006995 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306996
Krunal Sonibe766b02016-03-10 13:00:44 -08006997 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6998 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306999 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7000 adapter->device_mode);
7001 return -EINVAL;
7002 }
7003
7004 status = hdd_parse_set_channel_switch_command(value,
7005 &chan_number, &chan_bw);
7006 if (status) {
7007 hdd_err("Invalid CHANNEL_SWITCH command");
7008 return status;
7009 }
7010
7011 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7012 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7013 return -EINVAL;
7014 }
7015
7016 if (chan_bw == 80)
7017 width = CH_WIDTH_80MHZ;
7018 else if (chan_bw == 40)
7019 width = CH_WIDTH_40MHZ;
7020 else
7021 width = CH_WIDTH_20MHZ;
7022
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007023 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307024
Bala Venkatesh8b9bbde2019-07-03 16:25:16 +05307025 wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, adapter->vdev_id,
7026 CSA_REASON_USER_INITIATED);
Wu Gao9daee1a2018-05-22 14:49:59 +08007027 status = hdd_softap_set_channel_change(dev, chan_number, width, true);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307028 if (status) {
7029 hdd_err("Set channel change fail");
7030 return status;
7031 }
7032
7033 return 0;
7034}
7035
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307036#ifdef DISABLE_CHANNEL_LIST
7037void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7038{
7039 hdd_enter();
7040
7041 if (!hdd_ctx->original_channels)
7042 return;
7043
7044 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7045 hdd_ctx->original_channels->num_channels = 0;
7046 if (hdd_ctx->original_channels->channel_info) {
7047 qdf_mem_free(hdd_ctx->original_channels->channel_info);
7048 hdd_ctx->original_channels->channel_info = NULL;
7049 }
7050 qdf_mem_free(hdd_ctx->original_channels);
7051 hdd_ctx->original_channels = NULL;
7052 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7053
7054 hdd_exit();
7055}
7056
7057/**
7058 * hdd_alloc_chan_cache() - Allocate the memory to cache the channel
7059 * info for the channels received in command SET_DISABLE_CHANNEL_LIST
7060 * @hdd_ctx: Pointer to HDD context
7061 * @num_chan: Number of channels for which memory needs to
7062 * be allocated
7063 *
7064 * Return: 0 on success and error code on failure
7065 */
7066static int hdd_alloc_chan_cache(struct hdd_context *hdd_ctx, int num_chan)
7067{
7068 hdd_ctx->original_channels =
7069 qdf_mem_malloc(sizeof(struct hdd_cache_channels));
7070 if (!hdd_ctx->original_channels) {
7071 hdd_err("QDF_MALLOC_ERR");
7072 return -ENOMEM;
7073 }
7074 hdd_ctx->original_channels->num_channels = num_chan;
7075 hdd_ctx->original_channels->channel_info =
7076 qdf_mem_malloc(num_chan *
7077 sizeof(struct hdd_cache_channel_info));
7078 if (!hdd_ctx->original_channels->channel_info) {
7079 hdd_err("QDF_MALLOC_ERR");
7080 hdd_ctx->original_channels->num_channels = 0;
7081 qdf_mem_free(hdd_ctx->original_channels);
7082 hdd_ctx->original_channels = NULL;
7083 return -ENOMEM;
7084 }
7085 return 0;
7086}
7087
7088/**
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307089 * check_disable_channels() - Check for disable channel
7090 * @hdd_ctx: Pointer to hdd context
7091 * @operating_channel: Current operating channel of adapter
7092 *
7093 * This function checks original_channels array for a specific channel
7094 *
7095 * Return: 0 if channel not found, 1 if channel found
7096 */
7097static bool check_disable_channels(struct hdd_context *hdd_ctx,
7098 uint8_t operating_channel)
7099{
7100 uint32_t num_channels;
7101 uint8_t i;
7102
7103 if (!hdd_ctx || !hdd_ctx->original_channels ||
7104 !hdd_ctx->original_channels->channel_info)
7105 return false;
7106
7107 num_channels = hdd_ctx->original_channels->num_channels;
7108 for (i = 0; i < num_channels; i++)
7109 if (hdd_ctx->original_channels->channel_info[i].channel_num ==
7110 operating_channel)
7111 return true;
7112 return false;
7113}
7114
7115/**
7116 * disconnect_sta_and_stop_sap() - Disconnect STA and stop SAP
7117 *
7118 * @hdd_ctx: Pointer to hdd context
7119 *
7120 * Disable channels provided by user and disconnect STA if it is
7121 * connected to any AP, stop SAP and send deauthentication request
7122 * to STAs connected to SAP.
7123 *
7124 * Return: None
7125 */
7126static void disconnect_sta_and_stop_sap(struct hdd_context *hdd_ctx)
7127{
7128 struct hdd_adapter *adapter, *next = NULL;
7129 QDF_STATUS status;
7130
7131 if (!hdd_ctx)
7132 return;
7133
7134 hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx);
7135
7136 status = hdd_get_front_adapter(hdd_ctx, &adapter);
7137 while (adapter && (status == QDF_STATUS_SUCCESS)) {
7138 if (!hdd_validate_adapter(adapter) &&
7139 (adapter->device_mode == QDF_SAP_MODE) &&
7140 (check_disable_channels(hdd_ctx,
7141 adapter->session.ap.operating_channel)))
7142 wlan_hdd_stop_sap(adapter);
7143
7144 status = hdd_get_next_adapter(hdd_ctx, adapter, &next);
7145 adapter = next;
7146 }
7147}
7148
7149/**
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307150 * hdd_parse_disable_chan_cmd() - Parse the channel list received
7151 * in command.
7152 * @adapter: pointer to hdd adapter
7153 * @ptr: Pointer to the command string
7154 *
7155 * This function parses the channel list received in the command.
7156 * command should be a string having format
7157 * SET_DISABLE_CHANNEL_LIST <num of channels>
7158 * <channels separated by spaces>.
7159 * If the command comes multiple times than this function will compare
7160 * the channels received in the command with the channles cached in the
7161 * first command, if the channel list matches with the cached channles,
7162 * it returns success otherwise returns failure.
7163 *
7164 * Return: 0 on success, Error code on failure
7165 */
7166
7167static int hdd_parse_disable_chan_cmd(struct hdd_adapter *adapter, uint8_t *ptr)
7168{
7169 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7170 uint8_t *param;
7171 int j, i, temp_int, ret = 0, num_channels;
7172 uint32_t parsed_channels[MAX_CHANNEL];
7173 bool is_command_repeated = false;
7174
Jeff Johnsond36fa332019-03-18 13:42:25 -07007175 if (!hdd_ctx) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307176 hdd_err("HDD Context is NULL");
7177 return -EINVAL;
7178 }
7179
7180 param = strnchr(ptr, strlen(ptr), ' ');
7181 /*no argument after the command*/
Jeff Johnsond36fa332019-03-18 13:42:25 -07007182 if (!param)
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307183 return -EINVAL;
7184
7185 /*no space after the command*/
7186 else if (SPACE_ASCII_VALUE != *param)
7187 return -EINVAL;
7188
7189 param++;
7190
7191 /*removing empty spaces*/
7192 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7193 param++;
7194
7195 /*no argument followed by spaces*/
7196 if ('\0' == *param)
7197 return -EINVAL;
7198
7199 /*getting the first argument ie the number of channels*/
7200 if (sscanf(param, "%d ", &temp_int) != 1) {
7201 hdd_err("Cannot get number of channels from input");
7202 return -EINVAL;
7203 }
7204
7205 if (temp_int < 0 || temp_int > MAX_CHANNEL) {
7206 hdd_err("Invalid Number of channel received");
7207 return -EINVAL;
7208 }
7209
7210 hdd_debug("Number of channel to disable are: %d", temp_int);
7211
7212 if (!temp_int) {
7213 if (!wlan_hdd_restore_channels(hdd_ctx, false)) {
7214 /*
7215 * Free the cache channels only when the command is
7216 * received with num channels as 0
7217 */
7218 wlan_hdd_free_cache_channels(hdd_ctx);
7219 }
7220 return 0;
7221 }
7222
7223 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7224
7225 if (!hdd_ctx->original_channels) {
7226 if (hdd_alloc_chan_cache(hdd_ctx, temp_int)) {
7227 ret = -ENOMEM;
7228 goto mem_alloc_failed;
7229 }
7230 } else if (hdd_ctx->original_channels->num_channels != temp_int) {
7231 hdd_err("Invalid Number of channels");
7232 ret = -EINVAL;
7233 is_command_repeated = true;
7234 goto parse_failed;
7235 } else {
7236 is_command_repeated = true;
7237 }
7238 num_channels = temp_int;
7239 for (j = 0; j < num_channels; j++) {
7240 /*
7241 * param pointing to the beginning of first space
7242 * after number of channels
7243 */
7244 param = strpbrk(param, " ");
7245 /*no channel list after the number of channels argument*/
Jeff Johnsond36fa332019-03-18 13:42:25 -07007246 if (!param) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307247 hdd_err("Invalid No of channel provided in the list");
7248 ret = -EINVAL;
7249 goto parse_failed;
7250 }
7251
7252 param++;
7253
7254 /*removing empty space*/
7255 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7256 param++;
7257
7258 if ('\0' == *param) {
7259 hdd_err("No channel is provided in the list");
7260 ret = -EINVAL;
7261 goto parse_failed;
7262 }
7263
7264 if (sscanf(param, "%d ", &temp_int) != 1) {
7265 hdd_err("Cannot read channel number");
7266 ret = -EINVAL;
7267 goto parse_failed;
7268 }
7269
7270 if (!IS_CHANNEL_VALID(temp_int)) {
7271 hdd_err("Invalid channel number received");
7272 ret = -EINVAL;
7273 goto parse_failed;
7274 }
7275
7276 hdd_debug("channel[%d] = %d", j, temp_int);
7277 parsed_channels[j] = temp_int;
7278 }
7279
7280 /*extra arguments check*/
7281 param = strpbrk(param, " ");
Jeff Johnsond36fa332019-03-18 13:42:25 -07007282 if (param) {
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307283 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7284 param++;
7285
7286 if ('\0' != *param) {
7287 hdd_err("Invalid argument received");
7288 ret = -EINVAL;
7289 goto parse_failed;
7290 }
7291 }
7292
7293 /*
7294 * If command is received first time, cache the channels to
7295 * be disabled else compare the channels received in the
7296 * command with the cached channels, if channel list matches
7297 * return success otherewise return failure.
7298 */
7299 if (!is_command_repeated) {
7300 for (j = 0; j < num_channels; j++)
7301 hdd_ctx->original_channels->
7302 channel_info[j].channel_num =
7303 parsed_channels[j];
Dustin Brown3f0d7102018-08-02 12:01:52 -07007304
7305 /* Cache the channel list in regulatory also */
Dustin Brown07901ec2018-09-07 11:02:41 -07007306 ucfg_reg_cache_channel_state(hdd_ctx->pdev, parsed_channels,
Dustin Brown3f0d7102018-08-02 12:01:52 -07007307 num_channels);
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307308 } else {
7309 for (i = 0; i < num_channels; i++) {
7310 for (j = 0; j < num_channels; j++)
7311 if (hdd_ctx->original_channels->
7312 channel_info[i].channel_num ==
7313 parsed_channels[j])
7314 break;
7315 if (j == num_channels) {
7316 ret = -EINVAL;
7317 goto parse_failed;
7318 }
7319 }
7320 ret = 0;
7321 }
7322mem_alloc_failed:
7323
7324 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
Ashish Kumar Dhanotiyadd5f74c2019-03-14 16:50:41 +05307325 /* Disable the channels received in command SET_DISABLE_CHANNEL_LIST */
7326 if (!is_command_repeated && hdd_ctx->original_channels) {
Ashish Kumar Dhanotiyad63d6862019-03-14 18:54:10 +05307327 ret = wlan_hdd_disable_channels(hdd_ctx);
7328 if (ret)
7329 return ret;
7330 disconnect_sta_and_stop_sap(hdd_ctx);
Ashish Kumar Dhanotiyadd5f74c2019-03-14 16:50:41 +05307331 }
7332
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307333 hdd_exit();
7334
7335 return ret;
7336
7337parse_failed:
7338 if (!is_command_repeated)
7339 wlan_hdd_free_cache_channels(hdd_ctx);
Ashish Kumar Dhanotiyadd5f74c2019-03-14 16:50:41 +05307340
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307341 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7342 hdd_exit();
7343
7344 return ret;
7345}
7346
7347static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7348 struct hdd_context *hdd_ctx,
7349 uint8_t *command,
7350 uint8_t command_len,
7351 struct hdd_priv_data *priv_data)
7352{
7353 return hdd_parse_disable_chan_cmd(adapter, command);
7354}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307355
7356/**
7357 * hdd_get_disable_ch_list() - get disable channel list
7358 * @hdd_ctx: hdd context
7359 * @buf: buffer to hold disable channel list
7360 * @buf_len: buffer length
7361 *
7362 * Return: length of data copied to buf
7363 */
7364static int hdd_get_disable_ch_list(struct hdd_context *hdd_ctx, uint8_t *buf,
7365 uint32_t buf_len)
7366{
7367 struct hdd_cache_channel_info *ch_list;
7368 unsigned char i, num_ch;
7369 int len = 0;
7370
7371 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7372 if (hdd_ctx->original_channels &&
7373 hdd_ctx->original_channels->num_channels &&
7374 hdd_ctx->original_channels->channel_info) {
7375 num_ch = hdd_ctx->original_channels->num_channels;
7376
7377 len = scnprintf(buf, buf_len, "%s %hhu",
7378 "GET_DISABLE_CHANNEL_LIST", num_ch);
7379 ch_list = hdd_ctx->original_channels->channel_info;
7380 for (i = 0; (i < num_ch) && (len < buf_len - 1); i++) {
7381 len += scnprintf(buf + len, buf_len - len,
7382 " %d", ch_list[i].channel_num);
7383 }
7384 }
7385 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7386
7387 return len;
7388}
7389
7390static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7391 struct hdd_context *hdd_ctx,
7392 uint8_t *command,
7393 uint8_t command_len,
7394 struct hdd_priv_data *priv_data)
7395{
7396 char extra[512] = {0};
7397 int max_len, copied_length;
7398
7399 hdd_debug("Received Command to get disable Channels list");
7400
7401 max_len = QDF_MIN(priv_data->total_len, sizeof(extra));
7402 copied_length = hdd_get_disable_ch_list(hdd_ctx, extra, max_len);
7403 if (copied_length == 0) {
7404 hdd_err("disable channel list is not yet programmed");
7405 return -EINVAL;
7406 }
7407
7408 if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
7409 hdd_err("failed to copy data to user buffer");
7410 return -EFAULT;
7411 }
7412
7413 hdd_debug("data:%s", extra);
7414 return 0;
7415}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307416#else
7417
7418static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter,
7419 struct hdd_context *hdd_ctx,
7420 uint8_t *command,
7421 uint8_t command_len,
7422 struct hdd_priv_data *priv_data)
7423{
7424 return 0;
7425}
7426
7427void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7428{
7429}
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307430
7431static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter,
7432 struct hdd_context *hdd_ctx,
7433 uint8_t *command,
7434 uint8_t command_len,
7435 struct hdd_priv_data *priv_data)
7436{
7437 return 0;
7438}
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307439#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007440/*
7441 * The following table contains all supported WLAN HDD
7442 * IOCTL driver commands and the handler for each of them.
7443 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07007444static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307445 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false},
7446 {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true},
7447 {"P2P_SET_PS", drv_cmd_p2p_set_ps, true},
7448 {"SETBAND", drv_cmd_set_band, true},
7449 {"SETWMMPS", drv_cmd_set_wmmps, true},
7450 {"COUNTRY", drv_cmd_country, true},
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +05307451 {"SETCOUNTRYREV", drv_cmd_country, true},
7452 {"GETCOUNTRYREV", drv_cmd_get_country, false},
Pragaspathi Thilagarajaa8320e2019-04-16 02:47:50 +05307453 {"SETSUSPENDMODE", drv_cmd_set_suspend_mode, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307454 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307455 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true},
7456 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false},
7457 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true},
7458 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false},
7459 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period,
7460 true},
7461 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period,
7462 false},
7463 {"SETROAMMODE", drv_cmd_set_roam_mode, true},
7464 {"GETROAMMODE", drv_cmd_get_roam_mode, false},
7465 {"SETROAMDELTA", drv_cmd_set_roam_delta, true},
7466 {"GETROAMDELTA", drv_cmd_get_roam_delta, false},
7467 {"GETBAND", drv_cmd_get_band, false},
7468 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels, true},
7469 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels, false},
7470 {"GETCCXMODE", drv_cmd_get_ccx_mode, false},
7471 {"GETOKCMODE", drv_cmd_get_okc_mode, false},
7472 {"GETFASTROAM", drv_cmd_get_fast_roam, false},
7473 {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false},
7474 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
7475 true},
7476 {"SENDACTIONFRAME", drv_cmd_send_action_frame, true},
7477 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
7478 false},
7479 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true},
7480 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false},
7481 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true},
7482 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false},
7483 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true},
7484 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false},
7485 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true},
7486 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false},
7487 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true},
7488 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false},
7489 {"REASSOC", drv_cmd_reassoc, true},
7490 {"SETWESMODE", drv_cmd_set_wes_mode, true},
7491 {"GETWESMODE", drv_cmd_get_wes_mode, false},
7492 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff,
7493 true},
7494 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff,
7495 false},
7496 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true},
7497 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false},
7498 {"SETFASTROAM", drv_cmd_set_fast_roam, true},
7499 {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true},
7500 {"FASTREASSOC", drv_cmd_fast_reassoc, true},
7501 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control, true},
7502 {"SETOKCMODE", drv_cmd_set_okc_mode, true},
7503 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control, false},
7504 {"BTCOEXMODE", drv_cmd_bt_coex_mode, true},
7505 {"SCAN-ACTIVE", drv_cmd_scan_active, false},
7506 {"SCAN-PASSIVE", drv_cmd_scan_passive, false},
Dundi Ravitejae1f0d3b2018-04-25 16:48:05 +05307507 {"CONCSETDWELLTIME", drv_cmd_conc_set_dwell_time, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307508 {"GETDWELLTIME", drv_cmd_get_dwell_time, false},
7509 {"SETDWELLTIME", drv_cmd_set_dwell_time, true},
7510 {"MIRACAST", drv_cmd_miracast, true},
7511 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05307512#ifdef FEATURE_WLAN_RMC
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307513 {"SETRMCENABLE", drv_cmd_set_rmc_enable, true},
7514 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period, true},
Rachit Kankaneee1735c2018-08-02 13:19:34 +05307515 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate, true},
7516#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307517 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all, false},
7518 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info, true},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307519 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007520#ifdef FEATURE_WLAN_ESE
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307521 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true},
7522 {"GETTSMSTATS", drv_cmd_get_tsm_stats, true},
7523 {"SETCCKMIE", drv_cmd_set_cckm_ie, true},
7524 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true},
7525 {"CCXPLMREQ", drv_cmd_ccx_plm_req, true},
7526 {"SETCCXMODE", drv_cmd_set_ccx_mode, true},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007527#endif /* FEATURE_WLAN_ESE */
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307528 {"SETMCRATE", drv_cmd_set_mc_rate, true},
7529 {"MAXTXPOWER", drv_cmd_max_tx_power, true},
7530 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true},
7531 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false},
7532 {"GETLINKSTATUS", drv_cmd_get_link_status, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007533#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307534 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true},
7535 {"SETAPP1PARAMS", drv_cmd_set_app1_params, true},
7536 {"SETAPP2PARAMS", drv_cmd_set_app2_params, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007537#endif
7538#ifdef FEATURE_WLAN_TDLS
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307539 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
7540 true},
7541 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true},
7542 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true},
7543 {"TDLSSCAN", drv_cmd_tdls_scan, true},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007544#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307545 {"RSSI", drv_cmd_get_rssi, false},
7546 {"LINKSPEED", drv_cmd_get_linkspeed, false},
Qiwei Cai4505fc62018-05-17 18:35:19 +08007547#ifdef WLAN_FEATURE_PACKET_FILTERING
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307548 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true},
7549 {"RXFILTER-ADD", drv_cmd_rx_filter_add, true},
Qiwei Cai4505fc62018-05-17 18:35:19 +08007550#endif
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307551 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true},
7552 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true},
7553 {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true},
7554 {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false},
Ashish Kumar Dhanotiya3f78e682018-03-14 11:19:27 +05307555 {"SET_DISABLE_CHANNEL_LIST", drv_cmd_set_disable_chan_list, true},
Ashish Kumar Dhanotiya2853ba02018-03-15 15:51:25 +05307556 {"GET_DISABLE_CHANNEL_LIST", drv_cmd_get_disable_chan_list, false},
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307557 {"STOP", drv_cmd_dummy, false},
Srinivas Girigowda836475e2018-04-17 14:42:23 -07007558 /* Deprecated commands */
7559 {"RXFILTER-START", drv_cmd_dummy, false},
7560 {"RXFILTER-STOP", drv_cmd_dummy, false},
7561 {"BTCOEXSCAN-START", drv_cmd_dummy, false},
7562 {"BTCOEXSCAN-STOP", drv_cmd_dummy, false},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007563};
7564
7565/**
7566 * hdd_drv_cmd_process() - chooses and runs the proper
7567 * handler based on the input command
7568 * @adapter: Pointer to the hdd adapter
7569 * @cmd: Pointer to the driver command
7570 * @priv_data: Pointer to the data associated with the command
7571 *
7572 * This function parses the input hdd driver command and runs
7573 * the proper handler
7574 *
7575 * Return: 0 for success non-zero for failure
7576 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007577static int hdd_drv_cmd_process(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007578 uint8_t *cmd,
Jeff Johnson353cd292017-08-17 06:47:26 -07007579 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007580{
Jeff Johnson621cf972017-08-28 11:58:44 -07007581 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007582 int i;
7583 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7584 uint8_t *cmd_i = NULL;
7585 hdd_drv_cmd_handler_t handler = NULL;
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307586 int len = 0, cmd_len = 0;
7587 uint8_t *ptr;
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307588 bool args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007589
7590 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007591 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007592 return -EINVAL;
7593 }
7594
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307595 /* Calculate length of the first word */
7596 ptr = strchrnul(cmd, ' ');
7597 cmd_len = ptr - cmd;
7598
Jeff Johnson399c6272017-08-30 10:51:00 -07007599 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007600
7601 for (i = 0; i < cmd_num_total; i++) {
7602
7603 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7604 handler = hdd_drv_cmds[i].handler;
7605 len = strlen(cmd_i);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307606 args = hdd_drv_cmds[i].args;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007607
7608 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007609 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007610 return -EINVAL;
7611 }
7612
Nachiket Kukadeb7e04972017-12-13 20:38:00 +05307613 if (len == cmd_len && strncasecmp(cmd, cmd_i, len) == 0) {
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307614 if (args && drv_cmd_validate(cmd, len))
7615 return -EINVAL;
7616
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007617 return handler(adapter, hdd_ctx,
7618 cmd, len, priv_data);
Rajeev Kumar Sirasanagandlab50e3a52017-08-08 16:37:58 +05307619 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007620 }
7621
7622 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7623}
7624
7625/**
7626 * hdd_driver_command() - top level wlan hdd driver command handler
7627 * @adapter: Pointer to the hdd adapter
7628 * @priv_data: Pointer to the raw command data
7629 *
7630 * This function is the top level wlan hdd driver command handler. It
7631 * handles the command with the help of hdd_drv_cmd_process()
7632 *
7633 * Return: 0 for success non-zero for failure
7634 */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007635static int hdd_driver_command(struct hdd_adapter *adapter,
Jeff Johnson353cd292017-08-17 06:47:26 -07007636 struct hdd_priv_data *priv_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007637{
7638 uint8_t *command = NULL;
7639 int ret = 0;
Jeff Johnson621cf972017-08-28 11:58:44 -07007640 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007641
Dustin Brown491d54b2018-03-14 12:39:11 -07007642 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307643
Anurag Chouhan6d760662016-02-20 16:05:43 +05307644 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007645 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007646 return -EINVAL;
7647 }
7648
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05307649 ret = wlan_hdd_validate_context(hdd_ctx);
7650 if (ret)
7651 return ret;
7652
7653 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
7654 hdd_err("Driver module is closed; command can not be processed");
7655 return -EINVAL;
7656 }
7657
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007658 /*
7659 * Note that valid pointers are provided by caller
7660 */
7661
7662 /* copy to local struct to avoid numerous changes to legacy code */
7663 if (priv_data->total_len <= 0 ||
7664 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007665 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007666 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007667 ret = -EINVAL;
7668 goto exit;
7669 }
7670
7671 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007672 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007673 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007674 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007675 ret = -ENOMEM;
7676 goto exit;
7677 }
7678
7679 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7680 ret = -EFAULT;
7681 goto exit;
7682 }
7683
7684 /* Make sure the command is NUL-terminated */
7685 command[priv_data->total_len] = '\0';
7686
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007687 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007688 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7689
7690exit:
7691 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007692 qdf_mem_free(command);
Dustin Browne74003f2018-03-14 12:51:58 -07007693 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007694 return ret;
7695}
7696
7697#ifdef CONFIG_COMPAT
Jeff Johnsone44b7012017-09-10 15:25:47 -07007698static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007699{
7700 struct {
7701 compat_uptr_t buf;
7702 int used_len;
7703 int total_len;
7704 } compat_priv_data;
Jeff Johnson353cd292017-08-17 06:47:26 -07007705 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007706 int ret = 0;
7707
7708 /*
7709 * Note that adapter and ifr have already been verified by caller,
7710 * and HDD context has also been validated
7711 */
7712 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7713 sizeof(compat_priv_data))) {
7714 ret = -EFAULT;
7715 goto exit;
7716 }
7717 priv_data.buf = compat_ptr(compat_priv_data.buf);
7718 priv_data.used_len = compat_priv_data.used_len;
7719 priv_data.total_len = compat_priv_data.total_len;
7720 ret = hdd_driver_command(adapter, &priv_data);
7721exit:
7722 return ret;
7723}
7724#else /* CONFIG_COMPAT */
Jeff Johnsone44b7012017-09-10 15:25:47 -07007725static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007726{
7727 /* will never be invoked */
7728 return 0;
7729}
7730#endif /* CONFIG_COMPAT */
7731
Jeff Johnsone44b7012017-09-10 15:25:47 -07007732static int hdd_driver_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007733{
Jeff Johnson353cd292017-08-17 06:47:26 -07007734 struct hdd_priv_data priv_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007735 int ret = 0;
7736
7737 /*
7738 * Note that adapter and ifr have already been verified by caller,
7739 * and HDD context has also been validated
7740 */
7741 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7742 ret = -EFAULT;
7743 else
7744 ret = hdd_driver_command(adapter, &priv_data);
7745
7746 return ret;
7747}
7748
7749/**
7750 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7751 * @dev: device upon which the ioctl was received
7752 * @ifr: ioctl request information
7753 * @cmd: ioctl command
7754 *
7755 * This function does initial processing of wlan device ioctls.
7756 * Currently two flavors of ioctls are supported. The primary ioctl
7757 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7758 * for Android "DRIVER" commands. The other ioctl that is
7759 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7760 * for FTM on some platforms. This function simply verifies that the
7761 * driver is in a sane state, and that the ioctl is one of the
7762 * supported flavors, in which case flavor-specific handlers are
7763 * dispatched.
7764 *
7765 * Return: 0 on success, non-zero on error
7766 */
7767static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7768{
Jeff Johnsone44b7012017-09-10 15:25:47 -07007769 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson621cf972017-08-28 11:58:44 -07007770 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007771 int ret;
7772
Dustin Brownfdf17c12018-03-14 12:55:34 -07007773 hdd_enter_dev(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307774
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007775 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007776 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007777 ret = -ENODEV;
7778 goto exit;
7779 }
7780
7781 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007782 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007783 ret = -EINVAL;
7784 goto exit;
7785 }
7786#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307787 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007788 if (SIOCIOCTLTX99 == cmd) {
7789 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7790 goto exit;
7791 }
7792 }
7793#endif
7794
7795 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7796 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307797 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007798 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007799
7800 switch (cmd) {
7801 case (SIOCDEVPRIVATE + 1):
Mahesh Kumar Kalikot Veetil885a77b2018-03-26 14:46:59 -07007802 if (in_compat_syscall())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007803 ret = hdd_driver_compat_ioctl(adapter, ifr);
7804 else
7805 ret = hdd_driver_ioctl(adapter, ifr);
7806 break;
7807 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007808 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007809 ret = -EINVAL;
7810 break;
7811 }
7812exit:
Dustin Browne74003f2018-03-14 12:51:58 -07007813 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007814 return ret;
7815}
7816
7817/**
7818 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
Dustin Brown98f7c822019-03-06 12:25:49 -08007819 * @net_dev: device upon which the ioctl was received
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007820 * @ifr: ioctl request information
7821 * @cmd: ioctl command
7822 *
7823 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7824 * which is where the ioctls are really handled.
7825 *
7826 * Return: 0 on success, non-zero on error
7827 */
Dustin Brown98f7c822019-03-06 12:25:49 -08007828int hdd_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007829{
Dustin Brown98f7c822019-03-06 12:25:49 -08007830 struct osif_vdev_sync *vdev_sync;
7831 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007832
Dustin Brown98f7c822019-03-06 12:25:49 -08007833 errno = osif_vdev_sync_op_start(net_dev, &vdev_sync);
7834 if (errno)
7835 return errno;
7836
7837 errno = __hdd_ioctl(net_dev, ifr, cmd);
7838
7839 osif_vdev_sync_op_stop(vdev_sync);
7840
7841 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007842}
Dustin Brown98f7c822019-03-06 12:25:49 -08007843