xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /* Include Files */
21*5113495bSYour Name 
22*5113495bSYour Name #include "osif_sync.h"
23*5113495bSYour Name #include <wlan_hdd_includes.h>
24*5113495bSYour Name #include <wlan_hdd_wowl.h>
25*5113495bSYour Name #include <wlan_hdd_stats.h>
26*5113495bSYour Name #include "cfg_ucfg_api.h"
27*5113495bSYour Name #include "wlan_hdd_trace.h"
28*5113495bSYour Name #include "wlan_hdd_ioctl.h"
29*5113495bSYour Name #include "wlan_hdd_power.h"
30*5113495bSYour Name #include "wlan_hdd_regulatory.h"
31*5113495bSYour Name #include "wlan_osif_request_manager.h"
32*5113495bSYour Name #include "wlan_hdd_driver_ops.h"
33*5113495bSYour Name #include "wlan_policy_mgr_api.h"
34*5113495bSYour Name #include "wlan_hdd_hostapd.h"
35*5113495bSYour Name #include "scheduler_api.h"
36*5113495bSYour Name #include "wlan_reg_ucfg_api.h"
37*5113495bSYour Name #include "wlan_hdd_p2p.h"
38*5113495bSYour Name #include <linux/ctype.h>
39*5113495bSYour Name #include "wma.h"
40*5113495bSYour Name #include "wlan_hdd_napi.h"
41*5113495bSYour Name #include "wlan_mlme_ucfg_api.h"
42*5113495bSYour Name #include "target_type.h"
43*5113495bSYour Name #ifdef FEATURE_WLAN_ESE
44*5113495bSYour Name #include <sme_api.h>
45*5113495bSYour Name #include <sir_api.h>
46*5113495bSYour Name #endif
47*5113495bSYour Name #include "wlan_hdd_object_manager.h"
48*5113495bSYour Name #include "hif.h"
49*5113495bSYour Name #include "wlan_scan_ucfg_api.h"
50*5113495bSYour Name #include "wlan_reg_ucfg_api.h"
51*5113495bSYour Name #include "qdf_func_tracker.h"
52*5113495bSYour Name #include "wlan_cm_roam_ucfg_api.h"
53*5113495bSYour Name #include "wlan_tdls_api.h"
54*5113495bSYour Name 
55*5113495bSYour Name #if defined(LINUX_QCMBR)
56*5113495bSYour Name #define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
57*5113495bSYour Name #endif
58*5113495bSYour Name 
59*5113495bSYour Name #define SIZE_OF_WIFI6E_CHAN_LIST       512
60*5113495bSYour Name 
61*5113495bSYour Name /*
62*5113495bSYour Name  * Size of Driver command strings from upper layer
63*5113495bSYour Name  */
64*5113495bSYour Name #define SIZE_OF_SETROAMMODE             11      /* size of SETROAMMODE */
65*5113495bSYour Name #define SIZE_OF_GETROAMMODE             11      /* size of GETROAMMODE */
66*5113495bSYour Name #define SIZE_OF_SETSUSPENDMODE          14
67*5113495bSYour Name 
68*5113495bSYour Name /*
69*5113495bSYour Name  * Size of GETCOUNTRYREV output = (sizeof("GETCOUNTRYREV") = 14) + one (space) +
70*5113495bSYour Name  *				  (sizeof("country_code") = 3) +
71*5113495bSYour Name  *                                one (NULL terminating character)
72*5113495bSYour Name  */
73*5113495bSYour Name #define SIZE_OF_GETCOUNTRYREV_OUTPUT 20
74*5113495bSYour Name 
75*5113495bSYour Name #ifdef FEATURE_WLAN_ESE
76*5113495bSYour Name #define TID_MIN_VALUE 0
77*5113495bSYour Name #define TID_MAX_VALUE 15
78*5113495bSYour Name #endif /* FEATURE_WLAN_ESE */
79*5113495bSYour Name 
80*5113495bSYour Name /*
81*5113495bSYour Name  * Maximum buffer size used for returning the data back to user space
82*5113495bSYour Name  */
83*5113495bSYour Name #define WLAN_MAX_BUF_SIZE 1024
84*5113495bSYour Name #define WLAN_PRIV_DATA_MAX_LEN    8192
85*5113495bSYour Name 
86*5113495bSYour Name /*
87*5113495bSYour Name  * Driver miracast parameters:
88*5113495bSYour Name  * 0-Disabled
89*5113495bSYour Name  * 1-Source, 2-Sink
90*5113495bSYour Name  * 128: miracast connecting time optimization enabled. At present host
91*5113495bSYour Name  * will disable imps to reduce connection time for p2p.
92*5113495bSYour Name  * 129: miracast connecting time optimization disabled
93*5113495bSYour Name  */
94*5113495bSYour Name enum miracast_param {
95*5113495bSYour Name 	MIRACAST_DISABLED,
96*5113495bSYour Name 	MIRACAST_SOURCE,
97*5113495bSYour Name 	MIRACAST_SINK,
98*5113495bSYour Name 	MIRACAST_CONN_OPT_ENABLED = 128,
99*5113495bSYour Name 	MIRACAST_CONN_OPT_DISABLED = 129,
100*5113495bSYour Name };
101*5113495bSYour Name 
102*5113495bSYour Name /*
103*5113495bSYour Name  * When ever we need to print IBSSPEERINFOALL for more than 16 STA
104*5113495bSYour Name  * we will split the printing.
105*5113495bSYour Name  */
106*5113495bSYour Name #define NUM_OF_STA_DATA_TO_PRINT 16
107*5113495bSYour Name 
108*5113495bSYour Name /*
109*5113495bSYour Name  * The host sends the maximum channel count in RCL(Roam channel list) via a
110*5113495bSYour Name  * supplicant vendor event to notify RCL on disconnection.
111*5113495bSYour Name  */
112*5113495bSYour Name #define MAX_RCL_CHANNEL_COUNT 30
113*5113495bSYour Name 
114*5113495bSYour Name #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
115*5113495bSYour Name /**
116*5113495bSYour Name  * struct enable_ext_wow_priv - Private data structure for ext wow
117*5113495bSYour Name  * @ext_wow_should_suspend: Suspend status of ext wow
118*5113495bSYour Name  */
119*5113495bSYour Name struct enable_ext_wow_priv {
120*5113495bSYour Name 	bool ext_wow_should_suspend;
121*5113495bSYour Name };
122*5113495bSYour Name #endif
123*5113495bSYour Name 
124*5113495bSYour Name /*
125*5113495bSYour Name  * Android DRIVER command structures
126*5113495bSYour Name  */
127*5113495bSYour Name struct android_wifi_reassoc_params {
128*5113495bSYour Name 	unsigned char bssid[18];
129*5113495bSYour Name 	int channel;
130*5113495bSYour Name };
131*5113495bSYour Name 
132*5113495bSYour Name #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
133*5113495bSYour Name struct android_wifi_af_params {
134*5113495bSYour Name 	unsigned char bssid[18];
135*5113495bSYour Name 	int channel;
136*5113495bSYour Name 	int dwell_time;
137*5113495bSYour Name 	int len;
138*5113495bSYour Name 	unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
139*5113495bSYour Name };
140*5113495bSYour Name 
141*5113495bSYour Name /*
142*5113495bSYour Name  * Define HDD driver command handling entry, each contains a command
143*5113495bSYour Name  * string and the handler.
144*5113495bSYour Name  */
145*5113495bSYour Name typedef int (*hdd_drv_cmd_handler_t)(struct wlan_hdd_link_info *link_info,
146*5113495bSYour Name 				     struct hdd_context *hdd_ctx,
147*5113495bSYour Name 				     uint8_t *cmd,
148*5113495bSYour Name 				     uint8_t cmd_name_len,
149*5113495bSYour Name 				     struct hdd_priv_data *priv_data);
150*5113495bSYour Name 
151*5113495bSYour Name /**
152*5113495bSYour Name  * struct hdd_drv_cmd - Structure to store ioctl command handling info
153*5113495bSYour Name  * @cmd: Name of the command
154*5113495bSYour Name  * @handler: Command handler to be invoked
155*5113495bSYour Name  * @args: Set to true if command expects input parameters
156*5113495bSYour Name  */
157*5113495bSYour Name struct hdd_drv_cmd {
158*5113495bSYour Name 	const char *cmd;
159*5113495bSYour Name 	hdd_drv_cmd_handler_t handler;
160*5113495bSYour Name 	bool args;
161*5113495bSYour Name };
162*5113495bSYour Name 
163*5113495bSYour Name #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
164*5113495bSYour Name #define WLAN_WAIT_TIME_READY_TO_EXTWOW   2000
165*5113495bSYour Name #define WLAN_HDD_MAX_TCP_PORT            65535
166*5113495bSYour Name #endif
167*5113495bSYour Name 
168*5113495bSYour Name /**
169*5113495bSYour Name  * drv_cmd_validate() - Validates for space in hdd driver command
170*5113495bSYour Name  * @command: pointer to input data (its a NULL terminated string)
171*5113495bSYour Name  * @len: length of command name
172*5113495bSYour Name  *
173*5113495bSYour Name  * This function checks for space after command name and if no space
174*5113495bSYour Name  * is found returns error.
175*5113495bSYour Name  *
176*5113495bSYour Name  * Return: 0 for success non-zero for failure
177*5113495bSYour Name  */
drv_cmd_validate(uint8_t * command,int len)178*5113495bSYour Name static int drv_cmd_validate(uint8_t *command, int len)
179*5113495bSYour Name {
180*5113495bSYour Name 	if (command[len] != ' ')
181*5113495bSYour Name 		return -EINVAL;
182*5113495bSYour Name 
183*5113495bSYour Name 	return 0;
184*5113495bSYour Name }
185*5113495bSYour Name 
186*5113495bSYour Name #ifdef FEATURE_WLAN_ESE
187*5113495bSYour Name struct tsm_priv {
188*5113495bSYour Name 	tAniTrafStrmMetrics tsm_metrics;
189*5113495bSYour Name };
190*5113495bSYour Name 
hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,void * context)191*5113495bSYour Name static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
192*5113495bSYour Name 				 void *context)
193*5113495bSYour Name {
194*5113495bSYour Name 	struct osif_request *request;
195*5113495bSYour Name 	struct tsm_priv *priv;
196*5113495bSYour Name 
197*5113495bSYour Name 	request = osif_request_get(context);
198*5113495bSYour Name 	if (!request) {
199*5113495bSYour Name 		hdd_err("Obsolete request");
200*5113495bSYour Name 		return;
201*5113495bSYour Name 	}
202*5113495bSYour Name 	priv = osif_request_priv(request);
203*5113495bSYour Name 	priv->tsm_metrics = tsm_metrics;
204*5113495bSYour Name 	osif_request_complete(request);
205*5113495bSYour Name 	osif_request_put(request);
206*5113495bSYour Name 	hdd_exit();
207*5113495bSYour Name 
208*5113495bSYour Name }
209*5113495bSYour Name 
hdd_get_tsm_stats(struct hdd_adapter * adapter,const uint8_t tid,tAniTrafStrmMetrics * tsm_metrics)210*5113495bSYour Name static int hdd_get_tsm_stats(struct hdd_adapter *adapter,
211*5113495bSYour Name 			     const uint8_t tid,
212*5113495bSYour Name 			     tAniTrafStrmMetrics *tsm_metrics)
213*5113495bSYour Name {
214*5113495bSYour Name 	struct hdd_context *hdd_ctx;
215*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx;
216*5113495bSYour Name 	QDF_STATUS status;
217*5113495bSYour Name 	int ret;
218*5113495bSYour Name 	void *cookie;
219*5113495bSYour Name 	struct osif_request *request;
220*5113495bSYour Name 	struct tsm_priv *priv;
221*5113495bSYour Name 	static const struct osif_request_params params = {
222*5113495bSYour Name 		.priv_size = sizeof(*priv),
223*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_STATS,
224*5113495bSYour Name 	};
225*5113495bSYour Name 
226*5113495bSYour Name 	if (!adapter) {
227*5113495bSYour Name 		hdd_err("adapter is NULL");
228*5113495bSYour Name 		return -EINVAL;
229*5113495bSYour Name 	}
230*5113495bSYour Name 
231*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
232*5113495bSYour Name 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
233*5113495bSYour Name 
234*5113495bSYour Name 	request = osif_request_alloc(&params);
235*5113495bSYour Name 	if (!request) {
236*5113495bSYour Name 		hdd_err("Request allocation failure");
237*5113495bSYour Name 		return -ENOMEM;
238*5113495bSYour Name 	}
239*5113495bSYour Name 	cookie = osif_request_cookie(request);
240*5113495bSYour Name 
241*5113495bSYour Name 	status = sme_get_tsm_stats(hdd_ctx->mac_handle, hdd_get_tsm_stats_cb,
242*5113495bSYour Name 				   hdd_sta_ctx->conn_info.bssid,
243*5113495bSYour Name 				   cookie, tid);
244*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
245*5113495bSYour Name 		hdd_err("Unable to retrieve tsm statistics");
246*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
247*5113495bSYour Name 		goto cleanup;
248*5113495bSYour Name 	}
249*5113495bSYour Name 
250*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
251*5113495bSYour Name 	if (ret) {
252*5113495bSYour Name 		hdd_err("SME timed out while retrieving tsm statistics");
253*5113495bSYour Name 		goto cleanup;
254*5113495bSYour Name 	}
255*5113495bSYour Name 
256*5113495bSYour Name 	priv = osif_request_priv(request);
257*5113495bSYour Name 	*tsm_metrics = priv->tsm_metrics;
258*5113495bSYour Name 
259*5113495bSYour Name  cleanup:
260*5113495bSYour Name 	osif_request_put(request);
261*5113495bSYour Name 
262*5113495bSYour Name 	return ret;
263*5113495bSYour Name }
264*5113495bSYour Name #endif /*FEATURE_WLAN_ESE */
265*5113495bSYour Name 
hdd_get_band_helper(struct hdd_context * hdd_ctx,int * ui_band)266*5113495bSYour Name static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *ui_band)
267*5113495bSYour Name {
268*5113495bSYour Name 	enum band_info band = -1;
269*5113495bSYour Name 
270*5113495bSYour Name 	ucfg_reg_get_band(hdd_ctx->pdev, &band);
271*5113495bSYour Name 	switch (band) {
272*5113495bSYour Name 	case BAND_ALL:
273*5113495bSYour Name 		*ui_band = WLAN_HDD_UI_BAND_AUTO;
274*5113495bSYour Name 		break;
275*5113495bSYour Name 
276*5113495bSYour Name 	case BAND_2G:
277*5113495bSYour Name 		*ui_band = WLAN_HDD_UI_BAND_2_4_GHZ;
278*5113495bSYour Name 		break;
279*5113495bSYour Name 
280*5113495bSYour Name 	case BAND_5G:
281*5113495bSYour Name 		*ui_band = WLAN_HDD_UI_BAND_5_GHZ;
282*5113495bSYour Name 		break;
283*5113495bSYour Name 
284*5113495bSYour Name 	default:
285*5113495bSYour Name 		hdd_warn("Invalid Band %d", band);
286*5113495bSYour Name 		*ui_band = -1;
287*5113495bSYour Name 		break;
288*5113495bSYour Name 	}
289*5113495bSYour Name }
290*5113495bSYour Name 
291*5113495bSYour Name /**
292*5113495bSYour Name  * hdd_check_and_fill_freq() - to validate chan and convert into freq
293*5113495bSYour Name  * @in_chan: input as channel number or freq to be checked
294*5113495bSYour Name  * @freq: frequency for input in_chan (output parameter)
295*5113495bSYour Name  * @pdev: pdev object
296*5113495bSYour Name  *
297*5113495bSYour Name  * This function checks input "in_chan" is channel number, if yes then fills
298*5113495bSYour Name  * appropriate frequency into "freq" out param. If the "in_param" is greater
299*5113495bSYour Name  * than WNI_CFG_CURRENT_CHANNEL_STAMAX then checks for valid frequencies.
300*5113495bSYour Name  *
301*5113495bSYour Name  * Return: true if "in_chan" is valid channel/frequency; false otherwise
302*5113495bSYour Name  */
hdd_check_and_fill_freq(uint32_t in_chan,qdf_freq_t * freq,struct wlan_objmgr_pdev * pdev)303*5113495bSYour Name static bool hdd_check_and_fill_freq(uint32_t in_chan, qdf_freq_t *freq,
304*5113495bSYour Name 				    struct wlan_objmgr_pdev *pdev)
305*5113495bSYour Name {
306*5113495bSYour Name 	if (in_chan <= WNI_CFG_CURRENT_CHANNEL_STAMAX)
307*5113495bSYour Name 		*freq = wlan_reg_legacy_chan_to_freq(pdev, in_chan);
308*5113495bSYour Name 	else if (WLAN_REG_IS_24GHZ_CH_FREQ(in_chan) ||
309*5113495bSYour Name 		 WLAN_REG_IS_5GHZ_CH_FREQ(in_chan) ||
310*5113495bSYour Name 		 WLAN_REG_IS_6GHZ_CHAN_FREQ(in_chan))
311*5113495bSYour Name 		*freq = in_chan;
312*5113495bSYour Name 	else
313*5113495bSYour Name 		return false;
314*5113495bSYour Name 
315*5113495bSYour Name 	return true;
316*5113495bSYour Name }
317*5113495bSYour Name 
318*5113495bSYour Name /**
319*5113495bSYour Name  * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
320*5113495bSYour Name  * @data: input data
321*5113495bSYour Name  * @bssid: pointer to bssid (output parameter)
322*5113495bSYour Name  * @freq: pointer to freq (output parameter)
323*5113495bSYour Name  * @pdev: pdev object
324*5113495bSYour Name  *
325*5113495bSYour Name  * Return: 0 if parsing is successful; -EINVAL otherwise
326*5113495bSYour Name  */
_hdd_parse_bssid_and_chan(const uint8_t ** data,uint8_t * bssid,qdf_freq_t * freq,struct wlan_objmgr_pdev * pdev)327*5113495bSYour Name static int _hdd_parse_bssid_and_chan(const uint8_t **data,
328*5113495bSYour Name 				     uint8_t *bssid, qdf_freq_t *freq,
329*5113495bSYour Name 				     struct wlan_objmgr_pdev *pdev)
330*5113495bSYour Name {
331*5113495bSYour Name 	const uint8_t *in_ptr;
332*5113495bSYour Name 	int            v = 0;
333*5113495bSYour Name 	int            temp_int;
334*5113495bSYour Name 	uint8_t        temp_buf[32];
335*5113495bSYour Name 
336*5113495bSYour Name 	/* 12 hexa decimal digits, 5 ':' and '\0' */
337*5113495bSYour Name 	uint8_t        mac_addr[18];
338*5113495bSYour Name 
339*5113495bSYour Name 	if (!data || !*data)
340*5113495bSYour Name 		return -EINVAL;
341*5113495bSYour Name 
342*5113495bSYour Name 	in_ptr = *data;
343*5113495bSYour Name 
344*5113495bSYour Name 	in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
345*5113495bSYour Name 	/* no argument after the command */
346*5113495bSYour Name 	if (!in_ptr)
347*5113495bSYour Name 		goto error;
348*5113495bSYour Name 	/* no space after the command */
349*5113495bSYour Name 	else if (SPACE_ASCII_VALUE != *in_ptr)
350*5113495bSYour Name 		goto error;
351*5113495bSYour Name 
352*5113495bSYour Name 	/* remove empty spaces */
353*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
354*5113495bSYour Name 		in_ptr++;
355*5113495bSYour Name 
356*5113495bSYour Name 	/* no argument followed by spaces */
357*5113495bSYour Name 	if ('\0' == *in_ptr)
358*5113495bSYour Name 		goto error;
359*5113495bSYour Name 
360*5113495bSYour Name 	v = sscanf(in_ptr, "%17s", mac_addr);
361*5113495bSYour Name 	if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
362*5113495bSYour Name 		hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
363*5113495bSYour Name 			 v);
364*5113495bSYour Name 		goto error;
365*5113495bSYour Name 	}
366*5113495bSYour Name 
367*5113495bSYour Name 	bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
368*5113495bSYour Name 			hex_to_bin(mac_addr[1]);
369*5113495bSYour Name 	bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
370*5113495bSYour Name 			hex_to_bin(mac_addr[4]);
371*5113495bSYour Name 	bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
372*5113495bSYour Name 			hex_to_bin(mac_addr[7]);
373*5113495bSYour Name 	bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
374*5113495bSYour Name 			hex_to_bin(mac_addr[10]);
375*5113495bSYour Name 	bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
376*5113495bSYour Name 			hex_to_bin(mac_addr[13]);
377*5113495bSYour Name 	bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
378*5113495bSYour Name 			hex_to_bin(mac_addr[16]);
379*5113495bSYour Name 
380*5113495bSYour Name 	/* point to the next argument */
381*5113495bSYour Name 	in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
382*5113495bSYour Name 	/* no argument after the command */
383*5113495bSYour Name 	if (!in_ptr)
384*5113495bSYour Name 		goto error;
385*5113495bSYour Name 
386*5113495bSYour Name 	/* remove empty spaces */
387*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
388*5113495bSYour Name 		in_ptr++;
389*5113495bSYour Name 
390*5113495bSYour Name 	/* no argument followed by spaces */
391*5113495bSYour Name 	if ('\0' == *in_ptr)
392*5113495bSYour Name 		goto error;
393*5113495bSYour Name 
394*5113495bSYour Name 	/* get the next argument ie the channel/freq number */
395*5113495bSYour Name 	v = sscanf(in_ptr, "%31s ", temp_buf);
396*5113495bSYour Name 	if (1 != v)
397*5113495bSYour Name 		goto error;
398*5113495bSYour Name 
399*5113495bSYour Name 	v = kstrtos32(temp_buf, 10, &temp_int);
400*5113495bSYour Name 	if (v < 0 || temp_int < 0)
401*5113495bSYour Name 		goto error;
402*5113495bSYour Name 	else if (!hdd_check_and_fill_freq(temp_int, freq, pdev))
403*5113495bSYour Name 		goto error;
404*5113495bSYour Name 
405*5113495bSYour Name 	*data = in_ptr;
406*5113495bSYour Name 	return 0;
407*5113495bSYour Name error:
408*5113495bSYour Name 	*data = in_ptr;
409*5113495bSYour Name 	return -EINVAL;
410*5113495bSYour Name }
411*5113495bSYour Name 
412*5113495bSYour Name /**
413*5113495bSYour Name  * hdd_parse_send_action_frame_v1_data() - HDD Parse send action frame data
414*5113495bSYour Name  * @command: Pointer to input data
415*5113495bSYour Name  * @bssid: Pointer to target AP BSSID
416*5113495bSYour Name  * @freq: Pointer to the Target AP channel frequency
417*5113495bSYour Name  * @dwell_time: Pointer to the time to stay off-channel
418*5113495bSYour Name  *              after transmitting action frame
419*5113495bSYour Name  * @buf: Pointer to data
420*5113495bSYour Name  * @buf_len: Pointer to data length
421*5113495bSYour Name  * @pdev: pdev object
422*5113495bSYour Name  *
423*5113495bSYour Name  * This function parses the send action frame data passed in the format
424*5113495bSYour Name  * SENDACTIONFRAME<space><bssid><space><channel | frequency><space><dwelltime>
425*5113495bSYour Name  * <space><data>
426*5113495bSYour Name  *
427*5113495bSYour Name  * Return: 0 for success non-zero for failure
428*5113495bSYour Name  */
429*5113495bSYour Name static int
hdd_parse_send_action_frame_v1_data(const uint8_t * command,uint8_t * bssid,qdf_freq_t * freq,uint8_t * dwell_time,uint8_t ** buf,uint8_t * buf_len,struct wlan_objmgr_pdev * pdev)430*5113495bSYour Name hdd_parse_send_action_frame_v1_data(const uint8_t *command,
431*5113495bSYour Name 				    uint8_t *bssid,
432*5113495bSYour Name 				    qdf_freq_t *freq, uint8_t *dwell_time,
433*5113495bSYour Name 				    uint8_t **buf, uint8_t *buf_len,
434*5113495bSYour Name 				    struct wlan_objmgr_pdev *pdev)
435*5113495bSYour Name {
436*5113495bSYour Name 	const uint8_t *in_ptr = command;
437*5113495bSYour Name 	const uint8_t *end_ptr;
438*5113495bSYour Name 	int temp_int;
439*5113495bSYour Name 	int j = 0;
440*5113495bSYour Name 	int i = 0;
441*5113495bSYour Name 	int v = 0;
442*5113495bSYour Name 	uint8_t temp_buf[32];
443*5113495bSYour Name 	uint8_t temp_u8 = 0;
444*5113495bSYour Name 
445*5113495bSYour Name 	if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, freq, pdev))
446*5113495bSYour Name 		return -EINVAL;
447*5113495bSYour Name 
448*5113495bSYour Name 	/* point to the next argument */
449*5113495bSYour Name 	in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
450*5113495bSYour Name 	/* no argument after the command */
451*5113495bSYour Name 	if (!in_ptr)
452*5113495bSYour Name 		return -EINVAL;
453*5113495bSYour Name 	/* removing empty spaces */
454*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
455*5113495bSYour Name 		in_ptr++;
456*5113495bSYour Name 
457*5113495bSYour Name 	/* no argument followed by spaces */
458*5113495bSYour Name 	if ('\0' == *in_ptr)
459*5113495bSYour Name 		return -EINVAL;
460*5113495bSYour Name 
461*5113495bSYour Name 	/* getting the next argument ie the dwell time */
462*5113495bSYour Name 	v = sscanf(in_ptr, "%31s ", temp_buf);
463*5113495bSYour Name 	if (1 != v)
464*5113495bSYour Name 		return -EINVAL;
465*5113495bSYour Name 
466*5113495bSYour Name 	v = kstrtos32(temp_buf, 10, &temp_int);
467*5113495bSYour Name 	if (v < 0 || temp_int < 0)
468*5113495bSYour Name 		return -EINVAL;
469*5113495bSYour Name 
470*5113495bSYour Name 	*dwell_time = temp_int;
471*5113495bSYour Name 
472*5113495bSYour Name 	/* point to the next argument */
473*5113495bSYour Name 	in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
474*5113495bSYour Name 	/* no argument after the command */
475*5113495bSYour Name 	if (!in_ptr)
476*5113495bSYour Name 		return -EINVAL;
477*5113495bSYour Name 	/* removing empty spaces */
478*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
479*5113495bSYour Name 		in_ptr++;
480*5113495bSYour Name 
481*5113495bSYour Name 	/* no argument followed by spaces */
482*5113495bSYour Name 	if ('\0' == *in_ptr)
483*5113495bSYour Name 		return -EINVAL;
484*5113495bSYour Name 
485*5113495bSYour Name 	/* find the length of data */
486*5113495bSYour Name 	end_ptr = in_ptr;
487*5113495bSYour Name 	while (('\0' != *end_ptr))
488*5113495bSYour Name 		end_ptr++;
489*5113495bSYour Name 
490*5113495bSYour Name 	*buf_len = end_ptr - in_ptr;
491*5113495bSYour Name 	if (*buf_len <= 0)
492*5113495bSYour Name 		return -EINVAL;
493*5113495bSYour Name 
494*5113495bSYour Name 	/*
495*5113495bSYour Name 	 * Allocate the number of bytes based on the number of input characters
496*5113495bSYour Name 	 * whether it is even or odd.
497*5113495bSYour Name 	 * if the number of input characters are even, then we need N/2 byte.
498*5113495bSYour Name 	 * if the number of input characters are odd, then we need do (N+1)/2
499*5113495bSYour Name 	 * to compensate rounding off.
500*5113495bSYour Name 	 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
501*5113495bSYour Name 	 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
502*5113495bSYour Name 	 */
503*5113495bSYour Name 	*buf = qdf_mem_malloc((*buf_len + 1) / 2);
504*5113495bSYour Name 	if (!*buf)
505*5113495bSYour Name 		return -ENOMEM;
506*5113495bSYour Name 
507*5113495bSYour Name 	/* the buffer received from the upper layer is character buffer,
508*5113495bSYour Name 	 * we need to prepare the buffer taking 2 characters in to a U8 hex
509*5113495bSYour Name 	 * decimal number for example 7f0000f0...form a buffer to contain 7f
510*5113495bSYour Name 	 * in 0th location, 00 in 1st and f0 in 3rd location
511*5113495bSYour Name 	 */
512*5113495bSYour Name 	for (i = 0, j = 0; j < *buf_len; j += 2) {
513*5113495bSYour Name 		if (j + 1 == *buf_len) {
514*5113495bSYour Name 			temp_u8 = hex_to_bin(in_ptr[j]);
515*5113495bSYour Name 		} else {
516*5113495bSYour Name 			temp_u8 =
517*5113495bSYour Name 				(hex_to_bin(in_ptr[j]) << 4) |
518*5113495bSYour Name 				(hex_to_bin(in_ptr[j + 1]));
519*5113495bSYour Name 		}
520*5113495bSYour Name 		(*buf)[i++] = temp_u8;
521*5113495bSYour Name 	}
522*5113495bSYour Name 	*buf_len = i;
523*5113495bSYour Name 	return 0;
524*5113495bSYour Name }
525*5113495bSYour Name 
526*5113495bSYour Name /**
527*5113495bSYour Name  * hdd_parse_reassoc_command_v1_data() - HDD Parse reassoc command data
528*5113495bSYour Name  * @command: Pointer to input data (its a NULL terminated string)
529*5113495bSYour Name  * @bssid: Pointer to target Ap bssid
530*5113495bSYour Name  * @freq: Pointer to the Target AP frequency
531*5113495bSYour Name  * @pdev: pdev object
532*5113495bSYour Name  *
533*5113495bSYour Name  * This function parses the reasoc command data passed in the format
534*5113495bSYour Name  * REASSOC<space><bssid><space><channel/frequency>.
535*5113495bSYour Name  *
536*5113495bSYour Name  * If reassoc MAC from user space is broadcast MAC as:
537*5113495bSYour Name  * "wpa_cli DRIVER FASTREASSOC ff:ff:ff:ff:ff:ff 0",
538*5113495bSYour Name  * user space invoked roaming candidate selection will base on firmware score
539*5113495bSYour Name  * algorithm, current connection will be kept if current AP has highest
540*5113495bSYour Name  * score. It is requirement from customer which can avoid ping-pong roaming.
541*5113495bSYour Name  *
542*5113495bSYour Name  * Return: 0 for success non-zero for failure
543*5113495bSYour Name  */
hdd_parse_reassoc_command_v1_data(const uint8_t * command,uint8_t * bssid,qdf_freq_t * freq,struct wlan_objmgr_pdev * pdev)544*5113495bSYour Name static int hdd_parse_reassoc_command_v1_data(const uint8_t *command,
545*5113495bSYour Name 					     uint8_t *bssid, qdf_freq_t *freq,
546*5113495bSYour Name 					     struct wlan_objmgr_pdev *pdev)
547*5113495bSYour Name {
548*5113495bSYour Name 	const uint8_t *in_ptr = command;
549*5113495bSYour Name 
550*5113495bSYour Name 	if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, freq, pdev))
551*5113495bSYour Name 		return -EINVAL;
552*5113495bSYour Name 
553*5113495bSYour Name 	return 0;
554*5113495bSYour Name }
555*5113495bSYour Name 
556*5113495bSYour Name /**
557*5113495bSYour Name  * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
558*5113495bSYour Name  * @adapter:	Adapter upon which the command was received
559*5113495bSYour Name  * @command:	ASCII text command that was received
560*5113495bSYour Name  *
561*5113495bSYour Name  * This function parses the v1 REASSOC command with the format
562*5113495bSYour Name  *
563*5113495bSYour Name  *    REASSOC xx:xx:xx:xx:xx:xx CH/FREQ
564*5113495bSYour Name  *
565*5113495bSYour Name  * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
566*5113495bSYour Name  * BSSID and CH/FREQ is the ASCII representation of the channel/frequency.
567*5113495bSYour Name  * For example
568*5113495bSYour Name  *
569*5113495bSYour Name  *    REASSOC 00:0a:0b:11:22:33 48
570*5113495bSYour Name  *    REASSOC 00:0a:0b:11:22:33 2412
571*5113495bSYour Name  *
572*5113495bSYour Name  * Return: 0 for success non-zero for failure
573*5113495bSYour Name  */
hdd_parse_reassoc_v1(struct hdd_adapter * adapter,const char * command)574*5113495bSYour Name static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command)
575*5113495bSYour Name {
576*5113495bSYour Name 	qdf_freq_t freq = 0;
577*5113495bSYour Name 	tSirMacAddr bssid;
578*5113495bSYour Name 	int ret;
579*5113495bSYour Name 	struct qdf_mac_addr target_bssid;
580*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
581*5113495bSYour Name 	QDF_STATUS status;
582*5113495bSYour Name 	struct wlan_objmgr_pdev *pdev;
583*5113495bSYour Name 
584*5113495bSYour Name 	pdev = wlan_vdev_get_pdev(adapter->deflink->vdev);
585*5113495bSYour Name 	ret = hdd_parse_reassoc_command_v1_data(command, bssid, &freq, pdev);
586*5113495bSYour Name 	if (ret) {
587*5113495bSYour Name 		hdd_err("Failed to parse reassoc command data");
588*5113495bSYour Name 		return ret;
589*5113495bSYour Name 	}
590*5113495bSYour Name 
591*5113495bSYour Name 	qdf_mem_copy(target_bssid.bytes, bssid, sizeof(tSirMacAddr));
592*5113495bSYour Name 	status = ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev,
593*5113495bSYour Name 					  adapter->deflink->vdev_id,
594*5113495bSYour Name 					  &target_bssid, freq,
595*5113495bSYour Name 					  CM_ROAMING_USER);
596*5113495bSYour Name 	return qdf_status_to_os_return(status);
597*5113495bSYour Name }
598*5113495bSYour Name 
599*5113495bSYour Name /**
600*5113495bSYour Name  * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
601*5113495bSYour Name  * @adapter:	Adapter upon which the command was received
602*5113495bSYour Name  * @command:	Command that was received, ASCII command
603*5113495bSYour Name  *		followed by binary data
604*5113495bSYour Name  * @total_len:  Total length of the command received
605*5113495bSYour Name  *
606*5113495bSYour Name  * This function parses the v2 REASSOC command with the format
607*5113495bSYour Name  *
608*5113495bSYour Name  *    REASSOC <android_wifi_reassoc_params>
609*5113495bSYour Name  *
610*5113495bSYour Name  * Return: 0 for success non-zero for failure
611*5113495bSYour Name  */
hdd_parse_reassoc_v2(struct hdd_adapter * adapter,const char * command,int total_len)612*5113495bSYour Name static int hdd_parse_reassoc_v2(struct hdd_adapter *adapter,
613*5113495bSYour Name 				const char *command,
614*5113495bSYour Name 				int total_len)
615*5113495bSYour Name {
616*5113495bSYour Name 	struct android_wifi_reassoc_params params;
617*5113495bSYour Name 	tSirMacAddr bssid;
618*5113495bSYour Name 	qdf_freq_t freq = 0;
619*5113495bSYour Name 	int ret;
620*5113495bSYour Name 	struct qdf_mac_addr target_bssid;
621*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
622*5113495bSYour Name 	QDF_STATUS status;
623*5113495bSYour Name 	struct wlan_objmgr_pdev *pdev;
624*5113495bSYour Name 
625*5113495bSYour Name 	pdev = wlan_vdev_get_pdev(adapter->deflink->vdev);
626*5113495bSYour Name 	if (total_len < sizeof(params) + 8) {
627*5113495bSYour Name 		hdd_err("Invalid command length");
628*5113495bSYour Name 		return -EINVAL;
629*5113495bSYour Name 	}
630*5113495bSYour Name 
631*5113495bSYour Name 	/* The params are located after "REASSOC " */
632*5113495bSYour Name 	memcpy(&params, command + 8, sizeof(params));
633*5113495bSYour Name 
634*5113495bSYour Name 	if (!mac_pton(params.bssid, (u8 *) &bssid)) {
635*5113495bSYour Name 		hdd_err("MAC address parsing failed");
636*5113495bSYour Name 		ret = -EINVAL;
637*5113495bSYour Name 	} else {
638*5113495bSYour Name 		/*
639*5113495bSYour Name 		 * In Reassoc command, user can send channel number or frequency
640*5113495bSYour Name 		 * along with BSSID. If params.channel param of REASSOC command
641*5113495bSYour Name 		 * is less than WNI_CFG_CURRENT_CHANNEL_STAMAX, then host
642*5113495bSYour Name 		 * consider this as channel number else frequency.
643*5113495bSYour Name 		 */
644*5113495bSYour Name 		if (!hdd_check_and_fill_freq(params.channel, &freq, pdev))
645*5113495bSYour Name 			return -EINVAL;
646*5113495bSYour Name 
647*5113495bSYour Name 		qdf_mem_copy(target_bssid.bytes, bssid, sizeof(tSirMacAddr));
648*5113495bSYour Name 		status = ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev,
649*5113495bSYour Name 						  adapter->deflink->vdev_id,
650*5113495bSYour Name 						  &target_bssid, freq,
651*5113495bSYour Name 						  CM_ROAMING_USER);
652*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
653*5113495bSYour Name 	}
654*5113495bSYour Name 
655*5113495bSYour Name 	return ret;
656*5113495bSYour Name }
657*5113495bSYour Name 
658*5113495bSYour Name /**
659*5113495bSYour Name  * hdd_parse_reassoc() - parse the REASSOC command
660*5113495bSYour Name  * @adapter:	Adapter upon which the command was received
661*5113495bSYour Name  * @command:	Command that was received
662*5113495bSYour Name  * @total_len:  Total length of the command received
663*5113495bSYour Name  *
664*5113495bSYour Name  * There are two different versions of the REASSOC command.  Version 1
665*5113495bSYour Name  * of the command contains a parameter list that is ASCII characters
666*5113495bSYour Name  * whereas version 2 contains a combination of ASCII and binary
667*5113495bSYour Name  * payload.  Determine if a version 1 or a version 2 command is being
668*5113495bSYour Name  * parsed by examining the parameters, and then dispatch the parser
669*5113495bSYour Name  * that is appropriate for the command.
670*5113495bSYour Name  *
671*5113495bSYour Name  * Return: 0 for success non-zero for failure
672*5113495bSYour Name  */
hdd_parse_reassoc(struct hdd_adapter * adapter,const char * command,int total_len)673*5113495bSYour Name static int hdd_parse_reassoc(struct hdd_adapter *adapter, const char *command,
674*5113495bSYour Name 			     int total_len)
675*5113495bSYour Name {
676*5113495bSYour Name 	int ret;
677*5113495bSYour Name 
678*5113495bSYour Name 	/* both versions start with "REASSOC "
679*5113495bSYour Name 	 * v1 has a bssid and channel # as an ASCII string
680*5113495bSYour Name 	 *    REASSOC xx:xx:xx:xx:xx:xx CH/FREQ
681*5113495bSYour Name 	 * v2 has a C struct
682*5113495bSYour Name 	 *    REASSOC <binary c struct>
683*5113495bSYour Name 	 *
684*5113495bSYour Name 	 * The first field in the v2 struct is also the bssid in ASCII.
685*5113495bSYour Name 	 * But in the case of a v2 message the BSSID is NUL-terminated.
686*5113495bSYour Name 	 * Hence we can peek at that offset to see if this is V1 or V2
687*5113495bSYour Name 	 * REASSOC xx:xx:xx:xx:xx:xx*
688*5113495bSYour Name 	 *           1111111111222222
689*5113495bSYour Name 	 * 01234567890123456789012345
690*5113495bSYour Name 	 */
691*5113495bSYour Name 
692*5113495bSYour Name 	if (total_len < 26) {
693*5113495bSYour Name 		hdd_err("Invalid command, total_len = %d", total_len);
694*5113495bSYour Name 		return -EINVAL;
695*5113495bSYour Name 	}
696*5113495bSYour Name 
697*5113495bSYour Name 	if (command[25])
698*5113495bSYour Name 		ret = hdd_parse_reassoc_v1(adapter, command);
699*5113495bSYour Name 	else
700*5113495bSYour Name 		ret = hdd_parse_reassoc_v2(adapter, command, total_len);
701*5113495bSYour Name 
702*5113495bSYour Name 	return ret;
703*5113495bSYour Name }
704*5113495bSYour Name 
705*5113495bSYour Name /**
706*5113495bSYour Name  * hdd_sendactionframe() - send a userspace-supplied action frame
707*5113495bSYour Name  * @adapter:	Adapter upon which the command was received
708*5113495bSYour Name  * @bssid:	BSSID target of the action frame
709*5113495bSYour Name  * @freq:	Frequency upon which to send the frame
710*5113495bSYour Name  * @dwell_time:	Amount of time to dwell when the frame is sent
711*5113495bSYour Name  * @payload_len:Length of the payload
712*5113495bSYour Name  * @payload:	Payload of the frame
713*5113495bSYour Name  *
714*5113495bSYour Name  * This function sends a userspace-supplied action frame
715*5113495bSYour Name  *
716*5113495bSYour Name  * Return: 0 for success non-zero for failure
717*5113495bSYour Name  */
718*5113495bSYour Name static int
hdd_sendactionframe(struct hdd_adapter * adapter,const uint8_t * bssid,const qdf_freq_t freq,const uint8_t dwell_time,const int payload_len,const uint8_t * payload)719*5113495bSYour Name hdd_sendactionframe(struct hdd_adapter *adapter, const uint8_t *bssid,
720*5113495bSYour Name 		    const qdf_freq_t freq, const uint8_t dwell_time,
721*5113495bSYour Name 		    const int payload_len, const uint8_t *payload)
722*5113495bSYour Name {
723*5113495bSYour Name 	struct ieee80211_channel chan;
724*5113495bSYour Name 	int frame_len, ret = 0;
725*5113495bSYour Name 	uint8_t *frame;
726*5113495bSYour Name 	struct ieee80211_hdr_3addr *hdr;
727*5113495bSYour Name 	u64 cookie;
728*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
729*5113495bSYour Name 	struct hdd_context *hdd_ctx;
730*5113495bSYour Name 	tpSirMacVendorSpecificFrameHdr vendor =
731*5113495bSYour Name 		(tpSirMacVendorSpecificFrameHdr) payload;
732*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
733*5113495bSYour Name 	struct cfg80211_mgmt_tx_params params;
734*5113495bSYour Name #endif
735*5113495bSYour Name 
736*5113495bSYour Name 	if (payload_len < sizeof(tSirMacVendorSpecificFrameHdr)) {
737*5113495bSYour Name 		hdd_warn("Invalid payload length: %d", payload_len);
738*5113495bSYour Name 		return -EINVAL;
739*5113495bSYour Name 	}
740*5113495bSYour Name 
741*5113495bSYour Name 	if (QDF_STA_MODE != adapter->device_mode) {
742*5113495bSYour Name 		hdd_warn("Unsupported in mode %s(%d)",
743*5113495bSYour Name 			 qdf_opmode_str(adapter->device_mode),
744*5113495bSYour Name 			 adapter->device_mode);
745*5113495bSYour Name 		return -EINVAL;
746*5113495bSYour Name 	}
747*5113495bSYour Name 
748*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
749*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
750*5113495bSYour Name 
751*5113495bSYour Name 	/* if not associated, no need to send action frame */
752*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
753*5113495bSYour Name 		hdd_warn("Not associated");
754*5113495bSYour Name 		ret = -EINVAL;
755*5113495bSYour Name 		goto exit;
756*5113495bSYour Name 	}
757*5113495bSYour Name 
758*5113495bSYour Name 	/*
759*5113495bSYour Name 	 * if the target bssid is different from currently associated AP,
760*5113495bSYour Name 	 * then no need to send action frame
761*5113495bSYour Name 	 */
762*5113495bSYour Name 	if (memcmp(bssid, sta_ctx->conn_info.bssid.bytes,
763*5113495bSYour Name 			QDF_MAC_ADDR_SIZE)) {
764*5113495bSYour Name 		hdd_warn("STA is not associated to this AP");
765*5113495bSYour Name 		ret = -EINVAL;
766*5113495bSYour Name 		goto exit;
767*5113495bSYour Name 	}
768*5113495bSYour Name 
769*5113495bSYour Name 	chan.center_freq = freq;
770*5113495bSYour Name 	/* Check if it is specific action frame */
771*5113495bSYour Name 	if (vendor->category ==
772*5113495bSYour Name 	    ACTION_CATEGORY_VENDOR_SPECIFIC) {
773*5113495bSYour Name 		static const uint8_t oui[] = { 0x00, 0x00, 0xf0 };
774*5113495bSYour Name 
775*5113495bSYour Name 		if (!qdf_mem_cmp(vendor->Oui, oui, 3)) {
776*5113495bSYour Name 			/*
777*5113495bSYour Name 			 * if the freq number is different from operating
778*5113495bSYour Name 			 * freq then no need to send action frame
779*5113495bSYour Name 			 */
780*5113495bSYour Name 			if (freq) {
781*5113495bSYour Name 				if (freq != sta_ctx->conn_info.chan_freq) {
782*5113495bSYour Name 					hdd_warn("freq(%u) is different from operating freq(%u)",
783*5113495bSYour Name 						 freq,
784*5113495bSYour Name 						 sta_ctx->conn_info.chan_freq);
785*5113495bSYour Name 					ret = -EINVAL;
786*5113495bSYour Name 					goto exit;
787*5113495bSYour Name 				}
788*5113495bSYour Name 				/*
789*5113495bSYour Name 				 * If channel number is specified and same
790*5113495bSYour Name 				 * as home channel, ensure that action frame
791*5113495bSYour Name 				 * is sent immediately by cancelling
792*5113495bSYour Name 				 * roaming scans. Otherwise large dwell times
793*5113495bSYour Name 				 * may cause long delays in sending action
794*5113495bSYour Name 				 * frames.
795*5113495bSYour Name 				 */
796*5113495bSYour Name 				ucfg_cm_abort_roam_scan(
797*5113495bSYour Name 						hdd_ctx->pdev,
798*5113495bSYour Name 						adapter->deflink->vdev_id);
799*5113495bSYour Name 			} else {
800*5113495bSYour Name 				/*
801*5113495bSYour Name 				 * 0 is accepted as current home frequency,
802*5113495bSYour Name 				 * delayed transmission of action frame is ok.
803*5113495bSYour Name 				 */
804*5113495bSYour Name 				chan.center_freq = sta_ctx->conn_info.chan_freq;
805*5113495bSYour Name 			}
806*5113495bSYour Name 		}
807*5113495bSYour Name 	}
808*5113495bSYour Name 	if (chan.center_freq == 0) {
809*5113495bSYour Name 		hdd_nofl_err("Invalid freq : %d", freq);
810*5113495bSYour Name 		ret = -EINVAL;
811*5113495bSYour Name 		goto exit;
812*5113495bSYour Name 	}
813*5113495bSYour Name 
814*5113495bSYour Name 	frame_len = payload_len + 24;
815*5113495bSYour Name 	frame = qdf_mem_malloc(frame_len);
816*5113495bSYour Name 	if (!frame) {
817*5113495bSYour Name 		ret = -ENOMEM;
818*5113495bSYour Name 		goto exit;
819*5113495bSYour Name 	}
820*5113495bSYour Name 
821*5113495bSYour Name 	hdr = (struct ieee80211_hdr_3addr *)frame;
822*5113495bSYour Name 	hdr->frame_control =
823*5113495bSYour Name 		cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
824*5113495bSYour Name 	qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
825*5113495bSYour Name 	qdf_mem_copy(hdr->addr2, adapter->mac_addr.bytes,
826*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
827*5113495bSYour Name 	qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
828*5113495bSYour Name 	qdf_mem_copy(hdr + 1, payload, payload_len);
829*5113495bSYour Name 
830*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
831*5113495bSYour Name 	params.chan = &chan;
832*5113495bSYour Name 	params.offchan = 0;
833*5113495bSYour Name 	params.wait = dwell_time;
834*5113495bSYour Name 	params.buf = frame;
835*5113495bSYour Name 	params.len = frame_len;
836*5113495bSYour Name 	params.no_cck = 1;
837*5113495bSYour Name 	params.dont_wait_for_ack = 1;
838*5113495bSYour Name 	ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
839*5113495bSYour Name #else
840*5113495bSYour Name 	ret = wlan_hdd_mgmt_tx(NULL,
841*5113495bSYour Name 			       &(adapter->wdev),
842*5113495bSYour Name 			       &chan, 0,
843*5113495bSYour Name 
844*5113495bSYour Name 			       dwell_time, frame, frame_len, 1, 1, &cookie);
845*5113495bSYour Name #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
846*5113495bSYour Name 
847*5113495bSYour Name 	qdf_mem_free(frame);
848*5113495bSYour Name exit:
849*5113495bSYour Name 	return ret;
850*5113495bSYour Name }
851*5113495bSYour Name 
852*5113495bSYour Name /**
853*5113495bSYour Name  * hdd_parse_sendactionframe_v1() - parse version 1 of the
854*5113495bSYour Name  *       SENDACTIONFRAME command
855*5113495bSYour Name  * @adapter:	Adapter upon which the command was received
856*5113495bSYour Name  * @command:	ASCII text command that was received
857*5113495bSYour Name  *
858*5113495bSYour Name  * This function parses the v1 SENDACTIONFRAME command with the format
859*5113495bSYour Name  *
860*5113495bSYour Name  *    SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
861*5113495bSYour Name  *
862*5113495bSYour Name  * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
863*5113495bSYour Name  * BSSID, CH is the ASCII representation of the channel, DW is the
864*5113495bSYour Name  * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
865*5113495bSYour Name  * payload.  For example
866*5113495bSYour Name  *
867*5113495bSYour Name  *    SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
868*5113495bSYour Name  *
869*5113495bSYour Name  * Return: 0 for success non-zero for failure
870*5113495bSYour Name  */
871*5113495bSYour Name static int
hdd_parse_sendactionframe_v1(struct hdd_adapter * adapter,const char * command)872*5113495bSYour Name hdd_parse_sendactionframe_v1(struct hdd_adapter *adapter, const char *command)
873*5113495bSYour Name {
874*5113495bSYour Name 	qdf_freq_t freq = 0;
875*5113495bSYour Name 	uint8_t dwell_time = 0;
876*5113495bSYour Name 	uint8_t payload_len = 0;
877*5113495bSYour Name 	uint8_t *payload = NULL;
878*5113495bSYour Name 	tSirMacAddr bssid;
879*5113495bSYour Name 	int ret;
880*5113495bSYour Name 	struct wlan_objmgr_pdev *pdev;
881*5113495bSYour Name 
882*5113495bSYour Name 	pdev = wlan_vdev_get_pdev(adapter->deflink->vdev);
883*5113495bSYour Name 	ret = hdd_parse_send_action_frame_v1_data(command, bssid, &freq,
884*5113495bSYour Name 						  &dwell_time, &payload,
885*5113495bSYour Name 						  &payload_len, pdev);
886*5113495bSYour Name 	if (ret) {
887*5113495bSYour Name 		hdd_nofl_err("Failed to parse send action frame data");
888*5113495bSYour Name 	} else {
889*5113495bSYour Name 		ret = hdd_sendactionframe(adapter, bssid, freq,
890*5113495bSYour Name 					  dwell_time, payload_len, payload);
891*5113495bSYour Name 		qdf_mem_free(payload);
892*5113495bSYour Name 	}
893*5113495bSYour Name 
894*5113495bSYour Name 	return ret;
895*5113495bSYour Name }
896*5113495bSYour Name 
897*5113495bSYour Name /**
898*5113495bSYour Name  * hdd_parse_sendactionframe_v2() - parse version 2 of the
899*5113495bSYour Name  *       SENDACTIONFRAME command
900*5113495bSYour Name  * @adapter:	Adapter upon which the command was received
901*5113495bSYour Name  * @command:	Command that was received, ASCII command
902*5113495bSYour Name  *		followed by binary data
903*5113495bSYour Name  * @total_len:  Length of @command
904*5113495bSYour Name  *
905*5113495bSYour Name  * This function parses the v2 SENDACTIONFRAME command with the format
906*5113495bSYour Name  *
907*5113495bSYour Name  *    SENDACTIONFRAME <android_wifi_af_params>
908*5113495bSYour Name  *
909*5113495bSYour Name  * Return: 0 for success non-zero for failure
910*5113495bSYour Name  */
911*5113495bSYour Name static int
hdd_parse_sendactionframe_v2(struct hdd_adapter * adapter,const char * command,int total_len)912*5113495bSYour Name hdd_parse_sendactionframe_v2(struct hdd_adapter *adapter,
913*5113495bSYour Name 			     const char *command, int total_len)
914*5113495bSYour Name {
915*5113495bSYour Name 	struct android_wifi_af_params *params;
916*5113495bSYour Name 	tSirMacAddr bssid;
917*5113495bSYour Name 	int ret;
918*5113495bSYour Name 	int len_wo_payload = 0;
919*5113495bSYour Name 	qdf_freq_t freq = 0;
920*5113495bSYour Name 	struct wlan_objmgr_pdev *pdev;
921*5113495bSYour Name 
922*5113495bSYour Name 	pdev = wlan_vdev_get_pdev(adapter->deflink->vdev);
923*5113495bSYour Name 
924*5113495bSYour Name 	/* The params are located after "SENDACTIONFRAME " */
925*5113495bSYour Name 	total_len -= 16;
926*5113495bSYour Name 	len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE;
927*5113495bSYour Name 	if (total_len <= len_wo_payload) {
928*5113495bSYour Name 		hdd_err("Invalid command len");
929*5113495bSYour Name 		return -EINVAL;
930*5113495bSYour Name 	}
931*5113495bSYour Name 
932*5113495bSYour Name 	params = (struct android_wifi_af_params *)(command + 16);
933*5113495bSYour Name 
934*5113495bSYour Name 	if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
935*5113495bSYour Name 		(params->len > (total_len - len_wo_payload))) {
936*5113495bSYour Name 		hdd_err("Invalid payload length: %d", params->len);
937*5113495bSYour Name 		return -EINVAL;
938*5113495bSYour Name 	}
939*5113495bSYour Name 
940*5113495bSYour Name 	if (!mac_pton(params->bssid, (u8 *)&bssid)) {
941*5113495bSYour Name 		hdd_err("MAC address parsing failed");
942*5113495bSYour Name 		return -EINVAL;
943*5113495bSYour Name 	}
944*5113495bSYour Name 
945*5113495bSYour Name 	if (params->channel < 0 ||
946*5113495bSYour Name 	    params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
947*5113495bSYour Name 		hdd_err("Invalid channel: %d", params->channel);
948*5113495bSYour Name 		return -EINVAL;
949*5113495bSYour Name 	}
950*5113495bSYour Name 
951*5113495bSYour Name 	if (params->dwell_time < 0) {
952*5113495bSYour Name 		hdd_err("Invalid dwell_time: %d", params->dwell_time);
953*5113495bSYour Name 		return -EINVAL;
954*5113495bSYour Name 	}
955*5113495bSYour Name 
956*5113495bSYour Name 	if (!hdd_check_and_fill_freq(params->channel, &freq, pdev)) {
957*5113495bSYour Name 		hdd_err("Invalid channel: %d", params->channel);
958*5113495bSYour Name 		return -EINVAL;
959*5113495bSYour Name 	}
960*5113495bSYour Name 
961*5113495bSYour Name 	ret = hdd_sendactionframe(adapter, bssid, freq, params->dwell_time,
962*5113495bSYour Name 				  params->len, params->data);
963*5113495bSYour Name 
964*5113495bSYour Name 	return ret;
965*5113495bSYour Name }
966*5113495bSYour Name 
967*5113495bSYour Name /**
968*5113495bSYour Name  * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
969*5113495bSYour Name  * @adapter:	Adapter upon which the command was received
970*5113495bSYour Name  * @command:	Command that was received
971*5113495bSYour Name  * @total_len:  Length of @command
972*5113495bSYour Name  *
973*5113495bSYour Name  * There are two different versions of the SENDACTIONFRAME command.
974*5113495bSYour Name  * Version 1 of the command contains a parameter list that is ASCII
975*5113495bSYour Name  * characters whereas version 2 contains a combination of ASCII and
976*5113495bSYour Name  * binary payload.  Determine if a version 1 or a version 2 command is
977*5113495bSYour Name  * being parsed by examining the parameters, and then dispatch the
978*5113495bSYour Name  * parser that is appropriate for the version of the command.
979*5113495bSYour Name  *
980*5113495bSYour Name  * Return: 0 for success non-zero for failure
981*5113495bSYour Name  */
982*5113495bSYour Name static int
hdd_parse_sendactionframe(struct hdd_adapter * adapter,const char * command,int total_len)983*5113495bSYour Name hdd_parse_sendactionframe(struct hdd_adapter *adapter, const char *command,
984*5113495bSYour Name 			  int total_len)
985*5113495bSYour Name {
986*5113495bSYour Name 	int ret;
987*5113495bSYour Name 
988*5113495bSYour Name 	/*
989*5113495bSYour Name 	 * both versions start with "SENDACTIONFRAME "
990*5113495bSYour Name 	 * v1 has a bssid and other parameters as an ASCII string
991*5113495bSYour Name 	 *    SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
992*5113495bSYour Name 	 * v2 has a C struct
993*5113495bSYour Name 	 *    SENDACTIONFRAME <binary c struct>
994*5113495bSYour Name 	 *
995*5113495bSYour Name 	 * The first field in the v2 struct is also the bssid in ASCII.
996*5113495bSYour Name 	 * But in the case of a v2 message the BSSID is NUL-terminated.
997*5113495bSYour Name 	 * Hence we can peek at that offset to see if this is V1 or V2
998*5113495bSYour Name 	 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
999*5113495bSYour Name 	 *           111111111122222222223333
1000*5113495bSYour Name 	 * 0123456789012345678901234567890123
1001*5113495bSYour Name 	 * For both the commands, a valid command must have atleast
1002*5113495bSYour Name 	 * first 34 length of data.
1003*5113495bSYour Name 	 */
1004*5113495bSYour Name 	if (total_len < 34) {
1005*5113495bSYour Name 		hdd_err("Invalid command (total_len=%d)", total_len);
1006*5113495bSYour Name 		return -EINVAL;
1007*5113495bSYour Name 	}
1008*5113495bSYour Name 
1009*5113495bSYour Name 	if (command[33])
1010*5113495bSYour Name 		ret = hdd_parse_sendactionframe_v1(adapter, command);
1011*5113495bSYour Name 	else
1012*5113495bSYour Name 		ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
1013*5113495bSYour Name 
1014*5113495bSYour Name 	return ret;
1015*5113495bSYour Name }
1016*5113495bSYour Name 
1017*5113495bSYour Name #ifdef FEATURE_WLAN_ESE
1018*5113495bSYour Name /**
1019*5113495bSYour Name  * hdd_parse_channellist() - HDD Parse channel list
1020*5113495bSYour Name  * @hdd_ctx: hdd context
1021*5113495bSYour Name  * @command: Pointer to input channel list
1022*5113495bSYour Name  * @channel_freq_list: Pointer to local output array to record
1023*5113495bSYour Name  *                channel list
1024*5113495bSYour Name  * @num_channels: Pointer to number of roam scan channels
1025*5113495bSYour Name  *
1026*5113495bSYour Name  * This function parses the channel list passed in the format
1027*5113495bSYour Name  * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1028*5113495bSYour Name  * Channel 2<space>Channel N
1029*5113495bSYour Name  * if the Number of channels (N) does not match with the actual number
1030*5113495bSYour Name  * of channels passed then take the minimum of N and count of
1031*5113495bSYour Name  * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1032*5113495bSYour Name  * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1033*5113495bSYour Name  * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1034*5113495bSYour Name  * removing duplicate channels from the list
1035*5113495bSYour Name  *
1036*5113495bSYour Name  * Return: 0 for success non-zero for failure
1037*5113495bSYour Name  */
1038*5113495bSYour Name static int
hdd_parse_channellist(struct hdd_context * hdd_ctx,const uint8_t * command,uint32_t * channel_freq_list,uint8_t * num_channels)1039*5113495bSYour Name hdd_parse_channellist(struct hdd_context *hdd_ctx,
1040*5113495bSYour Name 		      const uint8_t *command,
1041*5113495bSYour Name 		      uint32_t *channel_freq_list,
1042*5113495bSYour Name 		      uint8_t *num_channels)
1043*5113495bSYour Name {
1044*5113495bSYour Name 	const uint8_t *in_ptr = command;
1045*5113495bSYour Name 	int temp_int;
1046*5113495bSYour Name 	int j = 0;
1047*5113495bSYour Name 	int v = 0;
1048*5113495bSYour Name 	char buf[32];
1049*5113495bSYour Name 
1050*5113495bSYour Name 	in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
1051*5113495bSYour Name 	/* no argument after the command */
1052*5113495bSYour Name 	if (!in_ptr)
1053*5113495bSYour Name 		return -EINVAL;
1054*5113495bSYour Name 	else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
1055*5113495bSYour Name 		return -EINVAL;
1056*5113495bSYour Name 
1057*5113495bSYour Name 	/* remove empty spaces */
1058*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1059*5113495bSYour Name 		in_ptr++;
1060*5113495bSYour Name 
1061*5113495bSYour Name 	/* no argument followed by spaces */
1062*5113495bSYour Name 	if ('\0' == *in_ptr)
1063*5113495bSYour Name 		return -EINVAL;
1064*5113495bSYour Name 
1065*5113495bSYour Name 	/* get the first argument ie the number of channels */
1066*5113495bSYour Name 	v = sscanf(in_ptr, "%31s ", buf);
1067*5113495bSYour Name 	if (1 != v)
1068*5113495bSYour Name 		return -EINVAL;
1069*5113495bSYour Name 
1070*5113495bSYour Name 	v = kstrtos32(buf, 10, &temp_int);
1071*5113495bSYour Name 	if ((v < 0) ||
1072*5113495bSYour Name 	    (temp_int <= 0) || (temp_int > CFG_VALID_CHANNEL_LIST_LEN))
1073*5113495bSYour Name 		return -EINVAL;
1074*5113495bSYour Name 
1075*5113495bSYour Name 	*num_channels = temp_int;
1076*5113495bSYour Name 
1077*5113495bSYour Name 	hdd_debug("Number of channels are: %d", *num_channels);
1078*5113495bSYour Name 
1079*5113495bSYour Name 	for (j = 0; j < (*num_channels); j++) {
1080*5113495bSYour Name 		/*
1081*5113495bSYour Name 		 * in_ptr pointing to the beginning of first space after number
1082*5113495bSYour Name 		 * of channels
1083*5113495bSYour Name 		 */
1084*5113495bSYour Name 		in_ptr = strpbrk(in_ptr, " ");
1085*5113495bSYour Name 		/* no channel list after the number of channels argument */
1086*5113495bSYour Name 		if (!in_ptr) {
1087*5113495bSYour Name 			if ((j != 0) && (*num_channels == j))
1088*5113495bSYour Name 				return 0;
1089*5113495bSYour Name 			else
1090*5113495bSYour Name 				goto cnt_mismatch;
1091*5113495bSYour Name 		}
1092*5113495bSYour Name 
1093*5113495bSYour Name 		/* remove empty space */
1094*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1095*5113495bSYour Name 			in_ptr++;
1096*5113495bSYour Name 
1097*5113495bSYour Name 		/*
1098*5113495bSYour Name 		 * no channel list after the number of channels
1099*5113495bSYour Name 		 * argument and spaces
1100*5113495bSYour Name 		 */
1101*5113495bSYour Name 		if ('\0' == *in_ptr) {
1102*5113495bSYour Name 			if ((j != 0) && (*num_channels == j))
1103*5113495bSYour Name 				return 0;
1104*5113495bSYour Name 			else
1105*5113495bSYour Name 				goto cnt_mismatch;
1106*5113495bSYour Name 		}
1107*5113495bSYour Name 
1108*5113495bSYour Name 		v = sscanf(in_ptr, "%31s ", buf);
1109*5113495bSYour Name 		if (1 != v)
1110*5113495bSYour Name 			return -EINVAL;
1111*5113495bSYour Name 
1112*5113495bSYour Name 		v = kstrtos32(buf, 10, &temp_int);
1113*5113495bSYour Name 		if ((v < 0) ||
1114*5113495bSYour Name 		    (temp_int <= 0) ||
1115*5113495bSYour Name 		    (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1116*5113495bSYour Name 			return -EINVAL;
1117*5113495bSYour Name 		}
1118*5113495bSYour Name 		channel_freq_list[j] =
1119*5113495bSYour Name 			wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, temp_int);
1120*5113495bSYour Name 
1121*5113495bSYour Name 		hdd_debug("Channel %d added to preferred channel list",
1122*5113495bSYour Name 			  channel_freq_list[j]);
1123*5113495bSYour Name 	}
1124*5113495bSYour Name 
1125*5113495bSYour Name 	return 0;
1126*5113495bSYour Name 
1127*5113495bSYour Name cnt_mismatch:
1128*5113495bSYour Name 	hdd_debug("Mismatch in ch cnt: %d and num of ch: %d", *num_channels, j);
1129*5113495bSYour Name 	*num_channels = 0;
1130*5113495bSYour Name 	return -EINVAL;
1131*5113495bSYour Name 
1132*5113495bSYour Name }
1133*5113495bSYour Name 
1134*5113495bSYour Name /**
1135*5113495bSYour Name  * hdd_parse_plm_cmd() - HDD Parse Plm command
1136*5113495bSYour Name  * @command: Pointer to input data
1137*5113495bSYour Name  * @req: Pointer to output struct plm_req
1138*5113495bSYour Name  *
1139*5113495bSYour Name  * This function parses the plm command passed in the format
1140*5113495bSYour Name  * CCXPLMREQ<space><enable><space><dialog_token><space>
1141*5113495bSYour Name  * <meas_token><space><num_of_bursts><space><burst_int><space>
1142*5113495bSYour Name  * <measu duration><space><burst_len><space><desired_tx_pwr>
1143*5113495bSYour Name  * <space><multcast_addr><space><number_of_channels>
1144*5113495bSYour Name  * <space><channel_numbers>
1145*5113495bSYour Name  *
1146*5113495bSYour Name  * Return: 0 for success non-zero for failure
1147*5113495bSYour Name  */
hdd_parse_plm_cmd(uint8_t * command,struct plm_req_params * req)1148*5113495bSYour Name static QDF_STATUS hdd_parse_plm_cmd(uint8_t *command,
1149*5113495bSYour Name 				    struct plm_req_params *req)
1150*5113495bSYour Name {
1151*5113495bSYour Name 	uint8_t *in_ptr = NULL;
1152*5113495bSYour Name 	int count, content = 0, ret = 0;
1153*5113495bSYour Name 	char buf[32];
1154*5113495bSYour Name 
1155*5113495bSYour Name 	/* move to argument list */
1156*5113495bSYour Name 	in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
1157*5113495bSYour Name 	if (!in_ptr)
1158*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1159*5113495bSYour Name 
1160*5113495bSYour Name 	/* no space after the command */
1161*5113495bSYour Name 	if (SPACE_ASCII_VALUE != *in_ptr)
1162*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1163*5113495bSYour Name 
1164*5113495bSYour Name 	/* remove empty spaces */
1165*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1166*5113495bSYour Name 		in_ptr++;
1167*5113495bSYour Name 
1168*5113495bSYour Name 	/* START/STOP PLM req */
1169*5113495bSYour Name 	ret = sscanf(in_ptr, "%31s ", buf);
1170*5113495bSYour Name 	if (1 != ret)
1171*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1172*5113495bSYour Name 
1173*5113495bSYour Name 	ret = kstrtos32(buf, 10, &content);
1174*5113495bSYour Name 	if (ret < 0)
1175*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1176*5113495bSYour Name 
1177*5113495bSYour Name 	req->enable = content;
1178*5113495bSYour Name 	in_ptr = strpbrk(in_ptr, " ");
1179*5113495bSYour Name 
1180*5113495bSYour Name 	if (!in_ptr)
1181*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1182*5113495bSYour Name 
1183*5113495bSYour Name 	/* remove empty spaces */
1184*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1185*5113495bSYour Name 		in_ptr++;
1186*5113495bSYour Name 
1187*5113495bSYour Name 	/* Dialog token of radio meas req containing meas reqIE */
1188*5113495bSYour Name 	ret = sscanf(in_ptr, "%31s ", buf);
1189*5113495bSYour Name 	if (1 != ret)
1190*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1191*5113495bSYour Name 
1192*5113495bSYour Name 	ret = kstrtos32(buf, 10, &content);
1193*5113495bSYour Name 	if (ret < 0)
1194*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1195*5113495bSYour Name 
1196*5113495bSYour Name 	req->diag_token = content;
1197*5113495bSYour Name 	hdd_debug("diag token %d", req->diag_token);
1198*5113495bSYour Name 	in_ptr = strpbrk(in_ptr, " ");
1199*5113495bSYour Name 
1200*5113495bSYour Name 	if (!in_ptr)
1201*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1202*5113495bSYour Name 
1203*5113495bSYour Name 	/* remove empty spaces */
1204*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1205*5113495bSYour Name 		in_ptr++;
1206*5113495bSYour Name 
1207*5113495bSYour Name 	/* measurement token of meas req IE */
1208*5113495bSYour Name 	ret = sscanf(in_ptr, "%31s ", buf);
1209*5113495bSYour Name 	if (1 != ret)
1210*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1211*5113495bSYour Name 
1212*5113495bSYour Name 	ret = kstrtos32(buf, 10, &content);
1213*5113495bSYour Name 	if (ret < 0)
1214*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1215*5113495bSYour Name 
1216*5113495bSYour Name 	req->meas_token = content;
1217*5113495bSYour Name 	hdd_debug("meas token %d", req->meas_token);
1218*5113495bSYour Name 
1219*5113495bSYour Name 	hdd_debug("PLM req %s", req->enable ? "START" : "STOP");
1220*5113495bSYour Name 	if (req->enable) {
1221*5113495bSYour Name 
1222*5113495bSYour Name 		in_ptr = strpbrk(in_ptr, " ");
1223*5113495bSYour Name 
1224*5113495bSYour Name 		if (!in_ptr)
1225*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1226*5113495bSYour Name 
1227*5113495bSYour Name 		/* remove empty spaces */
1228*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1229*5113495bSYour Name 			in_ptr++;
1230*5113495bSYour Name 
1231*5113495bSYour Name 		/* total number of bursts after which STA stops sending */
1232*5113495bSYour Name 		ret = sscanf(in_ptr, "%31s ", buf);
1233*5113495bSYour Name 		if (1 != ret)
1234*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1235*5113495bSYour Name 
1236*5113495bSYour Name 		ret = kstrtos32(buf, 10, &content);
1237*5113495bSYour Name 		if (ret < 0)
1238*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1239*5113495bSYour Name 
1240*5113495bSYour Name 		if (content < 0)
1241*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1242*5113495bSYour Name 
1243*5113495bSYour Name 		req->num_bursts = content;
1244*5113495bSYour Name 		hdd_debug("num bursts %d", req->num_bursts);
1245*5113495bSYour Name 		in_ptr = strpbrk(in_ptr, " ");
1246*5113495bSYour Name 
1247*5113495bSYour Name 		if (!in_ptr)
1248*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1249*5113495bSYour Name 
1250*5113495bSYour Name 		/* remove empty spaces */
1251*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1252*5113495bSYour Name 			in_ptr++;
1253*5113495bSYour Name 
1254*5113495bSYour Name 		/* burst interval in seconds */
1255*5113495bSYour Name 		ret = sscanf(in_ptr, "%31s ", buf);
1256*5113495bSYour Name 		if (1 != ret)
1257*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1258*5113495bSYour Name 
1259*5113495bSYour Name 		ret = kstrtos32(buf, 10, &content);
1260*5113495bSYour Name 		if (ret < 0)
1261*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1262*5113495bSYour Name 
1263*5113495bSYour Name 		if (content <= 0)
1264*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1265*5113495bSYour Name 
1266*5113495bSYour Name 		req->burst_int = content;
1267*5113495bSYour Name 		hdd_debug("burst int %d", req->burst_int);
1268*5113495bSYour Name 		in_ptr = strpbrk(in_ptr, " ");
1269*5113495bSYour Name 
1270*5113495bSYour Name 		if (!in_ptr)
1271*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1272*5113495bSYour Name 
1273*5113495bSYour Name 		/* remove empty spaces */
1274*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1275*5113495bSYour Name 			in_ptr++;
1276*5113495bSYour Name 
1277*5113495bSYour Name 		/* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1278*5113495bSYour Name 		ret = sscanf(in_ptr, "%31s ", buf);
1279*5113495bSYour Name 		if (1 != ret)
1280*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1281*5113495bSYour Name 
1282*5113495bSYour Name 		ret = kstrtos32(buf, 10, &content);
1283*5113495bSYour Name 		if (ret < 0)
1284*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1285*5113495bSYour Name 
1286*5113495bSYour Name 		if (content <= 0)
1287*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1288*5113495bSYour Name 
1289*5113495bSYour Name 		req->meas_duration = content;
1290*5113495bSYour Name 		hdd_debug("meas duration %d", req->meas_duration);
1291*5113495bSYour Name 		in_ptr = strpbrk(in_ptr, " ");
1292*5113495bSYour Name 
1293*5113495bSYour Name 		if (!in_ptr)
1294*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1295*5113495bSYour Name 
1296*5113495bSYour Name 		/* remove empty spaces */
1297*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1298*5113495bSYour Name 			in_ptr++;
1299*5113495bSYour Name 
1300*5113495bSYour Name 		/* burst length of PLM bursts */
1301*5113495bSYour Name 		ret = sscanf(in_ptr, "%31s ", buf);
1302*5113495bSYour Name 		if (1 != ret)
1303*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1304*5113495bSYour Name 
1305*5113495bSYour Name 		ret = kstrtos32(buf, 10, &content);
1306*5113495bSYour Name 		if (ret < 0)
1307*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1308*5113495bSYour Name 
1309*5113495bSYour Name 		if (content <= 0)
1310*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1311*5113495bSYour Name 
1312*5113495bSYour Name 		req->burst_len = content;
1313*5113495bSYour Name 		hdd_debug("burst len %d", req->burst_len);
1314*5113495bSYour Name 		in_ptr = strpbrk(in_ptr, " ");
1315*5113495bSYour Name 
1316*5113495bSYour Name 		if (!in_ptr)
1317*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1318*5113495bSYour Name 
1319*5113495bSYour Name 		/* remove empty spaces */
1320*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1321*5113495bSYour Name 			in_ptr++;
1322*5113495bSYour Name 
1323*5113495bSYour Name 		/* desired tx power for transmission of PLM bursts */
1324*5113495bSYour Name 		ret = sscanf(in_ptr, "%31s ", buf);
1325*5113495bSYour Name 		if (1 != ret)
1326*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1327*5113495bSYour Name 
1328*5113495bSYour Name 		ret = kstrtos32(buf, 10, &content);
1329*5113495bSYour Name 		if (ret < 0)
1330*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1331*5113495bSYour Name 
1332*5113495bSYour Name 		if (content <= 0)
1333*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1334*5113495bSYour Name 
1335*5113495bSYour Name 		req->desired_tx_pwr = content;
1336*5113495bSYour Name 		hdd_debug("desired tx pwr %d", req->desired_tx_pwr);
1337*5113495bSYour Name 
1338*5113495bSYour Name 		for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
1339*5113495bSYour Name 			in_ptr = strpbrk(in_ptr, " ");
1340*5113495bSYour Name 
1341*5113495bSYour Name 			if (!in_ptr)
1342*5113495bSYour Name 				return QDF_STATUS_E_FAILURE;
1343*5113495bSYour Name 
1344*5113495bSYour Name 			/* remove empty spaces */
1345*5113495bSYour Name 			while ((SPACE_ASCII_VALUE == *in_ptr)
1346*5113495bSYour Name 			       && ('\0' != *in_ptr))
1347*5113495bSYour Name 				in_ptr++;
1348*5113495bSYour Name 
1349*5113495bSYour Name 			ret = sscanf(in_ptr, "%31s ", buf);
1350*5113495bSYour Name 			if (1 != ret)
1351*5113495bSYour Name 				return QDF_STATUS_E_FAILURE;
1352*5113495bSYour Name 
1353*5113495bSYour Name 			ret = kstrtos32(buf, 16, &content);
1354*5113495bSYour Name 			if (ret < 0)
1355*5113495bSYour Name 				return QDF_STATUS_E_FAILURE;
1356*5113495bSYour Name 
1357*5113495bSYour Name 			req->mac_addr.bytes[count] = content;
1358*5113495bSYour Name 		}
1359*5113495bSYour Name 
1360*5113495bSYour Name 		hdd_debug("MAC addr " QDF_MAC_ADDR_FMT,
1361*5113495bSYour Name 			  QDF_MAC_ADDR_REF(req->mac_addr.bytes));
1362*5113495bSYour Name 
1363*5113495bSYour Name 		in_ptr = strpbrk(in_ptr, " ");
1364*5113495bSYour Name 
1365*5113495bSYour Name 		if (!in_ptr)
1366*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1367*5113495bSYour Name 
1368*5113495bSYour Name 		/* remove empty spaces */
1369*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1370*5113495bSYour Name 			in_ptr++;
1371*5113495bSYour Name 
1372*5113495bSYour Name 		/* number of channels */
1373*5113495bSYour Name 		ret = sscanf(in_ptr, "%31s ", buf);
1374*5113495bSYour Name 		if (1 != ret)
1375*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1376*5113495bSYour Name 
1377*5113495bSYour Name 		ret = kstrtos32(buf, 10, &content);
1378*5113495bSYour Name 		if (ret < 0)
1379*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1380*5113495bSYour Name 
1381*5113495bSYour Name 		if (content < 0)
1382*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1383*5113495bSYour Name 
1384*5113495bSYour Name 		content = QDF_MIN(content, CFG_VALID_CHANNEL_LIST_LEN);
1385*5113495bSYour Name 		req->plm_num_ch = content;
1386*5113495bSYour Name 		hdd_debug("num ch: %d", req->plm_num_ch);
1387*5113495bSYour Name 
1388*5113495bSYour Name 		/* Channel numbers */
1389*5113495bSYour Name 		for (count = 0; count < req->plm_num_ch; count++) {
1390*5113495bSYour Name 			in_ptr = strpbrk(in_ptr, " ");
1391*5113495bSYour Name 
1392*5113495bSYour Name 			if (!in_ptr)
1393*5113495bSYour Name 				return QDF_STATUS_E_FAILURE;
1394*5113495bSYour Name 
1395*5113495bSYour Name 			/* remove empty spaces */
1396*5113495bSYour Name 			while ((SPACE_ASCII_VALUE == *in_ptr)
1397*5113495bSYour Name 			       && ('\0' != *in_ptr))
1398*5113495bSYour Name 				in_ptr++;
1399*5113495bSYour Name 
1400*5113495bSYour Name 			ret = sscanf(in_ptr, "%31s ", buf);
1401*5113495bSYour Name 			if (1 != ret)
1402*5113495bSYour Name 				return QDF_STATUS_E_FAILURE;
1403*5113495bSYour Name 
1404*5113495bSYour Name 			ret = kstrtos32(buf, 10, &content);
1405*5113495bSYour Name 			if (ret < 0 || content <= 0 ||
1406*5113495bSYour Name 			    content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
1407*5113495bSYour Name 				return QDF_STATUS_E_FAILURE;
1408*5113495bSYour Name 
1409*5113495bSYour Name 			req->plm_ch_freq_list[count] =
1410*5113495bSYour Name 				cds_chan_to_freq(content);
1411*5113495bSYour Name 			hdd_debug(" ch-freq- %d", req->plm_ch_freq_list[count]);
1412*5113495bSYour Name 		}
1413*5113495bSYour Name 	}
1414*5113495bSYour Name 	/* If PLM START */
1415*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1416*5113495bSYour Name }
1417*5113495bSYour Name #endif
1418*5113495bSYour Name 
1419*5113495bSYour Name #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1420*5113495bSYour Name /**
1421*5113495bSYour Name  * wlan_hdd_ready_to_extwow() - Callback function for enable ext wow
1422*5113495bSYour Name  * @cookie: callback context
1423*5113495bSYour Name  * @is_success: suspend status of ext wow
1424*5113495bSYour Name  *
1425*5113495bSYour Name  * Return: none
1426*5113495bSYour Name  */
wlan_hdd_ready_to_extwow(void * cookie,bool is_success)1427*5113495bSYour Name static void wlan_hdd_ready_to_extwow(void *cookie, bool is_success)
1428*5113495bSYour Name {
1429*5113495bSYour Name 	struct osif_request *request = NULL;
1430*5113495bSYour Name 	struct enable_ext_wow_priv *priv = NULL;
1431*5113495bSYour Name 
1432*5113495bSYour Name 	request = osif_request_get(cookie);
1433*5113495bSYour Name 	if (!request) {
1434*5113495bSYour Name 		hdd_err("obsolete request");
1435*5113495bSYour Name 		return;
1436*5113495bSYour Name 	}
1437*5113495bSYour Name 	priv = osif_request_priv(request);
1438*5113495bSYour Name 	priv->ext_wow_should_suspend = is_success;
1439*5113495bSYour Name 
1440*5113495bSYour Name 	osif_request_complete(request);
1441*5113495bSYour Name 	osif_request_put(request);
1442*5113495bSYour Name }
1443*5113495bSYour Name 
hdd_enable_ext_wow(struct hdd_adapter * adapter,tpSirExtWoWParams arg_params)1444*5113495bSYour Name static int hdd_enable_ext_wow(struct hdd_adapter *adapter,
1445*5113495bSYour Name 			      tpSirExtWoWParams arg_params)
1446*5113495bSYour Name {
1447*5113495bSYour Name 	tSirExtWoWParams params;
1448*5113495bSYour Name 	QDF_STATUS status;
1449*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1450*5113495bSYour Name 	int rc;
1451*5113495bSYour Name 	struct enable_ext_wow_priv *priv = NULL;
1452*5113495bSYour Name 	struct osif_request *request = NULL;
1453*5113495bSYour Name 	void *cookie = NULL;
1454*5113495bSYour Name 	struct osif_request_params hdd_params = {
1455*5113495bSYour Name 		.priv_size = sizeof(*priv),
1456*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_READY_TO_EXTWOW,
1457*5113495bSYour Name 	};
1458*5113495bSYour Name 
1459*5113495bSYour Name 	qdf_mem_copy(&params, arg_params, sizeof(params));
1460*5113495bSYour Name 
1461*5113495bSYour Name 	request = osif_request_alloc(&hdd_params);
1462*5113495bSYour Name 	if (!request) {
1463*5113495bSYour Name 		hdd_err("Request Allocation Failure");
1464*5113495bSYour Name 		return -ENOMEM;
1465*5113495bSYour Name 	}
1466*5113495bSYour Name 	cookie = osif_request_cookie(request);
1467*5113495bSYour Name 
1468*5113495bSYour Name 	status = sme_configure_ext_wow(hdd_ctx->mac_handle, &params,
1469*5113495bSYour Name 				       &wlan_hdd_ready_to_extwow,
1470*5113495bSYour Name 				       cookie);
1471*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
1472*5113495bSYour Name 		hdd_err("sme_configure_ext_wow returned failure %d",
1473*5113495bSYour Name 			 status);
1474*5113495bSYour Name 		rc = -EPERM;
1475*5113495bSYour Name 		goto exit;
1476*5113495bSYour Name 	}
1477*5113495bSYour Name 
1478*5113495bSYour Name 	rc = osif_request_wait_for_response(request);
1479*5113495bSYour Name 	if (rc) {
1480*5113495bSYour Name 		hdd_err("Failed to get ready to extwow");
1481*5113495bSYour Name 		rc = -EPERM;
1482*5113495bSYour Name 		goto exit;
1483*5113495bSYour Name 	}
1484*5113495bSYour Name 
1485*5113495bSYour Name 	priv = osif_request_priv(request);
1486*5113495bSYour Name 	if (!priv->ext_wow_should_suspend) {
1487*5113495bSYour Name 		hdd_err("Received ready to ExtWoW failure");
1488*5113495bSYour Name 		rc = -EPERM;
1489*5113495bSYour Name 		goto exit;
1490*5113495bSYour Name 	}
1491*5113495bSYour Name 
1492*5113495bSYour Name 	if (ucfg_pmo_extwow_is_goto_suspend_enabled(hdd_ctx->psoc)) {
1493*5113495bSYour Name 		hdd_info("Received ready to ExtWoW. Going to suspend");
1494*5113495bSYour Name 
1495*5113495bSYour Name 		rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1496*5113495bSYour Name 		if (rc < 0) {
1497*5113495bSYour Name 			hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1498*5113495bSYour Name 				rc);
1499*5113495bSYour Name 			goto exit;
1500*5113495bSYour Name 		}
1501*5113495bSYour Name 		rc = wlan_hdd_bus_suspend();
1502*5113495bSYour Name 		if (rc) {
1503*5113495bSYour Name 			hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1504*5113495bSYour Name 				rc);
1505*5113495bSYour Name 			wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1506*5113495bSYour Name 			goto exit;
1507*5113495bSYour Name 		}
1508*5113495bSYour Name 	}
1509*5113495bSYour Name 
1510*5113495bSYour Name exit:
1511*5113495bSYour Name 	osif_request_put(request);
1512*5113495bSYour Name 	return rc;
1513*5113495bSYour Name }
1514*5113495bSYour Name 
hdd_enable_ext_wow_parser(struct hdd_adapter * adapter,int vdev_id,int value)1515*5113495bSYour Name static int hdd_enable_ext_wow_parser(struct hdd_adapter *adapter, int vdev_id,
1516*5113495bSYour Name 				     int value)
1517*5113495bSYour Name {
1518*5113495bSYour Name 	tSirExtWoWParams params;
1519*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1520*5113495bSYour Name 	int rc;
1521*5113495bSYour Name 	uint8_t pin1, pin2;
1522*5113495bSYour Name 
1523*5113495bSYour Name 	rc = wlan_hdd_validate_context(hdd_ctx);
1524*5113495bSYour Name 	if (rc)
1525*5113495bSYour Name 		return rc;
1526*5113495bSYour Name 
1527*5113495bSYour Name 	if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1528*5113495bSYour Name 	    value > EXT_WOW_TYPE_APP_TYPE1_2) {
1529*5113495bSYour Name 		hdd_err("Invalid type: %d", value);
1530*5113495bSYour Name 		return -EINVAL;
1531*5113495bSYour Name 	}
1532*5113495bSYour Name 
1533*5113495bSYour Name 	if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1534*5113495bSYour Name 	    hdd_ctx->is_extwow_app_type1_param_set)
1535*5113495bSYour Name 		params.type = value;
1536*5113495bSYour Name 	else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1537*5113495bSYour Name 		 hdd_ctx->is_extwow_app_type2_param_set)
1538*5113495bSYour Name 		params.type = value;
1539*5113495bSYour Name 	else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1540*5113495bSYour Name 		 hdd_ctx->is_extwow_app_type1_param_set &&
1541*5113495bSYour Name 		 hdd_ctx->is_extwow_app_type2_param_set)
1542*5113495bSYour Name 		params.type = value;
1543*5113495bSYour Name 	else {
1544*5113495bSYour Name 		hdd_err("Set app params before enable it value %d",
1545*5113495bSYour Name 			 value);
1546*5113495bSYour Name 		return -EINVAL;
1547*5113495bSYour Name 	}
1548*5113495bSYour Name 
1549*5113495bSYour Name 	params.vdev_id = vdev_id;
1550*5113495bSYour Name 	pin1 = ucfg_pmo_extwow_app1_wakeup_pin_num(hdd_ctx->psoc);
1551*5113495bSYour Name 	pin2 = ucfg_pmo_extwow_app2_wakeup_pin_num(hdd_ctx->psoc);
1552*5113495bSYour Name 	params.wakeup_pin_num = pin1 | (pin2 << 8);
1553*5113495bSYour Name 
1554*5113495bSYour Name 	return hdd_enable_ext_wow(adapter, &params);
1555*5113495bSYour Name }
1556*5113495bSYour Name 
hdd_set_app_type1_params(mac_handle_t mac_handle,tpSirAppType1Params arg_params)1557*5113495bSYour Name static int hdd_set_app_type1_params(mac_handle_t mac_handle,
1558*5113495bSYour Name 				    tpSirAppType1Params arg_params)
1559*5113495bSYour Name {
1560*5113495bSYour Name 	tSirAppType1Params params;
1561*5113495bSYour Name 	QDF_STATUS status;
1562*5113495bSYour Name 
1563*5113495bSYour Name 	qdf_mem_copy(&params, arg_params, sizeof(params));
1564*5113495bSYour Name 
1565*5113495bSYour Name 	status = sme_configure_app_type1_params(mac_handle, &params);
1566*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
1567*5113495bSYour Name 		hdd_err("sme_configure_app_type1_params returned failure %d",
1568*5113495bSYour Name 			 status);
1569*5113495bSYour Name 		return -EPERM;
1570*5113495bSYour Name 	}
1571*5113495bSYour Name 
1572*5113495bSYour Name 	return 0;
1573*5113495bSYour Name }
1574*5113495bSYour Name 
hdd_set_app_type1_parser(struct hdd_adapter * adapter,char * arg,int len)1575*5113495bSYour Name static int hdd_set_app_type1_parser(struct hdd_adapter *adapter,
1576*5113495bSYour Name 				    char *arg, int len)
1577*5113495bSYour Name {
1578*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1579*5113495bSYour Name 	char id[20], password[20];
1580*5113495bSYour Name 	tSirAppType1Params params;
1581*5113495bSYour Name 	int rc;
1582*5113495bSYour Name 
1583*5113495bSYour Name 	rc = wlan_hdd_validate_context(hdd_ctx);
1584*5113495bSYour Name 	if (rc)
1585*5113495bSYour Name 		return rc;
1586*5113495bSYour Name 
1587*5113495bSYour Name 	if (2 != sscanf(arg, "%8s %16s", id, password)) {
1588*5113495bSYour Name 		hdd_err("Invalid Number of arguments");
1589*5113495bSYour Name 		return -EINVAL;
1590*5113495bSYour Name 	}
1591*5113495bSYour Name 
1592*5113495bSYour Name 	memset(&params, 0, sizeof(tSirAppType1Params));
1593*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
1594*5113495bSYour Name 	qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->mac_addr);
1595*5113495bSYour Name 
1596*5113495bSYour Name 	params.id_length = strlen(id);
1597*5113495bSYour Name 	qdf_mem_copy(params.identification_id, id, params.id_length);
1598*5113495bSYour Name 	params.pass_length = strlen(password);
1599*5113495bSYour Name 	qdf_mem_copy(params.password, password, params.pass_length);
1600*5113495bSYour Name 
1601*5113495bSYour Name 	hdd_debug("%d "QDF_MAC_ADDR_FMT" %.8s %u %.16s %u",
1602*5113495bSYour Name 		  params.vdev_id,
1603*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params.wakee_mac_addr.bytes),
1604*5113495bSYour Name 		  params.identification_id, params.id_length,
1605*5113495bSYour Name 		  params.password, params.pass_length);
1606*5113495bSYour Name 
1607*5113495bSYour Name 	return hdd_set_app_type1_params(hdd_ctx->mac_handle, &params);
1608*5113495bSYour Name }
1609*5113495bSYour Name 
hdd_set_app_type2_params(mac_handle_t mac_handle,tpSirAppType2Params arg_params)1610*5113495bSYour Name static int hdd_set_app_type2_params(mac_handle_t mac_handle,
1611*5113495bSYour Name 				    tpSirAppType2Params arg_params)
1612*5113495bSYour Name {
1613*5113495bSYour Name 	tSirAppType2Params params;
1614*5113495bSYour Name 	QDF_STATUS status;
1615*5113495bSYour Name 
1616*5113495bSYour Name 	qdf_mem_copy(&params, arg_params, sizeof(params));
1617*5113495bSYour Name 
1618*5113495bSYour Name 	status = sme_configure_app_type2_params(mac_handle, &params);
1619*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
1620*5113495bSYour Name 		hdd_err("sme_configure_app_type2_params returned failure %d",
1621*5113495bSYour Name 			 status);
1622*5113495bSYour Name 		return -EPERM;
1623*5113495bSYour Name 	}
1624*5113495bSYour Name 
1625*5113495bSYour Name 	return 0;
1626*5113495bSYour Name }
1627*5113495bSYour Name 
hdd_set_app_type2_parser(struct hdd_adapter * adapter,char * arg,int len)1628*5113495bSYour Name static int hdd_set_app_type2_parser(struct hdd_adapter *adapter,
1629*5113495bSYour Name 				    char *arg, int len)
1630*5113495bSYour Name {
1631*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1632*5113495bSYour Name 	char mac_addr[20], rc4_key[20];
1633*5113495bSYour Name 	unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
1634*5113495bSYour Name 	tSirAppType2Params params;
1635*5113495bSYour Name 	int ret;
1636*5113495bSYour Name 
1637*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
1638*5113495bSYour Name 	if (ret)
1639*5113495bSYour Name 		return ret;
1640*5113495bSYour Name 
1641*5113495bSYour Name 	memset(&params, 0, sizeof(tSirAppType2Params));
1642*5113495bSYour Name 
1643*5113495bSYour Name 	ret = sscanf(arg, "%17s %16s %x %x %x %u %u %hu %hu %u %u %u %u %u %u",
1644*5113495bSYour Name 		     mac_addr, rc4_key, (unsigned int *)&params.ip_id,
1645*5113495bSYour Name 		     (unsigned int *)&params.ip_device_ip,
1646*5113495bSYour Name 		     (unsigned int *)&params.ip_server_ip,
1647*5113495bSYour Name 		     (unsigned int *)&params.tcp_seq,
1648*5113495bSYour Name 		     (unsigned int *)&params.tcp_ack_seq,
1649*5113495bSYour Name 		     (uint16_t *)&params.tcp_src_port,
1650*5113495bSYour Name 		     (uint16_t *)&params.tcp_dst_port,
1651*5113495bSYour Name 		     (unsigned int *)&params.keepalive_init,
1652*5113495bSYour Name 		     (unsigned int *)&params.keepalive_min,
1653*5113495bSYour Name 		     (unsigned int *)&params.keepalive_max,
1654*5113495bSYour Name 		     (unsigned int *)&params.keepalive_inc,
1655*5113495bSYour Name 		     (unsigned int *)&params.tcp_tx_timeout_val,
1656*5113495bSYour Name 		     (unsigned int *)&params.tcp_rx_timeout_val);
1657*5113495bSYour Name 
1658*5113495bSYour Name 	if (ret != 15 && ret != 7) {
1659*5113495bSYour Name 		hdd_err("Invalid Number of arguments");
1660*5113495bSYour Name 		return -EINVAL;
1661*5113495bSYour Name 	}
1662*5113495bSYour Name 
1663*5113495bSYour Name 	if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
1664*5113495bSYour Name 			&gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
1665*5113495bSYour Name 			&gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
1666*5113495bSYour Name 		hdd_err("Invalid MacAddress Input %s", mac_addr);
1667*5113495bSYour Name 		return -EINVAL;
1668*5113495bSYour Name 	}
1669*5113495bSYour Name 
1670*5113495bSYour Name 	if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
1671*5113495bSYour Name 	    params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
1672*5113495bSYour Name 		hdd_err("Invalid TCP Port Number");
1673*5113495bSYour Name 		return -EINVAL;
1674*5113495bSYour Name 	}
1675*5113495bSYour Name 
1676*5113495bSYour Name 	qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
1677*5113495bSYour Name 			QDF_MAC_ADDR_SIZE);
1678*5113495bSYour Name 
1679*5113495bSYour Name 	params.rc4_key_len = strlen(rc4_key);
1680*5113495bSYour Name 	qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
1681*5113495bSYour Name 
1682*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
1683*5113495bSYour Name 
1684*5113495bSYour Name 	if (!params.tcp_src_port)
1685*5113495bSYour Name 		params.tcp_src_port =
1686*5113495bSYour Name 		  ucfg_pmo_extwow_app2_tcp_src_port(hdd_ctx->psoc);
1687*5113495bSYour Name 
1688*5113495bSYour Name 	if (!params.tcp_dst_port)
1689*5113495bSYour Name 		params.tcp_dst_port =
1690*5113495bSYour Name 		  ucfg_pmo_extwow_app2_tcp_dst_port(hdd_ctx->psoc);
1691*5113495bSYour Name 
1692*5113495bSYour Name 	if (!params.keepalive_init)
1693*5113495bSYour Name 		params.keepalive_init =
1694*5113495bSYour Name 		  ucfg_pmo_extwow_app2_init_ping_interval(hdd_ctx->psoc);
1695*5113495bSYour Name 
1696*5113495bSYour Name 	if (!params.keepalive_min)
1697*5113495bSYour Name 		params.keepalive_min =
1698*5113495bSYour Name 		  ucfg_pmo_extwow_app2_min_ping_interval(hdd_ctx->psoc);
1699*5113495bSYour Name 
1700*5113495bSYour Name 	if (!params.keepalive_max)
1701*5113495bSYour Name 		params.keepalive_max =
1702*5113495bSYour Name 		  ucfg_pmo_extwow_app2_max_ping_interval(hdd_ctx->psoc);
1703*5113495bSYour Name 
1704*5113495bSYour Name 	if (!params.keepalive_inc)
1705*5113495bSYour Name 		params.keepalive_inc =
1706*5113495bSYour Name 		  ucfg_pmo_extwow_app2_inc_ping_interval(hdd_ctx->psoc);
1707*5113495bSYour Name 
1708*5113495bSYour Name 	if (!params.tcp_tx_timeout_val)
1709*5113495bSYour Name 		params.tcp_tx_timeout_val =
1710*5113495bSYour Name 		  ucfg_pmo_extwow_app2_tcp_tx_timeout(hdd_ctx->psoc);
1711*5113495bSYour Name 
1712*5113495bSYour Name 	if (!params.tcp_rx_timeout_val)
1713*5113495bSYour Name 		params.tcp_rx_timeout_val =
1714*5113495bSYour Name 		  ucfg_pmo_extwow_app2_tcp_rx_timeout(hdd_ctx->psoc);
1715*5113495bSYour Name 
1716*5113495bSYour Name 	hdd_debug(QDF_MAC_ADDR_FMT" %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
1717*5113495bSYour Name 		  QDF_MAC_ADDR_REF(gateway_mac), rc4_key, params.ip_id,
1718*5113495bSYour Name 		  params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
1719*5113495bSYour Name 		  params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
1720*5113495bSYour Name 		  params.keepalive_init, params.keepalive_min,
1721*5113495bSYour Name 		  params.keepalive_max, params.keepalive_inc,
1722*5113495bSYour Name 		  params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
1723*5113495bSYour Name 
1724*5113495bSYour Name 	return hdd_set_app_type2_params(hdd_ctx->mac_handle, &params);
1725*5113495bSYour Name }
1726*5113495bSYour Name #endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
1727*5113495bSYour Name 
1728*5113495bSYour Name /**
1729*5113495bSYour Name  * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
1730*5113495bSYour Name  * @command: Pointer to MAXTXPOWER command
1731*5113495bSYour Name  * @tx_power: Pointer to tx power
1732*5113495bSYour Name  *
1733*5113495bSYour Name  * This function parses the MAXTXPOWER command passed in the format
1734*5113495bSYour Name  * MAXTXPOWER<space>X(Tx power in dbm)
1735*5113495bSYour Name  *
1736*5113495bSYour Name  * For example input commands:
1737*5113495bSYour Name  * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
1738*5113495bSYour Name  * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
1739*5113495bSYour Name  *
1740*5113495bSYour Name  * Return: 0 for success non-zero for failure
1741*5113495bSYour Name  */
hdd_parse_setmaxtxpower_command(uint8_t * command,int * tx_power)1742*5113495bSYour Name static int hdd_parse_setmaxtxpower_command(uint8_t *command, int *tx_power)
1743*5113495bSYour Name {
1744*5113495bSYour Name 	uint8_t *in_ptr = command;
1745*5113495bSYour Name 	int temp_int;
1746*5113495bSYour Name 	int v = 0;
1747*5113495bSYour Name 	*tx_power = 0;
1748*5113495bSYour Name 
1749*5113495bSYour Name 	in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
1750*5113495bSYour Name 	/* no argument after the command */
1751*5113495bSYour Name 	if (!in_ptr)
1752*5113495bSYour Name 		return -EINVAL;
1753*5113495bSYour Name 	else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
1754*5113495bSYour Name 		return -EINVAL;
1755*5113495bSYour Name 
1756*5113495bSYour Name 	/* remove empty spaces */
1757*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1758*5113495bSYour Name 		in_ptr++;
1759*5113495bSYour Name 
1760*5113495bSYour Name 	/* no argument followed by spaces */
1761*5113495bSYour Name 	if ('\0' == *in_ptr)
1762*5113495bSYour Name 		return 0;
1763*5113495bSYour Name 
1764*5113495bSYour Name 	v = kstrtos32(in_ptr, 10, &temp_int);
1765*5113495bSYour Name 
1766*5113495bSYour Name 	/* Range checking for passed parameter */
1767*5113495bSYour Name 	if ((temp_int < HDD_MIN_TX_POWER) || (temp_int > HDD_MAX_TX_POWER))
1768*5113495bSYour Name 		return -EINVAL;
1769*5113495bSYour Name 
1770*5113495bSYour Name 	*tx_power = temp_int;
1771*5113495bSYour Name 
1772*5113495bSYour Name 	hdd_debug("SETMAXTXPOWER: %d", *tx_power);
1773*5113495bSYour Name 
1774*5113495bSYour Name 	return 0;
1775*5113495bSYour Name } /* End of hdd_parse_setmaxtxpower_command */
1776*5113495bSYour Name 
1777*5113495bSYour Name #ifdef CONFIG_BAND_6GHZ
hdd_get_dwell_time_6g(struct wlan_objmgr_psoc * psoc,uint8_t * command,char * extra,uint8_t n,uint8_t * len)1778*5113495bSYour Name static int hdd_get_dwell_time_6g(struct wlan_objmgr_psoc *psoc,
1779*5113495bSYour Name 				 uint8_t *command, char *extra, uint8_t n,
1780*5113495bSYour Name 				 uint8_t *len)
1781*5113495bSYour Name {
1782*5113495bSYour Name 	uint32_t val = 0;
1783*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
1784*5113495bSYour Name 
1785*5113495bSYour Name 	if (strncmp(command, "GETDWELLTIME 6G MAX", 19) == 0) {
1786*5113495bSYour Name 		status = ucfg_scan_cfg_get_active_6g_dwelltime(psoc, &val);
1787*5113495bSYour Name 		hdd_debug("active 6g dwelltime:%d", val);
1788*5113495bSYour Name 		if (QDF_IS_STATUS_SUCCESS(status))
1789*5113495bSYour Name 			*len = scnprintf(extra, n, "GETDWELLTIME 6G MAX %u\n",
1790*5113495bSYour Name 					 val);
1791*5113495bSYour Name 	} else if (strncmp(command, "GETDWELLTIME PASSIVE 6G MAX", 27) == 0) {
1792*5113495bSYour Name 		status = ucfg_scan_cfg_get_passive_6g_dwelltime(psoc, &val);
1793*5113495bSYour Name 		hdd_debug("passive 6g dwelltime:%d", val);
1794*5113495bSYour Name 		if (QDF_IS_STATUS_SUCCESS(status))
1795*5113495bSYour Name 			*len = scnprintf(extra, n,
1796*5113495bSYour Name 					 "GETDWELLTIME PASSIVE 6G MAX %u\n",
1797*5113495bSYour Name 					 val);
1798*5113495bSYour Name 	}
1799*5113495bSYour Name 
1800*5113495bSYour Name 	return qdf_status_to_os_return(status);
1801*5113495bSYour Name }
1802*5113495bSYour Name 
hdd_set_dwell_time_6g(struct wlan_objmgr_psoc * psoc,uint8_t * command)1803*5113495bSYour Name static int hdd_set_dwell_time_6g(struct wlan_objmgr_psoc *psoc,
1804*5113495bSYour Name 				 uint8_t *command)
1805*5113495bSYour Name {
1806*5113495bSYour Name 	uint8_t *value = command;
1807*5113495bSYour Name 	int temp = 0;
1808*5113495bSYour Name 	uint32_t val = 0;
1809*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
1810*5113495bSYour Name 
1811*5113495bSYour Name 	if (strncmp(command, "SETDWELLTIME 6G MAX", 19) == 0) {
1812*5113495bSYour Name 		if (drv_cmd_validate(command, 19))
1813*5113495bSYour Name 			return -EINVAL;
1814*5113495bSYour Name 
1815*5113495bSYour Name 		value = value + 20;
1816*5113495bSYour Name 		temp = kstrtou32(value, 10, &val);
1817*5113495bSYour Name 		if (temp || !cfg_in_range(CFG_ACTIVE_MAX_6G_CHANNEL_TIME,
1818*5113495bSYour Name 					  val)) {
1819*5113495bSYour Name 			hdd_err_rl("argument passed for SETDWELLTIME 6G MAX is incorrect");
1820*5113495bSYour Name 			return -EFAULT;
1821*5113495bSYour Name 		}
1822*5113495bSYour Name 		status = ucfg_scan_cfg_set_active_6g_dwelltime(psoc, val);
1823*5113495bSYour Name 	} else if (strncmp(command, "SETDWELLTIME PASSIVE 6G MAX", 27) == 0) {
1824*5113495bSYour Name 		if (drv_cmd_validate(command, 27))
1825*5113495bSYour Name 			return -EINVAL;
1826*5113495bSYour Name 
1827*5113495bSYour Name 		value = value + 28;
1828*5113495bSYour Name 		temp = kstrtou32(value, 10, &val);
1829*5113495bSYour Name 		if (temp || !cfg_in_range(CFG_PASSIVE_MAX_6G_CHANNEL_TIME,
1830*5113495bSYour Name 					  val)) {
1831*5113495bSYour Name 			hdd_err_rl("argument passed for SETDWELLTIME PASSIVE 6G MAX is incorrect");
1832*5113495bSYour Name 			return -EFAULT;
1833*5113495bSYour Name 		}
1834*5113495bSYour Name 		status = ucfg_scan_cfg_set_passive_6g_dwelltime(psoc, val);
1835*5113495bSYour Name 	}
1836*5113495bSYour Name 
1837*5113495bSYour Name 	return qdf_status_to_os_return(status);
1838*5113495bSYour Name }
1839*5113495bSYour Name #else
hdd_get_dwell_time_6g(struct wlan_objmgr_psoc * psoc,uint8_t * command,char * extra,uint8_t n,uint8_t * len)1840*5113495bSYour Name static int hdd_get_dwell_time_6g(struct wlan_objmgr_psoc *psoc,
1841*5113495bSYour Name 				 uint8_t *command, char *extra, uint8_t n,
1842*5113495bSYour Name 				 uint8_t *len)
1843*5113495bSYour Name {
1844*5113495bSYour Name 	return -EINVAL;
1845*5113495bSYour Name }
1846*5113495bSYour Name 
hdd_set_dwell_time_6g(struct wlan_objmgr_psoc * psoc,uint8_t * command)1847*5113495bSYour Name static int hdd_set_dwell_time_6g(struct wlan_objmgr_psoc *psoc,
1848*5113495bSYour Name 				 uint8_t *command)
1849*5113495bSYour Name {
1850*5113495bSYour Name 	return -EINVAL;
1851*5113495bSYour Name }
1852*5113495bSYour Name #endif
1853*5113495bSYour Name 
hdd_get_dwell_time(struct wlan_objmgr_psoc * psoc,uint8_t * command,char * extra,uint8_t n,uint8_t * len)1854*5113495bSYour Name static int hdd_get_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command,
1855*5113495bSYour Name 			      char *extra, uint8_t n, uint8_t *len)
1856*5113495bSYour Name {
1857*5113495bSYour Name 	uint32_t val = 0;
1858*5113495bSYour Name 
1859*5113495bSYour Name 	if (!psoc || !command || !extra || !len) {
1860*5113495bSYour Name 		hdd_err("argument passed for GETDWELLTIME is incorrect");
1861*5113495bSYour Name 		return -EINVAL;
1862*5113495bSYour Name 	}
1863*5113495bSYour Name 
1864*5113495bSYour Name 	if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
1865*5113495bSYour Name 		ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
1866*5113495bSYour Name 		hdd_debug("active max dwelltime:%d", val);
1867*5113495bSYour Name 		*len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n", val);
1868*5113495bSYour Name 		return 0;
1869*5113495bSYour Name 	}
1870*5113495bSYour Name 	if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
1871*5113495bSYour Name 		ucfg_scan_cfg_get_passive_dwelltime(psoc, &val);
1872*5113495bSYour Name 		hdd_debug("passive dwelltime:%d", val);
1873*5113495bSYour Name 		*len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
1874*5113495bSYour Name 				 val);
1875*5113495bSYour Name 		return 0;
1876*5113495bSYour Name 	}
1877*5113495bSYour Name 	if (strncmp(command, "GETDWELLTIME 2G MAX", 19) == 0) {
1878*5113495bSYour Name 		ucfg_scan_cfg_get_active_2g_dwelltime(psoc, &val);
1879*5113495bSYour Name 		hdd_debug("active 2g dwelltime:%d", val);
1880*5113495bSYour Name 		*len = scnprintf(extra, n, "GETDWELLTIME 2G MAX %u\n",
1881*5113495bSYour Name 				 val);
1882*5113495bSYour Name 		return 0;
1883*5113495bSYour Name 	}
1884*5113495bSYour Name 	if (strncmp(command, "GETDWELLTIME", 12) == 0) {
1885*5113495bSYour Name 		ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
1886*5113495bSYour Name 		hdd_debug("active dwelltime:%d", val);
1887*5113495bSYour Name 		*len = scnprintf(extra, n, "GETDWELLTIME %u\n", val);
1888*5113495bSYour Name 		return 0;
1889*5113495bSYour Name 	}
1890*5113495bSYour Name 
1891*5113495bSYour Name 	return hdd_get_dwell_time_6g(psoc, command, extra, n, len);
1892*5113495bSYour Name }
1893*5113495bSYour Name 
hdd_set_dwell_time(struct wlan_objmgr_psoc * psoc,uint8_t * command)1894*5113495bSYour Name static int hdd_set_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command)
1895*5113495bSYour Name {
1896*5113495bSYour Name 	uint8_t *value = command;
1897*5113495bSYour Name 	int retval = 0, temp = 0;
1898*5113495bSYour Name 	uint32_t val = 0;
1899*5113495bSYour Name 
1900*5113495bSYour Name 	if (!psoc) {
1901*5113495bSYour Name 		hdd_err("psoc is null");
1902*5113495bSYour Name 		return -EINVAL;
1903*5113495bSYour Name 	}
1904*5113495bSYour Name 
1905*5113495bSYour Name 	if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
1906*5113495bSYour Name 		if (drv_cmd_validate(command, 23))
1907*5113495bSYour Name 			return -EINVAL;
1908*5113495bSYour Name 
1909*5113495bSYour Name 		value = value + 24;
1910*5113495bSYour Name 		temp = kstrtou32(value, 10, &val);
1911*5113495bSYour Name 		if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
1912*5113495bSYour Name 			hdd_err_rl("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
1913*5113495bSYour Name 			return -EFAULT;
1914*5113495bSYour Name 		}
1915*5113495bSYour Name 		ucfg_scan_cfg_set_active_dwelltime(psoc, val);
1916*5113495bSYour Name 	} else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
1917*5113495bSYour Name 		if (drv_cmd_validate(command, 24))
1918*5113495bSYour Name 			return -EINVAL;
1919*5113495bSYour Name 
1920*5113495bSYour Name 		value = value + 25;
1921*5113495bSYour Name 		temp = kstrtou32(value, 10, &val);
1922*5113495bSYour Name 		if (temp || !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME, val)) {
1923*5113495bSYour Name 			hdd_err_rl("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
1924*5113495bSYour Name 			return -EFAULT;
1925*5113495bSYour Name 		}
1926*5113495bSYour Name 		ucfg_scan_cfg_set_passive_dwelltime(psoc, val);
1927*5113495bSYour Name 	} else if (strncmp(command, "SETDWELLTIME 2G MAX", 19) == 0) {
1928*5113495bSYour Name 		if (drv_cmd_validate(command, 19))
1929*5113495bSYour Name 			return -EINVAL;
1930*5113495bSYour Name 
1931*5113495bSYour Name 		value = value + 20;
1932*5113495bSYour Name 		temp = kstrtou32(value, 10, &val);
1933*5113495bSYour Name 		if (temp || !cfg_in_range(CFG_ACTIVE_MAX_2G_CHANNEL_TIME,
1934*5113495bSYour Name 					  val)) {
1935*5113495bSYour Name 			hdd_err_rl("argument passed for SETDWELLTIME 2G MAX is incorrect");
1936*5113495bSYour Name 			return -EFAULT;
1937*5113495bSYour Name 		}
1938*5113495bSYour Name 		ucfg_scan_cfg_set_active_2g_dwelltime(psoc, val);
1939*5113495bSYour Name 	} else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
1940*5113495bSYour Name 		if (drv_cmd_validate(command, 12))
1941*5113495bSYour Name 			return -EINVAL;
1942*5113495bSYour Name 
1943*5113495bSYour Name 		value = value + 13;
1944*5113495bSYour Name 		temp = kstrtou32(value, 10, &val);
1945*5113495bSYour Name 		if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
1946*5113495bSYour Name 			hdd_err_rl("argument passed for SETDWELLTIME is incorrect");
1947*5113495bSYour Name 			return -EFAULT;
1948*5113495bSYour Name 		}
1949*5113495bSYour Name 		ucfg_scan_cfg_set_active_dwelltime(psoc, val);
1950*5113495bSYour Name 	} else {
1951*5113495bSYour Name 		retval = hdd_set_dwell_time_6g(psoc, command);
1952*5113495bSYour Name 	}
1953*5113495bSYour Name 
1954*5113495bSYour Name 	return retval;
1955*5113495bSYour Name }
1956*5113495bSYour Name 
1957*5113495bSYour Name struct link_status_priv {
1958*5113495bSYour Name 	uint8_t link_status;
1959*5113495bSYour Name };
1960*5113495bSYour Name 
1961*5113495bSYour Name /**
1962*5113495bSYour Name  * hdd_conc_set_dwell_time() - Set Concurrent dwell time parameters
1963*5113495bSYour Name  * @adapter: Adapter upon which the command was received
1964*5113495bSYour Name  * @command: ASCII text command that is received
1965*5113495bSYour Name  *
1966*5113495bSYour Name  * Driver commands:
1967*5113495bSYour Name  * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MAX <value>
1968*5113495bSYour Name  * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MIN <value>
1969*5113495bSYour Name  * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MAX <value>
1970*5113495bSYour Name  * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MIN <value>
1971*5113495bSYour Name  *
1972*5113495bSYour Name  * Return: 0 for success non-zero for failure
1973*5113495bSYour Name  */
hdd_conc_set_dwell_time(struct hdd_adapter * adapter,uint8_t * command)1974*5113495bSYour Name static int hdd_conc_set_dwell_time(struct hdd_adapter *adapter,
1975*5113495bSYour Name 				   uint8_t *command)
1976*5113495bSYour Name {
1977*5113495bSYour Name 	u8 *value = command;
1978*5113495bSYour Name 	int val = 0, temp = 0;
1979*5113495bSYour Name 	int retval = 0;
1980*5113495bSYour Name 
1981*5113495bSYour Name 	if (strncmp(command, "CONCSETDWELLTIME ACTIVE MAX", 27) == 0) {
1982*5113495bSYour Name 		if (drv_cmd_validate(command, 27)) {
1983*5113495bSYour Name 			hdd_err("Invalid driver command");
1984*5113495bSYour Name 			return -EINVAL;
1985*5113495bSYour Name 		}
1986*5113495bSYour Name 
1987*5113495bSYour Name 		value = value + 28;
1988*5113495bSYour Name 		temp = kstrtou32(value, 10, &val);
1989*5113495bSYour Name 		if (temp ||
1990*5113495bSYour Name 		    !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC, val)) {
1991*5113495bSYour Name 			hdd_err("CONC ACTIVE MAX value %d incorrect", val);
1992*5113495bSYour Name 			return -EFAULT;
1993*5113495bSYour Name 		}
1994*5113495bSYour Name 		ucfg_scan_cfg_set_conc_active_dwelltime(
1995*5113495bSYour Name 				(WLAN_HDD_GET_CTX(adapter))->psoc, val);
1996*5113495bSYour Name 	} else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MAX", 28) == 0) {
1997*5113495bSYour Name 		if (drv_cmd_validate(command, 28)) {
1998*5113495bSYour Name 			hdd_err("Invalid driver command");
1999*5113495bSYour Name 			return -EINVAL;
2000*5113495bSYour Name 		}
2001*5113495bSYour Name 
2002*5113495bSYour Name 		value = value + 29;
2003*5113495bSYour Name 		temp = kstrtou32(value, 10, &val);
2004*5113495bSYour Name 		if (temp ||
2005*5113495bSYour Name 		    !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC, val)) {
2006*5113495bSYour Name 			hdd_err("CONC PASSIVE MAX val %d incorrect", val);
2007*5113495bSYour Name 			return -EFAULT;
2008*5113495bSYour Name 		}
2009*5113495bSYour Name 		ucfg_scan_cfg_set_conc_passive_dwelltime(
2010*5113495bSYour Name 				(WLAN_HDD_GET_CTX(adapter))->psoc, val);
2011*5113495bSYour Name 	} else {
2012*5113495bSYour Name 		retval = -EINVAL;
2013*5113495bSYour Name 	}
2014*5113495bSYour Name 
2015*5113495bSYour Name 	return retval;
2016*5113495bSYour Name }
2017*5113495bSYour Name 
hdd_enable_unit_test_commands(struct hdd_adapter * adapter,struct hdd_context * hdd_ctx)2018*5113495bSYour Name static int hdd_enable_unit_test_commands(struct hdd_adapter *adapter,
2019*5113495bSYour Name 					 struct hdd_context *hdd_ctx)
2020*5113495bSYour Name {
2021*5113495bSYour Name 	enum pld_bus_type bus_type = pld_get_bus_type(hdd_ctx->parent_dev);
2022*5113495bSYour Name 	u32 arg[3];
2023*5113495bSYour Name 	QDF_STATUS status;
2024*5113495bSYour Name 
2025*5113495bSYour Name 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE ||
2026*5113495bSYour Name 	    hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE)
2027*5113495bSYour Name 		return -EPERM;
2028*5113495bSYour Name 
2029*5113495bSYour Name 	if (adapter->deflink->vdev_id >= WLAN_MAX_VDEVS) {
2030*5113495bSYour Name 		hdd_err_rl("Invalid vdev id");
2031*5113495bSYour Name 		return -EINVAL;
2032*5113495bSYour Name 	}
2033*5113495bSYour Name 
2034*5113495bSYour Name 	if (bus_type == PLD_BUS_TYPE_PCIE) {
2035*5113495bSYour Name 		arg[0] = 360;
2036*5113495bSYour Name 		arg[1] = 1;
2037*5113495bSYour Name 
2038*5113495bSYour Name 		status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2039*5113495bSYour Name 						WLAN_MODULE_TX,
2040*5113495bSYour Name 						2,
2041*5113495bSYour Name 						arg);
2042*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
2043*5113495bSYour Name 			return qdf_status_to_os_return(status);
2044*5113495bSYour Name 
2045*5113495bSYour Name 		arg[0] = 361;
2046*5113495bSYour Name 		arg[1] = 1;
2047*5113495bSYour Name 
2048*5113495bSYour Name 		status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2049*5113495bSYour Name 						WLAN_MODULE_TX,
2050*5113495bSYour Name 						2,
2051*5113495bSYour Name 						arg);
2052*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
2053*5113495bSYour Name 			return qdf_status_to_os_return(status);
2054*5113495bSYour Name 
2055*5113495bSYour Name 		arg[0] = 84;
2056*5113495bSYour Name 		arg[1] = 1;
2057*5113495bSYour Name 		arg[2] = 1;
2058*5113495bSYour Name 
2059*5113495bSYour Name 		status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2060*5113495bSYour Name 						WLAN_MODULE_TX,
2061*5113495bSYour Name 						3,
2062*5113495bSYour Name 						arg);
2063*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
2064*5113495bSYour Name 			return qdf_status_to_os_return(status);
2065*5113495bSYour Name 
2066*5113495bSYour Name 		if (hdd_ctx->target_type == TARGET_TYPE_QCA6390) {
2067*5113495bSYour Name 			arg[0] = 37;
2068*5113495bSYour Name 			arg[1] = 3000;
2069*5113495bSYour Name 
2070*5113495bSYour Name 			status = sme_send_unit_test_cmd(
2071*5113495bSYour Name 						adapter->deflink->vdev_id,
2072*5113495bSYour Name 						WLAN_MODULE_RX,	2, arg);
2073*5113495bSYour Name 			if (status != QDF_STATUS_SUCCESS)
2074*5113495bSYour Name 				return qdf_status_to_os_return(status);
2075*5113495bSYour Name 		}
2076*5113495bSYour Name 
2077*5113495bSYour Name 		if (hdd_ctx->target_type == TARGET_TYPE_QCA6490) {
2078*5113495bSYour Name 			arg[0] = 44;
2079*5113495bSYour Name 			arg[1] = 3000;
2080*5113495bSYour Name 
2081*5113495bSYour Name 			status = sme_send_unit_test_cmd(
2082*5113495bSYour Name 						adapter->deflink->vdev_id,
2083*5113495bSYour Name 						WLAN_MODULE_RX, 2, arg);
2084*5113495bSYour Name 			if (status != QDF_STATUS_SUCCESS)
2085*5113495bSYour Name 				return qdf_status_to_os_return(status);
2086*5113495bSYour Name 		}
2087*5113495bSYour Name 	} else if (bus_type == PLD_BUS_TYPE_SNOC) {
2088*5113495bSYour Name 		arg[0] = 7;
2089*5113495bSYour Name 		arg[1] = 1;
2090*5113495bSYour Name 
2091*5113495bSYour Name 		status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2092*5113495bSYour Name 						0x44,
2093*5113495bSYour Name 						2,
2094*5113495bSYour Name 						arg);
2095*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
2096*5113495bSYour Name 			return qdf_status_to_os_return(status);
2097*5113495bSYour Name 	} else {
2098*5113495bSYour Name 		return -EINVAL;
2099*5113495bSYour Name 	}
2100*5113495bSYour Name 	return 0;
2101*5113495bSYour Name }
2102*5113495bSYour Name 
hdd_disable_unit_test_commands(struct hdd_adapter * adapter,struct hdd_context * hdd_ctx)2103*5113495bSYour Name static int hdd_disable_unit_test_commands(struct hdd_adapter *adapter,
2104*5113495bSYour Name 					  struct hdd_context *hdd_ctx)
2105*5113495bSYour Name {
2106*5113495bSYour Name 	enum pld_bus_type bus_type = pld_get_bus_type(hdd_ctx->parent_dev);
2107*5113495bSYour Name 	u32 arg[2];
2108*5113495bSYour Name 	QDF_STATUS status;
2109*5113495bSYour Name 
2110*5113495bSYour Name 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE ||
2111*5113495bSYour Name 	    hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE)
2112*5113495bSYour Name 		return -EPERM;
2113*5113495bSYour Name 
2114*5113495bSYour Name 	if (adapter->deflink->vdev_id >= WLAN_MAX_VDEVS) {
2115*5113495bSYour Name 		hdd_err_rl("Invalid vdev id");
2116*5113495bSYour Name 		return -EINVAL;
2117*5113495bSYour Name 	}
2118*5113495bSYour Name 
2119*5113495bSYour Name 	if (bus_type == PLD_BUS_TYPE_PCIE) {
2120*5113495bSYour Name 		arg[0] = 360;
2121*5113495bSYour Name 		arg[1] = 0;
2122*5113495bSYour Name 
2123*5113495bSYour Name 		status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2124*5113495bSYour Name 						WLAN_MODULE_TX,
2125*5113495bSYour Name 						2,
2126*5113495bSYour Name 						arg);
2127*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
2128*5113495bSYour Name 			return qdf_status_to_os_return(status);
2129*5113495bSYour Name 
2130*5113495bSYour Name 		arg[0] = 361;
2131*5113495bSYour Name 		arg[1] = 0;
2132*5113495bSYour Name 
2133*5113495bSYour Name 		status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2134*5113495bSYour Name 						WLAN_MODULE_TX,
2135*5113495bSYour Name 						2,
2136*5113495bSYour Name 						arg);
2137*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
2138*5113495bSYour Name 			return qdf_status_to_os_return(status);
2139*5113495bSYour Name 
2140*5113495bSYour Name 		arg[0] = 44;
2141*5113495bSYour Name 		arg[1] = 0;
2142*5113495bSYour Name 
2143*5113495bSYour Name 		status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2144*5113495bSYour Name 						WLAN_MODULE_RX,
2145*5113495bSYour Name 						2,
2146*5113495bSYour Name 						arg);
2147*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
2148*5113495bSYour Name 			return qdf_status_to_os_return(status);
2149*5113495bSYour Name 
2150*5113495bSYour Name 		arg[0] = 84;
2151*5113495bSYour Name 		arg[1] = 0;
2152*5113495bSYour Name 
2153*5113495bSYour Name 		status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2154*5113495bSYour Name 						WLAN_MODULE_RX,
2155*5113495bSYour Name 						2,
2156*5113495bSYour Name 						arg);
2157*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
2158*5113495bSYour Name 			return qdf_status_to_os_return(status);
2159*5113495bSYour Name 
2160*5113495bSYour Name 	} else if (bus_type == PLD_BUS_TYPE_SNOC) {
2161*5113495bSYour Name 		arg[0] = 7;
2162*5113495bSYour Name 		arg[1] = 0;
2163*5113495bSYour Name 
2164*5113495bSYour Name 		status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2165*5113495bSYour Name 						0x44,
2166*5113495bSYour Name 						2,
2167*5113495bSYour Name 						arg);
2168*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
2169*5113495bSYour Name 			return qdf_status_to_os_return(status);
2170*5113495bSYour Name 	} else {
2171*5113495bSYour Name 		return -EINVAL;
2172*5113495bSYour Name 	}
2173*5113495bSYour Name 	return 0;
2174*5113495bSYour Name }
2175*5113495bSYour Name 
hdd_get_link_status_cb(uint8_t status,void * context)2176*5113495bSYour Name static void hdd_get_link_status_cb(uint8_t status, void *context)
2177*5113495bSYour Name {
2178*5113495bSYour Name 	struct osif_request *request;
2179*5113495bSYour Name 	struct link_status_priv *priv;
2180*5113495bSYour Name 
2181*5113495bSYour Name 	request = osif_request_get(context);
2182*5113495bSYour Name 	if (!request) {
2183*5113495bSYour Name 		hdd_err("Obsolete request");
2184*5113495bSYour Name 		return;
2185*5113495bSYour Name 	}
2186*5113495bSYour Name 
2187*5113495bSYour Name 	priv = osif_request_priv(request);
2188*5113495bSYour Name 	priv->link_status = status;
2189*5113495bSYour Name 	osif_request_complete(request);
2190*5113495bSYour Name 	osif_request_put(request);
2191*5113495bSYour Name }
2192*5113495bSYour Name 
2193*5113495bSYour Name /**
2194*5113495bSYour Name  * wlan_hdd_get_link_status() - get link status
2195*5113495bSYour Name  * @adapter:     pointer to the adapter
2196*5113495bSYour Name  *
2197*5113495bSYour Name  * This function sends a request to query the link status and waits
2198*5113495bSYour Name  * on a timer to invoke the callback. if the callback is invoked then
2199*5113495bSYour Name  * latest link status shall be returned or otherwise cached value
2200*5113495bSYour Name  * will be returned.
2201*5113495bSYour Name  *
2202*5113495bSYour Name  * Return: On success, link status shall be returned.
2203*5113495bSYour Name  *         On error or not associated, link status 0 will be returned.
2204*5113495bSYour Name  */
wlan_hdd_get_link_status(struct hdd_adapter * adapter)2205*5113495bSYour Name static int wlan_hdd_get_link_status(struct hdd_adapter *adapter)
2206*5113495bSYour Name {
2207*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
2208*5113495bSYour Name 	QDF_STATUS status;
2209*5113495bSYour Name 	int ret;
2210*5113495bSYour Name 	void *cookie;
2211*5113495bSYour Name 	struct osif_request *request;
2212*5113495bSYour Name 	struct link_status_priv *priv;
2213*5113495bSYour Name 	static const struct osif_request_params params = {
2214*5113495bSYour Name 		.priv_size = sizeof(*priv),
2215*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2216*5113495bSYour Name 	};
2217*5113495bSYour Name 
2218*5113495bSYour Name 	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
2219*5113495bSYour Name 		hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2220*5113495bSYour Name 			 cds_get_driver_state());
2221*5113495bSYour Name 		return 0;
2222*5113495bSYour Name 	}
2223*5113495bSYour Name 
2224*5113495bSYour Name 	if ((QDF_STA_MODE != adapter->device_mode) &&
2225*5113495bSYour Name 	    (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
2226*5113495bSYour Name 		hdd_warn("Unsupported in mode %s(%d)",
2227*5113495bSYour Name 			 qdf_opmode_str(adapter->device_mode),
2228*5113495bSYour Name 			 adapter->device_mode);
2229*5113495bSYour Name 		return 0;
2230*5113495bSYour Name 	}
2231*5113495bSYour Name 
2232*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
2233*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
2234*5113495bSYour Name 		/* If not associated, then expected link status return
2235*5113495bSYour Name 		 * value is 0
2236*5113495bSYour Name 		 */
2237*5113495bSYour Name 		hdd_warn("Not associated!");
2238*5113495bSYour Name 		return 0;
2239*5113495bSYour Name 	}
2240*5113495bSYour Name 
2241*5113495bSYour Name 	request = osif_request_alloc(&params);
2242*5113495bSYour Name 	if (!request) {
2243*5113495bSYour Name 		hdd_err("Request allocation failure");
2244*5113495bSYour Name 		return 0;
2245*5113495bSYour Name 	}
2246*5113495bSYour Name 	cookie = osif_request_cookie(request);
2247*5113495bSYour Name 
2248*5113495bSYour Name 	status = sme_get_link_status(adapter->hdd_ctx->mac_handle,
2249*5113495bSYour Name 				     hdd_get_link_status_cb,
2250*5113495bSYour Name 				     cookie, adapter->deflink->vdev_id);
2251*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
2252*5113495bSYour Name 		hdd_err("Unable to retrieve link status");
2253*5113495bSYour Name 		/* return a cached value */
2254*5113495bSYour Name 	} else {
2255*5113495bSYour Name 		/* request is sent -- wait for the response */
2256*5113495bSYour Name 		ret = osif_request_wait_for_response(request);
2257*5113495bSYour Name 		if (ret) {
2258*5113495bSYour Name 			hdd_err("SME timed out while retrieving link status");
2259*5113495bSYour Name 			/* return a cached value */
2260*5113495bSYour Name 		} else {
2261*5113495bSYour Name 			/* update the adapter with the fresh results */
2262*5113495bSYour Name 			priv = osif_request_priv(request);
2263*5113495bSYour Name 			adapter->link_status = priv->link_status;
2264*5113495bSYour Name 		}
2265*5113495bSYour Name 	}
2266*5113495bSYour Name 
2267*5113495bSYour Name 	/*
2268*5113495bSYour Name 	 * either we never sent a request, we sent a request and
2269*5113495bSYour Name 	 * received a response or we sent a request and timed out.
2270*5113495bSYour Name 	 * regardless we are done with the request.
2271*5113495bSYour Name 	 */
2272*5113495bSYour Name 	osif_request_put(request);
2273*5113495bSYour Name 
2274*5113495bSYour Name 	/* either callback updated adapter stats or it has cached data */
2275*5113495bSYour Name 	return adapter->link_status;
2276*5113495bSYour Name }
2277*5113495bSYour Name 
2278*5113495bSYour Name #ifdef FEATURE_WLAN_ESE
2279*5113495bSYour Name /**
2280*5113495bSYour Name  * hdd_parse_ese_beacon_req() - Parse ese beacon request
2281*5113495bSYour Name  * @pdev: pdev object
2282*5113495bSYour Name  * @command: Pointer to data
2283*5113495bSYour Name  * @req:	Output pointer to store parsed ie information
2284*5113495bSYour Name  *
2285*5113495bSYour Name  * This function parses the ese beacon request passed in the format
2286*5113495bSYour Name  * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2287*5113495bSYour Name  * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2288*5113495bSYour Name  * <space>Scan Mode N<space>Meas Duration N
2289*5113495bSYour Name  *
2290*5113495bSYour Name  * If the Number of bcn req fields (N) does not match with the
2291*5113495bSYour Name  * actual number of fields passed then take N.
2292*5113495bSYour Name  * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2293*5113495bSYour Name  * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2294*5113495bSYour Name  * This function does not take care of removing duplicate channels from the
2295*5113495bSYour Name  * list
2296*5113495bSYour Name  *
2297*5113495bSYour Name  * Return: 0 for success non-zero for failure
2298*5113495bSYour Name  */
hdd_parse_ese_beacon_req(struct wlan_objmgr_pdev * pdev,uint8_t * command,tCsrEseBeaconReq * req)2299*5113495bSYour Name static int hdd_parse_ese_beacon_req(struct wlan_objmgr_pdev *pdev,
2300*5113495bSYour Name 				    uint8_t *command,
2301*5113495bSYour Name 				    tCsrEseBeaconReq *req)
2302*5113495bSYour Name {
2303*5113495bSYour Name 	uint8_t *in_ptr = command;
2304*5113495bSYour Name 	uint8_t input = 0;
2305*5113495bSYour Name 	uint32_t temp_int = 0;
2306*5113495bSYour Name 	int j = 0, i = 0, v = 0;
2307*5113495bSYour Name 	char buf[32];
2308*5113495bSYour Name 
2309*5113495bSYour Name 	in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
2310*5113495bSYour Name 	if (!in_ptr) /* no argument after the command */
2311*5113495bSYour Name 		return -EINVAL;
2312*5113495bSYour Name 	else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
2313*5113495bSYour Name 		return -EINVAL;
2314*5113495bSYour Name 
2315*5113495bSYour Name 	/* remove empty spaces */
2316*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2317*5113495bSYour Name 		in_ptr++;
2318*5113495bSYour Name 
2319*5113495bSYour Name 	/* no argument followed by spaces */
2320*5113495bSYour Name 	if ('\0' == *in_ptr)
2321*5113495bSYour Name 		return -EINVAL;
2322*5113495bSYour Name 
2323*5113495bSYour Name 	/* Getting the first argument ie Number of IE fields */
2324*5113495bSYour Name 	v = sscanf(in_ptr, "%31s ", buf);
2325*5113495bSYour Name 	if (1 != v)
2326*5113495bSYour Name 		return -EINVAL;
2327*5113495bSYour Name 
2328*5113495bSYour Name 	v = kstrtou8(buf, 10, &input);
2329*5113495bSYour Name 	if (v < 0)
2330*5113495bSYour Name 		return -EINVAL;
2331*5113495bSYour Name 
2332*5113495bSYour Name 	input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2333*5113495bSYour Name 	req->numBcnReqIe = input;
2334*5113495bSYour Name 
2335*5113495bSYour Name 	hdd_debug("Number of Bcn Req Ie fields: %d", req->numBcnReqIe);
2336*5113495bSYour Name 
2337*5113495bSYour Name 	for (j = 0; j < (req->numBcnReqIe); j++) {
2338*5113495bSYour Name 		for (i = 0; i < 4; i++) {
2339*5113495bSYour Name 			/*
2340*5113495bSYour Name 			 * in_ptr pointing to the beginning of 1st space
2341*5113495bSYour Name 			 * after number of ie fields
2342*5113495bSYour Name 			 */
2343*5113495bSYour Name 			in_ptr = strpbrk(in_ptr, " ");
2344*5113495bSYour Name 			/* no ie data after the number of ie fields argument */
2345*5113495bSYour Name 			if (!in_ptr)
2346*5113495bSYour Name 				return -EINVAL;
2347*5113495bSYour Name 
2348*5113495bSYour Name 			/* remove empty space */
2349*5113495bSYour Name 			while ((SPACE_ASCII_VALUE == *in_ptr)
2350*5113495bSYour Name 			       && ('\0' != *in_ptr))
2351*5113495bSYour Name 				in_ptr++;
2352*5113495bSYour Name 
2353*5113495bSYour Name 			/*
2354*5113495bSYour Name 			 * no ie data after the number of ie fields
2355*5113495bSYour Name 			 * argument and spaces
2356*5113495bSYour Name 			 */
2357*5113495bSYour Name 			if ('\0' == *in_ptr)
2358*5113495bSYour Name 				return -EINVAL;
2359*5113495bSYour Name 
2360*5113495bSYour Name 			v = sscanf(in_ptr, "%31s ", buf);
2361*5113495bSYour Name 			if (1 != v)
2362*5113495bSYour Name 				return -EINVAL;
2363*5113495bSYour Name 
2364*5113495bSYour Name 			v = kstrtou32(buf, 10, &temp_int);
2365*5113495bSYour Name 			if (v < 0)
2366*5113495bSYour Name 				return -EINVAL;
2367*5113495bSYour Name 
2368*5113495bSYour Name 			switch (i) {
2369*5113495bSYour Name 			case 0: /* Measurement token */
2370*5113495bSYour Name 				if (!temp_int) {
2371*5113495bSYour Name 					hdd_err("Invalid Measurement Token: %u",
2372*5113495bSYour Name 						  temp_int);
2373*5113495bSYour Name 					return -EINVAL;
2374*5113495bSYour Name 				}
2375*5113495bSYour Name 				req->bcnReq[j].measurementToken =
2376*5113495bSYour Name 					temp_int;
2377*5113495bSYour Name 				break;
2378*5113495bSYour Name 
2379*5113495bSYour Name 			case 1: /* Channel number */
2380*5113495bSYour Name 				if (!temp_int ||
2381*5113495bSYour Name 				    (temp_int >
2382*5113495bSYour Name 				     WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
2383*5113495bSYour Name 					hdd_err("Invalid Channel Number: %u",
2384*5113495bSYour Name 						  temp_int);
2385*5113495bSYour Name 					return -EINVAL;
2386*5113495bSYour Name 				}
2387*5113495bSYour Name 				req->bcnReq[j].ch_freq =
2388*5113495bSYour Name 				wlan_reg_legacy_chan_to_freq(pdev, temp_int);
2389*5113495bSYour Name 				break;
2390*5113495bSYour Name 
2391*5113495bSYour Name 			case 2: /* Scan mode */
2392*5113495bSYour Name 				if ((temp_int < eSIR_PASSIVE_SCAN)
2393*5113495bSYour Name 				    || (temp_int > eSIR_BEACON_TABLE)) {
2394*5113495bSYour Name 					hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
2395*5113495bSYour Name 						  temp_int);
2396*5113495bSYour Name 					return -EINVAL;
2397*5113495bSYour Name 				}
2398*5113495bSYour Name 				req->bcnReq[j].scanMode = temp_int;
2399*5113495bSYour Name 				break;
2400*5113495bSYour Name 
2401*5113495bSYour Name 			case 3: /* Measurement duration */
2402*5113495bSYour Name 				if ((!temp_int
2403*5113495bSYour Name 				     && (req->bcnReq[j].scanMode !=
2404*5113495bSYour Name 					 eSIR_BEACON_TABLE)) ||
2405*5113495bSYour Name 				    (req->bcnReq[j].scanMode ==
2406*5113495bSYour Name 						eSIR_BEACON_TABLE)) {
2407*5113495bSYour Name 					hdd_err("Invalid Measurement Duration: %u",
2408*5113495bSYour Name 						  temp_int);
2409*5113495bSYour Name 					return -EINVAL;
2410*5113495bSYour Name 				}
2411*5113495bSYour Name 				req->bcnReq[j].measurementDuration =
2412*5113495bSYour Name 					temp_int;
2413*5113495bSYour Name 				break;
2414*5113495bSYour Name 			}
2415*5113495bSYour Name 		}
2416*5113495bSYour Name 	}
2417*5113495bSYour Name 
2418*5113495bSYour Name 	for (j = 0; j < req->numBcnReqIe; j++) {
2419*5113495bSYour Name 		hdd_debug("Index: %d Measurement Token: %u ch_freq: %u Scan Mode: %u Measurement Duration: %u",
2420*5113495bSYour Name 			  j,
2421*5113495bSYour Name 			  req->bcnReq[j].measurementToken,
2422*5113495bSYour Name 			  req->bcnReq[j].ch_freq,
2423*5113495bSYour Name 			  req->bcnReq[j].scanMode,
2424*5113495bSYour Name 			  req->bcnReq[j].measurementDuration);
2425*5113495bSYour Name 	}
2426*5113495bSYour Name 
2427*5113495bSYour Name 	return 0;
2428*5113495bSYour Name }
2429*5113495bSYour Name 
2430*5113495bSYour Name /**
2431*5113495bSYour Name  * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2432*5113495bSYour Name  * @command: Pointer to input data
2433*5113495bSYour Name  * @cckm_ie: Pointer to output cckm Ie
2434*5113495bSYour Name  * @cckm_ie_len: Pointer to output cckm ie length
2435*5113495bSYour Name  *
2436*5113495bSYour Name  * This function parses the SETCCKM IE command
2437*5113495bSYour Name  * SETCCKMIE<space><ie data>
2438*5113495bSYour Name  *
2439*5113495bSYour Name  * Return: 0 for success non-zero for failure
2440*5113495bSYour Name  */
hdd_parse_get_cckm_ie(uint8_t * command,uint8_t ** cckm_ie,uint8_t * cckm_ie_len)2441*5113495bSYour Name static int hdd_parse_get_cckm_ie(uint8_t *command, uint8_t **cckm_ie,
2442*5113495bSYour Name 				 uint8_t *cckm_ie_len)
2443*5113495bSYour Name {
2444*5113495bSYour Name 	uint8_t *in_ptr = command;
2445*5113495bSYour Name 	uint8_t *end_ptr;
2446*5113495bSYour Name 	int j = 0;
2447*5113495bSYour Name 	int i = 0;
2448*5113495bSYour Name 	uint8_t temp_u8 = 0;
2449*5113495bSYour Name 
2450*5113495bSYour Name 	in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
2451*5113495bSYour Name 	/* no argument after the command */
2452*5113495bSYour Name 	if (!in_ptr)
2453*5113495bSYour Name 		return -EINVAL;
2454*5113495bSYour Name 	else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
2455*5113495bSYour Name 		return -EINVAL;
2456*5113495bSYour Name 
2457*5113495bSYour Name 	/* remove empty spaces */
2458*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2459*5113495bSYour Name 		in_ptr++;
2460*5113495bSYour Name 	/* no argument followed by spaces */
2461*5113495bSYour Name 	if ('\0' == *in_ptr)
2462*5113495bSYour Name 		return -EINVAL;
2463*5113495bSYour Name 
2464*5113495bSYour Name 	/* find the length of data */
2465*5113495bSYour Name 	end_ptr = in_ptr;
2466*5113495bSYour Name 	while (('\0' != *end_ptr)) {
2467*5113495bSYour Name 		end_ptr++;
2468*5113495bSYour Name 		++(*cckm_ie_len);
2469*5113495bSYour Name 	}
2470*5113495bSYour Name 	if (*cckm_ie_len <= 0)
2471*5113495bSYour Name 		return -EINVAL;
2472*5113495bSYour Name 	/*
2473*5113495bSYour Name 	 * Allocate the number of bytes based on the number of input characters
2474*5113495bSYour Name 	 * whether it is even or odd.
2475*5113495bSYour Name 	 * if the number of input characters are even, then we need N / 2 byte.
2476*5113495bSYour Name 	 * if the number of input characters are odd, then we need do
2477*5113495bSYour Name 	 * (N + 1) / 2 to compensate rounding off.
2478*5113495bSYour Name 	 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2479*5113495bSYour Name 	 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2480*5113495bSYour Name 	 */
2481*5113495bSYour Name 	*cckm_ie = qdf_mem_malloc((*cckm_ie_len + 1) / 2);
2482*5113495bSYour Name 	if (!*cckm_ie)
2483*5113495bSYour Name 		return -ENOMEM;
2484*5113495bSYour Name 
2485*5113495bSYour Name 	/*
2486*5113495bSYour Name 	 * the buffer received from the upper layer is character buffer,
2487*5113495bSYour Name 	 * we need to prepare the buffer taking 2 characters in to a U8 hex
2488*5113495bSYour Name 	 * decimal number for example 7f0000f0...form a buffer to contain
2489*5113495bSYour Name 	 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2490*5113495bSYour Name 	 */
2491*5113495bSYour Name 	for (i = 0, j = 0; j < *cckm_ie_len; j += 2) {
2492*5113495bSYour Name 		temp_u8 = (hex_to_bin(in_ptr[j]) << 4) |
2493*5113495bSYour Name 			   (hex_to_bin(in_ptr[j + 1]));
2494*5113495bSYour Name 		(*cckm_ie)[i++] = temp_u8;
2495*5113495bSYour Name 	}
2496*5113495bSYour Name 	*cckm_ie_len = i;
2497*5113495bSYour Name 	return 0;
2498*5113495bSYour Name }
2499*5113495bSYour Name #endif /* FEATURE_WLAN_ESE */
2500*5113495bSYour Name 
wlan_hdd_set_mc_rate(struct wlan_hdd_link_info * link_info,int target_rate)2501*5113495bSYour Name int wlan_hdd_set_mc_rate(struct wlan_hdd_link_info *link_info, int target_rate)
2502*5113495bSYour Name {
2503*5113495bSYour Name 	tSirRateUpdateInd rate_update = {0};
2504*5113495bSYour Name 	QDF_STATUS status;
2505*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
2506*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2507*5113495bSYour Name 	bool bval = false;
2508*5113495bSYour Name 
2509*5113495bSYour Name 	if (!hdd_ctx) {
2510*5113495bSYour Name 		hdd_err("HDD context is null");
2511*5113495bSYour Name 		return -EINVAL;
2512*5113495bSYour Name 	}
2513*5113495bSYour Name 	if ((QDF_SAP_MODE != adapter->device_mode) &&
2514*5113495bSYour Name 	    (QDF_STA_MODE != adapter->device_mode)) {
2515*5113495bSYour Name 		hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2516*5113495bSYour Name 			qdf_opmode_str(adapter->device_mode),
2517*5113495bSYour Name 			adapter->device_mode);
2518*5113495bSYour Name 		hdd_err("SETMCRATE cmd is allowed only in STA or SOFTAP mode");
2519*5113495bSYour Name 		return -EINVAL;
2520*5113495bSYour Name 	}
2521*5113495bSYour Name 
2522*5113495bSYour Name 	status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
2523*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status)) {
2524*5113495bSYour Name 		hdd_err("unable to get vht_enable2x2");
2525*5113495bSYour Name 		return -EINVAL;
2526*5113495bSYour Name 	}
2527*5113495bSYour Name 	rate_update.nss = (bval == 0) ? 0 : 1;
2528*5113495bSYour Name 
2529*5113495bSYour Name 	rate_update.dev_mode = adapter->device_mode;
2530*5113495bSYour Name 	rate_update.mcastDataRate24GHz = target_rate;
2531*5113495bSYour Name 	rate_update.mcastDataRate24GHzTxFlag = 1;
2532*5113495bSYour Name 	rate_update.mcastDataRate5GHz = target_rate;
2533*5113495bSYour Name 	rate_update.bcastDataRate = -1;
2534*5113495bSYour Name 	qdf_copy_macaddr(&rate_update.bssid, &adapter->mac_addr);
2535*5113495bSYour Name 	hdd_debug("MC Target rate %d, mac = "QDF_MAC_ADDR_FMT", dev_mode %s(%d)",
2536*5113495bSYour Name 		  rate_update.mcastDataRate24GHz,
2537*5113495bSYour Name 		  QDF_MAC_ADDR_REF(rate_update.bssid.bytes),
2538*5113495bSYour Name 		  qdf_opmode_str(adapter->device_mode), adapter->device_mode);
2539*5113495bSYour Name 	status = sme_send_rate_update_ind(hdd_ctx->mac_handle, &rate_update);
2540*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
2541*5113495bSYour Name 		hdd_err("SETMCRATE failed");
2542*5113495bSYour Name 		return -EFAULT;
2543*5113495bSYour Name 	}
2544*5113495bSYour Name 	return 0;
2545*5113495bSYour Name }
2546*5113495bSYour Name 
drv_cmd_p2p_dev_addr(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2547*5113495bSYour Name static int drv_cmd_p2p_dev_addr(struct wlan_hdd_link_info *link_info,
2548*5113495bSYour Name 				struct hdd_context *hdd_ctx,
2549*5113495bSYour Name 				uint8_t *command,
2550*5113495bSYour Name 				uint8_t command_len,
2551*5113495bSYour Name 				struct hdd_priv_data *priv_data)
2552*5113495bSYour Name {
2553*5113495bSYour Name 	struct qdf_mac_addr *addr = &hdd_ctx->p2p_device_address;
2554*5113495bSYour Name 	size_t user_size = qdf_min(sizeof(addr->bytes),
2555*5113495bSYour Name 				   (size_t)priv_data->total_len);
2556*5113495bSYour Name 
2557*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2558*5113495bSYour Name 		   TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2559*5113495bSYour Name 		   link_info->vdev_id,
2560*5113495bSYour Name 		   (unsigned int)(*(addr->bytes + 2) << 24 |
2561*5113495bSYour Name 				*(addr->bytes + 3) << 16 |
2562*5113495bSYour Name 				*(addr->bytes + 4) << 8 |
2563*5113495bSYour Name 				*(addr->bytes + 5)));
2564*5113495bSYour Name 
2565*5113495bSYour Name 
2566*5113495bSYour Name 	if (copy_to_user(priv_data->buf, addr->bytes, user_size)) {
2567*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
2568*5113495bSYour Name 		return -EFAULT;
2569*5113495bSYour Name 	}
2570*5113495bSYour Name 
2571*5113495bSYour Name 	return 0;
2572*5113495bSYour Name }
2573*5113495bSYour Name 
2574*5113495bSYour Name /**
2575*5113495bSYour Name  * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2576*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
2577*5113495bSYour Name  * @hdd_ctx: HDD global context
2578*5113495bSYour Name  * @command: Entire driver command received from userspace
2579*5113495bSYour Name  * @command_len: Length of @command
2580*5113495bSYour Name  * @priv_data: Pointer to ioctl private data structure
2581*5113495bSYour Name  *
2582*5113495bSYour Name  * This is a trivial command handler function which simply forwards the
2583*5113495bSYour Name  * command to the actual command processor within the P2P module.
2584*5113495bSYour Name  *
2585*5113495bSYour Name  * Return: 0 on success, non-zero on failure
2586*5113495bSYour Name  */
drv_cmd_p2p_set_noa(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2587*5113495bSYour Name static int drv_cmd_p2p_set_noa(struct wlan_hdd_link_info *link_info,
2588*5113495bSYour Name 			       struct hdd_context *hdd_ctx,
2589*5113495bSYour Name 			       uint8_t *command,
2590*5113495bSYour Name 			       uint8_t command_len,
2591*5113495bSYour Name 			       struct hdd_priv_data *priv_data)
2592*5113495bSYour Name {
2593*5113495bSYour Name 	return hdd_set_p2p_noa(link_info->adapter->dev, command);
2594*5113495bSYour Name }
2595*5113495bSYour Name 
2596*5113495bSYour Name /**
2597*5113495bSYour Name  * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2598*5113495bSYour Name  * @link_info: Link info pointer in adapter
2599*5113495bSYour Name  * @hdd_ctx: HDD global context
2600*5113495bSYour Name  * @command: Entire driver command received from userspace
2601*5113495bSYour Name  * @command_len: Length of @command
2602*5113495bSYour Name  * @priv_data: Pointer to ioctl private data structure
2603*5113495bSYour Name  *
2604*5113495bSYour Name  * This is a trivial command handler function which simply forwards the
2605*5113495bSYour Name  * command to the actual command processor within the P2P module.
2606*5113495bSYour Name  *
2607*5113495bSYour Name  * Return: 0 on success, non-zero on failure
2608*5113495bSYour Name  */
drv_cmd_p2p_set_ps(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2609*5113495bSYour Name static int drv_cmd_p2p_set_ps(struct wlan_hdd_link_info *link_info,
2610*5113495bSYour Name 			      struct hdd_context *hdd_ctx,
2611*5113495bSYour Name 			      uint8_t *command,
2612*5113495bSYour Name 			      uint8_t command_len,
2613*5113495bSYour Name 			      struct hdd_priv_data *priv_data)
2614*5113495bSYour Name {
2615*5113495bSYour Name 	return hdd_set_p2p_opps(link_info->adapter->dev, command);
2616*5113495bSYour Name }
2617*5113495bSYour Name 
drv_cmd_set_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2618*5113495bSYour Name static int drv_cmd_set_band(struct wlan_hdd_link_info *link_info,
2619*5113495bSYour Name 			    struct hdd_context *hdd_ctx,
2620*5113495bSYour Name 			    uint8_t *command,
2621*5113495bSYour Name 			    uint8_t command_len,
2622*5113495bSYour Name 			    struct hdd_priv_data *priv_data)
2623*5113495bSYour Name {
2624*5113495bSYour Name 	int err;
2625*5113495bSYour Name 	uint8_t band;
2626*5113495bSYour Name 	uint32_t band_bitmap;
2627*5113495bSYour Name 
2628*5113495bSYour Name 	/*
2629*5113495bSYour Name 	 * Parse the band value passed from userspace. The first 8 bytes
2630*5113495bSYour Name 	 * should be "SETBAND " and the 9th byte should be a UI band value
2631*5113495bSYour Name 	 */
2632*5113495bSYour Name 	err = kstrtou8(command + command_len + 1, 10, &band);
2633*5113495bSYour Name 	if (err) {
2634*5113495bSYour Name 		hdd_err("error %d parsing userspace band parameter", err);
2635*5113495bSYour Name 		return err;
2636*5113495bSYour Name 	}
2637*5113495bSYour Name 
2638*5113495bSYour Name 	band_bitmap = hdd_reg_legacy_setband_to_reg_wifi_band_bitmap(band);
2639*5113495bSYour Name 
2640*5113495bSYour Name 	return hdd_reg_set_band(link_info->adapter->dev, band_bitmap);
2641*5113495bSYour Name }
2642*5113495bSYour Name 
drv_cmd_set_wmmps(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2643*5113495bSYour Name static int drv_cmd_set_wmmps(struct wlan_hdd_link_info *link_info,
2644*5113495bSYour Name 			     struct hdd_context *hdd_ctx,
2645*5113495bSYour Name 			     uint8_t *command,
2646*5113495bSYour Name 			     uint8_t command_len,
2647*5113495bSYour Name 			     struct hdd_priv_data *priv_data)
2648*5113495bSYour Name {
2649*5113495bSYour Name 	return hdd_wmmps_helper(link_info->adapter, command);
2650*5113495bSYour Name }
2651*5113495bSYour Name 
2652*5113495bSYour Name #ifdef CONFIG_BAND_6GHZ
2653*5113495bSYour Name /**
2654*5113495bSYour Name  * drv_cmd_get_wifi6e_channels() - Handler for GET_WIFI6E_CHANNELS driver
2655*5113495bSYour Name  *                                 command
2656*5113495bSYour Name  * @link_info: Link info pointer in adapter
2657*5113495bSYour Name  * @hdd_ctx: pointer to hdd context
2658*5113495bSYour Name  * @command: command name
2659*5113495bSYour Name  * @command_len: command buffer length
2660*5113495bSYour Name  * @priv_data: output pointer to hold current country code
2661*5113495bSYour Name  *
2662*5113495bSYour Name  * Return: On success 0, negative value on error.
2663*5113495bSYour Name  */
drv_cmd_get_wifi6e_channels(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2664*5113495bSYour Name static int drv_cmd_get_wifi6e_channels(struct wlan_hdd_link_info *link_info,
2665*5113495bSYour Name 				       struct hdd_context *hdd_ctx,
2666*5113495bSYour Name 				       uint8_t *command,
2667*5113495bSYour Name 				       uint8_t command_len,
2668*5113495bSYour Name 				       struct hdd_priv_data *priv_data)
2669*5113495bSYour Name {
2670*5113495bSYour Name 	uint8_t power_type;
2671*5113495bSYour Name 	char extra[SIZE_OF_WIFI6E_CHAN_LIST] = {0};
2672*5113495bSYour Name 	int i, ret, copied_length = 0;
2673*5113495bSYour Name 	enum channel_state state;
2674*5113495bSYour Name 	struct regulatory_channel *chan_list;
2675*5113495bSYour Name 	size_t max_buf_len = QDF_MIN(priv_data->total_len,
2676*5113495bSYour Name 				     SIZE_OF_WIFI6E_CHAN_LIST);
2677*5113495bSYour Name 	QDF_STATUS status;
2678*5113495bSYour Name 
2679*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx))
2680*5113495bSYour Name 		return -EINVAL;
2681*5113495bSYour Name 
2682*5113495bSYour Name 	ret = kstrtou8(command + command_len + 1, 10, &power_type);
2683*5113495bSYour Name 	if (ret) {
2684*5113495bSYour Name 		hdd_err("error %d parsing userspace 6 GHz power type parameter",
2685*5113495bSYour Name 			ret);
2686*5113495bSYour Name 		return -EINVAL;
2687*5113495bSYour Name 	}
2688*5113495bSYour Name 
2689*5113495bSYour Name 	switch (power_type) {
2690*5113495bSYour Name 	case 0:
2691*5113495bSYour Name 		power_type = REG_CLI_DEF_LPI;
2692*5113495bSYour Name 		break;
2693*5113495bSYour Name 	case 1:
2694*5113495bSYour Name 		power_type = REG_CLI_DEF_VLP;
2695*5113495bSYour Name 		break;
2696*5113495bSYour Name 	case 2:
2697*5113495bSYour Name 		power_type = REG_CLI_DEF_SP;
2698*5113495bSYour Name 		break;
2699*5113495bSYour Name 	default:
2700*5113495bSYour Name 		hdd_err("The power type : %u, is incorrect", power_type);
2701*5113495bSYour Name 		return -EINVAL;
2702*5113495bSYour Name 	}
2703*5113495bSYour Name 
2704*5113495bSYour Name 	chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*chan_list));
2705*5113495bSYour Name 	if (!chan_list)
2706*5113495bSYour Name 		return -ENOMEM;
2707*5113495bSYour Name 
2708*5113495bSYour Name 	status = wlan_reg_get_pwrmode_chan_list(hdd_ctx->pdev, chan_list,
2709*5113495bSYour Name 						power_type);
2710*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2711*5113495bSYour Name 		hdd_err("Failed to get wifi6e channel list for given power type %u",
2712*5113495bSYour Name 			power_type);
2713*5113495bSYour Name 		ret =  qdf_status_to_os_return(status);
2714*5113495bSYour Name 		goto free;
2715*5113495bSYour Name 	}
2716*5113495bSYour Name 
2717*5113495bSYour Name 	for (i = 0; i < NUM_6GHZ_CHANNELS && copied_length < max_buf_len - 1;
2718*5113495bSYour Name 	     i++) {
2719*5113495bSYour Name 		state = chan_list[i + MIN_6GHZ_CHANNEL].state;
2720*5113495bSYour Name 		if (state == CHANNEL_STATE_INVALID ||
2721*5113495bSYour Name 		    state == CHANNEL_STATE_DISABLE)
2722*5113495bSYour Name 			continue;
2723*5113495bSYour Name 		copied_length += scnprintf(extra + copied_length,
2724*5113495bSYour Name 				max_buf_len - copied_length, "%u ",
2725*5113495bSYour Name 				chan_list[i + MIN_6GHZ_CHANNEL].chan_num);
2726*5113495bSYour Name 	}
2727*5113495bSYour Name 
2728*5113495bSYour Name 	if (copied_length == 0) {
2729*5113495bSYour Name 		hdd_err("No Channel List found for given power type %u",
2730*5113495bSYour Name 			power_type);
2731*5113495bSYour Name 		ret = -EINVAL;
2732*5113495bSYour Name 		goto free;
2733*5113495bSYour Name 	}
2734*5113495bSYour Name 
2735*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
2736*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
2737*5113495bSYour Name 		ret = -EFAULT;
2738*5113495bSYour Name 		goto free;
2739*5113495bSYour Name 	}
2740*5113495bSYour Name 
2741*5113495bSYour Name 	hdd_debug("Power type = %u, Data = %s", power_type, extra);
2742*5113495bSYour Name free:
2743*5113495bSYour Name 	qdf_mem_free(chan_list);
2744*5113495bSYour Name 	return ret;
2745*5113495bSYour Name }
2746*5113495bSYour Name #endif
2747*5113495bSYour Name 
__drv_cmd_country(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2748*5113495bSYour Name static inline int __drv_cmd_country(struct wlan_hdd_link_info *link_info,
2749*5113495bSYour Name 				    struct hdd_context *hdd_ctx,
2750*5113495bSYour Name 				    uint8_t *command,
2751*5113495bSYour Name 				    uint8_t command_len,
2752*5113495bSYour Name 				    struct hdd_priv_data *priv_data)
2753*5113495bSYour Name {
2754*5113495bSYour Name 	char *country_code;
2755*5113495bSYour Name 
2756*5113495bSYour Name 	country_code = strnchr(command, strlen(command), ' ');
2757*5113495bSYour Name 	/* no argument after the command */
2758*5113495bSYour Name 	if (!country_code)
2759*5113495bSYour Name 		return -EINVAL;
2760*5113495bSYour Name 
2761*5113495bSYour Name 	/* no space after the command */
2762*5113495bSYour Name 	if (*country_code != SPACE_ASCII_VALUE)
2763*5113495bSYour Name 		return -EINVAL;
2764*5113495bSYour Name 
2765*5113495bSYour Name 	country_code++;
2766*5113495bSYour Name 
2767*5113495bSYour Name 	/* removing empty spaces */
2768*5113495bSYour Name 	while ((*country_code == SPACE_ASCII_VALUE) &&
2769*5113495bSYour Name 	       (*country_code != '\0'))
2770*5113495bSYour Name 		country_code++;
2771*5113495bSYour Name 
2772*5113495bSYour Name 	/* no or less than 2  arguments followed by spaces */
2773*5113495bSYour Name 	if (*country_code == '\0' || *(country_code + 1) == '\0')
2774*5113495bSYour Name 		return -EINVAL;
2775*5113495bSYour Name 
2776*5113495bSYour Name 	return hdd_reg_set_country(hdd_ctx, country_code);
2777*5113495bSYour Name }
2778*5113495bSYour Name 
drv_cmd_country(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2779*5113495bSYour Name static inline int drv_cmd_country(struct wlan_hdd_link_info *link_info,
2780*5113495bSYour Name 				  struct hdd_context *hdd_ctx,
2781*5113495bSYour Name 				  uint8_t *command,
2782*5113495bSYour Name 				  uint8_t command_len,
2783*5113495bSYour Name 				  struct hdd_priv_data *priv_data)
2784*5113495bSYour Name {
2785*5113495bSYour Name 	struct osif_psoc_sync *psoc_sync;
2786*5113495bSYour Name 	int errno;
2787*5113495bSYour Name 
2788*5113495bSYour Name 	errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync);
2789*5113495bSYour Name 	if (errno)
2790*5113495bSYour Name 		return errno;
2791*5113495bSYour Name 	errno = __drv_cmd_country(link_info, hdd_ctx, command, command_len,
2792*5113495bSYour Name 				  priv_data);
2793*5113495bSYour Name 
2794*5113495bSYour Name 	osif_psoc_sync_op_stop(psoc_sync);
2795*5113495bSYour Name 
2796*5113495bSYour Name 	return errno;
2797*5113495bSYour Name }
2798*5113495bSYour Name 
2799*5113495bSYour Name /**
2800*5113495bSYour Name  * drv_cmd_get_country() - Helper function to get current county code
2801*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
2802*5113495bSYour Name  * @hdd_ctx: pointer to hdd context
2803*5113495bSYour Name  * @command: command name
2804*5113495bSYour Name  * @command_len: command buffer length
2805*5113495bSYour Name  * @priv_data: output pointer to hold current country code
2806*5113495bSYour Name  *
2807*5113495bSYour Name  * Return: On success 0, negative value on error.
2808*5113495bSYour Name  */
drv_cmd_get_country(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2809*5113495bSYour Name static int drv_cmd_get_country(struct wlan_hdd_link_info *link_info,
2810*5113495bSYour Name 			       struct hdd_context *hdd_ctx,
2811*5113495bSYour Name 			       uint8_t *command, uint8_t command_len,
2812*5113495bSYour Name 			       struct hdd_priv_data *priv_data)
2813*5113495bSYour Name {
2814*5113495bSYour Name 	uint8_t buf[SIZE_OF_GETCOUNTRYREV_OUTPUT] = {0};
2815*5113495bSYour Name 	uint8_t cc[REG_ALPHA2_LEN + 1];
2816*5113495bSYour Name 	int ret = 0, len;
2817*5113495bSYour Name 
2818*5113495bSYour Name 	qdf_mem_copy(cc, hdd_ctx->reg.alpha2, REG_ALPHA2_LEN);
2819*5113495bSYour Name 	cc[REG_ALPHA2_LEN] = '\0';
2820*5113495bSYour Name 
2821*5113495bSYour Name 	len = scnprintf(buf, sizeof(buf), "%s %s",
2822*5113495bSYour Name 			"GETCOUNTRYREV", cc);
2823*5113495bSYour Name 	hdd_debug("buf = %s", buf);
2824*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
2825*5113495bSYour Name 	if (copy_to_user(priv_data->buf, buf, len)) {
2826*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
2827*5113495bSYour Name 		ret = -EFAULT;
2828*5113495bSYour Name 	}
2829*5113495bSYour Name 
2830*5113495bSYour Name 	return ret;
2831*5113495bSYour Name }
2832*5113495bSYour Name 
drv_cmd_set_roam_trigger(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2833*5113495bSYour Name static int drv_cmd_set_roam_trigger(struct wlan_hdd_link_info *link_info,
2834*5113495bSYour Name 				    struct hdd_context *hdd_ctx,
2835*5113495bSYour Name 				    uint8_t *command,
2836*5113495bSYour Name 				    uint8_t command_len,
2837*5113495bSYour Name 				    struct hdd_priv_data *priv_data)
2838*5113495bSYour Name {
2839*5113495bSYour Name 	int ret;
2840*5113495bSYour Name 	uint8_t *value = command;
2841*5113495bSYour Name 	int8_t rssi = 0;
2842*5113495bSYour Name 	uint8_t lookup_threshold = cfg_default(
2843*5113495bSYour Name 					CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD);
2844*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2845*5113495bSYour Name 
2846*5113495bSYour Name 	/* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2847*5113495bSYour Name 	value = value + command_len + 1;
2848*5113495bSYour Name 
2849*5113495bSYour Name 	/* Convert the value from ascii to integer */
2850*5113495bSYour Name 	ret = kstrtos8(value, 10, &rssi);
2851*5113495bSYour Name 	if (ret < 0) {
2852*5113495bSYour Name 		/*
2853*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
2854*5113495bSYour Name 		 * then also kstrtou8 fails
2855*5113495bSYour Name 		 */
2856*5113495bSYour Name 		hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2857*5113495bSYour Name 			cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
2858*5113495bSYour Name 			cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
2859*5113495bSYour Name 		ret = -EINVAL;
2860*5113495bSYour Name 		goto exit;
2861*5113495bSYour Name 	}
2862*5113495bSYour Name 
2863*5113495bSYour Name 	if (!cfg_in_range(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD,
2864*5113495bSYour Name 			  rssi)) {
2865*5113495bSYour Name 		hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
2866*5113495bSYour Name 			  lookup_threshold,
2867*5113495bSYour Name 			  cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
2868*5113495bSYour Name 			  cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
2869*5113495bSYour Name 		ret = -EINVAL;
2870*5113495bSYour Name 		goto exit;
2871*5113495bSYour Name 	}
2872*5113495bSYour Name 
2873*5113495bSYour Name 	lookup_threshold = abs(rssi);
2874*5113495bSYour Name 
2875*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2876*5113495bSYour Name 		   TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
2877*5113495bSYour Name 		   link_info->vdev_id, lookup_threshold);
2878*5113495bSYour Name 
2879*5113495bSYour Name 	hdd_debug("Set Roam trigger: Neighbor lookup threshold = %d",
2880*5113495bSYour Name 		  lookup_threshold);
2881*5113495bSYour Name 
2882*5113495bSYour Name 	status = sme_set_neighbor_lookup_rssi_threshold(
2883*5113495bSYour Name 						    hdd_ctx->mac_handle,
2884*5113495bSYour Name 						    link_info->vdev_id,
2885*5113495bSYour Name 						    lookup_threshold);
2886*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
2887*5113495bSYour Name 		hdd_err("Failed to set roam trigger, try again");
2888*5113495bSYour Name 		ret = -EPERM;
2889*5113495bSYour Name 		goto exit;
2890*5113495bSYour Name 	}
2891*5113495bSYour Name 
2892*5113495bSYour Name exit:
2893*5113495bSYour Name 	return ret;
2894*5113495bSYour Name }
2895*5113495bSYour Name 
drv_cmd_get_roam_trigger(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2896*5113495bSYour Name static int drv_cmd_get_roam_trigger(struct wlan_hdd_link_info *link_info,
2897*5113495bSYour Name 				    struct hdd_context *hdd_ctx,
2898*5113495bSYour Name 				    uint8_t *command,
2899*5113495bSYour Name 				    uint8_t command_len,
2900*5113495bSYour Name 				    struct hdd_priv_data *priv_data)
2901*5113495bSYour Name {
2902*5113495bSYour Name 	int ret = 0;
2903*5113495bSYour Name 	uint8_t lookup_threshold;
2904*5113495bSYour Name 	int rssi;
2905*5113495bSYour Name 	char extra[32];
2906*5113495bSYour Name 	uint8_t len = 0;
2907*5113495bSYour Name 	QDF_STATUS status;
2908*5113495bSYour Name 
2909*5113495bSYour Name 	status = ucfg_cm_get_neighbor_lookup_rssi_threshold(
2910*5113495bSYour Name 						hdd_ctx->psoc,
2911*5113495bSYour Name 						link_info->vdev_id,
2912*5113495bSYour Name 						&lookup_threshold);
2913*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
2914*5113495bSYour Name 		return qdf_status_to_os_return(status);
2915*5113495bSYour Name 
2916*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2917*5113495bSYour Name 		   TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
2918*5113495bSYour Name 		   link_info->vdev_id, lookup_threshold);
2919*5113495bSYour Name 
2920*5113495bSYour Name 	hdd_debug("vdev_id: %u, lookup_threshold: %u",
2921*5113495bSYour Name 		  link_info->vdev_id, lookup_threshold);
2922*5113495bSYour Name 
2923*5113495bSYour Name 	rssi = (-1) * lookup_threshold;
2924*5113495bSYour Name 
2925*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
2926*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
2927*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
2928*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
2929*5113495bSYour Name 		ret = -EFAULT;
2930*5113495bSYour Name 	}
2931*5113495bSYour Name 
2932*5113495bSYour Name 	return ret;
2933*5113495bSYour Name }
2934*5113495bSYour Name 
drv_cmd_set_roam_scan_period(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2935*5113495bSYour Name static int drv_cmd_set_roam_scan_period(struct wlan_hdd_link_info *link_info,
2936*5113495bSYour Name 					struct hdd_context *hdd_ctx,
2937*5113495bSYour Name 					uint8_t *command,
2938*5113495bSYour Name 					uint8_t command_len,
2939*5113495bSYour Name 					struct hdd_priv_data *priv_data)
2940*5113495bSYour Name {
2941*5113495bSYour Name 	int ret = 0;
2942*5113495bSYour Name 	uint8_t *value = command;
2943*5113495bSYour Name 	uint8_t roam_scan_period = 0;
2944*5113495bSYour Name 	uint16_t empty_scan_refresh_period;
2945*5113495bSYour Name 	bool flag = false, val = false;
2946*5113495bSYour Name 
2947*5113495bSYour Name 	ucfg_mlme_get_connection_roaming_ini_present(hdd_ctx->psoc, &val);
2948*5113495bSYour Name 	if (val) {
2949*5113495bSYour Name 		flag = true;
2950*5113495bSYour Name 		empty_scan_refresh_period =
2951*5113495bSYour Name 			cfg_default(CFG_ROAM_SCAN_FIRST_TIMER) * 1000;
2952*5113495bSYour Name 	} else {
2953*5113495bSYour Name 		empty_scan_refresh_period =
2954*5113495bSYour Name 			cfg_default(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD);
2955*5113495bSYour Name 	}
2956*5113495bSYour Name 
2957*5113495bSYour Name 	/* input refresh period is in terms of seconds */
2958*5113495bSYour Name 
2959*5113495bSYour Name 	/* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
2960*5113495bSYour Name 	value = value + command_len + 1;
2961*5113495bSYour Name 
2962*5113495bSYour Name 	/* Convert the value from ascii to integer */
2963*5113495bSYour Name 	ret = kstrtou8(value, 10, &roam_scan_period);
2964*5113495bSYour Name 	if (ret < 0) {
2965*5113495bSYour Name 		/*
2966*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
2967*5113495bSYour Name 		 * then also kstrtou8 fails
2968*5113495bSYour Name 		 */
2969*5113495bSYour Name 		if (flag)
2970*5113495bSYour Name 			hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2971*5113495bSYour Name 				cfg_min(CFG_ROAM_SCAN_FIRST_TIMER),
2972*5113495bSYour Name 				cfg_max(CFG_ROAM_SCAN_FIRST_TIMER));
2973*5113495bSYour Name 		else
2974*5113495bSYour Name 			hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2975*5113495bSYour Name 				(cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000),
2976*5113495bSYour Name 				(cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000));
2977*5113495bSYour Name 		ret = -EINVAL;
2978*5113495bSYour Name 		goto exit;
2979*5113495bSYour Name 	}
2980*5113495bSYour Name 
2981*5113495bSYour Name 	if (!ucfg_mlme_validate_scan_period(hdd_ctx->psoc,
2982*5113495bSYour Name 					    roam_scan_period * 1000)) {
2983*5113495bSYour Name 		ret = -EINVAL;
2984*5113495bSYour Name 		goto exit;
2985*5113495bSYour Name 	}
2986*5113495bSYour Name 
2987*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2988*5113495bSYour Name 		   TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
2989*5113495bSYour Name 		   link_info->vdev_id, roam_scan_period);
2990*5113495bSYour Name 
2991*5113495bSYour Name 	empty_scan_refresh_period = roam_scan_period * 1000;
2992*5113495bSYour Name 
2993*5113495bSYour Name 	hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
2994*5113495bSYour Name 		  roam_scan_period);
2995*5113495bSYour Name 
2996*5113495bSYour Name 	sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle,
2997*5113495bSYour Name 					     link_info->vdev_id,
2998*5113495bSYour Name 					     empty_scan_refresh_period);
2999*5113495bSYour Name 
3000*5113495bSYour Name exit:
3001*5113495bSYour Name 	return ret;
3002*5113495bSYour Name }
3003*5113495bSYour Name 
drv_cmd_get_roam_scan_period(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3004*5113495bSYour Name static int drv_cmd_get_roam_scan_period(struct wlan_hdd_link_info *link_info,
3005*5113495bSYour Name 					struct hdd_context *hdd_ctx,
3006*5113495bSYour Name 					uint8_t *command,
3007*5113495bSYour Name 					uint8_t command_len,
3008*5113495bSYour Name 					struct hdd_priv_data *priv_data)
3009*5113495bSYour Name {
3010*5113495bSYour Name 	int ret = 0;
3011*5113495bSYour Name 	uint16_t empty_scan_refresh_period;
3012*5113495bSYour Name 	char extra[32];
3013*5113495bSYour Name 	uint8_t len;
3014*5113495bSYour Name 	QDF_STATUS status;
3015*5113495bSYour Name 
3016*5113495bSYour Name 	status = ucfg_cm_get_empty_scan_refresh_period(
3017*5113495bSYour Name 						hdd_ctx->psoc,
3018*5113495bSYour Name 						link_info->vdev_id,
3019*5113495bSYour Name 						&empty_scan_refresh_period);
3020*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
3021*5113495bSYour Name 		return qdf_status_to_os_return(status);
3022*5113495bSYour Name 
3023*5113495bSYour Name 	hdd_debug("vdev_id: %u, empty_scan_refresh_period: %u",
3024*5113495bSYour Name 		  link_info->vdev_id, empty_scan_refresh_period);
3025*5113495bSYour Name 
3026*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3027*5113495bSYour Name 		   TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3028*5113495bSYour Name 		   link_info->vdev_id,
3029*5113495bSYour Name 		   empty_scan_refresh_period);
3030*5113495bSYour Name 
3031*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
3032*5113495bSYour Name 			"GETROAMSCANPERIOD",
3033*5113495bSYour Name 			(empty_scan_refresh_period / 1000));
3034*5113495bSYour Name 	/* Returned value is in units of seconds */
3035*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3036*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3037*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3038*5113495bSYour Name 		ret = -EFAULT;
3039*5113495bSYour Name 	}
3040*5113495bSYour Name 
3041*5113495bSYour Name 	return ret;
3042*5113495bSYour Name }
3043*5113495bSYour Name 
3044*5113495bSYour Name static int
drv_cmd_set_roam_scan_refresh_period(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3045*5113495bSYour Name drv_cmd_set_roam_scan_refresh_period(struct wlan_hdd_link_info *link_info,
3046*5113495bSYour Name 				     struct hdd_context *hdd_ctx,
3047*5113495bSYour Name 				     uint8_t *command, uint8_t command_len,
3048*5113495bSYour Name 				     struct hdd_priv_data *priv_data)
3049*5113495bSYour Name {
3050*5113495bSYour Name 	int ret;
3051*5113495bSYour Name 	uint8_t *value = command;
3052*5113495bSYour Name 	uint8_t roam_scan_refresh_period = 0;
3053*5113495bSYour Name 	uint16_t neighbor_scan_refresh_period =
3054*5113495bSYour Name 		cfg_default(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD);
3055*5113495bSYour Name 
3056*5113495bSYour Name 	/* input refresh period is in terms of seconds */
3057*5113495bSYour Name 	/* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3058*5113495bSYour Name 	value = value + command_len + 1;
3059*5113495bSYour Name 
3060*5113495bSYour Name 	/* Convert the value from ascii to integer */
3061*5113495bSYour Name 	ret = kstrtou8(value, 10, &roam_scan_refresh_period);
3062*5113495bSYour Name 	if (ret < 0) {
3063*5113495bSYour Name 		/*
3064*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
3065*5113495bSYour Name 		 * then also kstrtou8 fails
3066*5113495bSYour Name 		 */
3067*5113495bSYour Name 		hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3068*5113495bSYour Name 			(cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3069*5113495bSYour Name 			 / 1000),
3070*5113495bSYour Name 			(cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3071*5113495bSYour Name 			 / 1000));
3072*5113495bSYour Name 		ret = -EINVAL;
3073*5113495bSYour Name 		goto exit;
3074*5113495bSYour Name 	}
3075*5113495bSYour Name 
3076*5113495bSYour Name 	if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD,
3077*5113495bSYour Name 			  roam_scan_refresh_period)) {
3078*5113495bSYour Name 		hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3079*5113495bSYour Name 			roam_scan_refresh_period,
3080*5113495bSYour Name 			(cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3081*5113495bSYour Name 			 / 1000),
3082*5113495bSYour Name 			(cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3083*5113495bSYour Name 			 / 1000));
3084*5113495bSYour Name 		ret = -EINVAL;
3085*5113495bSYour Name 		goto exit;
3086*5113495bSYour Name 	}
3087*5113495bSYour Name 	neighbor_scan_refresh_period = roam_scan_refresh_period * 1000;
3088*5113495bSYour Name 
3089*5113495bSYour Name 	hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
3090*5113495bSYour Name 		  neighbor_scan_refresh_period);
3091*5113495bSYour Name 
3092*5113495bSYour Name 	sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle,
3093*5113495bSYour Name 					     link_info->vdev_id,
3094*5113495bSYour Name 					     neighbor_scan_refresh_period);
3095*5113495bSYour Name 
3096*5113495bSYour Name exit:
3097*5113495bSYour Name 	return ret;
3098*5113495bSYour Name }
3099*5113495bSYour Name 
3100*5113495bSYour Name static int
drv_cmd_get_roam_scan_refresh_period(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3101*5113495bSYour Name drv_cmd_get_roam_scan_refresh_period(struct wlan_hdd_link_info *link_info,
3102*5113495bSYour Name 				     struct hdd_context *hdd_ctx,
3103*5113495bSYour Name 				     uint8_t *command, uint8_t command_len,
3104*5113495bSYour Name 				     struct hdd_priv_data *priv_data)
3105*5113495bSYour Name {
3106*5113495bSYour Name 	int ret = 0;
3107*5113495bSYour Name 	uint16_t value = 0;
3108*5113495bSYour Name 	char extra[32];
3109*5113495bSYour Name 	uint8_t len;
3110*5113495bSYour Name 
3111*5113495bSYour Name 	ucfg_cm_get_neighbor_scan_refresh_period(hdd_ctx->psoc, &value);
3112*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
3113*5113495bSYour Name 			"GETROAMSCANREFRESHPERIOD",
3114*5113495bSYour Name 			(value / 1000));
3115*5113495bSYour Name 	/* Returned value is in units of seconds */
3116*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3117*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3118*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3119*5113495bSYour Name 		ret = -EFAULT;
3120*5113495bSYour Name 	}
3121*5113495bSYour Name 
3122*5113495bSYour Name 	return ret;
3123*5113495bSYour Name }
3124*5113495bSYour Name 
drv_cmd_set_roam_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3125*5113495bSYour Name static int drv_cmd_set_roam_mode(struct wlan_hdd_link_info *link_info,
3126*5113495bSYour Name 				 struct hdd_context *hdd_ctx,
3127*5113495bSYour Name 				 uint8_t *command,
3128*5113495bSYour Name 				 uint8_t command_len,
3129*5113495bSYour Name 				 struct hdd_priv_data *priv_data)
3130*5113495bSYour Name {
3131*5113495bSYour Name 	mac_handle_t mac_handle;
3132*5113495bSYour Name 	int ret;
3133*5113495bSYour Name 	uint8_t *value = command;
3134*5113495bSYour Name 	uint8_t roam_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
3135*5113495bSYour Name 
3136*5113495bSYour Name 	/* Move pointer to ahead of SETROAMMODE<delimiter> */
3137*5113495bSYour Name 	value = value + SIZE_OF_SETROAMMODE + 1;
3138*5113495bSYour Name 
3139*5113495bSYour Name 	/* Convert the value from ascii to integer */
3140*5113495bSYour Name 	ret = kstrtou8(value, 10, &roam_mode);
3141*5113495bSYour Name 	if (ret < 0) {
3142*5113495bSYour Name 		/*
3143*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
3144*5113495bSYour Name 		 * then also kstrtou8 fails
3145*5113495bSYour Name 		 */
3146*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
3147*5113495bSYour Name 			cfg_min(CFG_LFR_FEATURE_ENABLED),
3148*5113495bSYour Name 			cfg_max(CFG_LFR_FEATURE_ENABLED));
3149*5113495bSYour Name 		ret = -EINVAL;
3150*5113495bSYour Name 		goto exit;
3151*5113495bSYour Name 	}
3152*5113495bSYour Name 
3153*5113495bSYour Name 	hdd_debug("Received Command to Set Roam Mode = %d",
3154*5113495bSYour Name 		  roam_mode);
3155*5113495bSYour Name 
3156*5113495bSYour Name 	if (sme_roaming_in_progress(hdd_ctx->mac_handle,
3157*5113495bSYour Name 				    link_info->vdev_id)) {
3158*5113495bSYour Name 		hdd_err_rl("Roaming in progress for vdev %d",
3159*5113495bSYour Name 			   link_info->vdev_id);
3160*5113495bSYour Name 		return -EAGAIN;
3161*5113495bSYour Name 	}
3162*5113495bSYour Name 
3163*5113495bSYour Name 	/*
3164*5113495bSYour Name 	 * Note that
3165*5113495bSYour Name 	 *     SETROAMMODE 0 is to enable LFR while
3166*5113495bSYour Name 	 *     SETROAMMODE 1 is to disable LFR, but
3167*5113495bSYour Name 	 *     notify_is_fast_roam_ini_feature_enabled 0/1 is to
3168*5113495bSYour Name 	 *     enable/disable. So, we have to invert the value
3169*5113495bSYour Name 	 *     to call sme_update_is_fast_roam_ini_feature_enabled.
3170*5113495bSYour Name 	 */
3171*5113495bSYour Name 	if (roam_mode) {
3172*5113495bSYour Name 		/* Roam enable */
3173*5113495bSYour Name 		roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
3174*5113495bSYour Name 	} else {
3175*5113495bSYour Name 		/* Roam disable */
3176*5113495bSYour Name 		roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
3177*5113495bSYour Name 	}
3178*5113495bSYour Name 
3179*5113495bSYour Name 	mac_handle = hdd_ctx->mac_handle;
3180*5113495bSYour Name 	if (roam_mode) {
3181*5113495bSYour Name 		ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3182*5113495bSYour Name 							(bool)roam_mode);
3183*5113495bSYour Name 		sme_update_is_fast_roam_ini_feature_enabled(
3184*5113495bSYour Name 			    mac_handle, link_info->vdev_id, roam_mode);
3185*5113495bSYour Name 	} else {
3186*5113495bSYour Name 		sme_update_is_fast_roam_ini_feature_enabled(
3187*5113495bSYour Name 			    mac_handle, link_info->vdev_id, roam_mode);
3188*5113495bSYour Name 		ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3189*5113495bSYour Name 							roam_mode);
3190*5113495bSYour Name 	}
3191*5113495bSYour Name 
3192*5113495bSYour Name exit:
3193*5113495bSYour Name 	return ret;
3194*5113495bSYour Name }
3195*5113495bSYour Name 
drv_cmd_set_suspend_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3196*5113495bSYour Name static int drv_cmd_set_suspend_mode(struct wlan_hdd_link_info *link_info,
3197*5113495bSYour Name 				    struct hdd_context *hdd_ctx,
3198*5113495bSYour Name 				    uint8_t *command,
3199*5113495bSYour Name 				    uint8_t command_len,
3200*5113495bSYour Name 				    struct hdd_priv_data *priv_data)
3201*5113495bSYour Name {
3202*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
3203*5113495bSYour Name 	int errno;
3204*5113495bSYour Name 	uint8_t *value = command;
3205*5113495bSYour Name 	QDF_STATUS status;
3206*5113495bSYour Name 	uint8_t idle_monitor;
3207*5113495bSYour Name 
3208*5113495bSYour Name 	if (QDF_STA_MODE != adapter->device_mode) {
3209*5113495bSYour Name 		hdd_debug("Non-STA interface");
3210*5113495bSYour Name 		return 0;
3211*5113495bSYour Name 	}
3212*5113495bSYour Name 
3213*5113495bSYour Name 	/* Move pointer to ahead of SETSUSPENDMODE<delimiter> */
3214*5113495bSYour Name 	value = value + SIZE_OF_SETSUSPENDMODE + 1;
3215*5113495bSYour Name 
3216*5113495bSYour Name 	/* Convert the value from ascii to integer */
3217*5113495bSYour Name 	errno = kstrtou8(value, 10, &idle_monitor);
3218*5113495bSYour Name 	if (errno < 0) {
3219*5113495bSYour Name 		/*
3220*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
3221*5113495bSYour Name 		 * then also kstrtou8 fails
3222*5113495bSYour Name 		 */
3223*5113495bSYour Name 		hdd_err("Range validation failed");
3224*5113495bSYour Name 		return -EINVAL;
3225*5113495bSYour Name 	}
3226*5113495bSYour Name 
3227*5113495bSYour Name 	hdd_debug("idle_monitor:%d", idle_monitor);
3228*5113495bSYour Name 	status = ucfg_pmo_tgt_psoc_send_idle_roam_suspend_mode(hdd_ctx->psoc,
3229*5113495bSYour Name 							       idle_monitor);
3230*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3231*5113495bSYour Name 		hdd_debug("Send suspend mode to fw failed");
3232*5113495bSYour Name 		return -EINVAL;
3233*5113495bSYour Name 	}
3234*5113495bSYour Name 	return 0;
3235*5113495bSYour Name }
3236*5113495bSYour Name 
drv_cmd_get_roam_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3237*5113495bSYour Name static int drv_cmd_get_roam_mode(struct wlan_hdd_link_info *link_info,
3238*5113495bSYour Name 				 struct hdd_context *hdd_ctx,
3239*5113495bSYour Name 				 uint8_t *command,
3240*5113495bSYour Name 				 uint8_t command_len,
3241*5113495bSYour Name 				 struct hdd_priv_data *priv_data)
3242*5113495bSYour Name {
3243*5113495bSYour Name 	int ret = 0;
3244*5113495bSYour Name 	bool roam_mode = ucfg_cm_get_is_lfr_feature_enabled(hdd_ctx->psoc);
3245*5113495bSYour Name 	char extra[32];
3246*5113495bSYour Name 	uint8_t len;
3247*5113495bSYour Name 
3248*5113495bSYour Name 	/*
3249*5113495bSYour Name 	 * roamMode value shall be inverted because the sementics is different.
3250*5113495bSYour Name 	 */
3251*5113495bSYour Name 	if (roam_mode)
3252*5113495bSYour Name 		roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
3253*5113495bSYour Name 	else
3254*5113495bSYour Name 		roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
3255*5113495bSYour Name 
3256*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, roam_mode);
3257*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3258*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3259*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3260*5113495bSYour Name 		ret = -EFAULT;
3261*5113495bSYour Name 	}
3262*5113495bSYour Name 
3263*5113495bSYour Name 	return ret;
3264*5113495bSYour Name }
3265*5113495bSYour Name 
drv_cmd_set_roam_delta(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3266*5113495bSYour Name static int drv_cmd_set_roam_delta(struct wlan_hdd_link_info *link_info,
3267*5113495bSYour Name 				  struct hdd_context *hdd_ctx,
3268*5113495bSYour Name 				  uint8_t *command,
3269*5113495bSYour Name 				  uint8_t command_len,
3270*5113495bSYour Name 				  struct hdd_priv_data *priv_data)
3271*5113495bSYour Name {
3272*5113495bSYour Name 	int ret;
3273*5113495bSYour Name 	uint8_t *value = command;
3274*5113495bSYour Name 	uint8_t roam_rssi_diff = cfg_default(CFG_LFR_ROAM_RSSI_DIFF);
3275*5113495bSYour Name 
3276*5113495bSYour Name 	/* Move pointer to ahead of SETROAMDELTA<delimiter> */
3277*5113495bSYour Name 	value = value + command_len + 1;
3278*5113495bSYour Name 
3279*5113495bSYour Name 	/* Convert the value from ascii to integer */
3280*5113495bSYour Name 	ret = kstrtou8(value, 10, &roam_rssi_diff);
3281*5113495bSYour Name 	if (ret < 0) {
3282*5113495bSYour Name 		/*
3283*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
3284*5113495bSYour Name 		 * then also kstrtou8 fails
3285*5113495bSYour Name 		 */
3286*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
3287*5113495bSYour Name 			cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3288*5113495bSYour Name 			cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
3289*5113495bSYour Name 		ret = -EINVAL;
3290*5113495bSYour Name 		goto exit;
3291*5113495bSYour Name 	}
3292*5113495bSYour Name 
3293*5113495bSYour Name 	if (!cfg_in_range(CFG_LFR_ROAM_RSSI_DIFF, roam_rssi_diff)) {
3294*5113495bSYour Name 		hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3295*5113495bSYour Name 			roam_rssi_diff,
3296*5113495bSYour Name 			cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3297*5113495bSYour Name 			cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
3298*5113495bSYour Name 		ret = -EINVAL;
3299*5113495bSYour Name 		goto exit;
3300*5113495bSYour Name 	}
3301*5113495bSYour Name 
3302*5113495bSYour Name 	hdd_debug("Received Command to Set roam rssi diff = %d",
3303*5113495bSYour Name 		  roam_rssi_diff);
3304*5113495bSYour Name 
3305*5113495bSYour Name 	sme_update_roam_rssi_diff(hdd_ctx->mac_handle,
3306*5113495bSYour Name 				  link_info->vdev_id,
3307*5113495bSYour Name 				  roam_rssi_diff);
3308*5113495bSYour Name 
3309*5113495bSYour Name exit:
3310*5113495bSYour Name 	return ret;
3311*5113495bSYour Name }
3312*5113495bSYour Name 
drv_cmd_get_roam_delta(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3313*5113495bSYour Name static int drv_cmd_get_roam_delta(struct wlan_hdd_link_info *link_info,
3314*5113495bSYour Name 				  struct hdd_context *hdd_ctx,
3315*5113495bSYour Name 				  uint8_t *command,
3316*5113495bSYour Name 				  uint8_t command_len,
3317*5113495bSYour Name 				  struct hdd_priv_data *priv_data)
3318*5113495bSYour Name {
3319*5113495bSYour Name 	int ret = 0;
3320*5113495bSYour Name 	uint8_t rssi_diff;
3321*5113495bSYour Name 	char extra[32];
3322*5113495bSYour Name 	uint8_t len;
3323*5113495bSYour Name 	QDF_STATUS status;
3324*5113495bSYour Name 
3325*5113495bSYour Name 	status = ucfg_cm_get_roam_rssi_diff(hdd_ctx->psoc,
3326*5113495bSYour Name 					    link_info->vdev_id,
3327*5113495bSYour Name 					    &rssi_diff);
3328*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
3329*5113495bSYour Name 		return qdf_status_to_os_return(status);
3330*5113495bSYour Name 
3331*5113495bSYour Name 	hdd_debug("vdev_id: %u, rssi_diff: %u",
3332*5113495bSYour Name 		  link_info->vdev_id, rssi_diff);
3333*5113495bSYour Name 
3334*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3335*5113495bSYour Name 		   TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3336*5113495bSYour Name 		   link_info->vdev_id, rssi_diff);
3337*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
3338*5113495bSYour Name 			command, rssi_diff);
3339*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3340*5113495bSYour Name 
3341*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3342*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3343*5113495bSYour Name 		ret = -EFAULT;
3344*5113495bSYour Name 	}
3345*5113495bSYour Name 
3346*5113495bSYour Name 	return ret;
3347*5113495bSYour Name }
3348*5113495bSYour Name 
drv_cmd_get_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3349*5113495bSYour Name static int drv_cmd_get_band(struct wlan_hdd_link_info *link_info,
3350*5113495bSYour Name 			    struct hdd_context *hdd_ctx,
3351*5113495bSYour Name 			    uint8_t *command,
3352*5113495bSYour Name 			    uint8_t command_len,
3353*5113495bSYour Name 			    struct hdd_priv_data *priv_data)
3354*5113495bSYour Name {
3355*5113495bSYour Name 	int ret = 0, band = -1;
3356*5113495bSYour Name 	char extra[32];
3357*5113495bSYour Name 	uint8_t len = 0;
3358*5113495bSYour Name 
3359*5113495bSYour Name 	hdd_get_band_helper(hdd_ctx, &band);
3360*5113495bSYour Name 
3361*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3362*5113495bSYour Name 		   TRACE_CODE_HDD_GETBAND_IOCTL,
3363*5113495bSYour Name 		   link_info->vdev_id, band);
3364*5113495bSYour Name 
3365*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
3366*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3367*5113495bSYour Name 
3368*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3369*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3370*5113495bSYour Name 		ret = -EFAULT;
3371*5113495bSYour Name 	}
3372*5113495bSYour Name 
3373*5113495bSYour Name 	return ret;
3374*5113495bSYour Name }
3375*5113495bSYour Name 
3376*5113495bSYour Name #ifdef WLAN_FEATURE_ROAM_OFFLOAD
is_roam_ch_from_fw_supported(struct hdd_context * hdd_ctx)3377*5113495bSYour Name static bool is_roam_ch_from_fw_supported(struct hdd_context *hdd_ctx)
3378*5113495bSYour Name {
3379*5113495bSYour Name 	return hdd_ctx->roam_ch_from_fw_supported;
3380*5113495bSYour Name }
3381*5113495bSYour Name 
3382*5113495bSYour Name struct roam_ch_priv {
3383*5113495bSYour Name 	struct roam_scan_ch_resp roam_ch;
3384*5113495bSYour Name };
3385*5113495bSYour Name 
3386*5113495bSYour Name /**
3387*5113495bSYour Name  * hdd_dump_roam_scan_ch_list() - Function to dump roam scan chan list content
3388*5113495bSYour Name  * @chan_list: pointer to channel list received from FW via an event
3389*5113495bSYour Name  * WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID
3390*5113495bSYour Name  * @num_channels: Number of channels
3391*5113495bSYour Name  *
3392*5113495bSYour Name  * Return: none
3393*5113495bSYour Name  */
3394*5113495bSYour Name static void
hdd_dump_roam_scan_ch_list(uint32_t * chan_list,uint16_t num_channels)3395*5113495bSYour Name hdd_dump_roam_scan_ch_list(uint32_t *chan_list, uint16_t num_channels)
3396*5113495bSYour Name {
3397*5113495bSYour Name 	uint8_t i, j;
3398*5113495bSYour Name 	uint8_t ch_cache_str[128] = {0};
3399*5113495bSYour Name 
3400*5113495bSYour Name 	/* print channel list after sorting in ascending order */
3401*5113495bSYour Name 	for (i = 0, j = 0; i < num_channels; i++) {
3402*5113495bSYour Name 		if (j < sizeof(ch_cache_str))
3403*5113495bSYour Name 			j += snprintf(ch_cache_str + j,
3404*5113495bSYour Name 				      sizeof(ch_cache_str) - j, " %d",
3405*5113495bSYour Name 				      chan_list[i]);
3406*5113495bSYour Name 		else
3407*5113495bSYour Name 			break;
3408*5113495bSYour Name 	}
3409*5113495bSYour Name 
3410*5113495bSYour Name 	hdd_debug("No of freq:%d, freq list : %s", num_channels, ch_cache_str);
3411*5113495bSYour Name }
3412*5113495bSYour Name 
3413*5113495bSYour Name /**
3414*5113495bSYour Name  * hdd_sort_roam_scan_ch_list() - Function to sort roam scan channel list in
3415*5113495bSYour Name  * descending order before sending it to supplicant
3416*5113495bSYour Name  * @chan_list: pointer to channel list received from FW via an event
3417*5113495bSYour Name  * WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID
3418*5113495bSYour Name  * @num_channels: Number of channels
3419*5113495bSYour Name  *
3420*5113495bSYour Name  * Return: none
3421*5113495bSYour Name  */
3422*5113495bSYour Name static void
hdd_sort_roam_scan_ch_list(uint32_t * chan_list,uint16_t num_channels)3423*5113495bSYour Name hdd_sort_roam_scan_ch_list(uint32_t *chan_list, uint16_t num_channels)
3424*5113495bSYour Name {
3425*5113495bSYour Name 	uint8_t i, j;
3426*5113495bSYour Name 	uint32_t swap = 0;
3427*5113495bSYour Name 
3428*5113495bSYour Name 	for (i = 0; i < (num_channels - 1) &&
3429*5113495bSYour Name 	     i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) {
3430*5113495bSYour Name 		for (j = 0; j < (num_channels - i - 1); j++) {
3431*5113495bSYour Name 			if (chan_list[j] < chan_list[j + 1]) {
3432*5113495bSYour Name 				swap = chan_list[j];
3433*5113495bSYour Name 				chan_list[j] = chan_list[j + 1];
3434*5113495bSYour Name 				chan_list[j + 1] = swap;
3435*5113495bSYour Name 			}
3436*5113495bSYour Name 		}
3437*5113495bSYour Name 	}
3438*5113495bSYour Name }
3439*5113495bSYour Name 
hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle,struct roam_scan_ch_resp * roam_ch,void * context)3440*5113495bSYour Name void hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle,
3441*5113495bSYour Name 			     struct roam_scan_ch_resp *roam_ch,
3442*5113495bSYour Name 			     void *context)
3443*5113495bSYour Name {
3444*5113495bSYour Name 	struct osif_request *request;
3445*5113495bSYour Name 	struct roam_ch_priv *priv;
3446*5113495bSYour Name 	uint8_t *event = NULL, i = 0;
3447*5113495bSYour Name 	uint32_t  *freq = NULL, len;
3448*5113495bSYour Name 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
3449*5113495bSYour Name 
3450*5113495bSYour Name 	hdd_debug("roam scan ch list event received : vdev_id:%d command resp: %d",
3451*5113495bSYour Name 		  roam_ch->vdev_id, roam_ch->command_resp);
3452*5113495bSYour Name 	/**
3453*5113495bSYour Name 	 * If command response is set in the response message, then it is
3454*5113495bSYour Name 	 * getroamscanchannels command response else this event is asynchronous
3455*5113495bSYour Name 	 * event raised by firmware.
3456*5113495bSYour Name 	 */
3457*5113495bSYour Name 	if (!roam_ch->command_resp) {
3458*5113495bSYour Name 		/*
3459*5113495bSYour Name 		 * Maximum allowed channel count is 30 in supplicant vendor
3460*5113495bSYour Name 		 * event of RCL list. So if number of channels present in
3461*5113495bSYour Name 		 * channel list received from FW is more than 30 channels then
3462*5113495bSYour Name 		 * restrict it to 30 channels only.
3463*5113495bSYour Name 		 */
3464*5113495bSYour Name 		if (roam_ch->num_channels > MAX_RCL_CHANNEL_COUNT)
3465*5113495bSYour Name 			roam_ch->num_channels =  MAX_RCL_CHANNEL_COUNT;
3466*5113495bSYour Name 
3467*5113495bSYour Name 		len = roam_ch->num_channels * sizeof(roam_ch->chan_list[0]);
3468*5113495bSYour Name 		if (!len) {
3469*5113495bSYour Name 			hdd_err("Invalid len");
3470*5113495bSYour Name 			return;
3471*5113495bSYour Name 		}
3472*5113495bSYour Name 		event = (uint8_t *)qdf_mem_malloc(len);
3473*5113495bSYour Name 		if (!event)
3474*5113495bSYour Name 			return;
3475*5113495bSYour Name 
3476*5113495bSYour Name 		freq = (uint32_t *)event;
3477*5113495bSYour Name 		hdd_sort_roam_scan_ch_list(roam_ch->chan_list,
3478*5113495bSYour Name 					   roam_ch->num_channels);
3479*5113495bSYour Name 		hdd_dump_roam_scan_ch_list(roam_ch->chan_list,
3480*5113495bSYour Name 					   roam_ch->num_channels);
3481*5113495bSYour Name 		for (i = 0; i < roam_ch->num_channels &&
3482*5113495bSYour Name 		     i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) {
3483*5113495bSYour Name 			freq[i] = roam_ch->chan_list[i];
3484*5113495bSYour Name 		}
3485*5113495bSYour Name 
3486*5113495bSYour Name 		hdd_send_roam_scan_ch_list_event(hdd_ctx, roam_ch->vdev_id,
3487*5113495bSYour Name 						 len, event);
3488*5113495bSYour Name 		qdf_mem_free(event);
3489*5113495bSYour Name 		return;
3490*5113495bSYour Name 	}
3491*5113495bSYour Name 
3492*5113495bSYour Name 	request = osif_request_get(context);
3493*5113495bSYour Name 	if (!request) {
3494*5113495bSYour Name 		hdd_err("Obsolete request");
3495*5113495bSYour Name 		return;
3496*5113495bSYour Name 	}
3497*5113495bSYour Name 	priv = osif_request_priv(request);
3498*5113495bSYour Name 
3499*5113495bSYour Name 	hdd_sort_roam_scan_ch_list(roam_ch->chan_list, roam_ch->num_channels);
3500*5113495bSYour Name 	hdd_dump_roam_scan_ch_list(roam_ch->chan_list, roam_ch->num_channels);
3501*5113495bSYour Name 
3502*5113495bSYour Name 	priv->roam_ch.num_channels = roam_ch->num_channels;
3503*5113495bSYour Name 	for (i = 0; i < priv->roam_ch.num_channels &&
3504*5113495bSYour Name 	     i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++)
3505*5113495bSYour Name 		priv->roam_ch.chan_list[i] = roam_ch->chan_list[i];
3506*5113495bSYour Name 
3507*5113495bSYour Name 	osif_request_complete(request);
3508*5113495bSYour Name 	osif_request_put(request);
3509*5113495bSYour Name }
3510*5113495bSYour Name 
3511*5113495bSYour Name static uint32_t
hdd_get_roam_chan_from_fw(struct hdd_adapter * adapter,uint32_t * chan_list,uint8_t * num_channels)3512*5113495bSYour Name hdd_get_roam_chan_from_fw(struct hdd_adapter *adapter, uint32_t *chan_list,
3513*5113495bSYour Name 			  uint8_t *num_channels)
3514*5113495bSYour Name {
3515*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
3516*5113495bSYour Name 	struct hdd_context *hdd_ctx;
3517*5113495bSYour Name 	int ret, i;
3518*5113495bSYour Name 	void *cookie;
3519*5113495bSYour Name 	struct osif_request *request;
3520*5113495bSYour Name 	struct roam_ch_priv *priv;
3521*5113495bSYour Name 	struct roam_scan_ch_resp *p_roam_ch;
3522*5113495bSYour Name 	static const struct osif_request_params params = {
3523*5113495bSYour Name 		.priv_size = sizeof(*priv) +
3524*5113495bSYour Name 			     sizeof(priv->roam_ch.chan_list[0]) *
3525*5113495bSYour Name 			     WNI_CFG_VALID_CHANNEL_LIST_LEN,
3526*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_STATS,
3527*5113495bSYour Name 	};
3528*5113495bSYour Name 
3529*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3530*5113495bSYour Name 	request = osif_request_alloc(&params);
3531*5113495bSYour Name 	if (!request) {
3532*5113495bSYour Name 		hdd_err("Request allocation failure");
3533*5113495bSYour Name 		return -ENOMEM;
3534*5113495bSYour Name 	}
3535*5113495bSYour Name 
3536*5113495bSYour Name 	priv = osif_request_priv(request);
3537*5113495bSYour Name 	p_roam_ch = &priv->roam_ch;
3538*5113495bSYour Name 	/** channel list starts after response structure*/
3539*5113495bSYour Name 	priv->roam_ch.chan_list = (uint32_t *)(p_roam_ch + 1);
3540*5113495bSYour Name 	cookie = osif_request_cookie(request);
3541*5113495bSYour Name 	status = sme_get_roam_scan_ch(hdd_ctx->mac_handle,
3542*5113495bSYour Name 				      adapter->deflink->vdev_id, cookie);
3543*5113495bSYour Name 
3544*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3545*5113495bSYour Name 		hdd_err("Unable to retrieve roam channels");
3546*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
3547*5113495bSYour Name 		goto cleanup;
3548*5113495bSYour Name 	}
3549*5113495bSYour Name 
3550*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
3551*5113495bSYour Name 	if (ret) {
3552*5113495bSYour Name 		hdd_err("SME timed out while retrieving raom channels");
3553*5113495bSYour Name 		goto cleanup;
3554*5113495bSYour Name 	}
3555*5113495bSYour Name 
3556*5113495bSYour Name 	priv = osif_request_priv(request);
3557*5113495bSYour Name 	*num_channels = priv->roam_ch.num_channels;
3558*5113495bSYour Name 	for (i = 0; i < *num_channels; i++)
3559*5113495bSYour Name 		chan_list[i] = priv->roam_ch.chan_list[i];
3560*5113495bSYour Name 
3561*5113495bSYour Name cleanup:
3562*5113495bSYour Name 	osif_request_put(request);
3563*5113495bSYour Name 
3564*5113495bSYour Name 	return ret;
3565*5113495bSYour Name }
3566*5113495bSYour Name 
3567*5113495bSYour Name int
hdd_get_roam_scan_freq(struct hdd_adapter * adapter,mac_handle_t mac_handle,uint32_t * chan_list,uint8_t * num_channels)3568*5113495bSYour Name hdd_get_roam_scan_freq(struct hdd_adapter *adapter, mac_handle_t mac_handle,
3569*5113495bSYour Name 		       uint32_t *chan_list, uint8_t *num_channels)
3570*5113495bSYour Name {
3571*5113495bSYour Name 	int ret = 0;
3572*5113495bSYour Name 
3573*5113495bSYour Name 	if (!adapter || !mac_handle || !chan_list || !num_channels) {
3574*5113495bSYour Name 		hdd_err("failed to get roam scan channel, invalid input");
3575*5113495bSYour Name 		return -EFAULT;
3576*5113495bSYour Name 	}
3577*5113495bSYour Name 
3578*5113495bSYour Name 	if (is_roam_ch_from_fw_supported(adapter->hdd_ctx)) {
3579*5113495bSYour Name 		ret = hdd_get_roam_chan_from_fw(adapter, chan_list,
3580*5113495bSYour Name 						num_channels);
3581*5113495bSYour Name 		if (ret != QDF_STATUS_SUCCESS) {
3582*5113495bSYour Name 			hdd_err("failed to get roam scan channel list from FW");
3583*5113495bSYour Name 			return -EFAULT;
3584*5113495bSYour Name 		}
3585*5113495bSYour Name 
3586*5113495bSYour Name 		return ret;
3587*5113495bSYour Name 	}
3588*5113495bSYour Name 
3589*5113495bSYour Name 	if (sme_get_roam_scan_channel_list(mac_handle, chan_list, num_channels,
3590*5113495bSYour Name 					   adapter->deflink->vdev_id) !=
3591*5113495bSYour Name 					   QDF_STATUS_SUCCESS) {
3592*5113495bSYour Name 		hdd_err("failed to get roam scan channel list");
3593*5113495bSYour Name 		return -EFAULT;
3594*5113495bSYour Name 	}
3595*5113495bSYour Name 
3596*5113495bSYour Name 	return ret;
3597*5113495bSYour Name }
3598*5113495bSYour Name #endif
3599*5113495bSYour Name 
3600*5113495bSYour Name enum host_target_comm_log {
3601*5113495bSYour Name 	HTC_CREDIT_HISTORY_LOG = 0,
3602*5113495bSYour Name 	COMMAND_LOG,
3603*5113495bSYour Name 	COMMAND_TX_CMP_LOG,
3604*5113495bSYour Name 	MGMT_COMMAND_LOG,
3605*5113495bSYour Name 	MGMT_COMMAND_TX_CMP_LOG,
3606*5113495bSYour Name 	EVENT_LOG,
3607*5113495bSYour Name 	RX_EVENT_LOG,
3608*5113495bSYour Name 	MGMT_EVENT_LOG
3609*5113495bSYour Name };
3610*5113495bSYour Name 
printk_adapter(void * priv,const char * fmt,...)3611*5113495bSYour Name static int printk_adapter(void *priv, const char *fmt, ...)
3612*5113495bSYour Name {
3613*5113495bSYour Name 	int ret;
3614*5113495bSYour Name 	va_list args;
3615*5113495bSYour Name 
3616*5113495bSYour Name 	va_start(args, fmt);
3617*5113495bSYour Name 	ret = vprintk(fmt, args);
3618*5113495bSYour Name 	ret += printk("\n");
3619*5113495bSYour Name 	va_end(args);
3620*5113495bSYour Name 
3621*5113495bSYour Name 	return ret;
3622*5113495bSYour Name }
3623*5113495bSYour Name 
hdd_ioctl_log_buffer(int log_id,uint32_t count,qdf_abstract_print * custom_print,void * print_ctx)3624*5113495bSYour Name void hdd_ioctl_log_buffer(int log_id, uint32_t count, qdf_abstract_print
3625*5113495bSYour Name 							     *custom_print,
3626*5113495bSYour Name 							     void *print_ctx)
3627*5113495bSYour Name {
3628*5113495bSYour Name 	qdf_abstract_print *print;
3629*5113495bSYour Name 
3630*5113495bSYour Name 	if (custom_print)
3631*5113495bSYour Name 		print = custom_print;
3632*5113495bSYour Name 	else
3633*5113495bSYour Name 		print = &printk_adapter;
3634*5113495bSYour Name 	switch (log_id) {
3635*5113495bSYour Name 	case HTC_CREDIT_HISTORY_LOG:
3636*5113495bSYour Name 		cds_print_htc_credit_history(count, print, print_ctx);
3637*5113495bSYour Name 		break;
3638*5113495bSYour Name 	case COMMAND_LOG:
3639*5113495bSYour Name 		wma_print_wmi_cmd_log(count, print, print_ctx);
3640*5113495bSYour Name 		break;
3641*5113495bSYour Name 	case COMMAND_TX_CMP_LOG:
3642*5113495bSYour Name 		wma_print_wmi_cmd_tx_cmp_log(count, print, print_ctx);
3643*5113495bSYour Name 		break;
3644*5113495bSYour Name 	case MGMT_COMMAND_LOG:
3645*5113495bSYour Name 		wma_print_wmi_mgmt_cmd_log(count, print, print_ctx);
3646*5113495bSYour Name 		break;
3647*5113495bSYour Name 	case MGMT_COMMAND_TX_CMP_LOG:
3648*5113495bSYour Name 		wma_print_wmi_mgmt_cmd_tx_cmp_log(count, print, print_ctx);
3649*5113495bSYour Name 		break;
3650*5113495bSYour Name 	case EVENT_LOG:
3651*5113495bSYour Name 		wma_print_wmi_event_log(count, print, print_ctx);
3652*5113495bSYour Name 		break;
3653*5113495bSYour Name 	case RX_EVENT_LOG:
3654*5113495bSYour Name 		wma_print_wmi_rx_event_log(count, print, print_ctx);
3655*5113495bSYour Name 		break;
3656*5113495bSYour Name 	case MGMT_EVENT_LOG:
3657*5113495bSYour Name 		wma_print_wmi_mgmt_event_log(count, print, print_ctx);
3658*5113495bSYour Name 		break;
3659*5113495bSYour Name 	default:
3660*5113495bSYour Name 		print(print_ctx, "Invalid Log Id %d", log_id);
3661*5113495bSYour Name 		break;
3662*5113495bSYour Name 	}
3663*5113495bSYour Name }
3664*5113495bSYour Name 
3665*5113495bSYour Name #ifdef WLAN_DUMP_LOG_BUF_CNT
hdd_dump_log_buffer(void * print_ctx,qdf_abstract_print * custom_print)3666*5113495bSYour Name void hdd_dump_log_buffer(void *print_ctx, qdf_abstract_print *custom_print)
3667*5113495bSYour Name {
3668*5113495bSYour Name 	int i;
3669*5113495bSYour Name 
3670*5113495bSYour Name 	for (i = 0; i <= MGMT_EVENT_LOG; i++)
3671*5113495bSYour Name 		hdd_ioctl_log_buffer(i, WLAN_DUMP_LOG_BUF_CNT, custom_print,
3672*5113495bSYour Name 				     print_ctx);
3673*5113495bSYour Name }
3674*5113495bSYour Name #endif
3675*5113495bSYour Name 
drv_cmd_get_ccx_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3676*5113495bSYour Name static int drv_cmd_get_ccx_mode(struct wlan_hdd_link_info *link_info,
3677*5113495bSYour Name 				struct hdd_context *hdd_ctx,
3678*5113495bSYour Name 				uint8_t *command,
3679*5113495bSYour Name 				uint8_t command_len,
3680*5113495bSYour Name 				struct hdd_priv_data *priv_data)
3681*5113495bSYour Name {
3682*5113495bSYour Name 	int ret = 0;
3683*5113495bSYour Name 	bool ese_mode = ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc);
3684*5113495bSYour Name 	char extra[32];
3685*5113495bSYour Name 	uint8_t len = 0;
3686*5113495bSYour Name 	struct pmkid_mode_bits pmkid_modes;
3687*5113495bSYour Name 
3688*5113495bSYour Name 	hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
3689*5113495bSYour Name 	/*
3690*5113495bSYour Name 	 * Check if the features PMKID/ESE/11R are supported simultaneously,
3691*5113495bSYour Name 	 * then this operation is not permitted (return FAILURE)
3692*5113495bSYour Name 	 */
3693*5113495bSYour Name 	if (ese_mode &&
3694*5113495bSYour Name 	    (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
3695*5113495bSYour Name 	    ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) {
3696*5113495bSYour Name 		hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
3697*5113495bSYour Name 		ret = -EPERM;
3698*5113495bSYour Name 		goto exit;
3699*5113495bSYour Name 	}
3700*5113495bSYour Name 
3701*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
3702*5113495bSYour Name 			"GETCCXMODE", ese_mode);
3703*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3704*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3705*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3706*5113495bSYour Name 		ret = -EFAULT;
3707*5113495bSYour Name 		goto exit;
3708*5113495bSYour Name 	}
3709*5113495bSYour Name 
3710*5113495bSYour Name exit:
3711*5113495bSYour Name 	return ret;
3712*5113495bSYour Name }
3713*5113495bSYour Name 
drv_cmd_get_okc_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3714*5113495bSYour Name static int drv_cmd_get_okc_mode(struct wlan_hdd_link_info *link_info,
3715*5113495bSYour Name 				struct hdd_context *hdd_ctx,
3716*5113495bSYour Name 				uint8_t *command,
3717*5113495bSYour Name 				uint8_t command_len,
3718*5113495bSYour Name 				struct hdd_priv_data *priv_data)
3719*5113495bSYour Name {
3720*5113495bSYour Name 	int ret = 0;
3721*5113495bSYour Name 	struct pmkid_mode_bits pmkid_modes;
3722*5113495bSYour Name 	char extra[32];
3723*5113495bSYour Name 	uint8_t len = 0;
3724*5113495bSYour Name 
3725*5113495bSYour Name 	hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
3726*5113495bSYour Name 	/*
3727*5113495bSYour Name 	 * Check if the features OKC/ESE/11R are supported simultaneously,
3728*5113495bSYour Name 	 * then this operation is not permitted (return FAILURE)
3729*5113495bSYour Name 	 */
3730*5113495bSYour Name 	if (pmkid_modes.fw_okc &&
3731*5113495bSYour Name 	    ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc) &&
3732*5113495bSYour Name 	    ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) {
3733*5113495bSYour Name 		hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
3734*5113495bSYour Name 		ret = -EPERM;
3735*5113495bSYour Name 		goto exit;
3736*5113495bSYour Name 	}
3737*5113495bSYour Name 
3738*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
3739*5113495bSYour Name 			"GETOKCMODE", pmkid_modes.fw_okc);
3740*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3741*5113495bSYour Name 
3742*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3743*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3744*5113495bSYour Name 		ret = -EFAULT;
3745*5113495bSYour Name 		goto exit;
3746*5113495bSYour Name 	}
3747*5113495bSYour Name 
3748*5113495bSYour Name exit:
3749*5113495bSYour Name 	return ret;
3750*5113495bSYour Name }
3751*5113495bSYour Name 
drv_cmd_get_fast_roam(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3752*5113495bSYour Name static int drv_cmd_get_fast_roam(struct wlan_hdd_link_info *link_info,
3753*5113495bSYour Name 				 struct hdd_context *hdd_ctx,
3754*5113495bSYour Name 				 uint8_t *command,
3755*5113495bSYour Name 				 uint8_t command_len,
3756*5113495bSYour Name 				 struct hdd_priv_data *priv_data)
3757*5113495bSYour Name {
3758*5113495bSYour Name 	int ret = 0;
3759*5113495bSYour Name 	bool lfr_mode = ucfg_cm_get_is_lfr_feature_enabled(hdd_ctx->psoc);
3760*5113495bSYour Name 	char extra[32];
3761*5113495bSYour Name 	uint8_t len = 0;
3762*5113495bSYour Name 
3763*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
3764*5113495bSYour Name 			"GETFASTROAM", lfr_mode);
3765*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3766*5113495bSYour Name 
3767*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3768*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3769*5113495bSYour Name 		ret = -EFAULT;
3770*5113495bSYour Name 	}
3771*5113495bSYour Name 
3772*5113495bSYour Name 	return ret;
3773*5113495bSYour Name }
3774*5113495bSYour Name 
drv_cmd_get_fast_transition(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3775*5113495bSYour Name static int drv_cmd_get_fast_transition(struct wlan_hdd_link_info *link_info,
3776*5113495bSYour Name 				       struct hdd_context *hdd_ctx,
3777*5113495bSYour Name 				       uint8_t *command,
3778*5113495bSYour Name 				       uint8_t command_len,
3779*5113495bSYour Name 				       struct hdd_priv_data *priv_data)
3780*5113495bSYour Name {
3781*5113495bSYour Name 	int ret = 0;
3782*5113495bSYour Name 	bool ft = ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc);
3783*5113495bSYour Name 	char extra[32];
3784*5113495bSYour Name 	uint8_t len = 0;
3785*5113495bSYour Name 
3786*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
3787*5113495bSYour Name 					"GETFASTTRANSITION", ft);
3788*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3789*5113495bSYour Name 
3790*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3791*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3792*5113495bSYour Name 		ret = -EFAULT;
3793*5113495bSYour Name 	}
3794*5113495bSYour Name 
3795*5113495bSYour Name 	return ret;
3796*5113495bSYour Name }
3797*5113495bSYour Name 
3798*5113495bSYour Name static int
drv_cmd_set_roam_scan_channel_min_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3799*5113495bSYour Name drv_cmd_set_roam_scan_channel_min_time(struct wlan_hdd_link_info *link_info,
3800*5113495bSYour Name 				       struct hdd_context *hdd_ctx,
3801*5113495bSYour Name 				       uint8_t *command, uint8_t command_len,
3802*5113495bSYour Name 				       struct hdd_priv_data *priv_data)
3803*5113495bSYour Name {
3804*5113495bSYour Name 	int ret = 0;
3805*5113495bSYour Name 	uint8_t *value = command;
3806*5113495bSYour Name 	uint8_t min_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME);
3807*5113495bSYour Name 
3808*5113495bSYour Name 	/* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3809*5113495bSYour Name 	value = value + command_len + 1;
3810*5113495bSYour Name 
3811*5113495bSYour Name 	/* Convert the value from ascii to integer */
3812*5113495bSYour Name 	ret = kstrtou8(value, 10, &min_time);
3813*5113495bSYour Name 	if (ret < 0) {
3814*5113495bSYour Name 		/*
3815*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
3816*5113495bSYour Name 		 * then also kstrtou8 fails
3817*5113495bSYour Name 		 */
3818*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
3819*5113495bSYour Name 			cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
3820*5113495bSYour Name 			cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
3821*5113495bSYour Name 		ret = -EINVAL;
3822*5113495bSYour Name 		goto exit;
3823*5113495bSYour Name 	}
3824*5113495bSYour Name 
3825*5113495bSYour Name 	if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME, min_time)) {
3826*5113495bSYour Name 		hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3827*5113495bSYour Name 			min_time,
3828*5113495bSYour Name 			cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
3829*5113495bSYour Name 			cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
3830*5113495bSYour Name 		ret = -EINVAL;
3831*5113495bSYour Name 		goto exit;
3832*5113495bSYour Name 	}
3833*5113495bSYour Name 
3834*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3835*5113495bSYour Name 		   TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3836*5113495bSYour Name 		   link_info->vdev_id, min_time);
3837*5113495bSYour Name 
3838*5113495bSYour Name 	hdd_debug("Received Command to change channel min time = %d",
3839*5113495bSYour Name 		  min_time);
3840*5113495bSYour Name 
3841*5113495bSYour Name 	sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
3842*5113495bSYour Name 					    min_time, link_info->vdev_id);
3843*5113495bSYour Name 
3844*5113495bSYour Name exit:
3845*5113495bSYour Name 	return ret;
3846*5113495bSYour Name }
3847*5113495bSYour Name 
drv_cmd_send_action_frame(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3848*5113495bSYour Name static int drv_cmd_send_action_frame(struct wlan_hdd_link_info *link_info,
3849*5113495bSYour Name 				     struct hdd_context *hdd_ctx,
3850*5113495bSYour Name 				     uint8_t *command,
3851*5113495bSYour Name 				     uint8_t command_len,
3852*5113495bSYour Name 				     struct hdd_priv_data *priv_data)
3853*5113495bSYour Name {
3854*5113495bSYour Name 	return hdd_parse_sendactionframe(link_info->adapter, command,
3855*5113495bSYour Name 					 priv_data->total_len);
3856*5113495bSYour Name }
3857*5113495bSYour Name 
3858*5113495bSYour Name static int
drv_cmd_get_roam_scan_channel_min_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3859*5113495bSYour Name drv_cmd_get_roam_scan_channel_min_time(struct wlan_hdd_link_info *link_info,
3860*5113495bSYour Name 				       struct hdd_context *hdd_ctx,
3861*5113495bSYour Name 				       uint8_t *command, uint8_t command_len,
3862*5113495bSYour Name 				       struct hdd_priv_data *priv_data)
3863*5113495bSYour Name {
3864*5113495bSYour Name 	int ret = 0;
3865*5113495bSYour Name 	uint16_t val;
3866*5113495bSYour Name 	char extra[32];
3867*5113495bSYour Name 	uint8_t len = 0;
3868*5113495bSYour Name 
3869*5113495bSYour Name 	val = ucfg_cm_get_neighbor_scan_min_chan_time(hdd_ctx->psoc,
3870*5113495bSYour Name 						      link_info->vdev_id);
3871*5113495bSYour Name 	/* value is interms of msec */
3872*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
3873*5113495bSYour Name 			"GETROAMSCANCHANNELMINTIME", val);
3874*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3875*5113495bSYour Name 
3876*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3877*5113495bSYour Name 		   TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3878*5113495bSYour Name 		   link_info->vdev_id, val);
3879*5113495bSYour Name 
3880*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3881*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3882*5113495bSYour Name 		ret = -EFAULT;
3883*5113495bSYour Name 	}
3884*5113495bSYour Name 
3885*5113495bSYour Name 	return ret;
3886*5113495bSYour Name }
3887*5113495bSYour Name 
drv_cmd_set_scan_channel_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3888*5113495bSYour Name static int drv_cmd_set_scan_channel_time(struct wlan_hdd_link_info *link_info,
3889*5113495bSYour Name 					 struct hdd_context *hdd_ctx,
3890*5113495bSYour Name 					 uint8_t *command,
3891*5113495bSYour Name 					 uint8_t command_len,
3892*5113495bSYour Name 					 struct hdd_priv_data *priv_data)
3893*5113495bSYour Name {
3894*5113495bSYour Name 	int ret = 0;
3895*5113495bSYour Name 	uint8_t *value = command;
3896*5113495bSYour Name 	uint16_t max_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME);
3897*5113495bSYour Name 
3898*5113495bSYour Name 	/* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3899*5113495bSYour Name 	value = value + command_len + 1;
3900*5113495bSYour Name 
3901*5113495bSYour Name 	/* Convert the value from ascii to integer */
3902*5113495bSYour Name 	ret = kstrtou16(value, 10, &max_time);
3903*5113495bSYour Name 	if (ret < 0) {
3904*5113495bSYour Name 		/*
3905*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
3906*5113495bSYour Name 		 * then also kstrtou8 fails
3907*5113495bSYour Name 		 */
3908*5113495bSYour Name 		hdd_err("kstrtou16 failed range [%d - %d]",
3909*5113495bSYour Name 			cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
3910*5113495bSYour Name 			cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
3911*5113495bSYour Name 		ret = -EINVAL;
3912*5113495bSYour Name 		goto exit;
3913*5113495bSYour Name 	}
3914*5113495bSYour Name 
3915*5113495bSYour Name 	if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME, max_time)) {
3916*5113495bSYour Name 		hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3917*5113495bSYour Name 			max_time,
3918*5113495bSYour Name 			cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
3919*5113495bSYour Name 			cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
3920*5113495bSYour Name 		ret = -EINVAL;
3921*5113495bSYour Name 		goto exit;
3922*5113495bSYour Name 	}
3923*5113495bSYour Name 
3924*5113495bSYour Name 	hdd_debug("Received Command to change channel max time = %d",
3925*5113495bSYour Name 		  max_time);
3926*5113495bSYour Name 
3927*5113495bSYour Name 	sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
3928*5113495bSYour Name 					    link_info->vdev_id,
3929*5113495bSYour Name 					    max_time);
3930*5113495bSYour Name 
3931*5113495bSYour Name exit:
3932*5113495bSYour Name 	return ret;
3933*5113495bSYour Name }
3934*5113495bSYour Name 
drv_cmd_get_scan_channel_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3935*5113495bSYour Name static int drv_cmd_get_scan_channel_time(struct wlan_hdd_link_info *link_info,
3936*5113495bSYour Name 					 struct hdd_context *hdd_ctx,
3937*5113495bSYour Name 					 uint8_t *command,
3938*5113495bSYour Name 					 uint8_t command_len,
3939*5113495bSYour Name 					 struct hdd_priv_data *priv_data)
3940*5113495bSYour Name {
3941*5113495bSYour Name 	int ret = 0;
3942*5113495bSYour Name 	uint16_t val;
3943*5113495bSYour Name 	char extra[32];
3944*5113495bSYour Name 	uint8_t len = 0;
3945*5113495bSYour Name 
3946*5113495bSYour Name 	val = ucfg_cm_get_neighbor_scan_max_chan_time(hdd_ctx->psoc,
3947*5113495bSYour Name 						      link_info->vdev_id);
3948*5113495bSYour Name 
3949*5113495bSYour Name 	hdd_debug("vdev_id: %u, scan channel time: %u",
3950*5113495bSYour Name 		  link_info->vdev_id, val);
3951*5113495bSYour Name 
3952*5113495bSYour Name 	/* value is interms of msec */
3953*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
3954*5113495bSYour Name 			"GETSCANCHANNELTIME", val);
3955*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
3956*5113495bSYour Name 
3957*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
3958*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
3959*5113495bSYour Name 		ret = -EFAULT;
3960*5113495bSYour Name 	}
3961*5113495bSYour Name 
3962*5113495bSYour Name 	return ret;
3963*5113495bSYour Name }
3964*5113495bSYour Name 
drv_cmd_set_scan_home_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3965*5113495bSYour Name static int drv_cmd_set_scan_home_time(struct wlan_hdd_link_info *link_info,
3966*5113495bSYour Name 				      struct hdd_context *hdd_ctx,
3967*5113495bSYour Name 				      uint8_t *command,
3968*5113495bSYour Name 				      uint8_t command_len,
3969*5113495bSYour Name 				      struct hdd_priv_data *priv_data)
3970*5113495bSYour Name {
3971*5113495bSYour Name 	int ret = 0;
3972*5113495bSYour Name 	uint8_t *value = command;
3973*5113495bSYour Name 	uint16_t val = cfg_default(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD);
3974*5113495bSYour Name 
3975*5113495bSYour Name 	/* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3976*5113495bSYour Name 	value = value + command_len + 1;
3977*5113495bSYour Name 
3978*5113495bSYour Name 	/* Convert the value from ascii to integer */
3979*5113495bSYour Name 	ret = kstrtou16(value, 10, &val);
3980*5113495bSYour Name 	if (ret < 0) {
3981*5113495bSYour Name 		/*
3982*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
3983*5113495bSYour Name 		 * then also kstrtou8 fails
3984*5113495bSYour Name 		 */
3985*5113495bSYour Name 		hdd_err("kstrtou16 failed range [%d - %d]",
3986*5113495bSYour Name 			cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
3987*5113495bSYour Name 			cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
3988*5113495bSYour Name 		ret = -EINVAL;
3989*5113495bSYour Name 		goto exit;
3990*5113495bSYour Name 	}
3991*5113495bSYour Name 
3992*5113495bSYour Name 	if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD, val)) {
3993*5113495bSYour Name 		hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3994*5113495bSYour Name 			val,
3995*5113495bSYour Name 			cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
3996*5113495bSYour Name 			cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
3997*5113495bSYour Name 		ret = -EINVAL;
3998*5113495bSYour Name 		goto exit;
3999*5113495bSYour Name 	}
4000*5113495bSYour Name 
4001*5113495bSYour Name 	hdd_debug("Received Command to change scan home time = %d",
4002*5113495bSYour Name 		  val);
4003*5113495bSYour Name 
4004*5113495bSYour Name 	sme_set_neighbor_scan_period(hdd_ctx->mac_handle,
4005*5113495bSYour Name 				     link_info->vdev_id, val);
4006*5113495bSYour Name 
4007*5113495bSYour Name exit:
4008*5113495bSYour Name 	return ret;
4009*5113495bSYour Name }
4010*5113495bSYour Name 
drv_cmd_get_scan_home_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4011*5113495bSYour Name static int drv_cmd_get_scan_home_time(struct wlan_hdd_link_info *link_info,
4012*5113495bSYour Name 				      struct hdd_context *hdd_ctx,
4013*5113495bSYour Name 				      uint8_t *command,
4014*5113495bSYour Name 				      uint8_t command_len,
4015*5113495bSYour Name 				      struct hdd_priv_data *priv_data)
4016*5113495bSYour Name {
4017*5113495bSYour Name 	int ret = 0;
4018*5113495bSYour Name 	uint16_t val;
4019*5113495bSYour Name 	char extra[32];
4020*5113495bSYour Name 	uint8_t len = 0;
4021*5113495bSYour Name 
4022*5113495bSYour Name 	val = ucfg_cm_get_neighbor_scan_period(hdd_ctx->psoc,
4023*5113495bSYour Name 					       link_info->vdev_id);
4024*5113495bSYour Name 	hdd_debug("vdev_id: %u, scan home time: %u",
4025*5113495bSYour Name 		  link_info->vdev_id, val);
4026*5113495bSYour Name 
4027*5113495bSYour Name 	/* value is interms of msec */
4028*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
4029*5113495bSYour Name 			"GETSCANHOMETIME", val);
4030*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
4031*5113495bSYour Name 
4032*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
4033*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
4034*5113495bSYour Name 		ret = -EFAULT;
4035*5113495bSYour Name 	}
4036*5113495bSYour Name 
4037*5113495bSYour Name 	return ret;
4038*5113495bSYour Name }
4039*5113495bSYour Name 
drv_cmd_set_roam_intra_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4040*5113495bSYour Name static int drv_cmd_set_roam_intra_band(struct wlan_hdd_link_info *link_info,
4041*5113495bSYour Name 				       struct hdd_context *hdd_ctx,
4042*5113495bSYour Name 				       uint8_t *command,
4043*5113495bSYour Name 				       uint8_t command_len,
4044*5113495bSYour Name 				       struct hdd_priv_data *priv_data)
4045*5113495bSYour Name {
4046*5113495bSYour Name 	int ret = 0;
4047*5113495bSYour Name 	uint8_t *value = command;
4048*5113495bSYour Name 	uint8_t val = cfg_default(CFG_LFR_ROAM_INTRA_BAND);
4049*5113495bSYour Name 
4050*5113495bSYour Name 	/* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
4051*5113495bSYour Name 	value = value + command_len + 1;
4052*5113495bSYour Name 
4053*5113495bSYour Name 	/* Convert the value from ascii to integer */
4054*5113495bSYour Name 	ret = kstrtou8(value, 10, &val);
4055*5113495bSYour Name 	if (ret < 0) {
4056*5113495bSYour Name 		/*
4057*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4058*5113495bSYour Name 		 * then also kstrtou8 fails
4059*5113495bSYour Name 		 */
4060*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
4061*5113495bSYour Name 			cfg_min(CFG_LFR_ROAM_INTRA_BAND),
4062*5113495bSYour Name 			cfg_max(CFG_LFR_ROAM_INTRA_BAND));
4063*5113495bSYour Name 		ret = -EINVAL;
4064*5113495bSYour Name 		goto exit;
4065*5113495bSYour Name 	}
4066*5113495bSYour Name 
4067*5113495bSYour Name 	hdd_debug("Received Command to change intra band = %d",
4068*5113495bSYour Name 		  val);
4069*5113495bSYour Name 
4070*5113495bSYour Name 	ucfg_mlme_set_roam_intra_band(hdd_ctx->psoc, (bool)val);
4071*5113495bSYour Name 
4072*5113495bSYour Name 	/* Disable roaming on Vdev before setting PCL */
4073*5113495bSYour Name 	sme_stop_roaming(hdd_ctx->mac_handle, link_info->vdev_id,
4074*5113495bSYour Name 			 REASON_DRIVER_DISABLED, RSO_SET_PCL);
4075*5113495bSYour Name 
4076*5113495bSYour Name 	policy_mgr_set_pcl_for_existing_combo(hdd_ctx->psoc, PM_STA_MODE,
4077*5113495bSYour Name 					      link_info->vdev_id);
4078*5113495bSYour Name 
4079*5113495bSYour Name 	/* Enable roaming once SET pcl is done */
4080*5113495bSYour Name 	sme_start_roaming(hdd_ctx->mac_handle, link_info->vdev_id,
4081*5113495bSYour Name 			  REASON_DRIVER_ENABLED, RSO_SET_PCL);
4082*5113495bSYour Name 
4083*5113495bSYour Name exit:
4084*5113495bSYour Name 	return ret;
4085*5113495bSYour Name }
4086*5113495bSYour Name 
drv_cmd_get_roam_intra_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4087*5113495bSYour Name static int drv_cmd_get_roam_intra_band(struct wlan_hdd_link_info *link_info,
4088*5113495bSYour Name 				       struct hdd_context *hdd_ctx,
4089*5113495bSYour Name 				       uint8_t *command,
4090*5113495bSYour Name 				       uint8_t command_len,
4091*5113495bSYour Name 				       struct hdd_priv_data *priv_data)
4092*5113495bSYour Name {
4093*5113495bSYour Name 	int ret = 0;
4094*5113495bSYour Name 	uint16_t val = 0;
4095*5113495bSYour Name 	char extra[32];
4096*5113495bSYour Name 	uint8_t len = 0;
4097*5113495bSYour Name 
4098*5113495bSYour Name 	ucfg_cm_get_roam_intra_band(hdd_ctx->psoc, &val);
4099*5113495bSYour Name 	/* value is interms of msec */
4100*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d",
4101*5113495bSYour Name 			"GETROAMINTRABAND", val);
4102*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
4103*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
4104*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
4105*5113495bSYour Name 		ret = -EFAULT;
4106*5113495bSYour Name 	}
4107*5113495bSYour Name 
4108*5113495bSYour Name 	return ret;
4109*5113495bSYour Name }
4110*5113495bSYour Name 
drv_cmd_set_scan_n_probes(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4111*5113495bSYour Name static int drv_cmd_set_scan_n_probes(struct wlan_hdd_link_info *link_info,
4112*5113495bSYour Name 				     struct hdd_context *hdd_ctx,
4113*5113495bSYour Name 				     uint8_t *command,
4114*5113495bSYour Name 				     uint8_t command_len,
4115*5113495bSYour Name 				     struct hdd_priv_data *priv_data)
4116*5113495bSYour Name {
4117*5113495bSYour Name 	int ret = 0;
4118*5113495bSYour Name 	uint8_t *value = command;
4119*5113495bSYour Name 	uint8_t nprobes = cfg_default(CFG_LFR_ROAM_SCAN_N_PROBES);
4120*5113495bSYour Name 
4121*5113495bSYour Name 	/* Move pointer to ahead of SETSCANNPROBES<delimiter> */
4122*5113495bSYour Name 	value = value + command_len + 1;
4123*5113495bSYour Name 
4124*5113495bSYour Name 	/* Convert the value from ascii to integer */
4125*5113495bSYour Name 	ret = kstrtou8(value, 10, &nprobes);
4126*5113495bSYour Name 	if (ret < 0) {
4127*5113495bSYour Name 		/*
4128*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4129*5113495bSYour Name 		 * then also kstrtou8 fails
4130*5113495bSYour Name 		 */
4131*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
4132*5113495bSYour Name 			cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
4133*5113495bSYour Name 			cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
4134*5113495bSYour Name 		ret = -EINVAL;
4135*5113495bSYour Name 		goto exit;
4136*5113495bSYour Name 	}
4137*5113495bSYour Name 
4138*5113495bSYour Name 	if (!cfg_in_range(CFG_LFR_ROAM_SCAN_N_PROBES, nprobes)) {
4139*5113495bSYour Name 		hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
4140*5113495bSYour Name 			nprobes,
4141*5113495bSYour Name 			cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
4142*5113495bSYour Name 			cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
4143*5113495bSYour Name 		ret = -EINVAL;
4144*5113495bSYour Name 		goto exit;
4145*5113495bSYour Name 	}
4146*5113495bSYour Name 
4147*5113495bSYour Name 	hdd_debug("Received Command to Set nProbes = %d",
4148*5113495bSYour Name 		  nprobes);
4149*5113495bSYour Name 
4150*5113495bSYour Name 	sme_update_roam_scan_n_probes(hdd_ctx->mac_handle,
4151*5113495bSYour Name 				      link_info->vdev_id, nprobes);
4152*5113495bSYour Name 
4153*5113495bSYour Name exit:
4154*5113495bSYour Name 	return ret;
4155*5113495bSYour Name }
4156*5113495bSYour Name 
drv_cmd_get_scan_n_probes(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4157*5113495bSYour Name static int drv_cmd_get_scan_n_probes(struct wlan_hdd_link_info *link_info,
4158*5113495bSYour Name 				     struct hdd_context *hdd_ctx,
4159*5113495bSYour Name 				     uint8_t *command,
4160*5113495bSYour Name 				     uint8_t command_len,
4161*5113495bSYour Name 				     struct hdd_priv_data *priv_data)
4162*5113495bSYour Name {
4163*5113495bSYour Name 	int ret = 0;
4164*5113495bSYour Name 	uint8_t val;
4165*5113495bSYour Name 	char extra[32];
4166*5113495bSYour Name 	uint8_t len = 0;
4167*5113495bSYour Name 	QDF_STATUS status;
4168*5113495bSYour Name 
4169*5113495bSYour Name 	status = sme_get_roam_scan_n_probes(hdd_ctx->mac_handle,
4170*5113495bSYour Name 					    link_info->vdev_id, &val);
4171*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
4172*5113495bSYour Name 		return qdf_status_to_os_return(status);
4173*5113495bSYour Name 
4174*5113495bSYour Name 	hdd_debug("vdev_id: %u, scan_n_probes: %u",
4175*5113495bSYour Name 		  link_info->vdev_id, val);
4176*5113495bSYour Name 
4177*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
4178*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
4179*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
4180*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
4181*5113495bSYour Name 		ret = -EFAULT;
4182*5113495bSYour Name 	}
4183*5113495bSYour Name 
4184*5113495bSYour Name 	return ret;
4185*5113495bSYour Name }
4186*5113495bSYour Name 
drv_cmd_set_scan_home_away_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4187*5113495bSYour Name static int drv_cmd_set_scan_home_away_time(struct wlan_hdd_link_info *link_info,
4188*5113495bSYour Name 					   struct hdd_context *hdd_ctx,
4189*5113495bSYour Name 					   uint8_t *command,
4190*5113495bSYour Name 					   uint8_t command_len,
4191*5113495bSYour Name 					   struct hdd_priv_data *priv_data)
4192*5113495bSYour Name {
4193*5113495bSYour Name 	int ret = 0;
4194*5113495bSYour Name 	uint8_t *value = command;
4195*5113495bSYour Name 	uint16_t home_away_time = cfg_default(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME);
4196*5113495bSYour Name 
4197*5113495bSYour Name 	/* input value is in units of msec */
4198*5113495bSYour Name 
4199*5113495bSYour Name 	/* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4200*5113495bSYour Name 	value = value + command_len + 1;
4201*5113495bSYour Name 
4202*5113495bSYour Name 	/* Convert the value from ascii to integer */
4203*5113495bSYour Name 	ret = kstrtou16(value, 10, &home_away_time);
4204*5113495bSYour Name 	if (ret < 0) {
4205*5113495bSYour Name 		/*
4206*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4207*5113495bSYour Name 		 * then also kstrtou8 fails
4208*5113495bSYour Name 		 */
4209*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
4210*5113495bSYour Name 			cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4211*5113495bSYour Name 			cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
4212*5113495bSYour Name 		ret = -EINVAL;
4213*5113495bSYour Name 		goto exit;
4214*5113495bSYour Name 	}
4215*5113495bSYour Name 
4216*5113495bSYour Name 	if (!cfg_in_range(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME, home_away_time)) {
4217*5113495bSYour Name 		hdd_err("home_away_time value %d is out of range (min: %d max: %d)",
4218*5113495bSYour Name 			home_away_time,
4219*5113495bSYour Name 			cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4220*5113495bSYour Name 			cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
4221*5113495bSYour Name 		ret = -EINVAL;
4222*5113495bSYour Name 		goto exit;
4223*5113495bSYour Name 	}
4224*5113495bSYour Name 
4225*5113495bSYour Name 	hdd_debug("Received Command to Set scan away time = %d",
4226*5113495bSYour Name 		  home_away_time);
4227*5113495bSYour Name 
4228*5113495bSYour Name 	sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle,
4229*5113495bSYour Name 					    link_info->vdev_id,
4230*5113495bSYour Name 					    home_away_time, true);
4231*5113495bSYour Name 
4232*5113495bSYour Name exit:
4233*5113495bSYour Name 	return ret;
4234*5113495bSYour Name }
4235*5113495bSYour Name 
drv_cmd_get_scan_home_away_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4236*5113495bSYour Name static int drv_cmd_get_scan_home_away_time(struct wlan_hdd_link_info *link_info,
4237*5113495bSYour Name 					   struct hdd_context *hdd_ctx,
4238*5113495bSYour Name 					   uint8_t *command,
4239*5113495bSYour Name 					   uint8_t command_len,
4240*5113495bSYour Name 					   struct hdd_priv_data *priv_data)
4241*5113495bSYour Name {
4242*5113495bSYour Name 	int ret = 0;
4243*5113495bSYour Name 	uint16_t val;
4244*5113495bSYour Name 	char extra[32] = {0};
4245*5113495bSYour Name 	uint8_t len = 0;
4246*5113495bSYour Name 	QDF_STATUS status;
4247*5113495bSYour Name 
4248*5113495bSYour Name 	status = ucfg_cm_get_roam_scan_home_away_time(hdd_ctx->psoc,
4249*5113495bSYour Name 						      link_info->vdev_id,
4250*5113495bSYour Name 						      &val);
4251*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
4252*5113495bSYour Name 		return qdf_status_to_os_return(status);
4253*5113495bSYour Name 
4254*5113495bSYour Name 	hdd_debug("vdev_id: %u, scan home away time: %u",
4255*5113495bSYour Name 		  link_info->vdev_id, val);
4256*5113495bSYour Name 
4257*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
4258*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
4259*5113495bSYour Name 
4260*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
4261*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
4262*5113495bSYour Name 		ret = -EFAULT;
4263*5113495bSYour Name 	}
4264*5113495bSYour Name 
4265*5113495bSYour Name 	return ret;
4266*5113495bSYour Name }
4267*5113495bSYour Name 
drv_cmd_reassoc(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4268*5113495bSYour Name static int drv_cmd_reassoc(struct wlan_hdd_link_info *link_info,
4269*5113495bSYour Name 			   struct hdd_context *hdd_ctx,
4270*5113495bSYour Name 			   uint8_t *command,
4271*5113495bSYour Name 			   uint8_t command_len,
4272*5113495bSYour Name 			   struct hdd_priv_data *priv_data)
4273*5113495bSYour Name {
4274*5113495bSYour Name 	return hdd_parse_reassoc(link_info->adapter, command,
4275*5113495bSYour Name 				 priv_data->total_len);
4276*5113495bSYour Name }
4277*5113495bSYour Name 
drv_cmd_set_wes_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4278*5113495bSYour Name static int drv_cmd_set_wes_mode(struct wlan_hdd_link_info *link_info,
4279*5113495bSYour Name 				struct hdd_context *hdd_ctx,
4280*5113495bSYour Name 				uint8_t *command,
4281*5113495bSYour Name 				uint8_t command_len,
4282*5113495bSYour Name 				struct hdd_priv_data *priv_data)
4283*5113495bSYour Name {
4284*5113495bSYour Name 	int ret = 0;
4285*5113495bSYour Name 	uint8_t *value = command;
4286*5113495bSYour Name 	uint8_t wes_mode = cfg_default(CFG_LFR_ENABLE_WES_MODE);
4287*5113495bSYour Name 
4288*5113495bSYour Name 	/* Move pointer to ahead of SETWESMODE<delimiter> */
4289*5113495bSYour Name 	value = value + command_len + 1;
4290*5113495bSYour Name 
4291*5113495bSYour Name 	/* Convert the value from ascii to integer */
4292*5113495bSYour Name 	ret = kstrtou8(value, 10, &wes_mode);
4293*5113495bSYour Name 	if (ret < 0) {
4294*5113495bSYour Name 		/*
4295*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4296*5113495bSYour Name 		 * then also kstrtou8 fails
4297*5113495bSYour Name 		 */
4298*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
4299*5113495bSYour Name 			cfg_min(CFG_LFR_ENABLE_WES_MODE),
4300*5113495bSYour Name 			cfg_max(CFG_LFR_ENABLE_WES_MODE));
4301*5113495bSYour Name 		ret = -EINVAL;
4302*5113495bSYour Name 		goto exit;
4303*5113495bSYour Name 	}
4304*5113495bSYour Name 
4305*5113495bSYour Name 	hdd_debug("Received Command to Set WES Mode rssi diff = %d", wes_mode);
4306*5113495bSYour Name 
4307*5113495bSYour Name 	sme_update_wes_mode(hdd_ctx->mac_handle, wes_mode, link_info->vdev_id);
4308*5113495bSYour Name 
4309*5113495bSYour Name exit:
4310*5113495bSYour Name 	return ret;
4311*5113495bSYour Name }
4312*5113495bSYour Name 
drv_cmd_get_wes_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4313*5113495bSYour Name static int drv_cmd_get_wes_mode(struct wlan_hdd_link_info *link_info,
4314*5113495bSYour Name 				struct hdd_context *hdd_ctx,
4315*5113495bSYour Name 				uint8_t *command,
4316*5113495bSYour Name 				uint8_t command_len,
4317*5113495bSYour Name 				struct hdd_priv_data *priv_data)
4318*5113495bSYour Name {
4319*5113495bSYour Name 	int ret = 0;
4320*5113495bSYour Name 	bool wes_mode = ucfg_cm_get_wes_mode(hdd_ctx->psoc);
4321*5113495bSYour Name 	char extra[32];
4322*5113495bSYour Name 	uint8_t len = 0;
4323*5113495bSYour Name 
4324*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, wes_mode);
4325*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
4326*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
4327*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
4328*5113495bSYour Name 		ret = -EFAULT;
4329*5113495bSYour Name 	}
4330*5113495bSYour Name 
4331*5113495bSYour Name 	return ret;
4332*5113495bSYour Name }
4333*5113495bSYour Name 
4334*5113495bSYour Name static int
drv_cmd_set_opportunistic_rssi_diff(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4335*5113495bSYour Name drv_cmd_set_opportunistic_rssi_diff(struct wlan_hdd_link_info *link_info,
4336*5113495bSYour Name 				    struct hdd_context *hdd_ctx,
4337*5113495bSYour Name 				    uint8_t *command, uint8_t command_len,
4338*5113495bSYour Name 				    struct hdd_priv_data *priv_data)
4339*5113495bSYour Name {
4340*5113495bSYour Name 	int ret = 0;
4341*5113495bSYour Name 	uint8_t *value = command;
4342*5113495bSYour Name 	uint8_t diff =
4343*5113495bSYour Name 		cfg_default(CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF);
4344*5113495bSYour Name 
4345*5113495bSYour Name 	/* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4346*5113495bSYour Name 	value = value + command_len + 1;
4347*5113495bSYour Name 
4348*5113495bSYour Name 	/* Convert the value from ascii to integer */
4349*5113495bSYour Name 	ret = kstrtou8(value, 10, &diff);
4350*5113495bSYour Name 	if (ret < 0) {
4351*5113495bSYour Name 		/*
4352*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4353*5113495bSYour Name 		 * then also kstrtou8 fails
4354*5113495bSYour Name 		 */
4355*5113495bSYour Name 		hdd_err("kstrtou8 failed");
4356*5113495bSYour Name 		ret = -EINVAL;
4357*5113495bSYour Name 		goto exit;
4358*5113495bSYour Name 	}
4359*5113495bSYour Name 
4360*5113495bSYour Name 	hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
4361*5113495bSYour Name 		  diff);
4362*5113495bSYour Name 
4363*5113495bSYour Name 	sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle,
4364*5113495bSYour Name 						       link_info->vdev_id,
4365*5113495bSYour Name 						       diff);
4366*5113495bSYour Name 
4367*5113495bSYour Name exit:
4368*5113495bSYour Name 	return ret;
4369*5113495bSYour Name }
4370*5113495bSYour Name 
4371*5113495bSYour Name static int
drv_cmd_get_opportunistic_rssi_diff(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4372*5113495bSYour Name drv_cmd_get_opportunistic_rssi_diff(struct wlan_hdd_link_info *link_info,
4373*5113495bSYour Name 				    struct hdd_context *hdd_ctx,
4374*5113495bSYour Name 				    uint8_t *command, uint8_t command_len,
4375*5113495bSYour Name 				    struct hdd_priv_data *priv_data)
4376*5113495bSYour Name {
4377*5113495bSYour Name 	int ret = 0;
4378*5113495bSYour Name 	int8_t val = 0;
4379*5113495bSYour Name 	char extra[32];
4380*5113495bSYour Name 	uint8_t len = 0;
4381*5113495bSYour Name 
4382*5113495bSYour Name 	ucfg_cm_get_roam_opportunistic_scan_threshold_diff(hdd_ctx->psoc, &val);
4383*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
4384*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
4385*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
4386*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
4387*5113495bSYour Name 		ret = -EFAULT;
4388*5113495bSYour Name 	}
4389*5113495bSYour Name 
4390*5113495bSYour Name 	return ret;
4391*5113495bSYour Name }
4392*5113495bSYour Name 
4393*5113495bSYour Name static int
drv_cmd_set_roam_rescan_rssi_diff(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4394*5113495bSYour Name drv_cmd_set_roam_rescan_rssi_diff(struct wlan_hdd_link_info *link_info,
4395*5113495bSYour Name 				  struct hdd_context *hdd_ctx,
4396*5113495bSYour Name 				  uint8_t *command, uint8_t command_len,
4397*5113495bSYour Name 				  struct hdd_priv_data *priv_data)
4398*5113495bSYour Name {
4399*5113495bSYour Name 	int ret = 0;
4400*5113495bSYour Name 	uint8_t *value = command;
4401*5113495bSYour Name 	uint8_t rescan_rssi_diff = cfg_default(CFG_LFR_ROAM_RESCAN_RSSI_DIFF);
4402*5113495bSYour Name 
4403*5113495bSYour Name 	/* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4404*5113495bSYour Name 	value = value + command_len + 1;
4405*5113495bSYour Name 
4406*5113495bSYour Name 	/* Convert the value from ascii to integer */
4407*5113495bSYour Name 	ret = kstrtou8(value, 10, &rescan_rssi_diff);
4408*5113495bSYour Name 	if (ret < 0) {
4409*5113495bSYour Name 		/*
4410*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4411*5113495bSYour Name 		 * then also kstrtou8 fails
4412*5113495bSYour Name 		 */
4413*5113495bSYour Name 		hdd_err("kstrtou8 failed");
4414*5113495bSYour Name 		ret = -EINVAL;
4415*5113495bSYour Name 		goto exit;
4416*5113495bSYour Name 	}
4417*5113495bSYour Name 
4418*5113495bSYour Name 	hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
4419*5113495bSYour Name 		  rescan_rssi_diff);
4420*5113495bSYour Name 
4421*5113495bSYour Name 	sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle,
4422*5113495bSYour Name 				      link_info->vdev_id, rescan_rssi_diff);
4423*5113495bSYour Name 
4424*5113495bSYour Name exit:
4425*5113495bSYour Name 	return ret;
4426*5113495bSYour Name }
4427*5113495bSYour Name 
4428*5113495bSYour Name static int
drv_cmd_get_roam_rescan_rssi_diff(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4429*5113495bSYour Name drv_cmd_get_roam_rescan_rssi_diff(struct wlan_hdd_link_info *link_info,
4430*5113495bSYour Name 				  struct hdd_context *hdd_ctx,
4431*5113495bSYour Name 				  uint8_t *command, uint8_t command_len,
4432*5113495bSYour Name 				  struct hdd_priv_data *priv_data)
4433*5113495bSYour Name {
4434*5113495bSYour Name 	int ret = 0;
4435*5113495bSYour Name 	uint8_t val = 0;
4436*5113495bSYour Name 	char extra[32];
4437*5113495bSYour Name 	uint8_t len = 0;
4438*5113495bSYour Name 
4439*5113495bSYour Name 	ucfg_cm_get_roam_rescan_rssi_diff(hdd_ctx->psoc, &val);
4440*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
4441*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
4442*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
4443*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
4444*5113495bSYour Name 		ret = -EFAULT;
4445*5113495bSYour Name 	}
4446*5113495bSYour Name 
4447*5113495bSYour Name 	return ret;
4448*5113495bSYour Name }
4449*5113495bSYour Name 
drv_cmd_set_fast_roam(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4450*5113495bSYour Name static int drv_cmd_set_fast_roam(struct wlan_hdd_link_info *link_info,
4451*5113495bSYour Name 				 struct hdd_context *hdd_ctx,
4452*5113495bSYour Name 				 uint8_t *command,
4453*5113495bSYour Name 				 uint8_t command_len,
4454*5113495bSYour Name 				 struct hdd_priv_data *priv_data)
4455*5113495bSYour Name {
4456*5113495bSYour Name 	int ret = 0;
4457*5113495bSYour Name 	uint8_t *value = command;
4458*5113495bSYour Name 	uint8_t lfr_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
4459*5113495bSYour Name 
4460*5113495bSYour Name 	/* Move pointer to ahead of SETFASTROAM<delimiter> */
4461*5113495bSYour Name 	value = value + command_len + 1;
4462*5113495bSYour Name 
4463*5113495bSYour Name 	/* Convert the value from ascii to integer */
4464*5113495bSYour Name 	ret = kstrtou8(value, 10, &lfr_mode);
4465*5113495bSYour Name 	if (ret < 0) {
4466*5113495bSYour Name 		/*
4467*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4468*5113495bSYour Name 		 * then also kstrtou8 fails
4469*5113495bSYour Name 		 */
4470*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
4471*5113495bSYour Name 			cfg_min(CFG_LFR_FEATURE_ENABLED),
4472*5113495bSYour Name 			cfg_max(CFG_LFR_FEATURE_ENABLED));
4473*5113495bSYour Name 		ret = -EINVAL;
4474*5113495bSYour Name 		goto exit;
4475*5113495bSYour Name 	}
4476*5113495bSYour Name 
4477*5113495bSYour Name 	hdd_debug("Received Command to change lfr mode = %d",
4478*5113495bSYour Name 		  lfr_mode);
4479*5113495bSYour Name 
4480*5113495bSYour Name 	if (sme_roaming_in_progress(hdd_ctx->mac_handle,
4481*5113495bSYour Name 				    link_info->vdev_id)) {
4482*5113495bSYour Name 		hdd_err_rl("Roaming in progress for vdev %d",
4483*5113495bSYour Name 			   link_info->vdev_id);
4484*5113495bSYour Name 		return -EAGAIN;
4485*5113495bSYour Name 	}
4486*5113495bSYour Name 
4487*5113495bSYour Name 	ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)lfr_mode);
4488*5113495bSYour Name 	sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle,
4489*5113495bSYour Name 						    link_info->vdev_id,
4490*5113495bSYour Name 						    lfr_mode);
4491*5113495bSYour Name 
4492*5113495bSYour Name exit:
4493*5113495bSYour Name 	return ret;
4494*5113495bSYour Name }
4495*5113495bSYour Name 
drv_cmd_set_fast_transition(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4496*5113495bSYour Name static int drv_cmd_set_fast_transition(struct wlan_hdd_link_info *link_info,
4497*5113495bSYour Name 				       struct hdd_context *hdd_ctx,
4498*5113495bSYour Name 				       uint8_t *command,
4499*5113495bSYour Name 				       uint8_t command_len,
4500*5113495bSYour Name 				       struct hdd_priv_data *priv_data)
4501*5113495bSYour Name {
4502*5113495bSYour Name 	int ret = 0;
4503*5113495bSYour Name 	uint8_t *value = command;
4504*5113495bSYour Name 	uint8_t ft = cfg_default(CFG_LFR_FAST_TRANSITION_ENABLED);
4505*5113495bSYour Name 
4506*5113495bSYour Name 	/* Move pointer to ahead of SETFASTROAM<delimiter> */
4507*5113495bSYour Name 	value = value + command_len + 1;
4508*5113495bSYour Name 
4509*5113495bSYour Name 	/* Convert the value from ascii to integer */
4510*5113495bSYour Name 	ret = kstrtou8(value, 10, &ft);
4511*5113495bSYour Name 	if (ret < 0) {
4512*5113495bSYour Name 		/*
4513*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4514*5113495bSYour Name 		 * then also kstrtou8 fails
4515*5113495bSYour Name 		 */
4516*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
4517*5113495bSYour Name 			cfg_min(CFG_LFR_FAST_TRANSITION_ENABLED),
4518*5113495bSYour Name 			cfg_max(CFG_LFR_FAST_TRANSITION_ENABLED));
4519*5113495bSYour Name 		ret = -EINVAL;
4520*5113495bSYour Name 		goto exit;
4521*5113495bSYour Name 	}
4522*5113495bSYour Name 
4523*5113495bSYour Name 	hdd_debug("Received Command to change ft mode = %d", ft);
4524*5113495bSYour Name 
4525*5113495bSYour Name 	ucfg_mlme_set_fast_transition_enabled(hdd_ctx->psoc, (bool)ft);
4526*5113495bSYour Name 
4527*5113495bSYour Name exit:
4528*5113495bSYour Name 	return ret;
4529*5113495bSYour Name }
4530*5113495bSYour Name 
4531*5113495bSYour Name /**
4532*5113495bSYour Name  * drv_cmd_fast_reassoc() - Handler for FASTREASSOC driver command
4533*5113495bSYour Name  * @link_info: Carries link specific info, which contains adapter
4534*5113495bSYour Name  * @hdd_ctx: pointer to hdd context
4535*5113495bSYour Name  * @command: Buffer that carries actual command data, which can be parsed by
4536*5113495bSYour Name  *           hdd_parse_reassoc_command_v1_data()
4537*5113495bSYour Name  * @command_len: Command length
4538*5113495bSYour Name  * @priv_data: to carry any priv data, FASTREASSOC doesn't have any priv
4539*5113495bSYour Name  *             data for now.
4540*5113495bSYour Name  *
4541*5113495bSYour Name  * This function parses the reasoc command data passed in the format
4542*5113495bSYour Name  * FASTREASSOC<space><bssid><space><channel/frequency>
4543*5113495bSYour Name  *
4544*5113495bSYour Name  * If MAC from user space is broadcast MAC as:
4545*5113495bSYour Name  * "wpa_cli DRIVER FASTREASSOC ff:ff:ff:ff:ff:ff 0",
4546*5113495bSYour Name  * user space invoked roaming candidate selection will base on firmware score
4547*5113495bSYour Name  * algorithm, current connection will be kept if current AP has highest
4548*5113495bSYour Name  * score. It is requirement from customer which can avoid ping-pong roaming.
4549*5113495bSYour Name  *
4550*5113495bSYour Name  * If firmware fails to roam to new AP due to any reason, host to disconnect
4551*5113495bSYour Name  * from current AP as it's unable to roam.
4552*5113495bSYour Name  *
4553*5113495bSYour Name  * Return: 0 for success non-zero for failure
4554*5113495bSYour Name  */
drv_cmd_fast_reassoc(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4555*5113495bSYour Name static int drv_cmd_fast_reassoc(struct wlan_hdd_link_info *link_info,
4556*5113495bSYour Name 				struct hdd_context *hdd_ctx,
4557*5113495bSYour Name 				uint8_t *command,
4558*5113495bSYour Name 				uint8_t command_len,
4559*5113495bSYour Name 				struct hdd_priv_data *priv_data)
4560*5113495bSYour Name {
4561*5113495bSYour Name 	int ret = 0;
4562*5113495bSYour Name 	uint8_t *value = command;
4563*5113495bSYour Name 	qdf_freq_t freq = 0;
4564*5113495bSYour Name 	tSirMacAddr bssid;
4565*5113495bSYour Name 	struct qdf_mac_addr target_bssid;
4566*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
4567*5113495bSYour Name 
4568*5113495bSYour Name 	if (QDF_STA_MODE != adapter->device_mode) {
4569*5113495bSYour Name 		hdd_warn("Unsupported in mode %s(%d)",
4570*5113495bSYour Name 			 qdf_opmode_str(adapter->device_mode),
4571*5113495bSYour Name 			 adapter->device_mode);
4572*5113495bSYour Name 		return -EINVAL;
4573*5113495bSYour Name 	}
4574*5113495bSYour Name 
4575*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
4576*5113495bSYour Name 
4577*5113495bSYour Name 	/* if not associated, no need to proceed with reassoc */
4578*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(link_info)) {
4579*5113495bSYour Name 		hdd_warn("Not associated!");
4580*5113495bSYour Name 		ret = -EINVAL;
4581*5113495bSYour Name 		goto exit;
4582*5113495bSYour Name 	}
4583*5113495bSYour Name 
4584*5113495bSYour Name 	ret = hdd_parse_reassoc_command_v1_data(value, bssid,
4585*5113495bSYour Name 						&freq, hdd_ctx->pdev);
4586*5113495bSYour Name 	if (ret) {
4587*5113495bSYour Name 		hdd_err("Failed to parse reassoc command data");
4588*5113495bSYour Name 		goto exit;
4589*5113495bSYour Name 	}
4590*5113495bSYour Name 
4591*5113495bSYour Name 	qdf_mem_copy(target_bssid.bytes, bssid, sizeof(tSirMacAddr));
4592*5113495bSYour Name 	ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev, link_info->vdev_id,
4593*5113495bSYour Name 				 &target_bssid, freq, CM_ROAMING_HOST);
4594*5113495bSYour Name 
4595*5113495bSYour Name exit:
4596*5113495bSYour Name 	return ret;
4597*5113495bSYour Name }
4598*5113495bSYour Name 
drv_cmd_set_okc_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4599*5113495bSYour Name static int drv_cmd_set_okc_mode(struct wlan_hdd_link_info *link_info,
4600*5113495bSYour Name 				struct hdd_context *hdd_ctx,
4601*5113495bSYour Name 				uint8_t *command,
4602*5113495bSYour Name 				uint8_t command_len,
4603*5113495bSYour Name 				struct hdd_priv_data *priv_data)
4604*5113495bSYour Name {
4605*5113495bSYour Name 	int ret = 0;
4606*5113495bSYour Name 	uint8_t *value = command;
4607*5113495bSYour Name 	uint32_t okc_mode;
4608*5113495bSYour Name 	struct pmkid_mode_bits pmkid_modes;
4609*5113495bSYour Name 	uint32_t cur_pmkid_modes;
4610*5113495bSYour Name 	QDF_STATUS status;
4611*5113495bSYour Name 
4612*5113495bSYour Name 	hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
4613*5113495bSYour Name 
4614*5113495bSYour Name 	/*
4615*5113495bSYour Name 	 * Check if the features PMKID/ESE/11R are supported simultaneously,
4616*5113495bSYour Name 	 * then this operation is not permitted (return FAILURE)
4617*5113495bSYour Name 	 */
4618*5113495bSYour Name 	if (ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc) &&
4619*5113495bSYour Name 	    pmkid_modes.fw_okc &&
4620*5113495bSYour Name 	    ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) {
4621*5113495bSYour Name 		hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
4622*5113495bSYour Name 		ret = -EPERM;
4623*5113495bSYour Name 		goto exit;
4624*5113495bSYour Name 	}
4625*5113495bSYour Name 
4626*5113495bSYour Name 	/* Move pointer to ahead of SETOKCMODE<delimiter> */
4627*5113495bSYour Name 	value = value + command_len + 1;
4628*5113495bSYour Name 
4629*5113495bSYour Name 	/* get the current configured value */
4630*5113495bSYour Name 	status = ucfg_mlme_get_pmkid_modes(hdd_ctx->psoc, &cur_pmkid_modes);
4631*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS)
4632*5113495bSYour Name 		hdd_err("get pmkid modes failed");
4633*5113495bSYour Name 
4634*5113495bSYour Name 	okc_mode = cur_pmkid_modes & CFG_PMKID_MODES_OKC;
4635*5113495bSYour Name 
4636*5113495bSYour Name 	/* Convert the value from ascii to integer */
4637*5113495bSYour Name 	ret = kstrtou32(value, 10, &okc_mode);
4638*5113495bSYour Name 	if (ret < 0) {
4639*5113495bSYour Name 		/*
4640*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4641*5113495bSYour Name 		 * then also kstrtou8 fails
4642*5113495bSYour Name 		 */
4643*5113495bSYour Name 		hdd_err("value out of range [0 - 1]");
4644*5113495bSYour Name 		ret = -EINVAL;
4645*5113495bSYour Name 		goto exit;
4646*5113495bSYour Name 	}
4647*5113495bSYour Name 
4648*5113495bSYour Name 	if ((okc_mode < 0) ||
4649*5113495bSYour Name 	    (okc_mode > 1)) {
4650*5113495bSYour Name 		hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4651*5113495bSYour Name 			  okc_mode);
4652*5113495bSYour Name 		ret = -EINVAL;
4653*5113495bSYour Name 		goto exit;
4654*5113495bSYour Name 	}
4655*5113495bSYour Name 	hdd_debug("Received Command to change okc mode = %d", okc_mode);
4656*5113495bSYour Name 
4657*5113495bSYour Name 	if (okc_mode)
4658*5113495bSYour Name 		cur_pmkid_modes |= CFG_PMKID_MODES_OKC;
4659*5113495bSYour Name 	else
4660*5113495bSYour Name 		cur_pmkid_modes &= ~CFG_PMKID_MODES_OKC;
4661*5113495bSYour Name 	status = ucfg_mlme_set_pmkid_modes(hdd_ctx->psoc,
4662*5113495bSYour Name 					   cur_pmkid_modes);
4663*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
4664*5113495bSYour Name 		ret = -EPERM;
4665*5113495bSYour Name 		hdd_err("set pmkid modes failed");
4666*5113495bSYour Name 	}
4667*5113495bSYour Name exit:
4668*5113495bSYour Name 	return ret;
4669*5113495bSYour Name }
4670*5113495bSYour Name 
drv_cmd_bt_coex_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4671*5113495bSYour Name static int drv_cmd_bt_coex_mode(struct wlan_hdd_link_info *link_info,
4672*5113495bSYour Name 				struct hdd_context *hdd_ctx,
4673*5113495bSYour Name 				uint8_t *command,
4674*5113495bSYour Name 				uint8_t command_len,
4675*5113495bSYour Name 				struct hdd_priv_data *priv_data)
4676*5113495bSYour Name {
4677*5113495bSYour Name 	int ret = 0;
4678*5113495bSYour Name 	char *coex_mode;
4679*5113495bSYour Name 
4680*5113495bSYour Name 	coex_mode = command + 11;
4681*5113495bSYour Name 	if ('1' == *coex_mode) {
4682*5113495bSYour Name 		hdd_debug("BTCOEXMODE %d", *coex_mode);
4683*5113495bSYour Name 		hdd_ctx->bt_coex_mode_set = true;
4684*5113495bSYour Name 		ret = wlan_hdd_scan_abort(link_info);
4685*5113495bSYour Name 		if (ret < 0) {
4686*5113495bSYour Name 			hdd_err("Failed to abort existing scan status: %d",
4687*5113495bSYour Name 				ret);
4688*5113495bSYour Name 		}
4689*5113495bSYour Name 	} else if ('2' == *coex_mode) {
4690*5113495bSYour Name 		hdd_debug("BTCOEXMODE %d", *coex_mode);
4691*5113495bSYour Name 		hdd_ctx->bt_coex_mode_set = false;
4692*5113495bSYour Name 	}
4693*5113495bSYour Name 
4694*5113495bSYour Name 	return ret;
4695*5113495bSYour Name }
4696*5113495bSYour Name 
drv_cmd_scan_active(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4697*5113495bSYour Name static int drv_cmd_scan_active(struct wlan_hdd_link_info *link_info,
4698*5113495bSYour Name 			       struct hdd_context *hdd_ctx,
4699*5113495bSYour Name 			       uint8_t *command,
4700*5113495bSYour Name 			       uint8_t command_len,
4701*5113495bSYour Name 			       struct hdd_priv_data *priv_data)
4702*5113495bSYour Name {
4703*5113495bSYour Name 	hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4704*5113495bSYour Name 	return 0;
4705*5113495bSYour Name }
4706*5113495bSYour Name 
drv_cmd_scan_passive(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4707*5113495bSYour Name static int drv_cmd_scan_passive(struct wlan_hdd_link_info *link_info,
4708*5113495bSYour Name 				struct hdd_context *hdd_ctx,
4709*5113495bSYour Name 				uint8_t *command,
4710*5113495bSYour Name 				uint8_t command_len,
4711*5113495bSYour Name 				struct hdd_priv_data *priv_data)
4712*5113495bSYour Name {
4713*5113495bSYour Name 	hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4714*5113495bSYour Name 	return 0;
4715*5113495bSYour Name }
4716*5113495bSYour Name 
drv_cmd_get_dwell_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4717*5113495bSYour Name static int drv_cmd_get_dwell_time(struct wlan_hdd_link_info *link_info,
4718*5113495bSYour Name 				  struct hdd_context *hdd_ctx,
4719*5113495bSYour Name 				  uint8_t *command,
4720*5113495bSYour Name 				  uint8_t command_len,
4721*5113495bSYour Name 				  struct hdd_priv_data *priv_data)
4722*5113495bSYour Name {
4723*5113495bSYour Name 	int ret = 0;
4724*5113495bSYour Name 	char extra[32];
4725*5113495bSYour Name 	uint8_t len = 0;
4726*5113495bSYour Name 
4727*5113495bSYour Name 	memset(extra, 0, sizeof(extra));
4728*5113495bSYour Name 	ret = hdd_get_dwell_time(hdd_ctx->psoc, command, extra,
4729*5113495bSYour Name 				 sizeof(extra), &len);
4730*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
4731*5113495bSYour Name 	if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
4732*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
4733*5113495bSYour Name 		ret = -EFAULT;
4734*5113495bSYour Name 		goto exit;
4735*5113495bSYour Name 	}
4736*5113495bSYour Name 	ret = len;
4737*5113495bSYour Name exit:
4738*5113495bSYour Name 	return ret;
4739*5113495bSYour Name }
4740*5113495bSYour Name 
drv_cmd_set_dwell_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4741*5113495bSYour Name static int drv_cmd_set_dwell_time(struct wlan_hdd_link_info *link_info,
4742*5113495bSYour Name 				  struct hdd_context *hdd_ctx,
4743*5113495bSYour Name 				  uint8_t *command,
4744*5113495bSYour Name 				  uint8_t command_len,
4745*5113495bSYour Name 				  struct hdd_priv_data *priv_data)
4746*5113495bSYour Name {
4747*5113495bSYour Name 	return hdd_set_dwell_time(hdd_ctx->psoc, command);
4748*5113495bSYour Name }
4749*5113495bSYour Name 
drv_cmd_conc_set_dwell_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,u8 * command,u8 command_len,struct hdd_priv_data * priv_data)4750*5113495bSYour Name static int drv_cmd_conc_set_dwell_time(struct wlan_hdd_link_info *link_info,
4751*5113495bSYour Name 				       struct hdd_context *hdd_ctx,
4752*5113495bSYour Name 				       u8 *command,
4753*5113495bSYour Name 				       u8 command_len,
4754*5113495bSYour Name 				       struct hdd_priv_data *priv_data)
4755*5113495bSYour Name {
4756*5113495bSYour Name 	return hdd_conc_set_dwell_time(link_info->adapter, command);
4757*5113495bSYour Name }
4758*5113495bSYour Name 
drv_cmd_miracast(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4759*5113495bSYour Name static int drv_cmd_miracast(struct wlan_hdd_link_info *link_info,
4760*5113495bSYour Name 			    struct hdd_context *hdd_ctx,
4761*5113495bSYour Name 			    uint8_t *command,
4762*5113495bSYour Name 			    uint8_t command_len,
4763*5113495bSYour Name 			    struct hdd_priv_data *priv_data)
4764*5113495bSYour Name {
4765*5113495bSYour Name 	QDF_STATUS ret_status;
4766*5113495bSYour Name 	int ret = 0;
4767*5113495bSYour Name 	uint8_t filter_type = 0;
4768*5113495bSYour Name 	uint8_t *value;
4769*5113495bSYour Name 
4770*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx))
4771*5113495bSYour Name 		return -EINVAL;
4772*5113495bSYour Name 
4773*5113495bSYour Name 	value = command + 9;
4774*5113495bSYour Name 
4775*5113495bSYour Name 	/* Convert the value from ascii to integer */
4776*5113495bSYour Name 	ret = kstrtou8(value, 10, &filter_type);
4777*5113495bSYour Name 	if (ret < 0) {
4778*5113495bSYour Name 		/*
4779*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4780*5113495bSYour Name 		 * then also kstrtou8 fails
4781*5113495bSYour Name 		 */
4782*5113495bSYour Name 		hdd_err("kstrtou8 failed range");
4783*5113495bSYour Name 		ret = -EINVAL;
4784*5113495bSYour Name 		goto exit;
4785*5113495bSYour Name 	}
4786*5113495bSYour Name 	hdd_debug("filter_type %d", filter_type);
4787*5113495bSYour Name 
4788*5113495bSYour Name 	switch (filter_type) {
4789*5113495bSYour Name 	case MIRACAST_DISABLED:
4790*5113495bSYour Name 	case MIRACAST_SOURCE:
4791*5113495bSYour Name 	case MIRACAST_SINK:
4792*5113495bSYour Name 		break;
4793*5113495bSYour Name 	case MIRACAST_CONN_OPT_ENABLED:
4794*5113495bSYour Name 	case MIRACAST_CONN_OPT_DISABLED:
4795*5113495bSYour Name 		{
4796*5113495bSYour Name 			wma_cli_set_command(
4797*5113495bSYour Name 				link_info->vdev_id,
4798*5113495bSYour Name 				wmi_pdev_param_power_collapse_enable,
4799*5113495bSYour Name 				(filter_type == MIRACAST_CONN_OPT_ENABLED ?
4800*5113495bSYour Name 				 0 : 1), PDEV_CMD);
4801*5113495bSYour Name 			return 0;
4802*5113495bSYour Name 		}
4803*5113495bSYour Name 	default:
4804*5113495bSYour Name 		hdd_err("accepted Values: 0-Disabled, 1-Source, 2-Sink, 128,129");
4805*5113495bSYour Name 		ret = -EINVAL;
4806*5113495bSYour Name 		goto exit;
4807*5113495bSYour Name 	}
4808*5113495bSYour Name 
4809*5113495bSYour Name 	/* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4810*5113495bSYour Name 	hdd_ctx->miracast_value = filter_type;
4811*5113495bSYour Name 	ucfg_mlme_set_vdev_traffic_low_latency(hdd_ctx->psoc,
4812*5113495bSYour Name 					       link_info->vdev_id,
4813*5113495bSYour Name 					       filter_type !=
4814*5113495bSYour Name 					       MIRACAST_DISABLED);
4815*5113495bSYour Name 
4816*5113495bSYour Name 	ret_status = sme_set_miracast(hdd_ctx->mac_handle, filter_type);
4817*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != ret_status) {
4818*5113495bSYour Name 		hdd_err("Failed to set miracast");
4819*5113495bSYour Name 		return -EBUSY;
4820*5113495bSYour Name 	}
4821*5113495bSYour Name 	ret_status = ucfg_scan_set_miracast(hdd_ctx->psoc,
4822*5113495bSYour Name 					    filter_type ? true : false);
4823*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(ret_status)) {
4824*5113495bSYour Name 		hdd_err("Failed to set miracastn scan");
4825*5113495bSYour Name 		return -EBUSY;
4826*5113495bSYour Name 	}
4827*5113495bSYour Name 
4828*5113495bSYour Name 	if (policy_mgr_is_mcc_in_24G(hdd_ctx->psoc))
4829*5113495bSYour Name 		return wlan_hdd_set_mas(link_info->adapter, filter_type);
4830*5113495bSYour Name 
4831*5113495bSYour Name exit:
4832*5113495bSYour Name 	return ret;
4833*5113495bSYour Name }
4834*5113495bSYour Name 
drv_cmd_tput_debug_mode_enable(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,u8 * command,u8 command_len,struct hdd_priv_data * priv_data)4835*5113495bSYour Name static int drv_cmd_tput_debug_mode_enable(struct wlan_hdd_link_info *link_info,
4836*5113495bSYour Name 					  struct hdd_context *hdd_ctx,
4837*5113495bSYour Name 					  u8 *command,
4838*5113495bSYour Name 					  u8 command_len,
4839*5113495bSYour Name 					  struct hdd_priv_data *priv_data)
4840*5113495bSYour Name {
4841*5113495bSYour Name 	return hdd_enable_unit_test_commands(link_info->adapter, hdd_ctx);
4842*5113495bSYour Name }
4843*5113495bSYour Name 
drv_cmd_tput_debug_mode_disable(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,u8 * command,u8 command_len,struct hdd_priv_data * priv_data)4844*5113495bSYour Name static int drv_cmd_tput_debug_mode_disable(struct wlan_hdd_link_info *link_info,
4845*5113495bSYour Name 					   struct hdd_context *hdd_ctx,
4846*5113495bSYour Name 					   u8 *command,
4847*5113495bSYour Name 					   u8 command_len,
4848*5113495bSYour Name 					   struct hdd_priv_data *priv_data)
4849*5113495bSYour Name {
4850*5113495bSYour Name 	return hdd_disable_unit_test_commands(link_info->adapter, hdd_ctx);
4851*5113495bSYour Name }
4852*5113495bSYour Name 
4853*5113495bSYour Name #ifdef FEATURE_WLAN_ESE
4854*5113495bSYour Name static int
drv_cmd_set_ccx_roam_scan_channels(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4855*5113495bSYour Name drv_cmd_set_ccx_roam_scan_channels(struct wlan_hdd_link_info *link_info,
4856*5113495bSYour Name 				   struct hdd_context *hdd_ctx,
4857*5113495bSYour Name 				   uint8_t *command, uint8_t command_len,
4858*5113495bSYour Name 				   struct hdd_priv_data *priv_data)
4859*5113495bSYour Name {
4860*5113495bSYour Name 	int ret = 0;
4861*5113495bSYour Name 	uint8_t *value = command;
4862*5113495bSYour Name 	uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
4863*5113495bSYour Name 	uint8_t num_channels = 0;
4864*5113495bSYour Name 	QDF_STATUS status;
4865*5113495bSYour Name 	mac_handle_t mac_handle;
4866*5113495bSYour Name 
4867*5113495bSYour Name 	if (!hdd_ctx) {
4868*5113495bSYour Name 		hdd_err("invalid hdd ctx");
4869*5113495bSYour Name 		ret = -EINVAL;
4870*5113495bSYour Name 		goto exit;
4871*5113495bSYour Name 	}
4872*5113495bSYour Name 
4873*5113495bSYour Name 	ret = hdd_parse_channellist(hdd_ctx, value, channel_freq_list,
4874*5113495bSYour Name 				    &num_channels);
4875*5113495bSYour Name 	if (ret) {
4876*5113495bSYour Name 		hdd_err("Failed to parse channel list information");
4877*5113495bSYour Name 		goto exit;
4878*5113495bSYour Name 	}
4879*5113495bSYour Name 	if (num_channels > CFG_VALID_CHANNEL_LIST_LEN) {
4880*5113495bSYour Name 		hdd_err("number of channels (%d) supported exceeded max (%d)",
4881*5113495bSYour Name 			num_channels, CFG_VALID_CHANNEL_LIST_LEN);
4882*5113495bSYour Name 		ret = -EINVAL;
4883*5113495bSYour Name 		goto exit;
4884*5113495bSYour Name 	}
4885*5113495bSYour Name 
4886*5113495bSYour Name 	mac_handle = hdd_ctx->mac_handle;
4887*5113495bSYour Name 	if (!sme_validate_channel_list(mac_handle, channel_freq_list,
4888*5113495bSYour Name 				       num_channels)) {
4889*5113495bSYour Name 		hdd_err("List contains invalid channel(s)");
4890*5113495bSYour Name 		ret = -EINVAL;
4891*5113495bSYour Name 		goto exit;
4892*5113495bSYour Name 	}
4893*5113495bSYour Name 
4894*5113495bSYour Name 	status = ucfg_cm_set_ese_roam_scan_channel_list(hdd_ctx->pdev,
4895*5113495bSYour Name 							link_info->vdev_id,
4896*5113495bSYour Name 							channel_freq_list,
4897*5113495bSYour Name 							num_channels);
4898*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
4899*5113495bSYour Name 		hdd_err("Failed to update channel list information");
4900*5113495bSYour Name 		ret = -EINVAL;
4901*5113495bSYour Name 		goto exit;
4902*5113495bSYour Name 	}
4903*5113495bSYour Name 
4904*5113495bSYour Name exit:
4905*5113495bSYour Name 	return ret;
4906*5113495bSYour Name }
4907*5113495bSYour Name 
drv_cmd_get_tsm_stats(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4908*5113495bSYour Name static int drv_cmd_get_tsm_stats(struct wlan_hdd_link_info *link_info,
4909*5113495bSYour Name 				 struct hdd_context *hdd_ctx,
4910*5113495bSYour Name 				 uint8_t *command,
4911*5113495bSYour Name 				 uint8_t command_len,
4912*5113495bSYour Name 				 struct hdd_priv_data *priv_data)
4913*5113495bSYour Name {
4914*5113495bSYour Name 	int ret = 0;
4915*5113495bSYour Name 	uint8_t *value = command;
4916*5113495bSYour Name 	char extra[128] = { 0 };
4917*5113495bSYour Name 	int len = 0;
4918*5113495bSYour Name 	uint8_t tid = 0;
4919*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
4920*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
4921*5113495bSYour Name 	tAniTrafStrmMetrics tsm_metrics = {0};
4922*5113495bSYour Name 
4923*5113495bSYour Name 	if ((QDF_STA_MODE != adapter->device_mode) &&
4924*5113495bSYour Name 	    (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
4925*5113495bSYour Name 		hdd_warn("Unsupported in mode %s(%d)",
4926*5113495bSYour Name 			 qdf_opmode_str(adapter->device_mode),
4927*5113495bSYour Name 			 adapter->device_mode);
4928*5113495bSYour Name 		return -EINVAL;
4929*5113495bSYour Name 	}
4930*5113495bSYour Name 
4931*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
4932*5113495bSYour Name 
4933*5113495bSYour Name 	/* if not associated, return error */
4934*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(link_info)) {
4935*5113495bSYour Name 		hdd_err("Not associated!");
4936*5113495bSYour Name 		ret = -EINVAL;
4937*5113495bSYour Name 		goto exit;
4938*5113495bSYour Name 	}
4939*5113495bSYour Name 
4940*5113495bSYour Name 	/* Move pointer to ahead of GETTSMSTATS<delimiter> */
4941*5113495bSYour Name 	value = value + command_len + 1;
4942*5113495bSYour Name 
4943*5113495bSYour Name 	/* Convert the value from ascii to integer */
4944*5113495bSYour Name 	ret = kstrtou8(value, 10, &tid);
4945*5113495bSYour Name 	if (ret < 0) {
4946*5113495bSYour Name 		/*
4947*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
4948*5113495bSYour Name 		 * then also kstrtou8 fails
4949*5113495bSYour Name 		 */
4950*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
4951*5113495bSYour Name 			  TID_MIN_VALUE,
4952*5113495bSYour Name 			  TID_MAX_VALUE);
4953*5113495bSYour Name 		ret = -EINVAL;
4954*5113495bSYour Name 		goto exit;
4955*5113495bSYour Name 	}
4956*5113495bSYour Name 	if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
4957*5113495bSYour Name 		hdd_err("tid value %d is out of range (Min: %d Max: %d)",
4958*5113495bSYour Name 			  tid, TID_MIN_VALUE, TID_MAX_VALUE);
4959*5113495bSYour Name 		ret = -EINVAL;
4960*5113495bSYour Name 		goto exit;
4961*5113495bSYour Name 	}
4962*5113495bSYour Name 	hdd_debug("Received Command to get tsm stats tid = %d",
4963*5113495bSYour Name 		 tid);
4964*5113495bSYour Name 	ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
4965*5113495bSYour Name 	if (ret) {
4966*5113495bSYour Name 		hdd_err("failed to get tsm stats");
4967*5113495bSYour Name 		goto exit;
4968*5113495bSYour Name 	}
4969*5113495bSYour Name 	hdd_debug(
4970*5113495bSYour Name 		"UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)",
4971*5113495bSYour Name 		  tsm_metrics.UplinkPktQueueDly,
4972*5113495bSYour Name 		  tsm_metrics.UplinkPktQueueDlyHist[0],
4973*5113495bSYour Name 		  tsm_metrics.UplinkPktQueueDlyHist[1],
4974*5113495bSYour Name 		  tsm_metrics.UplinkPktQueueDlyHist[2],
4975*5113495bSYour Name 		  tsm_metrics.UplinkPktQueueDlyHist[3],
4976*5113495bSYour Name 		  tsm_metrics.UplinkPktTxDly,
4977*5113495bSYour Name 		  tsm_metrics.UplinkPktLoss,
4978*5113495bSYour Name 		  tsm_metrics.UplinkPktCount,
4979*5113495bSYour Name 		  tsm_metrics.RoamingCount,
4980*5113495bSYour Name 		  tsm_metrics.RoamingDly);
4981*5113495bSYour Name 	/*
4982*5113495bSYour Name 	 * Output TSM stats is of the format
4983*5113495bSYour Name 	 * GETTSMSTATS [PktQueueDly]
4984*5113495bSYour Name 	 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
4985*5113495bSYour Name 	 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
4986*5113495bSYour Name 	 */
4987*5113495bSYour Name 	len = scnprintf(extra,
4988*5113495bSYour Name 			sizeof(extra),
4989*5113495bSYour Name 			"%s %d %d:%d:%d:%d %u %d %d %d %d",
4990*5113495bSYour Name 			command,
4991*5113495bSYour Name 			tsm_metrics.UplinkPktQueueDly,
4992*5113495bSYour Name 			tsm_metrics.UplinkPktQueueDlyHist[0],
4993*5113495bSYour Name 			tsm_metrics.UplinkPktQueueDlyHist[1],
4994*5113495bSYour Name 			tsm_metrics.UplinkPktQueueDlyHist[2],
4995*5113495bSYour Name 			tsm_metrics.UplinkPktQueueDlyHist[3],
4996*5113495bSYour Name 			tsm_metrics.UplinkPktTxDly,
4997*5113495bSYour Name 			tsm_metrics.UplinkPktLoss,
4998*5113495bSYour Name 			tsm_metrics.UplinkPktCount,
4999*5113495bSYour Name 			tsm_metrics.RoamingCount,
5000*5113495bSYour Name 			tsm_metrics.RoamingDly);
5001*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
5002*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
5003*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
5004*5113495bSYour Name 		ret = -EFAULT;
5005*5113495bSYour Name 		goto exit;
5006*5113495bSYour Name 	}
5007*5113495bSYour Name 
5008*5113495bSYour Name exit:
5009*5113495bSYour Name 	return ret;
5010*5113495bSYour Name }
5011*5113495bSYour Name 
drv_cmd_set_cckm_ie(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5012*5113495bSYour Name static int drv_cmd_set_cckm_ie(struct wlan_hdd_link_info *link_info,
5013*5113495bSYour Name 			       struct hdd_context *hdd_ctx,
5014*5113495bSYour Name 			       uint8_t *command,
5015*5113495bSYour Name 			       uint8_t command_len,
5016*5113495bSYour Name 			       struct hdd_priv_data *priv_data)
5017*5113495bSYour Name {
5018*5113495bSYour Name 	int ret;
5019*5113495bSYour Name 	uint8_t *value = command;
5020*5113495bSYour Name 	uint8_t *cckm_ie = NULL;
5021*5113495bSYour Name 	uint8_t cckm_ie_len = 0;
5022*5113495bSYour Name 
5023*5113495bSYour Name 	ret = hdd_parse_get_cckm_ie(value, &cckm_ie, &cckm_ie_len);
5024*5113495bSYour Name 	if (ret) {
5025*5113495bSYour Name 		hdd_err("Failed to parse cckm ie data");
5026*5113495bSYour Name 		goto exit;
5027*5113495bSYour Name 	}
5028*5113495bSYour Name 
5029*5113495bSYour Name 	if (cckm_ie_len > DOT11F_IE_RSN_MAX_LEN) {
5030*5113495bSYour Name 		hdd_err("CCKM Ie input length is more than max[%d]",
5031*5113495bSYour Name 			  DOT11F_IE_RSN_MAX_LEN);
5032*5113495bSYour Name 		if (cckm_ie) {
5033*5113495bSYour Name 			qdf_mem_free(cckm_ie);
5034*5113495bSYour Name 			cckm_ie = NULL;
5035*5113495bSYour Name 		}
5036*5113495bSYour Name 		ret = -EINVAL;
5037*5113495bSYour Name 		goto exit;
5038*5113495bSYour Name 	}
5039*5113495bSYour Name 
5040*5113495bSYour Name 	ucfg_cm_set_cckm_ie(hdd_ctx->psoc, link_info->vdev_id, cckm_ie,
5041*5113495bSYour Name 			    cckm_ie_len);
5042*5113495bSYour Name 	if (cckm_ie) {
5043*5113495bSYour Name 		qdf_mem_free(cckm_ie);
5044*5113495bSYour Name 		cckm_ie = NULL;
5045*5113495bSYour Name 	}
5046*5113495bSYour Name 
5047*5113495bSYour Name exit:
5048*5113495bSYour Name 	return ret;
5049*5113495bSYour Name }
5050*5113495bSYour Name 
drv_cmd_ccx_beacon_req(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5051*5113495bSYour Name static int drv_cmd_ccx_beacon_req(struct wlan_hdd_link_info *link_info,
5052*5113495bSYour Name 				  struct hdd_context *hdd_ctx,
5053*5113495bSYour Name 				  uint8_t *command,
5054*5113495bSYour Name 				  uint8_t command_len,
5055*5113495bSYour Name 				  struct hdd_priv_data *priv_data)
5056*5113495bSYour Name {
5057*5113495bSYour Name 	int ret;
5058*5113495bSYour Name 	uint8_t *value = command;
5059*5113495bSYour Name 	tCsrEseBeaconReq req = {0};
5060*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
5061*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
5062*5113495bSYour Name 
5063*5113495bSYour Name 	if (QDF_STA_MODE != adapter->device_mode) {
5064*5113495bSYour Name 		hdd_warn("Unsupported in mode %s(%d)",
5065*5113495bSYour Name 			 qdf_opmode_str(adapter->device_mode),
5066*5113495bSYour Name 			 adapter->device_mode);
5067*5113495bSYour Name 		return -EINVAL;
5068*5113495bSYour Name 	}
5069*5113495bSYour Name 
5070*5113495bSYour Name 	ret = hdd_parse_ese_beacon_req(hdd_ctx->pdev, value, &req);
5071*5113495bSYour Name 	if (ret) {
5072*5113495bSYour Name 		hdd_err("Failed to parse ese beacon req");
5073*5113495bSYour Name 		goto exit;
5074*5113495bSYour Name 	}
5075*5113495bSYour Name 
5076*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(link_info)) {
5077*5113495bSYour Name 		hdd_debug("Not associated");
5078*5113495bSYour Name 
5079*5113495bSYour Name 		if (!req.numBcnReqIe)
5080*5113495bSYour Name 			return -EINVAL;
5081*5113495bSYour Name 
5082*5113495bSYour Name 		hdd_indicate_ese_bcn_report_no_results(adapter,
5083*5113495bSYour Name 			req.bcnReq[0].measurementToken,
5084*5113495bSYour Name 			0x02, /* BIT(1) set for measurement done */
5085*5113495bSYour Name 			0);   /* no BSS */
5086*5113495bSYour Name 		goto exit;
5087*5113495bSYour Name 	}
5088*5113495bSYour Name 
5089*5113495bSYour Name 	status = sme_set_ese_beacon_request(hdd_ctx->mac_handle,
5090*5113495bSYour Name 					    link_info->vdev_id,
5091*5113495bSYour Name 					    &req);
5092*5113495bSYour Name 
5093*5113495bSYour Name 	if (QDF_STATUS_E_RESOURCES == status) {
5094*5113495bSYour Name 		hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
5095*5113495bSYour Name 			  status);
5096*5113495bSYour Name 		ret = -EBUSY;
5097*5113495bSYour Name 		goto exit;
5098*5113495bSYour Name 	} else if (QDF_STATUS_SUCCESS != status) {
5099*5113495bSYour Name 		hdd_err("sme_set_ese_beacon_request failed (%d)",
5100*5113495bSYour Name 			status);
5101*5113495bSYour Name 		ret = -EINVAL;
5102*5113495bSYour Name 		goto exit;
5103*5113495bSYour Name 	}
5104*5113495bSYour Name 
5105*5113495bSYour Name exit:
5106*5113495bSYour Name 	return ret;
5107*5113495bSYour Name }
5108*5113495bSYour Name 
5109*5113495bSYour Name /**
5110*5113495bSYour Name  * drv_cmd_ccx_plm_req() - Set ESE PLM request
5111*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
5112*5113495bSYour Name  * @hdd_ctx: Pointer to the HDD context
5113*5113495bSYour Name  * @command: Driver command string
5114*5113495bSYour Name  * @command_len: Driver command string length
5115*5113495bSYour Name  * @priv_data: Private data coming with the driver command. Unused here
5116*5113495bSYour Name  *
5117*5113495bSYour Name  * This function handles driver command that sets the ESE PLM request
5118*5113495bSYour Name  *
5119*5113495bSYour Name  * Return: 0 on success; negative errno otherwise
5120*5113495bSYour Name  */
drv_cmd_ccx_plm_req(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5121*5113495bSYour Name static int drv_cmd_ccx_plm_req(struct wlan_hdd_link_info *link_info,
5122*5113495bSYour Name 			       struct hdd_context *hdd_ctx,
5123*5113495bSYour Name 			       uint8_t *command,
5124*5113495bSYour Name 			       uint8_t command_len,
5125*5113495bSYour Name 			       struct hdd_priv_data *priv_data)
5126*5113495bSYour Name {
5127*5113495bSYour Name 	QDF_STATUS status;
5128*5113495bSYour Name 	struct plm_req_params *req;
5129*5113495bSYour Name 
5130*5113495bSYour Name 	req = qdf_mem_malloc(sizeof(*req));
5131*5113495bSYour Name 	if (!req)
5132*5113495bSYour Name 		return -ENOMEM;
5133*5113495bSYour Name 
5134*5113495bSYour Name 	status = hdd_parse_plm_cmd(command, req);
5135*5113495bSYour Name 	if (QDF_IS_STATUS_SUCCESS(status)) {
5136*5113495bSYour Name 		req->vdev_id = link_info->vdev_id;
5137*5113495bSYour Name 		status = sme_set_plm_request(hdd_ctx->mac_handle, req);
5138*5113495bSYour Name 	}
5139*5113495bSYour Name 	qdf_mem_free(req);
5140*5113495bSYour Name 
5141*5113495bSYour Name 	return qdf_status_to_os_return(status);
5142*5113495bSYour Name }
5143*5113495bSYour Name 
5144*5113495bSYour Name /**
5145*5113495bSYour Name  * drv_cmd_set_ccx_mode() - Set ESE mode
5146*5113495bSYour Name  * @link_info:   Link info pointer in HDD adapter
5147*5113495bSYour Name  * @hdd_ctx:     Pointer to the HDD context
5148*5113495bSYour Name  * @command:     Driver command string
5149*5113495bSYour Name  * @command_len: Driver command string length
5150*5113495bSYour Name  * @priv_data:   Private data coming with the driver command. Unused here
5151*5113495bSYour Name  *
5152*5113495bSYour Name  * This function handles driver command that sets ESE mode
5153*5113495bSYour Name  *
5154*5113495bSYour Name  * Return: 0 on success; negative errno otherwise
5155*5113495bSYour Name  */
drv_cmd_set_ccx_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5156*5113495bSYour Name static int drv_cmd_set_ccx_mode(struct wlan_hdd_link_info *link_info,
5157*5113495bSYour Name 				struct hdd_context *hdd_ctx,
5158*5113495bSYour Name 				uint8_t *command,
5159*5113495bSYour Name 				uint8_t command_len,
5160*5113495bSYour Name 				struct hdd_priv_data *priv_data)
5161*5113495bSYour Name {
5162*5113495bSYour Name 	int ret = 0;
5163*5113495bSYour Name 	uint8_t *value = command;
5164*5113495bSYour Name 	uint8_t ese_mode = cfg_default(CFG_LFR_ESE_FEATURE_ENABLED);
5165*5113495bSYour Name 	struct pmkid_mode_bits pmkid_modes;
5166*5113495bSYour Name 	mac_handle_t mac_handle;
5167*5113495bSYour Name 
5168*5113495bSYour Name 	hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
5169*5113495bSYour Name 	mac_handle = hdd_ctx->mac_handle;
5170*5113495bSYour Name 	/*
5171*5113495bSYour Name 	 * Check if the features OKC/ESE/11R are supported simultaneously,
5172*5113495bSYour Name 	 * then this operation is not permitted (return FAILURE)
5173*5113495bSYour Name 	 */
5174*5113495bSYour Name 	if (ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc) &&
5175*5113495bSYour Name 	    pmkid_modes.fw_okc &&
5176*5113495bSYour Name 	    ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) {
5177*5113495bSYour Name 		hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5178*5113495bSYour Name 		ret = -EPERM;
5179*5113495bSYour Name 		goto exit;
5180*5113495bSYour Name 	}
5181*5113495bSYour Name 
5182*5113495bSYour Name 	/* Move pointer to ahead of SETCCXMODE<delimiter> */
5183*5113495bSYour Name 	value = value + command_len + 1;
5184*5113495bSYour Name 
5185*5113495bSYour Name 	/* Convert the value from ascii to integer */
5186*5113495bSYour Name 	ret = kstrtou8(value, 10, &ese_mode);
5187*5113495bSYour Name 	if (ret < 0) {
5188*5113495bSYour Name 		/*
5189*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
5190*5113495bSYour Name 		 * then also kstrtou8 fails
5191*5113495bSYour Name 		 */
5192*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
5193*5113495bSYour Name 			cfg_min(CFG_LFR_ESE_FEATURE_ENABLED),
5194*5113495bSYour Name 			cfg_max(CFG_LFR_ESE_FEATURE_ENABLED));
5195*5113495bSYour Name 		ret = -EINVAL;
5196*5113495bSYour Name 		goto exit;
5197*5113495bSYour Name 	}
5198*5113495bSYour Name 
5199*5113495bSYour Name 	hdd_debug("Received Command to change ese mode = %d", ese_mode);
5200*5113495bSYour Name 
5201*5113495bSYour Name 	sme_update_is_ese_feature_enabled(mac_handle,
5202*5113495bSYour Name 					  link_info->vdev_id,
5203*5113495bSYour Name 					  ese_mode);
5204*5113495bSYour Name 
5205*5113495bSYour Name exit:
5206*5113495bSYour Name 	return ret;
5207*5113495bSYour Name }
5208*5113495bSYour Name #endif /* FEATURE_WLAN_ESE */
5209*5113495bSYour Name 
drv_cmd_set_mc_rate(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5210*5113495bSYour Name static int drv_cmd_set_mc_rate(struct wlan_hdd_link_info *link_info,
5211*5113495bSYour Name 			       struct hdd_context *hdd_ctx,
5212*5113495bSYour Name 			       uint8_t *command, uint8_t command_len,
5213*5113495bSYour Name 			       struct hdd_priv_data *priv_data)
5214*5113495bSYour Name {
5215*5113495bSYour Name 	int ret = 0;
5216*5113495bSYour Name 	uint8_t *value = command;
5217*5113495bSYour Name 	uint32_t target_rate = 0;
5218*5113495bSYour Name 
5219*5113495bSYour Name 	/* input value is in units of hundred kbps */
5220*5113495bSYour Name 
5221*5113495bSYour Name 	/* Move pointer to ahead of SETMCRATE<delimiter> */
5222*5113495bSYour Name 	value = value + command_len + 1;
5223*5113495bSYour Name 
5224*5113495bSYour Name 	/* Convert the value from ascii to integer, decimal base */
5225*5113495bSYour Name 	ret = kstrtouint(value, 10, &target_rate);
5226*5113495bSYour Name 
5227*5113495bSYour Name 	ret = wlan_hdd_set_mc_rate(link_info, target_rate);
5228*5113495bSYour Name 	return ret;
5229*5113495bSYour Name }
5230*5113495bSYour Name 
drv_cmd_max_tx_power(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5231*5113495bSYour Name static int drv_cmd_max_tx_power(struct wlan_hdd_link_info *link_info,
5232*5113495bSYour Name 				struct hdd_context *hdd_ctx,
5233*5113495bSYour Name 				uint8_t *command,
5234*5113495bSYour Name 				uint8_t command_len,
5235*5113495bSYour Name 				struct hdd_priv_data *priv_data)
5236*5113495bSYour Name {
5237*5113495bSYour Name 	int ret;
5238*5113495bSYour Name 	int tx_power;
5239*5113495bSYour Name 	QDF_STATUS status;
5240*5113495bSYour Name 	uint8_t *value = command;
5241*5113495bSYour Name 	struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
5242*5113495bSYour Name 	struct qdf_mac_addr selfmac = QDF_MAC_ADDR_BCAST_INIT;
5243*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter, *next_adapter = NULL;
5244*5113495bSYour Name 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_DRV_CMD_MAX_TX_POWER;
5245*5113495bSYour Name 
5246*5113495bSYour Name 	ret = hdd_parse_setmaxtxpower_command(value, &tx_power);
5247*5113495bSYour Name 	if (ret) {
5248*5113495bSYour Name 		hdd_err("Invalid MAXTXPOWER command");
5249*5113495bSYour Name 		return ret;
5250*5113495bSYour Name 	}
5251*5113495bSYour Name 
5252*5113495bSYour Name 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
5253*5113495bSYour Name 					   dbgid) {
5254*5113495bSYour Name 		/* Assign correct self MAC address */
5255*5113495bSYour Name 		if (adapter->device_mode == QDF_SAP_MODE ||
5256*5113495bSYour Name 		    adapter->device_mode == QDF_P2P_GO_MODE) {
5257*5113495bSYour Name 			qdf_copy_macaddr(&bssid, &adapter->mac_addr);
5258*5113495bSYour Name 		} else {
5259*5113495bSYour Name 			struct hdd_station_ctx *sta_ctx =
5260*5113495bSYour Name 				WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
5261*5113495bSYour Name 
5262*5113495bSYour Name 			if (hdd_cm_is_vdev_associated(adapter->deflink))
5263*5113495bSYour Name 				qdf_copy_macaddr(&bssid,
5264*5113495bSYour Name 						 &sta_ctx->conn_info.bssid);
5265*5113495bSYour Name 		}
5266*5113495bSYour Name 
5267*5113495bSYour Name 		qdf_copy_macaddr(&selfmac,
5268*5113495bSYour Name 				 &adapter->mac_addr);
5269*5113495bSYour Name 
5270*5113495bSYour Name 		hdd_debug("Device mode %d max tx power %d selfMac: "
5271*5113495bSYour Name 			  QDF_MAC_ADDR_FMT " bssId: " QDF_MAC_ADDR_FMT,
5272*5113495bSYour Name 			  adapter->device_mode, tx_power,
5273*5113495bSYour Name 			  QDF_MAC_ADDR_REF(selfmac.bytes),
5274*5113495bSYour Name 			  QDF_MAC_ADDR_REF(bssid.bytes));
5275*5113495bSYour Name 
5276*5113495bSYour Name 		status = sme_set_max_tx_power(hdd_ctx->mac_handle,
5277*5113495bSYour Name 					      bssid, selfmac, tx_power);
5278*5113495bSYour Name 		if (QDF_STATUS_SUCCESS != status) {
5279*5113495bSYour Name 			hdd_err("Set max tx power failed");
5280*5113495bSYour Name 			ret = -EINVAL;
5281*5113495bSYour Name 			hdd_adapter_dev_put_debug(adapter, dbgid);
5282*5113495bSYour Name 			if (next_adapter)
5283*5113495bSYour Name 				hdd_adapter_dev_put_debug(next_adapter,
5284*5113495bSYour Name 							  dbgid);
5285*5113495bSYour Name 			goto exit;
5286*5113495bSYour Name 		}
5287*5113495bSYour Name 		hdd_debug("Set max tx power success");
5288*5113495bSYour Name 		hdd_adapter_dev_put_debug(adapter, dbgid);
5289*5113495bSYour Name 	}
5290*5113495bSYour Name 
5291*5113495bSYour Name exit:
5292*5113495bSYour Name 	return ret;
5293*5113495bSYour Name }
5294*5113495bSYour Name 
drv_cmd_set_dfs_scan_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5295*5113495bSYour Name static int drv_cmd_set_dfs_scan_mode(struct wlan_hdd_link_info *link_info,
5296*5113495bSYour Name 				     struct hdd_context *hdd_ctx,
5297*5113495bSYour Name 				     uint8_t *command, uint8_t command_len,
5298*5113495bSYour Name 				     struct hdd_priv_data *priv_data)
5299*5113495bSYour Name {
5300*5113495bSYour Name 	int ret = 0;
5301*5113495bSYour Name 	uint8_t *value = command;
5302*5113495bSYour Name 	uint8_t dfs_scan_mode = cfg_default(CFG_LFR_ROAMING_DFS_CHANNEL);
5303*5113495bSYour Name 
5304*5113495bSYour Name 	/* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5305*5113495bSYour Name 	value = value + command_len + 1;
5306*5113495bSYour Name 
5307*5113495bSYour Name 	/* Convert the value from ascii to integer */
5308*5113495bSYour Name 	ret = kstrtou8(value, 10, &dfs_scan_mode);
5309*5113495bSYour Name 	if (ret < 0) {
5310*5113495bSYour Name 		/*
5311*5113495bSYour Name 		 * If the input value is greater than max value of datatype,
5312*5113495bSYour Name 		 * then also kstrtou8 fails
5313*5113495bSYour Name 		 */
5314*5113495bSYour Name 		hdd_err("kstrtou8 failed range [%d - %d]",
5315*5113495bSYour Name 			  cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5316*5113495bSYour Name 			  cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
5317*5113495bSYour Name 		ret = -EINVAL;
5318*5113495bSYour Name 		goto exit;
5319*5113495bSYour Name 	}
5320*5113495bSYour Name 
5321*5113495bSYour Name 	if (!cfg_in_range(CFG_LFR_ROAMING_DFS_CHANNEL, dfs_scan_mode)) {
5322*5113495bSYour Name 		hdd_err("dfs_scan_mode value %d is out of range (Min: %d Max: %d)",
5323*5113495bSYour Name 			  dfs_scan_mode,
5324*5113495bSYour Name 			  cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5325*5113495bSYour Name 			  cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
5326*5113495bSYour Name 		ret = -EINVAL;
5327*5113495bSYour Name 		goto exit;
5328*5113495bSYour Name 	}
5329*5113495bSYour Name 
5330*5113495bSYour Name 	hdd_debug("Received Command to Set DFS Scan Mode = %d",
5331*5113495bSYour Name 		  dfs_scan_mode);
5332*5113495bSYour Name 
5333*5113495bSYour Name 	/* When DFS scanning is disabled, the DFS channels need to be
5334*5113495bSYour Name 	 * removed from the operation of device.
5335*5113495bSYour Name 	 */
5336*5113495bSYour Name 	ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5337*5113495bSYour Name 			dfs_scan_mode != ROAMING_DFS_CHANNEL_DISABLED);
5338*5113495bSYour Name 	if (ret < 0) {
5339*5113495bSYour Name 		/* Some conditions prevented it from disabling DFS channels */
5340*5113495bSYour Name 		hdd_err("disable/enable DFS channel request was denied");
5341*5113495bSYour Name 		goto exit;
5342*5113495bSYour Name 	}
5343*5113495bSYour Name 
5344*5113495bSYour Name 	sme_update_dfs_scan_mode(hdd_ctx->mac_handle, link_info->vdev_id,
5345*5113495bSYour Name 				 dfs_scan_mode);
5346*5113495bSYour Name 
5347*5113495bSYour Name exit:
5348*5113495bSYour Name 	return ret;
5349*5113495bSYour Name }
5350*5113495bSYour Name 
drv_cmd_get_dfs_scan_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5351*5113495bSYour Name static int drv_cmd_get_dfs_scan_mode(struct wlan_hdd_link_info *link_info,
5352*5113495bSYour Name 				     struct hdd_context *hdd_ctx,
5353*5113495bSYour Name 				     uint8_t *command,
5354*5113495bSYour Name 				     uint8_t command_len,
5355*5113495bSYour Name 				     struct hdd_priv_data *priv_data)
5356*5113495bSYour Name {
5357*5113495bSYour Name 	int ret = 0;
5358*5113495bSYour Name 	uint8_t dfs_scan_mode = sme_get_dfs_scan_mode(hdd_ctx->mac_handle);
5359*5113495bSYour Name 	char extra[32];
5360*5113495bSYour Name 	uint8_t len = 0;
5361*5113495bSYour Name 
5362*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, dfs_scan_mode);
5363*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
5364*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
5365*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
5366*5113495bSYour Name 		ret = -EFAULT;
5367*5113495bSYour Name 	}
5368*5113495bSYour Name 
5369*5113495bSYour Name 	return ret;
5370*5113495bSYour Name }
5371*5113495bSYour Name 
drv_cmd_get_link_status(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5372*5113495bSYour Name static int drv_cmd_get_link_status(struct wlan_hdd_link_info *link_info,
5373*5113495bSYour Name 				   struct hdd_context *hdd_ctx,
5374*5113495bSYour Name 				   uint8_t *command,
5375*5113495bSYour Name 				   uint8_t command_len,
5376*5113495bSYour Name 				   struct hdd_priv_data *priv_data)
5377*5113495bSYour Name {
5378*5113495bSYour Name 	int ret = 0;
5379*5113495bSYour Name 	int value = wlan_hdd_get_link_status(link_info->adapter);
5380*5113495bSYour Name 	char extra[32];
5381*5113495bSYour Name 	uint8_t len;
5382*5113495bSYour Name 
5383*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
5384*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
5385*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
5386*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
5387*5113495bSYour Name 		ret = -EFAULT;
5388*5113495bSYour Name 	}
5389*5113495bSYour Name 
5390*5113495bSYour Name 	return ret;
5391*5113495bSYour Name }
5392*5113495bSYour Name 
5393*5113495bSYour Name #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
drv_cmd_enable_ext_wow(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5394*5113495bSYour Name static int drv_cmd_enable_ext_wow(struct wlan_hdd_link_info *link_info,
5395*5113495bSYour Name 				  struct hdd_context *hdd_ctx,
5396*5113495bSYour Name 				  uint8_t *command,
5397*5113495bSYour Name 				  uint8_t command_len,
5398*5113495bSYour Name 				  struct hdd_priv_data *priv_data)
5399*5113495bSYour Name {
5400*5113495bSYour Name 	uint8_t *value = command;
5401*5113495bSYour Name 	int set_value;
5402*5113495bSYour Name 
5403*5113495bSYour Name 	/* Move pointer to ahead of ENABLEEXTWOW */
5404*5113495bSYour Name 	value = value + command_len;
5405*5113495bSYour Name 
5406*5113495bSYour Name 	if (!(sscanf(value, "%d", &set_value))) {
5407*5113495bSYour Name 		hdd_info("No input identified");
5408*5113495bSYour Name 		return -EINVAL;
5409*5113495bSYour Name 	}
5410*5113495bSYour Name 
5411*5113495bSYour Name 	return hdd_enable_ext_wow_parser(link_info->adapter,
5412*5113495bSYour Name 					 link_info->vdev_id, set_value);
5413*5113495bSYour Name }
5414*5113495bSYour Name 
drv_cmd_set_app1_params(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5415*5113495bSYour Name static int drv_cmd_set_app1_params(struct wlan_hdd_link_info *link_info,
5416*5113495bSYour Name 				   struct hdd_context *hdd_ctx,
5417*5113495bSYour Name 				   uint8_t *command,
5418*5113495bSYour Name 				   uint8_t command_len,
5419*5113495bSYour Name 				   struct hdd_priv_data *priv_data)
5420*5113495bSYour Name {
5421*5113495bSYour Name 	int ret;
5422*5113495bSYour Name 	uint8_t *value = command;
5423*5113495bSYour Name 
5424*5113495bSYour Name 	/* Move pointer to ahead of SETAPP1PARAMS */
5425*5113495bSYour Name 	value = value + command_len;
5426*5113495bSYour Name 
5427*5113495bSYour Name 	ret = hdd_set_app_type1_parser(link_info->adapter,
5428*5113495bSYour Name 				       value, strlen(value));
5429*5113495bSYour Name 	if (ret >= 0)
5430*5113495bSYour Name 		hdd_ctx->is_extwow_app_type1_param_set = true;
5431*5113495bSYour Name 
5432*5113495bSYour Name 	return ret;
5433*5113495bSYour Name }
5434*5113495bSYour Name 
drv_cmd_set_app2_params(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5435*5113495bSYour Name static int drv_cmd_set_app2_params(struct wlan_hdd_link_info *link_info,
5436*5113495bSYour Name 				   struct hdd_context *hdd_ctx,
5437*5113495bSYour Name 				   uint8_t *command,
5438*5113495bSYour Name 				   uint8_t command_len,
5439*5113495bSYour Name 				   struct hdd_priv_data *priv_data)
5440*5113495bSYour Name {
5441*5113495bSYour Name 	int ret;
5442*5113495bSYour Name 	uint8_t *value = command;
5443*5113495bSYour Name 
5444*5113495bSYour Name 	/* Move pointer to ahead of SETAPP2PARAMS */
5445*5113495bSYour Name 	value = value + command_len;
5446*5113495bSYour Name 
5447*5113495bSYour Name 	ret = hdd_set_app_type2_parser(link_info->adapter,
5448*5113495bSYour Name 				       value, strlen(value));
5449*5113495bSYour Name 	if (ret >= 0)
5450*5113495bSYour Name 		hdd_ctx->is_extwow_app_type2_param_set = true;
5451*5113495bSYour Name 
5452*5113495bSYour Name 	return ret;
5453*5113495bSYour Name }
5454*5113495bSYour Name #endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5455*5113495bSYour Name 
5456*5113495bSYour Name #ifdef FEATURE_WLAN_TDLS
5457*5113495bSYour Name /**
5458*5113495bSYour Name  * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5459*5113495bSYour Name  * @link_info:   Link info pointer in HDD adapter
5460*5113495bSYour Name  * @hdd_ctx:     Pointer to the HDD context
5461*5113495bSYour Name  * @command:     Driver command string
5462*5113495bSYour Name  * @command_len: Driver command string length
5463*5113495bSYour Name  * @priv_data:   Private data coming with the driver command. Unused here
5464*5113495bSYour Name  *
5465*5113495bSYour Name  * This function handles driver command that sets the secondary tdls off channel
5466*5113495bSYour Name  * offset
5467*5113495bSYour Name  *
5468*5113495bSYour Name  * Return: 0 on success; negative errno otherwise
5469*5113495bSYour Name  */
5470*5113495bSYour Name static int
drv_cmd_tdls_secondary_channel_offset(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5471*5113495bSYour Name drv_cmd_tdls_secondary_channel_offset(struct wlan_hdd_link_info *link_info,
5472*5113495bSYour Name 				      struct hdd_context *hdd_ctx,
5473*5113495bSYour Name 				      uint8_t *command, uint8_t command_len,
5474*5113495bSYour Name 				      struct hdd_priv_data *priv_data)
5475*5113495bSYour Name {
5476*5113495bSYour Name 	int ret;
5477*5113495bSYour Name 	uint8_t *value = command;
5478*5113495bSYour Name 	int set_value;
5479*5113495bSYour Name 
5480*5113495bSYour Name 	/* Move pointer to point the string */
5481*5113495bSYour Name 	value += command_len;
5482*5113495bSYour Name 
5483*5113495bSYour Name 	ret = sscanf(value, "%d", &set_value);
5484*5113495bSYour Name 	if (ret != 1)
5485*5113495bSYour Name 		return -EINVAL;
5486*5113495bSYour Name 
5487*5113495bSYour Name 	hdd_debug("Tdls offchannel offset:%d", set_value);
5488*5113495bSYour Name 
5489*5113495bSYour Name 	ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, link_info->adapter,
5490*5113495bSYour Name 					       set_value);
5491*5113495bSYour Name 
5492*5113495bSYour Name 	return ret;
5493*5113495bSYour Name }
5494*5113495bSYour Name 
5495*5113495bSYour Name /**
5496*5113495bSYour Name  * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5497*5113495bSYour Name  * @link_info:   Link info pointer in HDD adapter
5498*5113495bSYour Name  * @hdd_ctx:     Pointer to the HDD context
5499*5113495bSYour Name  * @command:     Driver command string
5500*5113495bSYour Name  * @command_len: Driver command string length
5501*5113495bSYour Name  * @priv_data:   Private data coming with the driver command. Unused here
5502*5113495bSYour Name  *
5503*5113495bSYour Name  * This function handles driver command that sets tdls off channel mode
5504*5113495bSYour Name  *
5505*5113495bSYour Name  * Return: 0 on success; negative errno otherwise
5506*5113495bSYour Name  */
drv_cmd_tdls_off_channel_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5507*5113495bSYour Name static int drv_cmd_tdls_off_channel_mode(struct wlan_hdd_link_info *link_info,
5508*5113495bSYour Name 					 struct hdd_context *hdd_ctx,
5509*5113495bSYour Name 					 uint8_t *command,
5510*5113495bSYour Name 					 uint8_t command_len,
5511*5113495bSYour Name 					 struct hdd_priv_data *priv_data)
5512*5113495bSYour Name {
5513*5113495bSYour Name 	int ret;
5514*5113495bSYour Name 	uint8_t *value = command;
5515*5113495bSYour Name 	int set_value;
5516*5113495bSYour Name 
5517*5113495bSYour Name 	/* Move pointer to point the string */
5518*5113495bSYour Name 	value += command_len;
5519*5113495bSYour Name 
5520*5113495bSYour Name 	ret = sscanf(value, "%d", &set_value);
5521*5113495bSYour Name 	if (ret != 1)
5522*5113495bSYour Name 		return -EINVAL;
5523*5113495bSYour Name 
5524*5113495bSYour Name 	hdd_debug("Tdls offchannel mode:%d", set_value);
5525*5113495bSYour Name 
5526*5113495bSYour Name 	ret = hdd_set_tdls_offchannelmode(hdd_ctx,
5527*5113495bSYour Name 					  link_info->adapter, set_value);
5528*5113495bSYour Name 
5529*5113495bSYour Name 	return ret;
5530*5113495bSYour Name }
5531*5113495bSYour Name 
5532*5113495bSYour Name /**
5533*5113495bSYour Name  * drv_cmd_tdls_off_channel() - set tdls off channel number
5534*5113495bSYour Name  * @link_info:   Link info pointer in HDD adapter
5535*5113495bSYour Name  * @hdd_ctx:     Pointer to the HDD context
5536*5113495bSYour Name  * @command:     Driver command string
5537*5113495bSYour Name  * @command_len: Driver command string length
5538*5113495bSYour Name  * @priv_data:   Private data coming with the driver command. Unused here
5539*5113495bSYour Name  *
5540*5113495bSYour Name  * This function handles driver command that sets tdls off channel number
5541*5113495bSYour Name  *
5542*5113495bSYour Name  * Return: 0 on success; negative errno otherwise
5543*5113495bSYour Name  */
drv_cmd_tdls_off_channel(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5544*5113495bSYour Name static int drv_cmd_tdls_off_channel(struct wlan_hdd_link_info *link_info,
5545*5113495bSYour Name 				    struct hdd_context *hdd_ctx,
5546*5113495bSYour Name 				    uint8_t *command,
5547*5113495bSYour Name 				    uint8_t command_len,
5548*5113495bSYour Name 				    struct hdd_priv_data *priv_data)
5549*5113495bSYour Name {
5550*5113495bSYour Name 	int ret;
5551*5113495bSYour Name 	uint8_t *value = command;
5552*5113495bSYour Name 	int channel;
5553*5113495bSYour Name 	enum channel_state reg_state;
5554*5113495bSYour Name 	qdf_freq_t ch_freq;
5555*5113495bSYour Name 
5556*5113495bSYour Name 	/* Move pointer to point the string */
5557*5113495bSYour Name 	value += command_len;
5558*5113495bSYour Name 
5559*5113495bSYour Name 	ret = sscanf(value, "%d", &channel);
5560*5113495bSYour Name 	if (ret != 1)
5561*5113495bSYour Name 		return -EINVAL;
5562*5113495bSYour Name 
5563*5113495bSYour Name 	ch_freq = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, channel);
5564*5113495bSYour Name 	reg_state =
5565*5113495bSYour Name 		wlan_reg_get_channel_state_for_pwrmode(hdd_ctx->pdev, ch_freq,
5566*5113495bSYour Name 						       REG_CURRENT_PWR_MODE);
5567*5113495bSYour Name 
5568*5113495bSYour Name 	if (reg_state == CHANNEL_STATE_DFS ||
5569*5113495bSYour Name 		reg_state == CHANNEL_STATE_DISABLE ||
5570*5113495bSYour Name 		reg_state == CHANNEL_STATE_INVALID) {
5571*5113495bSYour Name 		hdd_err("reg state of the  channel %d is %d and not supported",
5572*5113495bSYour Name 			channel, reg_state);
5573*5113495bSYour Name 		return -EINVAL;
5574*5113495bSYour Name 	}
5575*5113495bSYour Name 
5576*5113495bSYour Name 	hdd_debug("Tdls offchannel num: %d", channel);
5577*5113495bSYour Name 
5578*5113495bSYour Name 	ret = hdd_set_tdls_offchannel(hdd_ctx, link_info->adapter, channel);
5579*5113495bSYour Name 
5580*5113495bSYour Name 	return ret;
5581*5113495bSYour Name }
5582*5113495bSYour Name 
5583*5113495bSYour Name /**
5584*5113495bSYour Name  * drv_cmd_tdls_scan() - set tdls scan type
5585*5113495bSYour Name  * @link_info:   Link info pointer in HDD adapter
5586*5113495bSYour Name  * @hdd_ctx:     Pointer to the HDD context
5587*5113495bSYour Name  * @command:     Driver command string
5588*5113495bSYour Name  * @command_len: Driver command string length
5589*5113495bSYour Name  * @priv_data:   Private data coming with the driver command. Unused here
5590*5113495bSYour Name  *
5591*5113495bSYour Name  * This function handles driver command that sets tdls scan type
5592*5113495bSYour Name  *
5593*5113495bSYour Name  * Return: 0 on success; negative errno otherwise
5594*5113495bSYour Name  */
drv_cmd_tdls_scan(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5595*5113495bSYour Name static int drv_cmd_tdls_scan(struct wlan_hdd_link_info *link_info,
5596*5113495bSYour Name 			     struct hdd_context *hdd_ctx,
5597*5113495bSYour Name 			     uint8_t *command, uint8_t command_len,
5598*5113495bSYour Name 			     struct hdd_priv_data *priv_data)
5599*5113495bSYour Name {
5600*5113495bSYour Name 	int ret;
5601*5113495bSYour Name 	uint8_t *value = command;
5602*5113495bSYour Name 	int set_value;
5603*5113495bSYour Name 
5604*5113495bSYour Name 	/* Move pointer to point the string */
5605*5113495bSYour Name 	value += command_len;
5606*5113495bSYour Name 
5607*5113495bSYour Name 	ret = sscanf(value, "%d", &set_value);
5608*5113495bSYour Name 	if (ret != 1)
5609*5113495bSYour Name 		return -EINVAL;
5610*5113495bSYour Name 
5611*5113495bSYour Name 	hdd_debug("Tdls scan type val: %d", set_value);
5612*5113495bSYour Name 
5613*5113495bSYour Name 	ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
5614*5113495bSYour Name 
5615*5113495bSYour Name 	return ret;
5616*5113495bSYour Name }
5617*5113495bSYour Name #endif
5618*5113495bSYour Name 
drv_cmd_get_rssi(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5619*5113495bSYour Name static int drv_cmd_get_rssi(struct wlan_hdd_link_info *link_info,
5620*5113495bSYour Name 			    struct hdd_context *hdd_ctx,
5621*5113495bSYour Name 			    uint8_t *command, uint8_t command_len,
5622*5113495bSYour Name 			    struct hdd_priv_data *priv_data)
5623*5113495bSYour Name {
5624*5113495bSYour Name 	int ret = 0;
5625*5113495bSYour Name 	int8_t rssi = 0;
5626*5113495bSYour Name 	char extra[32];
5627*5113495bSYour Name 
5628*5113495bSYour Name 	uint8_t len = 0;
5629*5113495bSYour Name 
5630*5113495bSYour Name 	wlan_hdd_get_rssi(link_info, &rssi);
5631*5113495bSYour Name 
5632*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
5633*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
5634*5113495bSYour Name 
5635*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
5636*5113495bSYour Name 		hdd_err("Failed to copy data to user buffer");
5637*5113495bSYour Name 		ret = -EFAULT;
5638*5113495bSYour Name 	}
5639*5113495bSYour Name 
5640*5113495bSYour Name 	return ret;
5641*5113495bSYour Name }
5642*5113495bSYour Name 
5643*5113495bSYour Name /**
5644*5113495bSYour Name  * drv_cmd_get_sap_go_linkspeed() - Driver command to get SAP/P2P Go peer link
5645*5113495bSYour Name  *                                  speed
5646*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
5647*5113495bSYour Name  * @hdd_ctx: HDD context pointer
5648*5113495bSYour Name  * @command: Driver command string
5649*5113495bSYour Name  * @command_len: Driver command string length
5650*5113495bSYour Name  * @priv_data: Pointer to HDD private data
5651*5113495bSYour Name  *
5652*5113495bSYour Name  * Return: 0 if linkspeed data is available, negative errno otherwise
5653*5113495bSYour Name  */
drv_cmd_get_sap_go_linkspeed(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5654*5113495bSYour Name static int drv_cmd_get_sap_go_linkspeed(struct wlan_hdd_link_info *link_info,
5655*5113495bSYour Name 					struct hdd_context *hdd_ctx,
5656*5113495bSYour Name 					uint8_t *command,
5657*5113495bSYour Name 					uint8_t command_len,
5658*5113495bSYour Name 					struct hdd_priv_data *priv_data)
5659*5113495bSYour Name {
5660*5113495bSYour Name 	int ret;
5661*5113495bSYour Name 	uint32_t link_speed = 0;
5662*5113495bSYour Name 	char extra[64];
5663*5113495bSYour Name 	uint8_t len = 0;
5664*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
5665*5113495bSYour Name 
5666*5113495bSYour Name 	if (adapter->device_mode == QDF_P2P_GO_MODE ||
5667*5113495bSYour Name 	    adapter->device_mode == QDF_SAP_MODE) {
5668*5113495bSYour Name 		ret = wlan_hdd_get_sap_go_peer_linkspeed(link_info,
5669*5113495bSYour Name 							 &link_speed,
5670*5113495bSYour Name 							 command,
5671*5113495bSYour Name 							 command_len);
5672*5113495bSYour Name 	} else {
5673*5113495bSYour Name 		hdd_err("Link Speed is not allowed in Device mode %s(%d)",
5674*5113495bSYour Name 			qdf_opmode_str(adapter->device_mode),
5675*5113495bSYour Name 			adapter->device_mode);
5676*5113495bSYour Name 		ret = -ENOTSUPP;
5677*5113495bSYour Name 	}
5678*5113495bSYour Name 
5679*5113495bSYour Name 	if (0 != ret)
5680*5113495bSYour Name 		return ret;
5681*5113495bSYour Name 
5682*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d\n",
5683*5113495bSYour Name 			"SOFT-AP LINKSPEED", link_speed);
5684*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
5685*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
5686*5113495bSYour Name 		hdd_err("Failed to copy data to user buffer");
5687*5113495bSYour Name 		ret = -EFAULT;
5688*5113495bSYour Name 	}
5689*5113495bSYour Name 
5690*5113495bSYour Name 	return ret;
5691*5113495bSYour Name }
5692*5113495bSYour Name 
drv_cmd_get_linkspeed(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5693*5113495bSYour Name static int drv_cmd_get_linkspeed(struct wlan_hdd_link_info *link_info,
5694*5113495bSYour Name 				 struct hdd_context *hdd_ctx,
5695*5113495bSYour Name 				 uint8_t *command,
5696*5113495bSYour Name 				 uint8_t command_len,
5697*5113495bSYour Name 				 struct hdd_priv_data *priv_data)
5698*5113495bSYour Name {
5699*5113495bSYour Name 	int ret;
5700*5113495bSYour Name 	uint32_t link_speed = 0;
5701*5113495bSYour Name 	char extra[32];
5702*5113495bSYour Name 	uint8_t len = 0;
5703*5113495bSYour Name 
5704*5113495bSYour Name 	ret = wlan_hdd_get_link_speed(link_info, &link_speed);
5705*5113495bSYour Name 	if (0 != ret)
5706*5113495bSYour Name 		return ret;
5707*5113495bSYour Name 
5708*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
5709*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
5710*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
5711*5113495bSYour Name 		hdd_err("Failed to copy data to user buffer");
5712*5113495bSYour Name 		ret = -EFAULT;
5713*5113495bSYour Name 	}
5714*5113495bSYour Name 
5715*5113495bSYour Name 	return ret;
5716*5113495bSYour Name }
5717*5113495bSYour Name 
5718*5113495bSYour Name #ifdef WLAN_FEATURE_PACKET_FILTERING
5719*5113495bSYour Name /**
5720*5113495bSYour Name  * hdd_set_rx_filter() - set RX filter
5721*5113495bSYour Name  * @adapter: Pointer to adapter
5722*5113495bSYour Name  * @action: Filter action
5723*5113495bSYour Name  * @pattern: Address pattern
5724*5113495bSYour Name  *
5725*5113495bSYour Name  * Address pattern is most significant byte of address for example
5726*5113495bSYour Name  * 0x01 for IPV4 multicast address
5727*5113495bSYour Name  * 0x33 for IPV6 multicast address
5728*5113495bSYour Name  * 0xFF for broadcast address
5729*5113495bSYour Name  *
5730*5113495bSYour Name  * Return: 0 for success, non-zero for failure
5731*5113495bSYour Name  */
hdd_set_rx_filter(struct hdd_adapter * adapter,bool action,uint8_t pattern)5732*5113495bSYour Name static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action,
5733*5113495bSYour Name 			uint8_t pattern)
5734*5113495bSYour Name {
5735*5113495bSYour Name 	int ret;
5736*5113495bSYour Name 	uint8_t i, j;
5737*5113495bSYour Name 	tSirRcvFltMcAddrList *filter;
5738*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5739*5113495bSYour Name 	mac_handle_t mac_handle;
5740*5113495bSYour Name 
5741*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
5742*5113495bSYour Name 	if (0 != ret)
5743*5113495bSYour Name 		return ret;
5744*5113495bSYour Name 
5745*5113495bSYour Name 	mac_handle = hdd_ctx->mac_handle;
5746*5113495bSYour Name 	if (!mac_handle) {
5747*5113495bSYour Name 		hdd_err("MAC Handle is NULL");
5748*5113495bSYour Name 		return -EINVAL;
5749*5113495bSYour Name 	}
5750*5113495bSYour Name 
5751*5113495bSYour Name 	if (!ucfg_pmo_is_mc_addr_list_enabled(hdd_ctx->psoc)) {
5752*5113495bSYour Name 		hdd_warn("mc addr ini is disabled");
5753*5113495bSYour Name 		return -EINVAL;
5754*5113495bSYour Name 	}
5755*5113495bSYour Name 
5756*5113495bSYour Name 	/*
5757*5113495bSYour Name 	 * If action is false it means start dropping packets
5758*5113495bSYour Name 	 * Set addr_filter_pattern which will be used when sending
5759*5113495bSYour Name 	 * MC/BC address list to target
5760*5113495bSYour Name 	 */
5761*5113495bSYour Name 	if (!action)
5762*5113495bSYour Name 		adapter->addr_filter_pattern = pattern;
5763*5113495bSYour Name 	else
5764*5113495bSYour Name 		adapter->addr_filter_pattern = 0;
5765*5113495bSYour Name 
5766*5113495bSYour Name 	if (((adapter->device_mode == QDF_STA_MODE) ||
5767*5113495bSYour Name 		(adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
5768*5113495bSYour Name 		adapter->mc_addr_list.mc_cnt &&
5769*5113495bSYour Name 		hdd_cm_is_vdev_associated(adapter->deflink)) {
5770*5113495bSYour Name 
5771*5113495bSYour Name 
5772*5113495bSYour Name 		filter = qdf_mem_malloc(sizeof(*filter));
5773*5113495bSYour Name 		if (!filter)
5774*5113495bSYour Name 			return -ENOMEM;
5775*5113495bSYour Name 
5776*5113495bSYour Name 		filter->action = action;
5777*5113495bSYour Name 		for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
5778*5113495bSYour Name 			if (!memcmp(adapter->mc_addr_list.addr[i],
5779*5113495bSYour Name 				&pattern, 1)) {
5780*5113495bSYour Name 				memcpy(filter->multicastAddr[j].bytes,
5781*5113495bSYour Name 					adapter->mc_addr_list.addr[i],
5782*5113495bSYour Name 					sizeof(adapter->mc_addr_list.addr[i]));
5783*5113495bSYour Name 
5784*5113495bSYour Name 				hdd_debug("%s RX filter : addr ="
5785*5113495bSYour Name 				    QDF_MAC_ADDR_FMT,
5786*5113495bSYour Name 				    action ? "setting" : "clearing",
5787*5113495bSYour Name 				    QDF_MAC_ADDR_REF(filter->multicastAddr[j].bytes));
5788*5113495bSYour Name 				j++;
5789*5113495bSYour Name 			}
5790*5113495bSYour Name 			if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
5791*5113495bSYour Name 				break;
5792*5113495bSYour Name 		}
5793*5113495bSYour Name 		filter->ulMulticastAddrCnt = j;
5794*5113495bSYour Name 		/* Set rx filter */
5795*5113495bSYour Name 		sme_8023_multicast_list(mac_handle, adapter->deflink->vdev_id,
5796*5113495bSYour Name 					filter);
5797*5113495bSYour Name 		qdf_mem_free(filter);
5798*5113495bSYour Name 	} else {
5799*5113495bSYour Name 		hdd_debug("mode %d mc_cnt %d",
5800*5113495bSYour Name 			  adapter->device_mode, adapter->mc_addr_list.mc_cnt);
5801*5113495bSYour Name 	}
5802*5113495bSYour Name 
5803*5113495bSYour Name 	return 0;
5804*5113495bSYour Name }
5805*5113495bSYour Name 
5806*5113495bSYour Name /**
5807*5113495bSYour Name  * hdd_driver_rxfilter_command_handler() - RXFILTER driver command handler
5808*5113495bSYour Name  * @command: Pointer to input string driver command
5809*5113495bSYour Name  * @adapter: Pointer to adapter
5810*5113495bSYour Name  * @action: Action to enable/disable filtering
5811*5113495bSYour Name  *
5812*5113495bSYour Name  * If action == false
5813*5113495bSYour Name  * Start filtering out data packets based on type
5814*5113495bSYour Name  * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
5815*5113495bSYour Name  * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
5816*5113495bSYour Name  * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
5817*5113495bSYour Name  * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
5818*5113495bSYour Name  *
5819*5113495bSYour Name  * if action == true
5820*5113495bSYour Name  * Stop filtering data packets based on type
5821*5113495bSYour Name  * RXFILTER-ADD 0 -> Stop filtering unicast data packets
5822*5113495bSYour Name  * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
5823*5113495bSYour Name  * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
5824*5113495bSYour Name  * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
5825*5113495bSYour Name  *
5826*5113495bSYour Name  * Current implementation only supports IPV4 address filtering by
5827*5113495bSYour Name  * selectively allowing IPV4 multicast data packest based on
5828*5113495bSYour Name  * address list received in .ndo_set_rx_mode
5829*5113495bSYour Name  *
5830*5113495bSYour Name  * Return: 0 for success, non-zero for failure
5831*5113495bSYour Name  */
hdd_driver_rxfilter_command_handler(uint8_t * command,struct hdd_adapter * adapter,bool action)5832*5113495bSYour Name static int hdd_driver_rxfilter_command_handler(uint8_t *command,
5833*5113495bSYour Name 						struct hdd_adapter *adapter,
5834*5113495bSYour Name 						bool action)
5835*5113495bSYour Name {
5836*5113495bSYour Name 	int ret = 0;
5837*5113495bSYour Name 	uint8_t *value;
5838*5113495bSYour Name 	uint8_t type;
5839*5113495bSYour Name 
5840*5113495bSYour Name 	value = command;
5841*5113495bSYour Name 	/* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
5842*5113495bSYour Name 	if (!action)
5843*5113495bSYour Name 		value = command + 16;
5844*5113495bSYour Name 	else
5845*5113495bSYour Name 		value = command + 13;
5846*5113495bSYour Name 	ret = kstrtou8(value, 10, &type);
5847*5113495bSYour Name 	if (ret < 0) {
5848*5113495bSYour Name 		hdd_err("kstrtou8 failed invalid input value");
5849*5113495bSYour Name 		return -EINVAL;
5850*5113495bSYour Name 	}
5851*5113495bSYour Name 
5852*5113495bSYour Name 	switch (type) {
5853*5113495bSYour Name 	case 2:
5854*5113495bSYour Name 		/* Set rx filter for IPV4 multicast data packets */
5855*5113495bSYour Name 		ret = hdd_set_rx_filter(adapter, action, 0x01);
5856*5113495bSYour Name 		break;
5857*5113495bSYour Name 	default:
5858*5113495bSYour Name 		hdd_debug("Unsupported RXFILTER type %d", type);
5859*5113495bSYour Name 		break;
5860*5113495bSYour Name 	}
5861*5113495bSYour Name 
5862*5113495bSYour Name 	return ret;
5863*5113495bSYour Name }
5864*5113495bSYour Name 
5865*5113495bSYour Name /**
5866*5113495bSYour Name  * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
5867*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
5868*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
5869*5113495bSYour Name  * @command: Pointer to input command
5870*5113495bSYour Name  * @command_len: Command length
5871*5113495bSYour Name  * @priv_data: Pointer to private data in command
5872*5113495bSYour Name  */
drv_cmd_rx_filter_remove(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5873*5113495bSYour Name static int drv_cmd_rx_filter_remove(struct wlan_hdd_link_info *link_info,
5874*5113495bSYour Name 				    struct hdd_context *hdd_ctx,
5875*5113495bSYour Name 				    uint8_t *command, uint8_t command_len,
5876*5113495bSYour Name 				    struct hdd_priv_data *priv_data)
5877*5113495bSYour Name {
5878*5113495bSYour Name 	return hdd_driver_rxfilter_command_handler(command,
5879*5113495bSYour Name 						   link_info->adapter, false);
5880*5113495bSYour Name }
5881*5113495bSYour Name 
5882*5113495bSYour Name /**
5883*5113495bSYour Name  * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
5884*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
5885*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
5886*5113495bSYour Name  * @command: Pointer to input command
5887*5113495bSYour Name  * @command_len: Command length
5888*5113495bSYour Name  * @priv_data: Pointer to private data in command
5889*5113495bSYour Name  */
drv_cmd_rx_filter_add(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5890*5113495bSYour Name static int drv_cmd_rx_filter_add(struct wlan_hdd_link_info *link_info,
5891*5113495bSYour Name 				 struct hdd_context *hdd_ctx,
5892*5113495bSYour Name 				 uint8_t *command, uint8_t command_len,
5893*5113495bSYour Name 				 struct hdd_priv_data *priv_data)
5894*5113495bSYour Name {
5895*5113495bSYour Name 	return hdd_driver_rxfilter_command_handler(command,
5896*5113495bSYour Name 						   link_info->adapter, true);
5897*5113495bSYour Name }
5898*5113495bSYour Name #endif /* WLAN_FEATURE_PACKET_FILTERING */
5899*5113495bSYour Name 
5900*5113495bSYour Name /**
5901*5113495bSYour Name  * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
5902*5113495bSYour Name  * command
5903*5113495bSYour Name  * @value: Pointer to SETANTENNAMODE command
5904*5113495bSYour Name  *
5905*5113495bSYour Name  * This function parses the SETANTENNAMODE command passed in the format
5906*5113495bSYour Name  * SETANTENNAMODE<space>mode
5907*5113495bSYour Name  *
5908*5113495bSYour Name  * Return: parsed antenna mode
5909*5113495bSYour Name  */
hdd_parse_setantennamode_command(const uint8_t * value)5910*5113495bSYour Name static int hdd_parse_setantennamode_command(const uint8_t *value)
5911*5113495bSYour Name {
5912*5113495bSYour Name 	const uint8_t *in_ptr = value;
5913*5113495bSYour Name 	int tmp, v;
5914*5113495bSYour Name 	char arg1[32];
5915*5113495bSYour Name 
5916*5113495bSYour Name 	in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
5917*5113495bSYour Name 
5918*5113495bSYour Name 	/* no argument after the command */
5919*5113495bSYour Name 	if (!in_ptr) {
5920*5113495bSYour Name 		hdd_err("No argument after the command");
5921*5113495bSYour Name 		return -EINVAL;
5922*5113495bSYour Name 	}
5923*5113495bSYour Name 
5924*5113495bSYour Name 	/* no space after the command */
5925*5113495bSYour Name 	if (SPACE_ASCII_VALUE != *in_ptr) {
5926*5113495bSYour Name 		hdd_err("No space after the command");
5927*5113495bSYour Name 		return -EINVAL;
5928*5113495bSYour Name 	}
5929*5113495bSYour Name 
5930*5113495bSYour Name 	/* remove empty spaces */
5931*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
5932*5113495bSYour Name 		in_ptr++;
5933*5113495bSYour Name 
5934*5113495bSYour Name 	/* no argument followed by spaces */
5935*5113495bSYour Name 	if ('\0' == *in_ptr) {
5936*5113495bSYour Name 		hdd_err("No argument followed by spaces");
5937*5113495bSYour Name 		return -EINVAL;
5938*5113495bSYour Name 	}
5939*5113495bSYour Name 
5940*5113495bSYour Name 	/* get the argument i.e. antenna mode */
5941*5113495bSYour Name 	v = sscanf(in_ptr, "%31s ", arg1);
5942*5113495bSYour Name 	if (1 != v) {
5943*5113495bSYour Name 		hdd_err("argument retrieval from cmd string failed");
5944*5113495bSYour Name 		return -EINVAL;
5945*5113495bSYour Name 	}
5946*5113495bSYour Name 
5947*5113495bSYour Name 	v = kstrtos32(arg1, 10, &tmp);
5948*5113495bSYour Name 	if (v < 0) {
5949*5113495bSYour Name 		hdd_err("argument string to int conversion failed");
5950*5113495bSYour Name 		return -EINVAL;
5951*5113495bSYour Name 	}
5952*5113495bSYour Name 
5953*5113495bSYour Name 	return tmp;
5954*5113495bSYour Name }
5955*5113495bSYour Name 
5956*5113495bSYour Name /**
5957*5113495bSYour Name  * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
5958*5113495bSYour Name  * mask is 2x2 mode
5959*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
5960*5113495bSYour Name  *
5961*5113495bSYour Name  * Return: true if supported chain mask 2x2 else false
5962*5113495bSYour Name  */
hdd_is_supported_chain_mask_2x2(struct hdd_context * hdd_ctx)5963*5113495bSYour Name static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
5964*5113495bSYour Name {
5965*5113495bSYour Name 	QDF_STATUS status;
5966*5113495bSYour Name 	bool bval = false;
5967*5113495bSYour Name 
5968*5113495bSYour Name /*
5969*5113495bSYour Name 	 * Revisit and the update logic to determine the number
5970*5113495bSYour Name 	 * of TX/RX chains supported in the system when
5971*5113495bSYour Name 	 * antenna sharing per band chain mask support is
5972*5113495bSYour Name 	 * brought in
5973*5113495bSYour Name 	 */
5974*5113495bSYour Name 	status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
5975*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status))
5976*5113495bSYour Name 		hdd_err("unable to get vht_enable2x2");
5977*5113495bSYour Name 
5978*5113495bSYour Name 	return (bval == 0x01) ? true : false;
5979*5113495bSYour Name }
5980*5113495bSYour Name 
5981*5113495bSYour Name /**
5982*5113495bSYour Name  * hdd_is_supported_chain_mask_1x1() - Verify if the supported
5983*5113495bSYour Name  * chain mask is 1x1
5984*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
5985*5113495bSYour Name  *
5986*5113495bSYour Name  * Return: true if supported chain mask 1x1 else false
5987*5113495bSYour Name  */
hdd_is_supported_chain_mask_1x1(struct hdd_context * hdd_ctx)5988*5113495bSYour Name static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
5989*5113495bSYour Name {
5990*5113495bSYour Name 	QDF_STATUS status;
5991*5113495bSYour Name 	bool bval = false;
5992*5113495bSYour Name 
5993*5113495bSYour Name 	/*
5994*5113495bSYour Name 	 * Revisit and update the logic to determine the number
5995*5113495bSYour Name 	 * of TX/RX chains supported in the system when
5996*5113495bSYour Name 	 * antenna sharing per band chain mask support is
5997*5113495bSYour Name 	 * brought in
5998*5113495bSYour Name 	 */
5999*5113495bSYour Name 	status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6000*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status))
6001*5113495bSYour Name 		hdd_err("unable to get vht_enable2x2");
6002*5113495bSYour Name 
6003*5113495bSYour Name 	return (!bval) ? true : false;
6004*5113495bSYour Name }
6005*5113495bSYour Name 
hdd_update_smps_antenna_mode(struct hdd_context * hdd_ctx,int mode)6006*5113495bSYour Name QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
6007*5113495bSYour Name {
6008*5113495bSYour Name 	mac_handle_t mac_handle = hdd_ctx->mac_handle;
6009*5113495bSYour Name 
6010*5113495bSYour Name 	hdd_ctx->current_antenna_mode = mode;
6011*5113495bSYour Name 	/*
6012*5113495bSYour Name 	 * Update the user requested nss in the mac context.
6013*5113495bSYour Name 	 * This will be used in tdls protocol engine to form tdls
6014*5113495bSYour Name 	 * Management frames.
6015*5113495bSYour Name 	 */
6016*5113495bSYour Name 	sme_update_user_configured_nss(mac_handle,
6017*5113495bSYour Name 				       hdd_ctx->current_antenna_mode);
6018*5113495bSYour Name 
6019*5113495bSYour Name 	hdd_debug("Successfully switched to mode: %d x %d",
6020*5113495bSYour Name 		 hdd_ctx->current_antenna_mode,
6021*5113495bSYour Name 		 hdd_ctx->current_antenna_mode);
6022*5113495bSYour Name 
6023*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
6024*5113495bSYour Name }
6025*5113495bSYour Name 
6026*5113495bSYour Name /**
6027*5113495bSYour Name  * wlan_hdd_soc_set_antenna_mode_cb() - Callback for set antenna mode
6028*5113495bSYour Name  * @status: Status of set antenna mode
6029*5113495bSYour Name  * @context: callback context
6030*5113495bSYour Name  *
6031*5113495bSYour Name  * Callback on setting antenna mode
6032*5113495bSYour Name  *
6033*5113495bSYour Name  * Return: None
6034*5113495bSYour Name  */
6035*5113495bSYour Name static void
wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status,void * context)6036*5113495bSYour Name wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status,
6037*5113495bSYour Name 				 void *context)
6038*5113495bSYour Name {
6039*5113495bSYour Name 	struct osif_request *request = NULL;
6040*5113495bSYour Name 
6041*5113495bSYour Name 	hdd_debug("Status: %d", status);
6042*5113495bSYour Name 
6043*5113495bSYour Name 	request = osif_request_get(context);
6044*5113495bSYour Name 	if (!request) {
6045*5113495bSYour Name 		hdd_err("obsolete request");
6046*5113495bSYour Name 		return;
6047*5113495bSYour Name 	}
6048*5113495bSYour Name 
6049*5113495bSYour Name 	/* Signal the completion of set dual mac config */
6050*5113495bSYour Name 	osif_request_complete(request);
6051*5113495bSYour Name 	osif_request_put(request);
6052*5113495bSYour Name }
6053*5113495bSYour Name 
hdd_set_antenna_mode(struct wlan_hdd_link_info * link_info,int mode)6054*5113495bSYour Name int hdd_set_antenna_mode(struct wlan_hdd_link_info *link_info, int mode)
6055*5113495bSYour Name {
6056*5113495bSYour Name 	struct hdd_adapter *adapter =  link_info->adapter;
6057*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6058*5113495bSYour Name 	struct sir_antenna_mode_param params;
6059*5113495bSYour Name 	QDF_STATUS status;
6060*5113495bSYour Name 	int ret = 0;
6061*5113495bSYour Name 	struct osif_request *request = NULL;
6062*5113495bSYour Name 	static const struct osif_request_params request_params = {
6063*5113495bSYour Name 		.priv_size = 0,
6064*5113495bSYour Name 		.timeout_ms = SME_POLICY_MGR_CMD_TIMEOUT,
6065*5113495bSYour Name 	};
6066*5113495bSYour Name 
6067*5113495bSYour Name 	if (QDF_STATUS_SUCCESS ==
6068*5113495bSYour Name 	    wlan_is_tdls_session_present(link_info->vdev)) {
6069*5113495bSYour Name 		hdd_debug("TDLS session exists");
6070*5113495bSYour Name 		ret = -EINVAL;
6071*5113495bSYour Name 		goto exit;
6072*5113495bSYour Name 	}
6073*5113495bSYour Name 
6074*5113495bSYour Name 	switch (mode) {
6075*5113495bSYour Name 	case HDD_ANTENNA_MODE_1X1:
6076*5113495bSYour Name 		params.num_rx_chains = 1;
6077*5113495bSYour Name 		params.num_tx_chains = 1;
6078*5113495bSYour Name 		break;
6079*5113495bSYour Name 	case HDD_ANTENNA_MODE_2X2:
6080*5113495bSYour Name 		params.num_rx_chains = 2;
6081*5113495bSYour Name 		params.num_tx_chains = 2;
6082*5113495bSYour Name 		break;
6083*5113495bSYour Name 	default:
6084*5113495bSYour Name 		hdd_err("unsupported antenna mode");
6085*5113495bSYour Name 		ret = -EINVAL;
6086*5113495bSYour Name 		goto exit;
6087*5113495bSYour Name 	}
6088*5113495bSYour Name 
6089*5113495bSYour Name 	if (hdd_ctx->dynamic_nss_chains_support)
6090*5113495bSYour Name 		return hdd_set_dynamic_antenna_mode(link_info,
6091*5113495bSYour Name 						    params.num_rx_chains,
6092*5113495bSYour Name 						    params.num_tx_chains);
6093*5113495bSYour Name 
6094*5113495bSYour Name 	if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6095*5113495bSYour Name 	    (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6096*5113495bSYour Name 		hdd_err("System does not support 2x2 mode");
6097*5113495bSYour Name 		ret = -EPERM;
6098*5113495bSYour Name 		goto exit;
6099*5113495bSYour Name 	}
6100*5113495bSYour Name 
6101*5113495bSYour Name 	if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6102*5113495bSYour Name 	    hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6103*5113495bSYour Name 		hdd_err("System only supports 1x1 mode");
6104*5113495bSYour Name 		goto exit;
6105*5113495bSYour Name 	}
6106*5113495bSYour Name 
6107*5113495bSYour Name 	/* Check TDLS status and update antenna mode */
6108*5113495bSYour Name 	if ((QDF_STA_MODE == adapter->device_mode) &&
6109*5113495bSYour Name 	    policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) {
6110*5113495bSYour Name 		ret = wlan_hdd_tdls_antenna_switch(link_info, mode);
6111*5113495bSYour Name 		if (0 != ret)
6112*5113495bSYour Name 			goto exit;
6113*5113495bSYour Name 	}
6114*5113495bSYour Name 
6115*5113495bSYour Name 	request = osif_request_alloc(&request_params);
6116*5113495bSYour Name 	if (!request) {
6117*5113495bSYour Name 		hdd_err("Request Allocation Failure");
6118*5113495bSYour Name 		ret = -ENOMEM;
6119*5113495bSYour Name 		goto exit;
6120*5113495bSYour Name 	}
6121*5113495bSYour Name 
6122*5113495bSYour Name 	params.set_antenna_mode_ctx = osif_request_cookie(request);
6123*5113495bSYour Name 	params.set_antenna_mode_resp = (void *)wlan_hdd_soc_set_antenna_mode_cb;
6124*5113495bSYour Name 	hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
6125*5113495bSYour Name 		 params.num_rx_chains,
6126*5113495bSYour Name 		 params.num_tx_chains);
6127*5113495bSYour Name 
6128*5113495bSYour Name 	status = sme_soc_set_antenna_mode(hdd_ctx->mac_handle, &params);
6129*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
6130*5113495bSYour Name 		hdd_err("set antenna mode failed status : %d", status);
6131*5113495bSYour Name 		ret = -EFAULT;
6132*5113495bSYour Name 		goto request_put;
6133*5113495bSYour Name 	}
6134*5113495bSYour Name 
6135*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
6136*5113495bSYour Name 	if (ret) {
6137*5113495bSYour Name 		hdd_err("send set antenna mode timed out");
6138*5113495bSYour Name 		goto request_put;
6139*5113495bSYour Name 	}
6140*5113495bSYour Name 
6141*5113495bSYour Name 	status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
6142*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
6143*5113495bSYour Name 		ret = -EFAULT;
6144*5113495bSYour Name 		goto request_put;
6145*5113495bSYour Name 	}
6146*5113495bSYour Name 	ret = 0;
6147*5113495bSYour Name request_put:
6148*5113495bSYour Name 	osif_request_put(request);
6149*5113495bSYour Name exit:
6150*5113495bSYour Name 	hdd_debug("Set antenna status: %d current mode: %d",
6151*5113495bSYour Name 		 ret, hdd_ctx->current_antenna_mode);
6152*5113495bSYour Name 
6153*5113495bSYour Name 	return ret;
6154*5113495bSYour Name }
6155*5113495bSYour Name 
6156*5113495bSYour Name /**
6157*5113495bSYour Name  * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6158*5113495bSYour Name  * handler
6159*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
6160*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
6161*5113495bSYour Name  * @command: Pointer to input command
6162*5113495bSYour Name  * @command_len: Command length
6163*5113495bSYour Name  * @priv_data: Pointer to private data in command
6164*5113495bSYour Name  */
drv_cmd_set_antenna_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6165*5113495bSYour Name static int drv_cmd_set_antenna_mode(struct wlan_hdd_link_info *link_info,
6166*5113495bSYour Name 				    struct hdd_context *hdd_ctx,
6167*5113495bSYour Name 				    uint8_t *command, uint8_t command_len,
6168*5113495bSYour Name 				    struct hdd_priv_data *priv_data)
6169*5113495bSYour Name {
6170*5113495bSYour Name 	int mode;
6171*5113495bSYour Name 	uint8_t *value = command;
6172*5113495bSYour Name 
6173*5113495bSYour Name 	mode = hdd_parse_setantennamode_command(value);
6174*5113495bSYour Name 	if (mode < 0) {
6175*5113495bSYour Name 		hdd_err("Invalid SETANTENNA command");
6176*5113495bSYour Name 		return mode;
6177*5113495bSYour Name 	}
6178*5113495bSYour Name 
6179*5113495bSYour Name 	hdd_debug("Processing antenna mode switch to: %d", mode);
6180*5113495bSYour Name 
6181*5113495bSYour Name 	return hdd_set_antenna_mode(link_info, mode);
6182*5113495bSYour Name }
6183*5113495bSYour Name 
6184*5113495bSYour Name /**
6185*5113495bSYour Name  * hdd_get_dynamic_antenna_mode() -get the dynamic antenna mode for vdev
6186*5113495bSYour Name  * @antenna_mode: pointer to antenna mode of vdev
6187*5113495bSYour Name  * @dynamic_nss_chains_support: feature support for dynamic nss chains update
6188*5113495bSYour Name  * @vdev: Pointer to vdev
6189*5113495bSYour Name  *
6190*5113495bSYour Name  * This API will check for the num of chains configured for the vdev, and fill
6191*5113495bSYour Name  * that info in the antenna mode if the dynamic chains per vdev are supported.
6192*5113495bSYour Name  *
6193*5113495bSYour Name  * Return: None
6194*5113495bSYour Name  */
6195*5113495bSYour Name static void
hdd_get_dynamic_antenna_mode(uint32_t * antenna_mode,bool dynamic_nss_chains_support,struct wlan_objmgr_vdev * vdev)6196*5113495bSYour Name hdd_get_dynamic_antenna_mode(uint32_t *antenna_mode,
6197*5113495bSYour Name 			     bool dynamic_nss_chains_support,
6198*5113495bSYour Name 			     struct wlan_objmgr_vdev *vdev)
6199*5113495bSYour Name {
6200*5113495bSYour Name 	struct wlan_mlme_nss_chains *nss_chains_dynamic_cfg;
6201*5113495bSYour Name 
6202*5113495bSYour Name 	if (!dynamic_nss_chains_support)
6203*5113495bSYour Name 		return;
6204*5113495bSYour Name 
6205*5113495bSYour Name 	nss_chains_dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
6206*5113495bSYour Name 	if (!nss_chains_dynamic_cfg) {
6207*5113495bSYour Name 		hdd_err("nss chain dynamic config NULL");
6208*5113495bSYour Name 		return;
6209*5113495bSYour Name 	}
6210*5113495bSYour Name 	/*
6211*5113495bSYour Name 	 * At present, this command doesn't include band, so by default
6212*5113495bSYour Name 	 * it will return the band 2ghz present rf chains.
6213*5113495bSYour Name 	 */
6214*5113495bSYour Name 	*antenna_mode =
6215*5113495bSYour Name 		nss_chains_dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
6216*5113495bSYour Name }
6217*5113495bSYour Name 
6218*5113495bSYour Name /**
6219*5113495bSYour Name  * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6220*5113495bSYour Name  * handler
6221*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
6222*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
6223*5113495bSYour Name  * @command: Pointer to input command
6224*5113495bSYour Name  * @command_len: length of the command
6225*5113495bSYour Name  * @priv_data: private data coming with the driver command
6226*5113495bSYour Name  *
6227*5113495bSYour Name  * Return: 0 for success non-zero for failure
6228*5113495bSYour Name  */
drv_cmd_get_antenna_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6229*5113495bSYour Name static inline int drv_cmd_get_antenna_mode(struct wlan_hdd_link_info *link_info,
6230*5113495bSYour Name 					   struct hdd_context *hdd_ctx,
6231*5113495bSYour Name 					   uint8_t *command,
6232*5113495bSYour Name 					   uint8_t command_len,
6233*5113495bSYour Name 					   struct hdd_priv_data *priv_data)
6234*5113495bSYour Name {
6235*5113495bSYour Name 	uint32_t antenna_mode = 0;
6236*5113495bSYour Name 	char extra[32];
6237*5113495bSYour Name 	uint8_t len = 0;
6238*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
6239*5113495bSYour Name 
6240*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
6241*5113495bSYour Name 	if (!vdev) {
6242*5113495bSYour Name 		hdd_err("vdev is NULL");
6243*5113495bSYour Name 		return -EINVAL;
6244*5113495bSYour Name 	}
6245*5113495bSYour Name 
6246*5113495bSYour Name 	antenna_mode = hdd_ctx->current_antenna_mode;
6247*5113495bSYour Name 	/* Overwrite this antenna mode if dynamic vdev chains are supported */
6248*5113495bSYour Name 	hdd_get_dynamic_antenna_mode(&antenna_mode,
6249*5113495bSYour Name 				     hdd_ctx->dynamic_nss_chains_support, vdev);
6250*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
6251*5113495bSYour Name 	len = scnprintf(extra, sizeof(extra), "%s %d", command,
6252*5113495bSYour Name 			antenna_mode);
6253*5113495bSYour Name 	len = QDF_MIN(priv_data->total_len, len + 1);
6254*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, len)) {
6255*5113495bSYour Name 		hdd_err("Failed to copy data to user buffer");
6256*5113495bSYour Name 		return -EFAULT;
6257*5113495bSYour Name 	}
6258*5113495bSYour Name 
6259*5113495bSYour Name 	hdd_debug("Get antenna mode: %d", antenna_mode);
6260*5113495bSYour Name 
6261*5113495bSYour Name 	return 0;
6262*5113495bSYour Name }
6263*5113495bSYour Name 
6264*5113495bSYour Name /*
6265*5113495bSYour Name  * dummy (no-op) hdd driver command handler
6266*5113495bSYour Name  */
drv_cmd_dummy(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6267*5113495bSYour Name static int drv_cmd_dummy(struct wlan_hdd_link_info *link_info,
6268*5113495bSYour Name 			 struct hdd_context *hdd_ctx,
6269*5113495bSYour Name 			 uint8_t *command,
6270*5113495bSYour Name 			 uint8_t command_len,
6271*5113495bSYour Name 			 struct hdd_priv_data *priv_data)
6272*5113495bSYour Name {
6273*5113495bSYour Name 	hdd_debug("%s: Ignoring driver command \"%s\"",
6274*5113495bSYour Name 		  link_info->adapter->dev->name, command);
6275*5113495bSYour Name 	return 0;
6276*5113495bSYour Name }
6277*5113495bSYour Name 
6278*5113495bSYour Name /*
6279*5113495bSYour Name  * handler for any unsupported wlan hdd driver command
6280*5113495bSYour Name  */
drv_cmd_invalid(struct hdd_adapter * adapter,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6281*5113495bSYour Name static int drv_cmd_invalid(struct hdd_adapter *adapter,
6282*5113495bSYour Name 			   struct hdd_context *hdd_ctx,
6283*5113495bSYour Name 			   uint8_t *command,
6284*5113495bSYour Name 			   uint8_t command_len,
6285*5113495bSYour Name 			   struct hdd_priv_data *priv_data)
6286*5113495bSYour Name {
6287*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
6288*5113495bSYour Name 		   TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6289*5113495bSYour Name 		   adapter->deflink->vdev_id, 0);
6290*5113495bSYour Name 
6291*5113495bSYour Name 	hdd_debug("%s: Unsupported driver command \"%s\"",
6292*5113495bSYour Name 		  adapter->dev->name, command);
6293*5113495bSYour Name 
6294*5113495bSYour Name 	return -ENOTSUPP;
6295*5113495bSYour Name }
6296*5113495bSYour Name 
6297*5113495bSYour Name /**
6298*5113495bSYour Name  * hdd_apply_fcc_constraint() - Set FCC constraint
6299*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
6300*5113495bSYour Name  * @fcc_constraint: Fcc constraint flag
6301*5113495bSYour Name  *
6302*5113495bSYour Name  * Return: Return 0 incase of success else return error number
6303*5113495bSYour Name  */
hdd_apply_fcc_constraint(struct hdd_context * hdd_ctx,bool fcc_constraint)6304*5113495bSYour Name static int hdd_apply_fcc_constraint(struct hdd_context *hdd_ctx,
6305*5113495bSYour Name 				    bool fcc_constraint)
6306*5113495bSYour Name {
6307*5113495bSYour Name 	QDF_STATUS status;
6308*5113495bSYour Name 
6309*5113495bSYour Name 	status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev,
6310*5113495bSYour Name 					     fcc_constraint);
6311*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
6312*5113495bSYour Name 		hdd_err("Failed to update tx power for channels 12/13");
6313*5113495bSYour Name 		return qdf_status_to_os_return(status);
6314*5113495bSYour Name 	}
6315*5113495bSYour Name 
6316*5113495bSYour Name 	status = wlan_reg_recompute_current_chan_list(hdd_ctx->psoc,
6317*5113495bSYour Name 						      hdd_ctx->pdev);
6318*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
6319*5113495bSYour Name 		hdd_err("Failed to update tx power for channels 12/13");
6320*5113495bSYour Name 		return qdf_status_to_os_return(status);
6321*5113495bSYour Name 	}
6322*5113495bSYour Name 
6323*5113495bSYour Name 	return 0;
6324*5113495bSYour Name }
6325*5113495bSYour Name 
6326*5113495bSYour Name /**
6327*5113495bSYour Name  * hdd_apply_fcc_constraint_update_band() - Set FCC constraint and update band
6328*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
6329*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
6330*5113495bSYour Name  * @fcc_constraint: FCC constraint flag
6331*5113495bSYour Name  * @dis_6g_keep_sta_cli_conn: Disable 6 GHz band and keep STA, P2P client
6332*5113495bSYour Name  *                            connection flag
6333*5113495bSYour Name  * @band_bitmap: Band bitmap
6334*5113495bSYour Name  *
6335*5113495bSYour Name  * Return:  Return 0 incase of success else return error number
6336*5113495bSYour Name  */
6337*5113495bSYour Name static int
hdd_apply_fcc_constraint_update_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,bool fcc_constraint,bool dis_6g_keep_sta_cli_conn,uint32_t band_bitmap)6338*5113495bSYour Name hdd_apply_fcc_constraint_update_band(struct wlan_hdd_link_info *link_info,
6339*5113495bSYour Name 				     struct hdd_context *hdd_ctx,
6340*5113495bSYour Name 				     bool fcc_constraint,
6341*5113495bSYour Name 				     bool dis_6g_keep_sta_cli_conn,
6342*5113495bSYour Name 				     uint32_t band_bitmap)
6343*5113495bSYour Name {
6344*5113495bSYour Name 	QDF_STATUS status;
6345*5113495bSYour Name 
6346*5113495bSYour Name 	status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev,
6347*5113495bSYour Name 					     fcc_constraint);
6348*5113495bSYour Name 	if (status) {
6349*5113495bSYour Name 		hdd_err("Failed to update tx power for channels 12/13");
6350*5113495bSYour Name 		return qdf_status_to_os_return(status);
6351*5113495bSYour Name 	}
6352*5113495bSYour Name 
6353*5113495bSYour Name 	status = ucfg_reg_set_keep_6ghz_sta_cli_connection(hdd_ctx->pdev,
6354*5113495bSYour Name 						dis_6g_keep_sta_cli_conn);
6355*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
6356*5113495bSYour Name 		hdd_err("Failed to update keep sta cli connection");
6357*5113495bSYour Name 		return qdf_status_to_os_return(status);
6358*5113495bSYour Name 	}
6359*5113495bSYour Name 
6360*5113495bSYour Name 	return hdd_reg_set_band(link_info->adapter->dev, band_bitmap);
6361*5113495bSYour Name }
6362*5113495bSYour Name 
6363*5113495bSYour Name /**
6364*5113495bSYour Name  * drv_cmd_set_fcc_channel() - Handle fcc constraint request
6365*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
6366*5113495bSYour Name  * @hdd_ctx: HDD context
6367*5113495bSYour Name  * @command: command ptr, SET_FCC_CHANNEL 0/1/2/-1 is the command
6368*5113495bSYour Name  * @command_len: command len
6369*5113495bSYour Name  * @priv_data: private data
6370*5113495bSYour Name  *
6371*5113495bSYour Name  * Return: status
6372*5113495bSYour Name  */
drv_cmd_set_fcc_channel(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6373*5113495bSYour Name static int drv_cmd_set_fcc_channel(struct wlan_hdd_link_info *link_info,
6374*5113495bSYour Name 				   struct hdd_context *hdd_ctx,
6375*5113495bSYour Name 				   uint8_t *command, uint8_t command_len,
6376*5113495bSYour Name 				   struct hdd_priv_data *priv_data)
6377*5113495bSYour Name {
6378*5113495bSYour Name 	QDF_STATUS status;
6379*5113495bSYour Name 	QDF_STATUS status_6G = QDF_STATUS_SUCCESS;
6380*5113495bSYour Name 	int8_t input_value;
6381*5113495bSYour Name 	int err;
6382*5113495bSYour Name 	uint32_t band_bitmap = 0, curr_band_bitmap;
6383*5113495bSYour Name 	bool rf_test_mode, fcc_constraint, dis_6g_keep_sta_cli_conn;
6384*5113495bSYour Name 	bool modify_band = false;
6385*5113495bSYour Name 
6386*5113495bSYour Name 	/*
6387*5113495bSYour Name 	 * This command would be called by user-space when it detects WLAN
6388*5113495bSYour Name 	 * ON after airplane mode is set. When APM is set, WLAN turns off.
6389*5113495bSYour Name 	 * But it can be turned back on. Otherwise; when APM is turned back
6390*5113495bSYour Name 	 * off, WLAN would turn back on. So at that point the command is
6391*5113495bSYour Name 	 * expected to come down.
6392*5113495bSYour Name 	 * a) 0 means reduce power as per fcc constraint and disable 6 GHz band
6393*5113495bSYour Name 	 *    but keep existing STA/P2P Client connections intact.
6394*5113495bSYour Name 	 * b) 1 means reduce power as per fcc constraint and enable 6 GHz band.
6395*5113495bSYour Name 	 * c) 2 means reset fcc constraint but disable 6 GHz band but keep
6396*5113495bSYour Name 	 *    existing STA/P2P Client connections intact.
6397*5113495bSYour Name 	 * d) -1 means reset fcc constraint and enable 6 GHz band.
6398*5113495bSYour Name 	 */
6399*5113495bSYour Name 
6400*5113495bSYour Name 	err = kstrtos8(command + command_len + 1, 10, &input_value);
6401*5113495bSYour Name 	if (err) {
6402*5113495bSYour Name 		hdd_err("error %d parsing userspace fcc parameter", err);
6403*5113495bSYour Name 		return err;
6404*5113495bSYour Name 	}
6405*5113495bSYour Name 
6406*5113495bSYour Name 	hdd_debug("input_value = %d", input_value);
6407*5113495bSYour Name 
6408*5113495bSYour Name 	switch (input_value) {
6409*5113495bSYour Name 	case -1:
6410*5113495bSYour Name 		fcc_constraint = false;
6411*5113495bSYour Name 		dis_6g_keep_sta_cli_conn = false;
6412*5113495bSYour Name 		break;
6413*5113495bSYour Name 	case 0:
6414*5113495bSYour Name 		fcc_constraint = true;
6415*5113495bSYour Name 		dis_6g_keep_sta_cli_conn = true;
6416*5113495bSYour Name 		break;
6417*5113495bSYour Name 	case 1:
6418*5113495bSYour Name 		fcc_constraint = true;
6419*5113495bSYour Name 		dis_6g_keep_sta_cli_conn = false;
6420*5113495bSYour Name 		break;
6421*5113495bSYour Name 	case 2:
6422*5113495bSYour Name 		fcc_constraint = false;
6423*5113495bSYour Name 		dis_6g_keep_sta_cli_conn = true;
6424*5113495bSYour Name 		break;
6425*5113495bSYour Name 	default:
6426*5113495bSYour Name 		hdd_err("Invalie input value");
6427*5113495bSYour Name 		return -EINVAL;
6428*5113495bSYour Name 	}
6429*5113495bSYour Name 
6430*5113495bSYour Name 	status = ucfg_mlme_is_rf_test_mode_enabled(hdd_ctx->psoc,
6431*5113495bSYour Name 						   &rf_test_mode);
6432*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status_6G)) {
6433*5113495bSYour Name 		hdd_err("Get rf test mode failed");
6434*5113495bSYour Name 		return qdf_status_to_os_return(status);
6435*5113495bSYour Name 	}
6436*5113495bSYour Name 
6437*5113495bSYour Name 	if (!rf_test_mode) {
6438*5113495bSYour Name 		status = ucfg_reg_get_band(hdd_ctx->pdev, &curr_band_bitmap);
6439*5113495bSYour Name 		if (!QDF_IS_STATUS_SUCCESS(status)) {
6440*5113495bSYour Name 			hdd_err("failed to get band");
6441*5113495bSYour Name 			return qdf_status_to_os_return(status);
6442*5113495bSYour Name 		}
6443*5113495bSYour Name 
6444*5113495bSYour Name 		if (dis_6g_keep_sta_cli_conn) {
6445*5113495bSYour Name 			band_bitmap |= (BIT(REG_BAND_5G) | BIT(REG_BAND_2G));
6446*5113495bSYour Name 		} else {
6447*5113495bSYour Name 			if (wlan_reg_is_6ghz_supported(hdd_ctx->psoc))
6448*5113495bSYour Name 				band_bitmap = REG_BAND_MASK_ALL;
6449*5113495bSYour Name 			else
6450*5113495bSYour Name 				band_bitmap = curr_band_bitmap;
6451*5113495bSYour Name 		}
6452*5113495bSYour Name 
6453*5113495bSYour Name 		hdd_debug("Current band bitmap = %d, set band bitmap = %d",
6454*5113495bSYour Name 			  curr_band_bitmap,
6455*5113495bSYour Name 			  band_bitmap);
6456*5113495bSYour Name 
6457*5113495bSYour Name 		if (band_bitmap != curr_band_bitmap)
6458*5113495bSYour Name 			modify_band = true;
6459*5113495bSYour Name 
6460*5113495bSYour Name 		if (ucfg_reg_is_fcc_constraint_set(hdd_ctx->pdev) ==
6461*5113495bSYour Name 		    fcc_constraint &&
6462*5113495bSYour Name 		    ucfg_reg_get_keep_6ghz_sta_cli_connection(hdd_ctx->pdev) ==
6463*5113495bSYour Name 		    dis_6g_keep_sta_cli_conn) {
6464*5113495bSYour Name 			hdd_debug("Same FCC constraint and band bitmap value");
6465*5113495bSYour Name 			return 0;
6466*5113495bSYour Name 		} else if (modify_band) {
6467*5113495bSYour Name 			return hdd_apply_fcc_constraint_update_band(link_info,
6468*5113495bSYour Name 						hdd_ctx,
6469*5113495bSYour Name 						fcc_constraint,
6470*5113495bSYour Name 						dis_6g_keep_sta_cli_conn,
6471*5113495bSYour Name 						band_bitmap);
6472*5113495bSYour Name 		}
6473*5113495bSYour Name 	} else {
6474*5113495bSYour Name 		if (ucfg_reg_is_fcc_constraint_set(hdd_ctx->pdev) ==
6475*5113495bSYour Name 		    fcc_constraint) {
6476*5113495bSYour Name 			hdd_debug("Same FCC constraint value");
6477*5113495bSYour Name 			return 0;
6478*5113495bSYour Name 		}
6479*5113495bSYour Name 	}
6480*5113495bSYour Name 
6481*5113495bSYour Name 	return hdd_apply_fcc_constraint(hdd_ctx, fcc_constraint);
6482*5113495bSYour Name }
6483*5113495bSYour Name 
6484*5113495bSYour Name /**
6485*5113495bSYour Name  * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6486*5113495bSYour Name  * command
6487*5113495bSYour Name  * @value: Pointer to the command
6488*5113495bSYour Name  * @chan_number: Pointer to the channel number
6489*5113495bSYour Name  * @chan_bw: Pointer to the channel bandwidth
6490*5113495bSYour Name  *
6491*5113495bSYour Name  * Parses and provides the channel number and channel width from the input
6492*5113495bSYour Name  * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6493*5113495bSYour Name  * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6494*5113495bSYour Name  * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6495*5113495bSYour Name  *
6496*5113495bSYour Name  * Return: 0 for success, non-zero for failure
6497*5113495bSYour Name  */
hdd_parse_set_channel_switch_command(uint8_t * value,uint32_t * chan_number,uint32_t * chan_bw)6498*5113495bSYour Name static int hdd_parse_set_channel_switch_command(uint8_t *value,
6499*5113495bSYour Name 					 uint32_t *chan_number,
6500*5113495bSYour Name 					 uint32_t *chan_bw)
6501*5113495bSYour Name {
6502*5113495bSYour Name 	const uint8_t *in_ptr = value;
6503*5113495bSYour Name 	int ret;
6504*5113495bSYour Name 
6505*5113495bSYour Name 	in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6506*5113495bSYour Name 
6507*5113495bSYour Name 	/* no argument after the command */
6508*5113495bSYour Name 	if (!in_ptr) {
6509*5113495bSYour Name 		hdd_err("No argument after the command");
6510*5113495bSYour Name 		return -EINVAL;
6511*5113495bSYour Name 	}
6512*5113495bSYour Name 
6513*5113495bSYour Name 	/* no space after the command */
6514*5113495bSYour Name 	if (SPACE_ASCII_VALUE != *in_ptr) {
6515*5113495bSYour Name 		hdd_err("No space after the command ");
6516*5113495bSYour Name 		return -EINVAL;
6517*5113495bSYour Name 	}
6518*5113495bSYour Name 
6519*5113495bSYour Name 	/* remove empty spaces and move the next argument */
6520*5113495bSYour Name 	while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6521*5113495bSYour Name 		in_ptr++;
6522*5113495bSYour Name 
6523*5113495bSYour Name 	/* no argument followed by spaces */
6524*5113495bSYour Name 	if ('\0' == *in_ptr) {
6525*5113495bSYour Name 		hdd_err("No argument followed by spaces");
6526*5113495bSYour Name 		return -EINVAL;
6527*5113495bSYour Name 	}
6528*5113495bSYour Name 
6529*5113495bSYour Name 	/* get the two arguments: channel number and bandwidth */
6530*5113495bSYour Name 	ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6531*5113495bSYour Name 	if (ret != 2) {
6532*5113495bSYour Name 		hdd_err("Arguments retrieval from cmd string failed");
6533*5113495bSYour Name 		return -EINVAL;
6534*5113495bSYour Name 	}
6535*5113495bSYour Name 
6536*5113495bSYour Name 	return 0;
6537*5113495bSYour Name }
6538*5113495bSYour Name 
6539*5113495bSYour Name /**
6540*5113495bSYour Name  * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6541*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
6542*5113495bSYour Name  * @hdd_ctx: HDD context
6543*5113495bSYour Name  * @command: Pointer to the input command CHANNEL_SWITCH
6544*5113495bSYour Name  * @command_len: Command len
6545*5113495bSYour Name  * @priv_data: Private data
6546*5113495bSYour Name  *
6547*5113495bSYour Name  * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6548*5113495bSYour Name  * of SAP/P2P-GO
6549*5113495bSYour Name  *
6550*5113495bSYour Name  * Return: 0 for success, non-zero for failure
6551*5113495bSYour Name  */
drv_cmd_set_channel_switch(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6552*5113495bSYour Name static int drv_cmd_set_channel_switch(struct wlan_hdd_link_info *link_info,
6553*5113495bSYour Name 				      struct hdd_context *hdd_ctx,
6554*5113495bSYour Name 				      uint8_t *command, uint8_t command_len,
6555*5113495bSYour Name 				      struct hdd_priv_data *priv_data)
6556*5113495bSYour Name {
6557*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
6558*5113495bSYour Name 	struct net_device *dev = adapter->dev;
6559*5113495bSYour Name 	int status;
6560*5113495bSYour Name 	uint32_t chan_number = 0, chan_bw = 0;
6561*5113495bSYour Name 	uint8_t *value = command;
6562*5113495bSYour Name 	enum phy_ch_width width;
6563*5113495bSYour Name 
6564*5113495bSYour Name 	if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6565*5113495bSYour Name 		(adapter->device_mode != QDF_SAP_MODE)) {
6566*5113495bSYour Name 		hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6567*5113495bSYour Name 			adapter->device_mode);
6568*5113495bSYour Name 		return -EINVAL;
6569*5113495bSYour Name 	}
6570*5113495bSYour Name 
6571*5113495bSYour Name 	if (!qdf_atomic_test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) {
6572*5113495bSYour Name 		hdd_err("SAP not started");
6573*5113495bSYour Name 		return -EINVAL;
6574*5113495bSYour Name 	}
6575*5113495bSYour Name 
6576*5113495bSYour Name 	status = hdd_parse_set_channel_switch_command(value,
6577*5113495bSYour Name 							&chan_number, &chan_bw);
6578*5113495bSYour Name 	if (status) {
6579*5113495bSYour Name 		hdd_err("Invalid CHANNEL_SWITCH command");
6580*5113495bSYour Name 		return status;
6581*5113495bSYour Name 	}
6582*5113495bSYour Name 
6583*5113495bSYour Name 	if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80) &&
6584*5113495bSYour Name 	    (chan_bw != 160)) {
6585*5113495bSYour Name 		hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6586*5113495bSYour Name 		return -EINVAL;
6587*5113495bSYour Name 	}
6588*5113495bSYour Name 
6589*5113495bSYour Name 	if (chan_bw == 160)
6590*5113495bSYour Name 		width = CH_WIDTH_160MHZ;
6591*5113495bSYour Name 	else if (chan_bw == 80)
6592*5113495bSYour Name 		width = CH_WIDTH_80MHZ;
6593*5113495bSYour Name 	else if (chan_bw == 40)
6594*5113495bSYour Name 		width = CH_WIDTH_40MHZ;
6595*5113495bSYour Name 	else
6596*5113495bSYour Name 		width = CH_WIDTH_20MHZ;
6597*5113495bSYour Name 
6598*5113495bSYour Name 	hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
6599*5113495bSYour Name 
6600*5113495bSYour Name 	wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, link_info->vdev_id,
6601*5113495bSYour Name 				    CSA_REASON_USER_INITIATED);
6602*5113495bSYour Name 
6603*5113495bSYour Name 	if (chan_number <= wlan_reg_max_5ghz_ch_num())
6604*5113495bSYour Name 		chan_number = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev,
6605*5113495bSYour Name 							   chan_number);
6606*5113495bSYour Name 
6607*5113495bSYour Name 	status = hdd_softap_set_channel_change(dev, chan_number, width, false);
6608*5113495bSYour Name 	if (status) {
6609*5113495bSYour Name 		hdd_err("Set channel change fail");
6610*5113495bSYour Name 		return status;
6611*5113495bSYour Name 	}
6612*5113495bSYour Name 
6613*5113495bSYour Name 	return 0;
6614*5113495bSYour Name }
6615*5113495bSYour Name 
6616*5113495bSYour Name #ifdef DISABLE_CHANNEL_LIST
wlan_hdd_free_cache_channels(struct hdd_context * hdd_ctx)6617*5113495bSYour Name void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
6618*5113495bSYour Name {
6619*5113495bSYour Name 	hdd_enter();
6620*5113495bSYour Name 
6621*5113495bSYour Name 	if (!hdd_ctx->original_channels)
6622*5113495bSYour Name 		return;
6623*5113495bSYour Name 
6624*5113495bSYour Name 	qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
6625*5113495bSYour Name 	hdd_ctx->original_channels->num_channels = 0;
6626*5113495bSYour Name 	if (hdd_ctx->original_channels->channel_info) {
6627*5113495bSYour Name 		qdf_mem_free(hdd_ctx->original_channels->channel_info);
6628*5113495bSYour Name 		hdd_ctx->original_channels->channel_info = NULL;
6629*5113495bSYour Name 	}
6630*5113495bSYour Name 	qdf_mem_free(hdd_ctx->original_channels);
6631*5113495bSYour Name 	hdd_ctx->original_channels = NULL;
6632*5113495bSYour Name 	qdf_mutex_release(&hdd_ctx->cache_channel_lock);
6633*5113495bSYour Name 
6634*5113495bSYour Name 	hdd_exit();
6635*5113495bSYour Name }
6636*5113495bSYour Name 
6637*5113495bSYour Name /**
6638*5113495bSYour Name  * hdd_alloc_chan_cache() - Allocate the memory to cache the channel
6639*5113495bSYour Name  * info for the channels received in command SET_DISABLE_CHANNEL_LIST
6640*5113495bSYour Name  * @hdd_ctx: Pointer to HDD context
6641*5113495bSYour Name  * @num_chan: Number of channels for which memory needs to
6642*5113495bSYour Name  * be allocated
6643*5113495bSYour Name  *
6644*5113495bSYour Name  * Return: 0 on success and error code on failure
6645*5113495bSYour Name  */
hdd_alloc_chan_cache(struct hdd_context * hdd_ctx,int num_chan)6646*5113495bSYour Name static int hdd_alloc_chan_cache(struct hdd_context *hdd_ctx, int num_chan)
6647*5113495bSYour Name {
6648*5113495bSYour Name 	hdd_ctx->original_channels =
6649*5113495bSYour Name 			qdf_mem_malloc(sizeof(struct hdd_cache_channels));
6650*5113495bSYour Name 	if (!hdd_ctx->original_channels)
6651*5113495bSYour Name 		return -ENOMEM;
6652*5113495bSYour Name 
6653*5113495bSYour Name 	hdd_ctx->original_channels->num_channels = num_chan;
6654*5113495bSYour Name 	hdd_ctx->original_channels->channel_info =
6655*5113495bSYour Name 					qdf_mem_malloc(num_chan *
6656*5113495bSYour Name 					sizeof(struct hdd_cache_channel_info));
6657*5113495bSYour Name 	if (!hdd_ctx->original_channels->channel_info) {
6658*5113495bSYour Name 		hdd_ctx->original_channels->num_channels = 0;
6659*5113495bSYour Name 		qdf_mem_free(hdd_ctx->original_channels);
6660*5113495bSYour Name 		hdd_ctx->original_channels = NULL;
6661*5113495bSYour Name 		return -ENOMEM;
6662*5113495bSYour Name 	}
6663*5113495bSYour Name 	return 0;
6664*5113495bSYour Name }
6665*5113495bSYour Name 
6666*5113495bSYour Name /**
6667*5113495bSYour Name  * check_disable_channels() - Check for disable channel
6668*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
6669*5113495bSYour Name  * @operating_freq: Current operating frequency of adapter
6670*5113495bSYour Name  *
6671*5113495bSYour Name  * This function checks original_channels array for a specific channel
6672*5113495bSYour Name  *
6673*5113495bSYour Name  * Return: 0 if channel not found, 1 if channel found
6674*5113495bSYour Name  */
check_disable_channels(struct hdd_context * hdd_ctx,qdf_freq_t operating_freq)6675*5113495bSYour Name static bool check_disable_channels(struct hdd_context *hdd_ctx,
6676*5113495bSYour Name 				   qdf_freq_t operating_freq)
6677*5113495bSYour Name {
6678*5113495bSYour Name 	uint32_t num_channels;
6679*5113495bSYour Name 	uint8_t i;
6680*5113495bSYour Name 	if (!hdd_ctx || !hdd_ctx->original_channels ||
6681*5113495bSYour Name 	    !hdd_ctx->original_channels->channel_info)
6682*5113495bSYour Name 		return false;
6683*5113495bSYour Name 
6684*5113495bSYour Name 	num_channels = hdd_ctx->original_channels->num_channels;
6685*5113495bSYour Name 	for (i = 0; i < num_channels; i++) {
6686*5113495bSYour Name 		if (operating_freq ==
6687*5113495bSYour Name 		    hdd_ctx->original_channels->channel_info[i].freq)
6688*5113495bSYour Name 			return true;
6689*5113495bSYour Name 	}
6690*5113495bSYour Name 
6691*5113495bSYour Name 	return false;
6692*5113495bSYour Name }
6693*5113495bSYour Name 
6694*5113495bSYour Name /**
6695*5113495bSYour Name  * disconnect_sta_and_restart_sap() - Disconnect STA and restart SAP
6696*5113495bSYour Name  *
6697*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
6698*5113495bSYour Name  * @reason: Disconnect reason code as per @enum wlan_reason_code
6699*5113495bSYour Name  *
6700*5113495bSYour Name  * Disable channels provided by user and disconnect STA if it is
6701*5113495bSYour Name  * connected to any AP, restart SAP.
6702*5113495bSYour Name  *
6703*5113495bSYour Name  * Return: None
6704*5113495bSYour Name  */
disconnect_sta_and_restart_sap(struct hdd_context * hdd_ctx,enum wlan_reason_code reason)6705*5113495bSYour Name static void disconnect_sta_and_restart_sap(struct hdd_context *hdd_ctx,
6706*5113495bSYour Name 					   enum wlan_reason_code reason)
6707*5113495bSYour Name {
6708*5113495bSYour Name 	struct hdd_adapter *adapter, *next = NULL;
6709*5113495bSYour Name 	QDF_STATUS status;
6710*5113495bSYour Name 	struct hdd_ap_ctx *ap_ctx;
6711*5113495bSYour Name 	uint32_t ch_list[NUM_CHANNELS];
6712*5113495bSYour Name 	uint32_t ch_count = 0;
6713*5113495bSYour Name 	bool is_valid_chan_present = true;
6714*5113495bSYour Name 
6715*5113495bSYour Name 	if (!hdd_ctx)
6716*5113495bSYour Name 		return;
6717*5113495bSYour Name 
6718*5113495bSYour Name 	hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx, reason);
6719*5113495bSYour Name 
6720*5113495bSYour Name 	status = policy_mgr_get_valid_chans(hdd_ctx->psoc, ch_list, &ch_count);
6721*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status) || !ch_count) {
6722*5113495bSYour Name 		hdd_debug("No valid channels present, stop the SAPs");
6723*5113495bSYour Name 		is_valid_chan_present = false;
6724*5113495bSYour Name 	}
6725*5113495bSYour Name 
6726*5113495bSYour Name 	status = hdd_get_front_adapter(hdd_ctx, &adapter);
6727*5113495bSYour Name 	while (adapter && (status == QDF_STATUS_SUCCESS)) {
6728*5113495bSYour Name 		if (hdd_validate_adapter(adapter) ||
6729*5113495bSYour Name 		    adapter->device_mode != QDF_SAP_MODE) {
6730*5113495bSYour Name 			goto next_adapter;
6731*5113495bSYour Name 		}
6732*5113495bSYour Name 
6733*5113495bSYour Name 		ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink);
6734*5113495bSYour Name 		if (!is_valid_chan_present)
6735*5113495bSYour Name 			wlan_hdd_stop_sap(adapter);
6736*5113495bSYour Name 		else if (check_disable_channels(hdd_ctx,
6737*5113495bSYour Name 						ap_ctx->operating_chan_freq))
6738*5113495bSYour Name 			policy_mgr_check_sap_restart(hdd_ctx->psoc,
6739*5113495bSYour Name 						     adapter->deflink->vdev_id);
6740*5113495bSYour Name next_adapter:
6741*5113495bSYour Name 		status = hdd_get_next_adapter(hdd_ctx, adapter, &next);
6742*5113495bSYour Name 		adapter = next;
6743*5113495bSYour Name 	}
6744*5113495bSYour Name }
6745*5113495bSYour Name 
6746*5113495bSYour Name /**
6747*5113495bSYour Name  * hdd_check_chan_and_fill_freq() - to validate chan and convert into freq
6748*5113495bSYour Name  * @pdev: The physical dev to cache the channels for
6749*5113495bSYour Name  * @in_chan: input as channel number or freq
6750*5113495bSYour Name  * @freq: frequency for input in_chan (output parameter)
6751*5113495bSYour Name  *
6752*5113495bSYour Name  * This function checks input "in_chan" is channel number, if yes then fills
6753*5113495bSYour Name  * appropriate frequency into "freq" out param. If the "in_param" is greater
6754*5113495bSYour Name  * than MAX_5GHZ_CHANNEL then gets the valid frequencies for legacy channels
6755*5113495bSYour Name  * else get the valid channel for 6Ghz frequency.
6756*5113495bSYour Name  *
6757*5113495bSYour Name  * Return: true if "in_chan" is valid channel/frequency; false otherwise
6758*5113495bSYour Name  */
hdd_check_chan_and_fill_freq(struct wlan_objmgr_pdev * pdev,uint32_t * in_chan,qdf_freq_t * freq)6759*5113495bSYour Name static bool hdd_check_chan_and_fill_freq(struct wlan_objmgr_pdev *pdev,
6760*5113495bSYour Name 					 uint32_t *in_chan, qdf_freq_t *freq)
6761*5113495bSYour Name {
6762*5113495bSYour Name 	if (IS_CHANNEL_VALID(*in_chan)) {
6763*5113495bSYour Name 		*freq = wlan_reg_legacy_chan_to_freq(pdev, *in_chan);
6764*5113495bSYour Name 	} else if (WLAN_REG_IS_24GHZ_CH_FREQ(*in_chan) ||
6765*5113495bSYour Name 		   WLAN_REG_IS_5GHZ_CH_FREQ(*in_chan) ||
6766*5113495bSYour Name 		   WLAN_REG_IS_6GHZ_CHAN_FREQ(*in_chan)) {
6767*5113495bSYour Name 		*freq = *in_chan;
6768*5113495bSYour Name 		*in_chan = wlan_reg_freq_to_chan(pdev, *in_chan);
6769*5113495bSYour Name 	} else {
6770*5113495bSYour Name 		return false;
6771*5113495bSYour Name 	}
6772*5113495bSYour Name 
6773*5113495bSYour Name 	return true;
6774*5113495bSYour Name }
6775*5113495bSYour Name 
6776*5113495bSYour Name /**
6777*5113495bSYour Name  * hdd_parse_disable_chan_cmd() - Parse the channel list received
6778*5113495bSYour Name  * in command.
6779*5113495bSYour Name  * @adapter: pointer to hdd adapter
6780*5113495bSYour Name  * @ptr: Pointer to the command string
6781*5113495bSYour Name  *
6782*5113495bSYour Name  * This function parses the channel list/frequency received in the command.
6783*5113495bSYour Name  * command should be a string having format
6784*5113495bSYour Name  * SET_DISABLE_CHANNEL_LIST <num of channels>
6785*5113495bSYour Name  * <channels separated by spaces>/<frequency separated by spaces>.
6786*5113495bSYour Name  * If this command has frequency as input, this function first converts into
6787*5113495bSYour Name  * equivalent channel.
6788*5113495bSYour Name  * If the command comes multiple times then the channels received in the
6789*5113495bSYour Name  * command or channels converted from frequency will be compared with the
6790*5113495bSYour Name  * channels cached in the first command, if the channel list matches with
6791*5113495bSYour Name  * the cached channels, it returns success otherwise returns failure.
6792*5113495bSYour Name  *
6793*5113495bSYour Name  * Return: 0 on success, Error code on failure
6794*5113495bSYour Name  */
6795*5113495bSYour Name 
hdd_parse_disable_chan_cmd(struct hdd_adapter * adapter,uint8_t * ptr)6796*5113495bSYour Name static int hdd_parse_disable_chan_cmd(struct hdd_adapter *adapter, uint8_t *ptr)
6797*5113495bSYour Name {
6798*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6799*5113495bSYour Name 	uint8_t *param;
6800*5113495bSYour Name 	int j, i, temp_int, ret = 0, num_channels;
6801*5113495bSYour Name 	qdf_freq_t *chan_freq_list = NULL;
6802*5113495bSYour Name 	bool is_command_repeated = false;
6803*5113495bSYour Name 	qdf_freq_t freq = 0;
6804*5113495bSYour Name 
6805*5113495bSYour Name 	if (!hdd_ctx) {
6806*5113495bSYour Name 		hdd_err("HDD Context is NULL");
6807*5113495bSYour Name 		return -EINVAL;
6808*5113495bSYour Name 	}
6809*5113495bSYour Name 
6810*5113495bSYour Name 	param = strnchr(ptr, strlen(ptr), ' ');
6811*5113495bSYour Name 	/*no argument after the command*/
6812*5113495bSYour Name 	if (!param)
6813*5113495bSYour Name 		return -EINVAL;
6814*5113495bSYour Name 
6815*5113495bSYour Name 	/*no space after the command*/
6816*5113495bSYour Name 	else if (SPACE_ASCII_VALUE != *param)
6817*5113495bSYour Name 		return -EINVAL;
6818*5113495bSYour Name 
6819*5113495bSYour Name 	param++;
6820*5113495bSYour Name 
6821*5113495bSYour Name 	/*removing empty spaces*/
6822*5113495bSYour Name 	while ((SPACE_ASCII_VALUE  == *param) && ('\0' !=  *param))
6823*5113495bSYour Name 		param++;
6824*5113495bSYour Name 
6825*5113495bSYour Name 	/*no argument followed by spaces*/
6826*5113495bSYour Name 	if ('\0' == *param)
6827*5113495bSYour Name 		return -EINVAL;
6828*5113495bSYour Name 
6829*5113495bSYour Name 	/*getting the first argument ie the number of channels*/
6830*5113495bSYour Name 	if (sscanf(param, "%d ", &temp_int) != 1) {
6831*5113495bSYour Name 		hdd_err("Cannot get number of channels from input");
6832*5113495bSYour Name 		return -EINVAL;
6833*5113495bSYour Name 	}
6834*5113495bSYour Name 
6835*5113495bSYour Name 	if (temp_int < 0 || temp_int > NUM_CHANNELS) {
6836*5113495bSYour Name 		hdd_err("Invalid Number of channel received");
6837*5113495bSYour Name 		return -EINVAL;
6838*5113495bSYour Name 	}
6839*5113495bSYour Name 
6840*5113495bSYour Name 	hdd_debug("Number of channel to disable are: %d", temp_int);
6841*5113495bSYour Name 
6842*5113495bSYour Name 	if (!temp_int) {
6843*5113495bSYour Name 		/*
6844*5113495bSYour Name 		 * Restore and Free the cache channels when the command is
6845*5113495bSYour Name 		 * received with num channels as 0
6846*5113495bSYour Name 		 */
6847*5113495bSYour Name 		wlan_hdd_restore_channels(hdd_ctx);
6848*5113495bSYour Name 		return 0;
6849*5113495bSYour Name 	}
6850*5113495bSYour Name 
6851*5113495bSYour Name 	qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
6852*5113495bSYour Name 
6853*5113495bSYour Name 	if (!hdd_ctx->original_channels) {
6854*5113495bSYour Name 		if (hdd_alloc_chan_cache(hdd_ctx, temp_int)) {
6855*5113495bSYour Name 			ret = -ENOMEM;
6856*5113495bSYour Name 			goto mem_alloc_failed;
6857*5113495bSYour Name 		}
6858*5113495bSYour Name 	} else if (hdd_ctx->original_channels->num_channels != temp_int) {
6859*5113495bSYour Name 		hdd_err("Invalid Number of channels");
6860*5113495bSYour Name 		ret = -EINVAL;
6861*5113495bSYour Name 		is_command_repeated = true;
6862*5113495bSYour Name 		goto parse_failed;
6863*5113495bSYour Name 	} else {
6864*5113495bSYour Name 		is_command_repeated = true;
6865*5113495bSYour Name 	}
6866*5113495bSYour Name 	num_channels = temp_int;
6867*5113495bSYour Name 
6868*5113495bSYour Name 	chan_freq_list = qdf_mem_malloc(num_channels * sizeof(qdf_freq_t));
6869*5113495bSYour Name 	if (!chan_freq_list)
6870*5113495bSYour Name 		return -ENOMEM;
6871*5113495bSYour Name 
6872*5113495bSYour Name 	for (j = 0; j < num_channels; j++) {
6873*5113495bSYour Name 		/*
6874*5113495bSYour Name 		 * param pointing to the beginning of first space
6875*5113495bSYour Name 		 * after number of channels
6876*5113495bSYour Name 		 */
6877*5113495bSYour Name 		param = strpbrk(param, " ");
6878*5113495bSYour Name 		/*no channel list after the number of channels argument*/
6879*5113495bSYour Name 		if (!param) {
6880*5113495bSYour Name 			hdd_err("Invalid No of channel provided in the list");
6881*5113495bSYour Name 			ret = -EINVAL;
6882*5113495bSYour Name 			goto parse_failed;
6883*5113495bSYour Name 		}
6884*5113495bSYour Name 
6885*5113495bSYour Name 		param++;
6886*5113495bSYour Name 
6887*5113495bSYour Name 		/*removing empty space*/
6888*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
6889*5113495bSYour Name 			param++;
6890*5113495bSYour Name 
6891*5113495bSYour Name 		if ('\0' == *param) {
6892*5113495bSYour Name 			hdd_err("No channel is provided in the list");
6893*5113495bSYour Name 			ret = -EINVAL;
6894*5113495bSYour Name 			goto parse_failed;
6895*5113495bSYour Name 		}
6896*5113495bSYour Name 
6897*5113495bSYour Name 		if (sscanf(param, "%d ", &temp_int) != 1) {
6898*5113495bSYour Name 			hdd_err("Cannot read channel number");
6899*5113495bSYour Name 			ret = -EINVAL;
6900*5113495bSYour Name 			goto parse_failed;
6901*5113495bSYour Name 		}
6902*5113495bSYour Name 
6903*5113495bSYour Name 		if (!hdd_check_chan_and_fill_freq(hdd_ctx->pdev, &temp_int,
6904*5113495bSYour Name 						  &freq)) {
6905*5113495bSYour Name 			hdd_err("Invalid channel number received");
6906*5113495bSYour Name 			ret = -EINVAL;
6907*5113495bSYour Name 			goto parse_failed;
6908*5113495bSYour Name 		}
6909*5113495bSYour Name 
6910*5113495bSYour Name 		hdd_debug("channel[%d] = %d Frequency[%d] = %d", j, temp_int,
6911*5113495bSYour Name 			  j, freq);
6912*5113495bSYour Name 		chan_freq_list[j] = freq;
6913*5113495bSYour Name 	}
6914*5113495bSYour Name 
6915*5113495bSYour Name 	/*extra arguments check*/
6916*5113495bSYour Name 	param = strpbrk(param, " ");
6917*5113495bSYour Name 	if (param) {
6918*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
6919*5113495bSYour Name 			param++;
6920*5113495bSYour Name 
6921*5113495bSYour Name 		if ('\0' !=  *param) {
6922*5113495bSYour Name 			hdd_err("Invalid argument received");
6923*5113495bSYour Name 			ret = -EINVAL;
6924*5113495bSYour Name 			goto parse_failed;
6925*5113495bSYour Name 		}
6926*5113495bSYour Name 	}
6927*5113495bSYour Name 
6928*5113495bSYour Name 	/*
6929*5113495bSYour Name 	 * If command is received first time, cache the channels to
6930*5113495bSYour Name 	 * be disabled else compare the channels received in the
6931*5113495bSYour Name 	 * command with the cached channels, if channel list matches
6932*5113495bSYour Name 	 * return success otherwise return failure.
6933*5113495bSYour Name 	 */
6934*5113495bSYour Name 	if (!is_command_repeated) {
6935*5113495bSYour Name 		for (j = 0; j < num_channels; j++)
6936*5113495bSYour Name 			hdd_ctx->original_channels->channel_info[j].freq =
6937*5113495bSYour Name 							chan_freq_list[j];
6938*5113495bSYour Name 
6939*5113495bSYour Name 		/* Cache the channel list in regulatory also */
6940*5113495bSYour Name 		ucfg_reg_cache_channel_freq_state(hdd_ctx->pdev,
6941*5113495bSYour Name 						  chan_freq_list,
6942*5113495bSYour Name 						  num_channels);
6943*5113495bSYour Name 	} else {
6944*5113495bSYour Name 		for (i = 0; i < num_channels; i++) {
6945*5113495bSYour Name 			for (j = 0; j < num_channels; j++)
6946*5113495bSYour Name 				if (hdd_ctx->original_channels->
6947*5113495bSYour Name 					channel_info[i].freq ==
6948*5113495bSYour Name 							chan_freq_list[j])
6949*5113495bSYour Name 					break;
6950*5113495bSYour Name 			if (j == num_channels) {
6951*5113495bSYour Name 				ret = -EINVAL;
6952*5113495bSYour Name 				goto parse_failed;
6953*5113495bSYour Name 			}
6954*5113495bSYour Name 		}
6955*5113495bSYour Name 		ret = 0;
6956*5113495bSYour Name 	}
6957*5113495bSYour Name mem_alloc_failed:
6958*5113495bSYour Name 	if (chan_freq_list)
6959*5113495bSYour Name 		qdf_mem_free(chan_freq_list);
6960*5113495bSYour Name 	qdf_mutex_release(&hdd_ctx->cache_channel_lock);
6961*5113495bSYour Name 	/* Disable the channels received in command SET_DISABLE_CHANNEL_LIST */
6962*5113495bSYour Name 	if (!is_command_repeated && hdd_ctx->original_channels) {
6963*5113495bSYour Name 		ret = wlan_hdd_disable_channels(hdd_ctx);
6964*5113495bSYour Name 		if (ret)
6965*5113495bSYour Name 			return ret;
6966*5113495bSYour Name 		disconnect_sta_and_restart_sap(
6967*5113495bSYour Name 					hdd_ctx,
6968*5113495bSYour Name 					REASON_OPER_CHANNEL_BAND_CHANGE);
6969*5113495bSYour Name 	}
6970*5113495bSYour Name 
6971*5113495bSYour Name 	hdd_exit();
6972*5113495bSYour Name 
6973*5113495bSYour Name 	return ret;
6974*5113495bSYour Name 
6975*5113495bSYour Name parse_failed:
6976*5113495bSYour Name 	if (!is_command_repeated)
6977*5113495bSYour Name 		wlan_hdd_free_cache_channels(hdd_ctx);
6978*5113495bSYour Name 
6979*5113495bSYour Name 	if (chan_freq_list)
6980*5113495bSYour Name 		qdf_mem_free(chan_freq_list);
6981*5113495bSYour Name 	qdf_mutex_release(&hdd_ctx->cache_channel_lock);
6982*5113495bSYour Name 	hdd_exit();
6983*5113495bSYour Name 
6984*5113495bSYour Name 	return ret;
6985*5113495bSYour Name }
6986*5113495bSYour Name 
drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6987*5113495bSYour Name static int drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info *link_info,
6988*5113495bSYour Name 					 struct hdd_context *hdd_ctx,
6989*5113495bSYour Name 					 uint8_t *command,
6990*5113495bSYour Name 					 uint8_t command_len,
6991*5113495bSYour Name 					 struct hdd_priv_data *priv_data)
6992*5113495bSYour Name {
6993*5113495bSYour Name 	return hdd_parse_disable_chan_cmd(link_info->adapter, command);
6994*5113495bSYour Name }
6995*5113495bSYour Name 
6996*5113495bSYour Name /**
6997*5113495bSYour Name  * hdd_get_disable_ch_list() - get disable channel list
6998*5113495bSYour Name  * @hdd_ctx: hdd context
6999*5113495bSYour Name  * @buf: buffer to hold disable channel list
7000*5113495bSYour Name  * @buf_len: buffer length
7001*5113495bSYour Name  *
7002*5113495bSYour Name  * Return: length of data copied to buf
7003*5113495bSYour Name  */
hdd_get_disable_ch_list(struct hdd_context * hdd_ctx,uint8_t * buf,uint32_t buf_len)7004*5113495bSYour Name static int hdd_get_disable_ch_list(struct hdd_context *hdd_ctx, uint8_t *buf,
7005*5113495bSYour Name 				   uint32_t buf_len)
7006*5113495bSYour Name {
7007*5113495bSYour Name 	struct hdd_cache_channel_info *ch_list;
7008*5113495bSYour Name 	unsigned char i, num_ch;
7009*5113495bSYour Name 	int len = 0;
7010*5113495bSYour Name 
7011*5113495bSYour Name 	qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7012*5113495bSYour Name 	if (hdd_ctx->original_channels &&
7013*5113495bSYour Name 	    hdd_ctx->original_channels->num_channels &&
7014*5113495bSYour Name 	    hdd_ctx->original_channels->channel_info) {
7015*5113495bSYour Name 		num_ch = hdd_ctx->original_channels->num_channels;
7016*5113495bSYour Name 
7017*5113495bSYour Name 		len = scnprintf(buf, buf_len, "%s %hhu",
7018*5113495bSYour Name 				"GET_DISABLE_CHANNEL_LIST", num_ch);
7019*5113495bSYour Name 		ch_list = hdd_ctx->original_channels->channel_info;
7020*5113495bSYour Name 		for (i = 0; (i < num_ch) && (len < buf_len - 1); i++) {
7021*5113495bSYour Name 			len += scnprintf(buf + len, buf_len - len,
7022*5113495bSYour Name 					 " %d",
7023*5113495bSYour Name 					 wlan_reg_freq_to_chan(hdd_ctx->pdev,
7024*5113495bSYour Name 							      ch_list[i].freq));
7025*5113495bSYour Name 		}
7026*5113495bSYour Name 	}
7027*5113495bSYour Name 	qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7028*5113495bSYour Name 
7029*5113495bSYour Name 	return len;
7030*5113495bSYour Name }
7031*5113495bSYour Name 
drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7032*5113495bSYour Name static int drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info *link_info,
7033*5113495bSYour Name 					 struct hdd_context *hdd_ctx,
7034*5113495bSYour Name 					 uint8_t *command, uint8_t command_len,
7035*5113495bSYour Name 					 struct hdd_priv_data *priv_data)
7036*5113495bSYour Name {
7037*5113495bSYour Name 	char extra[512] = {0};
7038*5113495bSYour Name 	int max_len, copied_length;
7039*5113495bSYour Name 
7040*5113495bSYour Name 	hdd_debug("Received Command to get disable Channels list");
7041*5113495bSYour Name 
7042*5113495bSYour Name 	max_len = QDF_MIN(priv_data->total_len, sizeof(extra));
7043*5113495bSYour Name 	copied_length = hdd_get_disable_ch_list(hdd_ctx, extra, max_len);
7044*5113495bSYour Name 	if (copied_length == 0) {
7045*5113495bSYour Name 		hdd_err("disable channel list is not yet programmed");
7046*5113495bSYour Name 		return -EINVAL;
7047*5113495bSYour Name 	}
7048*5113495bSYour Name 
7049*5113495bSYour Name 	if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
7050*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
7051*5113495bSYour Name 		return -EFAULT;
7052*5113495bSYour Name 	}
7053*5113495bSYour Name 
7054*5113495bSYour Name 	hdd_debug("data:%s", extra);
7055*5113495bSYour Name 	return 0;
7056*5113495bSYour Name }
7057*5113495bSYour Name #else
7058*5113495bSYour Name 
7059*5113495bSYour Name static inline int
drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7060*5113495bSYour Name drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info *link_info,
7061*5113495bSYour Name 			      struct hdd_context *hdd_ctx,
7062*5113495bSYour Name 			      uint8_t *command, uint8_t command_len,
7063*5113495bSYour Name 			      struct hdd_priv_data *priv_data)
7064*5113495bSYour Name {
7065*5113495bSYour Name 	return 0;
7066*5113495bSYour Name }
7067*5113495bSYour Name 
wlan_hdd_free_cache_channels(struct hdd_context * hdd_ctx)7068*5113495bSYour Name void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7069*5113495bSYour Name {
7070*5113495bSYour Name }
7071*5113495bSYour Name 
7072*5113495bSYour Name static inline int
drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7073*5113495bSYour Name drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info *link_info,
7074*5113495bSYour Name 			      struct hdd_context *hdd_ctx,
7075*5113495bSYour Name 			      uint8_t *command, uint8_t command_len,
7076*5113495bSYour Name 			      struct hdd_priv_data *priv_data)
7077*5113495bSYour Name {
7078*5113495bSYour Name 	return 0;
7079*5113495bSYour Name }
7080*5113495bSYour Name #endif
7081*5113495bSYour Name 
7082*5113495bSYour Name #ifdef FEATURE_ANI_LEVEL_REQUEST
drv_cmd_get_ani_level(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7083*5113495bSYour Name static int drv_cmd_get_ani_level(struct wlan_hdd_link_info *link_info,
7084*5113495bSYour Name 				 struct hdd_context *hdd_ctx,
7085*5113495bSYour Name 				 uint8_t *command, uint8_t command_len,
7086*5113495bSYour Name 				 struct hdd_priv_data *priv_data)
7087*5113495bSYour Name {
7088*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
7089*5113495bSYour Name 	char *extra;
7090*5113495bSYour Name 	int copied_length = 0, j, temp_int, ret = 0;
7091*5113495bSYour Name 	uint8_t *param, num_freqs, num_recv_channels;
7092*5113495bSYour Name 	uint32_t parsed_freqs[MAX_NUM_FREQS_FOR_ANI_LEVEL];
7093*5113495bSYour Name 	struct wmi_host_ani_level_event ani[MAX_NUM_FREQS_FOR_ANI_LEVEL];
7094*5113495bSYour Name 	size_t user_size = priv_data->total_len;
7095*5113495bSYour Name 
7096*5113495bSYour Name 	hdd_debug("Received Command to get ANI level");
7097*5113495bSYour Name 
7098*5113495bSYour Name 	param = strnchr(command, strlen(command), ' ');
7099*5113495bSYour Name 
7100*5113495bSYour Name 	/* No argument after the command */
7101*5113495bSYour Name 	if (!param)
7102*5113495bSYour Name 		return -EINVAL;
7103*5113495bSYour Name 
7104*5113495bSYour Name 	/* No space after the command */
7105*5113495bSYour Name 	else if (SPACE_ASCII_VALUE != *param)
7106*5113495bSYour Name 		return -EINVAL;
7107*5113495bSYour Name 
7108*5113495bSYour Name 	param++;
7109*5113495bSYour Name 
7110*5113495bSYour Name 	/* Removing empty spaces*/
7111*5113495bSYour Name 	while ((SPACE_ASCII_VALUE  == *param) && ('\0' !=  *param))
7112*5113495bSYour Name 		param++;
7113*5113495bSYour Name 
7114*5113495bSYour Name 	/*no argument followed by spaces */
7115*5113495bSYour Name 	if ('\0' == *param)
7116*5113495bSYour Name 		return -EINVAL;
7117*5113495bSYour Name 
7118*5113495bSYour Name 	/* Getting the first argument ie the number of channels */
7119*5113495bSYour Name 	if (sscanf(param, "%d ", &temp_int) != 1) {
7120*5113495bSYour Name 		hdd_err("Cannot get number of freq from input");
7121*5113495bSYour Name 		return -EINVAL;
7122*5113495bSYour Name 	}
7123*5113495bSYour Name 
7124*5113495bSYour Name 	if (temp_int < 0 || temp_int > MAX_NUM_FREQS_FOR_ANI_LEVEL) {
7125*5113495bSYour Name 		hdd_err("Invalid Number of channel received");
7126*5113495bSYour Name 		return -EINVAL;
7127*5113495bSYour Name 	}
7128*5113495bSYour Name 
7129*5113495bSYour Name 	hdd_debug("Number of freq to fetch ANI level are: %d", temp_int);
7130*5113495bSYour Name 
7131*5113495bSYour Name 	if (!temp_int)
7132*5113495bSYour Name 		return 0;
7133*5113495bSYour Name 
7134*5113495bSYour Name 	num_freqs = temp_int;
7135*5113495bSYour Name 
7136*5113495bSYour Name 	for (j = 0; j < num_freqs; j++) {
7137*5113495bSYour Name 		/*
7138*5113495bSYour Name 		 * Param pointing to the beginning of first space
7139*5113495bSYour Name 		 * after number of channels.
7140*5113495bSYour Name 		 */
7141*5113495bSYour Name 		param = strpbrk(param, " ");
7142*5113495bSYour Name 		/*no channel list after the number of channels argument*/
7143*5113495bSYour Name 		if (!param) {
7144*5113495bSYour Name 			hdd_err("Invalid No of freq provided in the list");
7145*5113495bSYour Name 			ret = -EINVAL;
7146*5113495bSYour Name 			goto parse_failed;
7147*5113495bSYour Name 		}
7148*5113495bSYour Name 
7149*5113495bSYour Name 		param++;
7150*5113495bSYour Name 
7151*5113495bSYour Name 		/* Removing empty space */
7152*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7153*5113495bSYour Name 			param++;
7154*5113495bSYour Name 
7155*5113495bSYour Name 		if ('\0' == *param) {
7156*5113495bSYour Name 			hdd_err("No freq is provided in the list");
7157*5113495bSYour Name 			ret = -EINVAL;
7158*5113495bSYour Name 			goto parse_failed;
7159*5113495bSYour Name 		}
7160*5113495bSYour Name 
7161*5113495bSYour Name 		if (sscanf(param, "%d ", &temp_int) != 1) {
7162*5113495bSYour Name 			hdd_err("Cannot read freq number");
7163*5113495bSYour Name 			ret = -EINVAL;
7164*5113495bSYour Name 			goto parse_failed;
7165*5113495bSYour Name 		}
7166*5113495bSYour Name 
7167*5113495bSYour Name 		hdd_debug("channel_freq[%d] = %d", j, temp_int);
7168*5113495bSYour Name 		parsed_freqs[j] = temp_int;
7169*5113495bSYour Name 	}
7170*5113495bSYour Name 
7171*5113495bSYour Name 	/* Extra arguments check */
7172*5113495bSYour Name 	param = strpbrk(param, " ");
7173*5113495bSYour Name 	if (param) {
7174*5113495bSYour Name 		while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7175*5113495bSYour Name 			param++;
7176*5113495bSYour Name 
7177*5113495bSYour Name 		if ('\0' !=  *param) {
7178*5113495bSYour Name 			hdd_err("Invalid argument received");
7179*5113495bSYour Name 			ret = -EINVAL;
7180*5113495bSYour Name 			goto parse_failed;
7181*5113495bSYour Name 		}
7182*5113495bSYour Name 	}
7183*5113495bSYour Name 
7184*5113495bSYour Name 	qdf_mem_zero(ani, sizeof(ani));
7185*5113495bSYour Name 	hdd_debug("num_freq: %d", num_freqs);
7186*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(wlan_hdd_get_ani_level(adapter, ani,
7187*5113495bSYour Name 						       parsed_freqs,
7188*5113495bSYour Name 						       num_freqs))) {
7189*5113495bSYour Name 		hdd_err("Unable to retrieve ani level");
7190*5113495bSYour Name 		return -EINVAL;
7191*5113495bSYour Name 	}
7192*5113495bSYour Name 
7193*5113495bSYour Name 	extra = qdf_mem_malloc(user_size);
7194*5113495bSYour Name 	if (!extra) {
7195*5113495bSYour Name 		ret = -ENOMEM;
7196*5113495bSYour Name 		goto parse_failed;
7197*5113495bSYour Name 	}
7198*5113495bSYour Name 
7199*5113495bSYour Name 	/*
7200*5113495bSYour Name 	 * Find the number of channels that are populated. If freq is not
7201*5113495bSYour Name 	 * filled then stop count there
7202*5113495bSYour Name 	 */
7203*5113495bSYour Name 	for (num_recv_channels = 0;
7204*5113495bSYour Name 	     (num_recv_channels < num_freqs &&
7205*5113495bSYour Name 	     ani[num_recv_channels].chan_freq); num_recv_channels++)
7206*5113495bSYour Name 		;
7207*5113495bSYour Name 
7208*5113495bSYour Name 	for (j = 0; j < num_recv_channels; j++) {
7209*5113495bSYour Name 		/* Sanity check for ANI level validity */
7210*5113495bSYour Name 		if (ani[j].ani_level > MAX_ANI_LEVEL)
7211*5113495bSYour Name 			continue;
7212*5113495bSYour Name 
7213*5113495bSYour Name 		copied_length += scnprintf(extra + copied_length,
7214*5113495bSYour Name 					   user_size - copied_length, "%d:%d\n",
7215*5113495bSYour Name 					   ani[j].chan_freq, ani[j].ani_level);
7216*5113495bSYour Name 	}
7217*5113495bSYour Name 
7218*5113495bSYour Name 	if (copied_length == 0) {
7219*5113495bSYour Name 		hdd_err("ANI level not fetched");
7220*5113495bSYour Name 		ret = -EINVAL;
7221*5113495bSYour Name 		goto free;
7222*5113495bSYour Name 	}
7223*5113495bSYour Name 
7224*5113495bSYour Name 	hdd_debug("data: %s", extra);
7225*5113495bSYour Name 
7226*5113495bSYour Name 	if (copy_to_user(priv_data->buf, extra, copied_length + 1)) {
7227*5113495bSYour Name 		hdd_err("failed to copy data to user buffer");
7228*5113495bSYour Name 		ret = -EFAULT;
7229*5113495bSYour Name 		goto free;
7230*5113495bSYour Name 	}
7231*5113495bSYour Name 
7232*5113495bSYour Name free:
7233*5113495bSYour Name 	qdf_mem_free(extra);
7234*5113495bSYour Name 
7235*5113495bSYour Name parse_failed:
7236*5113495bSYour Name 	return ret;
7237*5113495bSYour Name }
7238*5113495bSYour Name 
7239*5113495bSYour Name #else
drv_cmd_get_ani_level(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7240*5113495bSYour Name static inline int drv_cmd_get_ani_level(struct wlan_hdd_link_info *link_info,
7241*5113495bSYour Name 					struct hdd_context *hdd_ctx,
7242*5113495bSYour Name 					uint8_t *command, uint8_t command_len,
7243*5113495bSYour Name 					struct hdd_priv_data *priv_data)
7244*5113495bSYour Name {
7245*5113495bSYour Name 	return 0;
7246*5113495bSYour Name }
7247*5113495bSYour Name #endif
7248*5113495bSYour Name 
7249*5113495bSYour Name #ifdef FUNC_CALL_MAP
drv_cmd_get_function_call_map(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7250*5113495bSYour Name static int drv_cmd_get_function_call_map(struct wlan_hdd_link_info *link_info,
7251*5113495bSYour Name 					 struct hdd_context *hdd_ctx,
7252*5113495bSYour Name 					 uint8_t *command,
7253*5113495bSYour Name 					 uint8_t command_len,
7254*5113495bSYour Name 					 struct hdd_priv_data *priv_data)
7255*5113495bSYour Name {
7256*5113495bSYour Name 	char *cc_buf = qdf_mem_malloc(QDF_FUNCTION_CALL_MAP_BUF_LEN);
7257*5113495bSYour Name 	uint8_t *param;
7258*5113495bSYour Name 	int temp_int;
7259*5113495bSYour Name 
7260*5113495bSYour Name 	param = strnchr(command, strlen(command), ' ');
7261*5113495bSYour Name 	/*no argument after the command*/
7262*5113495bSYour Name 	if (NULL == param)
7263*5113495bSYour Name 		return -EINVAL;
7264*5113495bSYour Name 
7265*5113495bSYour Name 	/*no space after the command*/
7266*5113495bSYour Name 	else if (SPACE_ASCII_VALUE != *param)
7267*5113495bSYour Name 		return -EINVAL;
7268*5113495bSYour Name 
7269*5113495bSYour Name 	param++;
7270*5113495bSYour Name 
7271*5113495bSYour Name 	/*removing empty spaces*/
7272*5113495bSYour Name 	while ((SPACE_ASCII_VALUE  == *param) && ('\0' !=  *param))
7273*5113495bSYour Name 		param++;
7274*5113495bSYour Name 
7275*5113495bSYour Name 	/*no argument followed by spaces*/
7276*5113495bSYour Name 	if ('\0' == *param)
7277*5113495bSYour Name 		return -EINVAL;
7278*5113495bSYour Name 
7279*5113495bSYour Name 	/*getting the first argument */
7280*5113495bSYour Name 	if (sscanf(param, "%d ", &temp_int) != 1) {
7281*5113495bSYour Name 		hdd_err("No option given");
7282*5113495bSYour Name 		return -EINVAL;
7283*5113495bSYour Name 	}
7284*5113495bSYour Name 
7285*5113495bSYour Name 	if (temp_int < 0 || temp_int > 1) {
7286*5113495bSYour Name 		hdd_err("Invalid option given");
7287*5113495bSYour Name 		return -EINVAL;
7288*5113495bSYour Name 	}
7289*5113495bSYour Name 
7290*5113495bSYour Name 	/* Read the buffer */
7291*5113495bSYour Name 	if (temp_int) {
7292*5113495bSYour Name 	/*
7293*5113495bSYour Name 	 * These logs are required as these indicates the start and end of the
7294*5113495bSYour Name 	 * dump for the auto script to parse
7295*5113495bSYour Name 	 */
7296*5113495bSYour Name 		hdd_info("Function call map dump start");
7297*5113495bSYour Name 		qdf_get_func_call_map(cc_buf);
7298*5113495bSYour Name 		qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
7299*5113495bSYour Name 				   cc_buf, QDF_FUNCTION_CALL_MAP_BUF_LEN);
7300*5113495bSYour Name 		hdd_info("Function call map dump end");
7301*5113495bSYour Name 	} else {
7302*5113495bSYour Name 		qdf_clear_func_call_map();
7303*5113495bSYour Name 		hdd_info("Function call map clear");
7304*5113495bSYour Name 	}
7305*5113495bSYour Name 	qdf_mem_free(cc_buf);
7306*5113495bSYour Name 
7307*5113495bSYour Name 	return 0;
7308*5113495bSYour Name }
7309*5113495bSYour Name #endif
7310*5113495bSYour Name 
7311*5113495bSYour Name /*
7312*5113495bSYour Name  * The following table contains all supported WLAN HDD
7313*5113495bSYour Name  * IOCTL driver commands and the handler for each of them.
7314*5113495bSYour Name  */
7315*5113495bSYour Name static const struct hdd_drv_cmd hdd_drv_cmds[] = {
7316*5113495bSYour Name 	{"P2P_DEV_ADDR",              drv_cmd_p2p_dev_addr, false},
7317*5113495bSYour Name 	{"P2P_SET_NOA",               drv_cmd_p2p_set_noa, true},
7318*5113495bSYour Name 	{"P2P_SET_PS",                drv_cmd_p2p_set_ps, true},
7319*5113495bSYour Name 	{"SETBAND",                   drv_cmd_set_band, true},
7320*5113495bSYour Name 	{"SETWMMPS",                  drv_cmd_set_wmmps, true},
7321*5113495bSYour Name 	{"COUNTRY",                   drv_cmd_country, true},
7322*5113495bSYour Name 	{"SETCOUNTRYREV",             drv_cmd_country, true},
7323*5113495bSYour Name 	{"GETCOUNTRYREV",             drv_cmd_get_country, false},
7324*5113495bSYour Name 	{"SETSUSPENDMODE",            drv_cmd_set_suspend_mode, true},
7325*5113495bSYour Name 	{"SET_AP_WPS_P2P_IE",         drv_cmd_dummy, false},
7326*5113495bSYour Name 	{"SETROAMTRIGGER",            drv_cmd_set_roam_trigger, true},
7327*5113495bSYour Name 	{"GETROAMTRIGGER",            drv_cmd_get_roam_trigger, false},
7328*5113495bSYour Name 	{"SETROAMSCANPERIOD",         drv_cmd_set_roam_scan_period, true},
7329*5113495bSYour Name 	{"GETROAMSCANPERIOD",         drv_cmd_get_roam_scan_period, false},
7330*5113495bSYour Name 	{"SETROAMSCANREFRESHPERIOD",  drv_cmd_set_roam_scan_refresh_period,
7331*5113495bSYour Name 	 true},
7332*5113495bSYour Name 	{"GETROAMSCANREFRESHPERIOD",  drv_cmd_get_roam_scan_refresh_period,
7333*5113495bSYour Name 	 false},
7334*5113495bSYour Name 	{"SETROAMMODE",               drv_cmd_set_roam_mode, true},
7335*5113495bSYour Name 	{"GETROAMMODE",               drv_cmd_get_roam_mode, false},
7336*5113495bSYour Name 	{"SETROAMDELTA",              drv_cmd_set_roam_delta, true},
7337*5113495bSYour Name 	{"GETROAMDELTA",              drv_cmd_get_roam_delta, false},
7338*5113495bSYour Name 	{"GETBAND",                   drv_cmd_get_band, false},
7339*5113495bSYour Name 	{"GETCCXMODE",                drv_cmd_get_ccx_mode, false},
7340*5113495bSYour Name 	{"GETOKCMODE",                drv_cmd_get_okc_mode, false},
7341*5113495bSYour Name 	{"GETFASTROAM",               drv_cmd_get_fast_roam, false},
7342*5113495bSYour Name 	{"GETFASTTRANSITION",         drv_cmd_get_fast_transition, false},
7343*5113495bSYour Name 	{"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
7344*5113495bSYour Name 	 true},
7345*5113495bSYour Name 	{"SENDACTIONFRAME",           drv_cmd_send_action_frame, true},
7346*5113495bSYour Name 	{"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
7347*5113495bSYour Name 	 false},
7348*5113495bSYour Name 	{"SETSCANCHANNELTIME",        drv_cmd_set_scan_channel_time, true},
7349*5113495bSYour Name 	{"GETSCANCHANNELTIME",        drv_cmd_get_scan_channel_time, false},
7350*5113495bSYour Name 	{"SETSCANHOMETIME",           drv_cmd_set_scan_home_time, true},
7351*5113495bSYour Name 	{"GETSCANHOMETIME",           drv_cmd_get_scan_home_time, false},
7352*5113495bSYour Name 	{"SETROAMINTRABAND",          drv_cmd_set_roam_intra_band, true},
7353*5113495bSYour Name 	{"GETROAMINTRABAND",          drv_cmd_get_roam_intra_band, false},
7354*5113495bSYour Name 	{"SETSCANNPROBES",            drv_cmd_set_scan_n_probes, true},
7355*5113495bSYour Name 	{"GETSCANNPROBES",            drv_cmd_get_scan_n_probes, false},
7356*5113495bSYour Name 	{"SETSCANHOMEAWAYTIME",       drv_cmd_set_scan_home_away_time, true},
7357*5113495bSYour Name 	{"GETSCANHOMEAWAYTIME",       drv_cmd_get_scan_home_away_time, false},
7358*5113495bSYour Name 	{"REASSOC",                   drv_cmd_reassoc, true},
7359*5113495bSYour Name 	{"SETWESMODE",                drv_cmd_set_wes_mode, true},
7360*5113495bSYour Name 	{"GETWESMODE",                drv_cmd_get_wes_mode, false},
7361*5113495bSYour Name 	{"SETOPPORTUNISTICRSSIDIFF",  drv_cmd_set_opportunistic_rssi_diff,
7362*5113495bSYour Name 	 true},
7363*5113495bSYour Name 	{"GETOPPORTUNISTICRSSIDIFF",  drv_cmd_get_opportunistic_rssi_diff,
7364*5113495bSYour Name 	 false},
7365*5113495bSYour Name 	{"SETROAMRESCANRSSIDIFF",     drv_cmd_set_roam_rescan_rssi_diff, true},
7366*5113495bSYour Name 	{"GETROAMRESCANRSSIDIFF",     drv_cmd_get_roam_rescan_rssi_diff, false},
7367*5113495bSYour Name 	{"SETFASTROAM",               drv_cmd_set_fast_roam, true},
7368*5113495bSYour Name 	{"SETFASTTRANSITION",         drv_cmd_set_fast_transition, true},
7369*5113495bSYour Name 	{"FASTREASSOC",               drv_cmd_fast_reassoc, true},
7370*5113495bSYour Name 	{"SETOKCMODE",                drv_cmd_set_okc_mode, true},
7371*5113495bSYour Name 	{"BTCOEXMODE",                drv_cmd_bt_coex_mode, true},
7372*5113495bSYour Name 	{"SCAN-ACTIVE",               drv_cmd_scan_active, false},
7373*5113495bSYour Name 	{"SCAN-PASSIVE",              drv_cmd_scan_passive, false},
7374*5113495bSYour Name 	{"CONCSETDWELLTIME",          drv_cmd_conc_set_dwell_time, true},
7375*5113495bSYour Name 	{"GETDWELLTIME",              drv_cmd_get_dwell_time, false},
7376*5113495bSYour Name 	{"SETDWELLTIME",              drv_cmd_set_dwell_time, true},
7377*5113495bSYour Name 	{"MIRACAST",                  drv_cmd_miracast, true},
7378*5113495bSYour Name 	{"TPUT_DEBUG_MODE_ENABLE",    drv_cmd_tput_debug_mode_enable, false},
7379*5113495bSYour Name 	{"TPUT_DEBUG_MODE_DISABLE",   drv_cmd_tput_debug_mode_disable, false},
7380*5113495bSYour Name #ifdef FEATURE_WLAN_ESE
7381*5113495bSYour Name 	{"SETCCXROAMSCANCHANNELS",    drv_cmd_set_ccx_roam_scan_channels, true},
7382*5113495bSYour Name 	{"GETTSMSTATS",               drv_cmd_get_tsm_stats, true},
7383*5113495bSYour Name 	{"SETCCKMIE",                 drv_cmd_set_cckm_ie, true},
7384*5113495bSYour Name 	{"CCXBEACONREQ",	      drv_cmd_ccx_beacon_req, true},
7385*5113495bSYour Name 	{"CCXPLMREQ",                 drv_cmd_ccx_plm_req, true},
7386*5113495bSYour Name 	{"SETCCXMODE",                drv_cmd_set_ccx_mode, true},
7387*5113495bSYour Name #endif /* FEATURE_WLAN_ESE */
7388*5113495bSYour Name 	{"SETMCRATE",                 drv_cmd_set_mc_rate, true},
7389*5113495bSYour Name 	{"MAXTXPOWER",                drv_cmd_max_tx_power, true},
7390*5113495bSYour Name 	{"SETDFSSCANMODE",            drv_cmd_set_dfs_scan_mode, true},
7391*5113495bSYour Name 	{"GETDFSSCANMODE",            drv_cmd_get_dfs_scan_mode, false},
7392*5113495bSYour Name 	{"GETLINKSTATUS",             drv_cmd_get_link_status, false},
7393*5113495bSYour Name #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7394*5113495bSYour Name 	{"ENABLEEXTWOW",              drv_cmd_enable_ext_wow, true},
7395*5113495bSYour Name 	{"SETAPP1PARAMS",             drv_cmd_set_app1_params, true},
7396*5113495bSYour Name 	{"SETAPP2PARAMS",             drv_cmd_set_app2_params, true},
7397*5113495bSYour Name #endif
7398*5113495bSYour Name #ifdef FEATURE_WLAN_TDLS
7399*5113495bSYour Name 	{"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
7400*5113495bSYour Name 	 true},
7401*5113495bSYour Name 	{"TDLSOFFCHANNELMODE",        drv_cmd_tdls_off_channel_mode, true},
7402*5113495bSYour Name 	{"TDLSOFFCHANNEL",            drv_cmd_tdls_off_channel, true},
7403*5113495bSYour Name 	{"TDLSSCAN",                  drv_cmd_tdls_scan, true},
7404*5113495bSYour Name #endif
7405*5113495bSYour Name 	{"RSSI",                      drv_cmd_get_rssi, false},
7406*5113495bSYour Name 	{"LINKSPEED",                 drv_cmd_get_linkspeed, false},
7407*5113495bSYour Name #ifdef WLAN_FEATURE_PACKET_FILTERING
7408*5113495bSYour Name 	{"RXFILTER-REMOVE",           drv_cmd_rx_filter_remove, true},
7409*5113495bSYour Name 	{"RXFILTER-ADD",              drv_cmd_rx_filter_add, true},
7410*5113495bSYour Name #endif
7411*5113495bSYour Name 	{"SET_FCC_CHANNEL",           drv_cmd_set_fcc_channel, true},
7412*5113495bSYour Name 	{"CHANNEL_SWITCH",            drv_cmd_set_channel_switch, true},
7413*5113495bSYour Name 	{"SETANTENNAMODE",            drv_cmd_set_antenna_mode, true},
7414*5113495bSYour Name 	{"GETANTENNAMODE",            drv_cmd_get_antenna_mode, false},
7415*5113495bSYour Name 	{"SET_DISABLE_CHANNEL_LIST",  drv_cmd_set_disable_chan_list, true},
7416*5113495bSYour Name 	{"GET_DISABLE_CHANNEL_LIST",  drv_cmd_get_disable_chan_list, false},
7417*5113495bSYour Name 	{"GET_ANI_LEVEL",             drv_cmd_get_ani_level, false},
7418*5113495bSYour Name #ifdef FUNC_CALL_MAP
7419*5113495bSYour Name 	{"GET_FUNCTION_CALL_MAP",     drv_cmd_get_function_call_map, true},
7420*5113495bSYour Name #endif
7421*5113495bSYour Name 	{"STOP",                      drv_cmd_dummy, false},
7422*5113495bSYour Name 	/* Deprecated commands */
7423*5113495bSYour Name 	{"RXFILTER-START",            drv_cmd_dummy, false},
7424*5113495bSYour Name 	{"RXFILTER-STOP",             drv_cmd_dummy, false},
7425*5113495bSYour Name 	{"BTCOEXSCAN-START",          drv_cmd_dummy, false},
7426*5113495bSYour Name 	{"BTCOEXSCAN-STOP",           drv_cmd_dummy, false},
7427*5113495bSYour Name 	{"GET_SOFTAP_LINK_SPEED",     drv_cmd_get_sap_go_linkspeed, true},
7428*5113495bSYour Name #ifdef CONFIG_BAND_6GHZ
7429*5113495bSYour Name 	{"GET_WIFI6E_CHANNELS",       drv_cmd_get_wifi6e_channels, true},
7430*5113495bSYour Name #endif
7431*5113495bSYour Name };
7432*5113495bSYour Name 
7433*5113495bSYour Name /**
7434*5113495bSYour Name  * hdd_drv_cmd_process() - chooses and runs the proper
7435*5113495bSYour Name  *                                handler based on the input command
7436*5113495bSYour Name  * @link_info:  Link info pointer in adapter.
7437*5113495bSYour Name  * @cmd:	Pointer to the driver command
7438*5113495bSYour Name  * @priv_data:	Pointer to the data associated with the command
7439*5113495bSYour Name  *
7440*5113495bSYour Name  * This function parses the input hdd driver command and runs
7441*5113495bSYour Name  * the proper handler
7442*5113495bSYour Name  *
7443*5113495bSYour Name  * Return: 0 for success non-zero for failure
7444*5113495bSYour Name  */
hdd_drv_cmd_process(struct wlan_hdd_link_info * link_info,uint8_t * cmd,struct hdd_priv_data * priv_data)7445*5113495bSYour Name static int hdd_drv_cmd_process(struct wlan_hdd_link_info *link_info,
7446*5113495bSYour Name 			       uint8_t *cmd, struct hdd_priv_data *priv_data)
7447*5113495bSYour Name {
7448*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
7449*5113495bSYour Name 	struct hdd_context *hdd_ctx;
7450*5113495bSYour Name 	int i;
7451*5113495bSYour Name 	const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7452*5113495bSYour Name 	uint8_t *cmd_i = NULL;
7453*5113495bSYour Name 	hdd_drv_cmd_handler_t handler = NULL;
7454*5113495bSYour Name 	int len = 0, cmd_len = 0;
7455*5113495bSYour Name 	uint8_t *ptr;
7456*5113495bSYour Name 	bool args;
7457*5113495bSYour Name 
7458*5113495bSYour Name 	if (!cmd || !priv_data) {
7459*5113495bSYour Name 		hdd_err("at least 1 param is NULL");
7460*5113495bSYour Name 		return -EINVAL;
7461*5113495bSYour Name 	}
7462*5113495bSYour Name 
7463*5113495bSYour Name 	/* Calculate length of the first word */
7464*5113495bSYour Name 	ptr = strchrnul(cmd, ' ');
7465*5113495bSYour Name 	cmd_len = ptr - cmd;
7466*5113495bSYour Name 
7467*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7468*5113495bSYour Name 
7469*5113495bSYour Name 	for (i = 0; i < cmd_num_total; i++) {
7470*5113495bSYour Name 
7471*5113495bSYour Name 		cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7472*5113495bSYour Name 		handler = hdd_drv_cmds[i].handler;
7473*5113495bSYour Name 		len = strlen(cmd_i);
7474*5113495bSYour Name 		args = hdd_drv_cmds[i].args;
7475*5113495bSYour Name 
7476*5113495bSYour Name 		if (!handler) {
7477*5113495bSYour Name 			hdd_err("no. %d handler is NULL", i);
7478*5113495bSYour Name 			return -EINVAL;
7479*5113495bSYour Name 		}
7480*5113495bSYour Name 
7481*5113495bSYour Name 		if (len == cmd_len && strncasecmp(cmd, cmd_i, len) == 0) {
7482*5113495bSYour Name 			if (args && drv_cmd_validate(cmd, len))
7483*5113495bSYour Name 				return -EINVAL;
7484*5113495bSYour Name 
7485*5113495bSYour Name 			return handler(link_info, hdd_ctx,
7486*5113495bSYour Name 				       cmd, len, priv_data);
7487*5113495bSYour Name 		}
7488*5113495bSYour Name 	}
7489*5113495bSYour Name 
7490*5113495bSYour Name 	return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7491*5113495bSYour Name }
7492*5113495bSYour Name 
7493*5113495bSYour Name /**
7494*5113495bSYour Name  * hdd_driver_command() - top level wlan hdd driver command handler
7495*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
7496*5113495bSYour Name  * @priv_data:	Pointer to the raw command data
7497*5113495bSYour Name  *
7498*5113495bSYour Name  * This function is the top level wlan hdd driver command handler. It
7499*5113495bSYour Name  * handles the command with the help of hdd_drv_cmd_process()
7500*5113495bSYour Name  *
7501*5113495bSYour Name  * Return: 0 for success non-zero for failure
7502*5113495bSYour Name  */
hdd_driver_command(struct wlan_hdd_link_info * link_info,struct hdd_priv_data * priv_data)7503*5113495bSYour Name static int hdd_driver_command(struct wlan_hdd_link_info *link_info,
7504*5113495bSYour Name 			      struct hdd_priv_data *priv_data)
7505*5113495bSYour Name {
7506*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
7507*5113495bSYour Name 	uint8_t *command = NULL;
7508*5113495bSYour Name 	int ret = 0;
7509*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7510*5113495bSYour Name 
7511*5113495bSYour Name 	hdd_enter();
7512*5113495bSYour Name 
7513*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
7514*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
7515*5113495bSYour Name 		return -EINVAL;
7516*5113495bSYour Name 	}
7517*5113495bSYour Name 
7518*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
7519*5113495bSYour Name 	if (ret)
7520*5113495bSYour Name 		return ret;
7521*5113495bSYour Name 
7522*5113495bSYour Name 	if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
7523*5113495bSYour Name 		hdd_err("Driver module is closed; command can not be processed");
7524*5113495bSYour Name 		return -EINVAL;
7525*5113495bSYour Name 	}
7526*5113495bSYour Name 
7527*5113495bSYour Name 	/*
7528*5113495bSYour Name 	 * Note that valid pointers are provided by caller
7529*5113495bSYour Name 	 */
7530*5113495bSYour Name 
7531*5113495bSYour Name 	/* copy to local struct to avoid numerous changes to legacy code */
7532*5113495bSYour Name 	if (priv_data->total_len <= 0 ||
7533*5113495bSYour Name 	    priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
7534*5113495bSYour Name 		hdd_warn("Invalid priv_data.total_len: %d!!!",
7535*5113495bSYour Name 			  priv_data->total_len);
7536*5113495bSYour Name 		ret = -EINVAL;
7537*5113495bSYour Name 		goto exit;
7538*5113495bSYour Name 	}
7539*5113495bSYour Name 
7540*5113495bSYour Name 	/* Allocate +1 for '\0' */
7541*5113495bSYour Name 	command = qdf_mem_malloc(priv_data->total_len + 1);
7542*5113495bSYour Name 	if (!command) {
7543*5113495bSYour Name 		ret = -ENOMEM;
7544*5113495bSYour Name 		goto exit;
7545*5113495bSYour Name 	}
7546*5113495bSYour Name 
7547*5113495bSYour Name 	if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7548*5113495bSYour Name 		ret = -EFAULT;
7549*5113495bSYour Name 		goto exit;
7550*5113495bSYour Name 	}
7551*5113495bSYour Name 
7552*5113495bSYour Name 	/* Make sure the command is NUL-terminated */
7553*5113495bSYour Name 	command[priv_data->total_len] = '\0';
7554*5113495bSYour Name 
7555*5113495bSYour Name 	hdd_debug("%s: %s", adapter->dev->name, command);
7556*5113495bSYour Name 	ret = hdd_drv_cmd_process(link_info, command, priv_data);
7557*5113495bSYour Name 
7558*5113495bSYour Name exit:
7559*5113495bSYour Name 	if (command)
7560*5113495bSYour Name 		qdf_mem_free(command);
7561*5113495bSYour Name 	hdd_exit();
7562*5113495bSYour Name 	return ret;
7563*5113495bSYour Name }
7564*5113495bSYour Name 
7565*5113495bSYour Name #ifdef CONFIG_COMPAT
hdd_driver_compat_ioctl(struct wlan_hdd_link_info * link_info,void __user * data)7566*5113495bSYour Name static int hdd_driver_compat_ioctl(struct wlan_hdd_link_info *link_info,
7567*5113495bSYour Name 				   void __user *data)
7568*5113495bSYour Name {
7569*5113495bSYour Name 	struct {
7570*5113495bSYour Name 		compat_uptr_t buf;
7571*5113495bSYour Name 		int used_len;
7572*5113495bSYour Name 		int total_len;
7573*5113495bSYour Name 	} compat_priv_data;
7574*5113495bSYour Name 	struct hdd_priv_data priv_data;
7575*5113495bSYour Name 	int ret = 0;
7576*5113495bSYour Name 
7577*5113495bSYour Name 	/*
7578*5113495bSYour Name 	 * Note that adapter and ifr have already been verified by caller,
7579*5113495bSYour Name 	 * and HDD context has also been validated
7580*5113495bSYour Name 	 */
7581*5113495bSYour Name 	if (copy_from_user(&compat_priv_data, data,
7582*5113495bSYour Name 			   sizeof(compat_priv_data))) {
7583*5113495bSYour Name 		ret = -EFAULT;
7584*5113495bSYour Name 		goto exit;
7585*5113495bSYour Name 	}
7586*5113495bSYour Name 	priv_data.buf = compat_ptr(compat_priv_data.buf);
7587*5113495bSYour Name 	priv_data.used_len = compat_priv_data.used_len;
7588*5113495bSYour Name 	priv_data.total_len = compat_priv_data.total_len;
7589*5113495bSYour Name 	ret = hdd_driver_command(link_info, &priv_data);
7590*5113495bSYour Name exit:
7591*5113495bSYour Name 	return ret;
7592*5113495bSYour Name }
7593*5113495bSYour Name #else /* CONFIG_COMPAT */
hdd_driver_compat_ioctl(struct wlan_hdd_link_info * link_info,void __user * data)7594*5113495bSYour Name static inline int hdd_driver_compat_ioctl(struct wlan_hdd_link_info *link_info,
7595*5113495bSYour Name 					  void __user *data)
7596*5113495bSYour Name {
7597*5113495bSYour Name 	/* will never be invoked */
7598*5113495bSYour Name 	return 0;
7599*5113495bSYour Name }
7600*5113495bSYour Name #endif /* CONFIG_COMPAT */
7601*5113495bSYour Name 
hdd_driver_ioctl(struct wlan_hdd_link_info * link_info,void __user * data)7602*5113495bSYour Name static int hdd_driver_ioctl(struct wlan_hdd_link_info *link_info,
7603*5113495bSYour Name 			    void __user *data)
7604*5113495bSYour Name {
7605*5113495bSYour Name 	struct hdd_priv_data priv_data;
7606*5113495bSYour Name 	int ret = 0;
7607*5113495bSYour Name 
7608*5113495bSYour Name 	/*
7609*5113495bSYour Name 	 * Note that adapter and ifr have already been verified by caller,
7610*5113495bSYour Name 	 * and HDD context has also been validated
7611*5113495bSYour Name 	 */
7612*5113495bSYour Name 	if (copy_from_user(&priv_data, data, sizeof(priv_data)))
7613*5113495bSYour Name 		ret = -EFAULT;
7614*5113495bSYour Name 	else
7615*5113495bSYour Name 		ret = hdd_driver_command(link_info, &priv_data);
7616*5113495bSYour Name 
7617*5113495bSYour Name 	return ret;
7618*5113495bSYour Name }
7619*5113495bSYour Name 
7620*5113495bSYour Name /**
7621*5113495bSYour Name  * __hdd_ioctl() - ioctl handler for wlan network interfaces
7622*5113495bSYour Name  * @dev: device upon which the ioctl was received
7623*5113495bSYour Name  * @data: pointer to the raw command data in the ioctl request
7624*5113495bSYour Name  * @cmd: ioctl command
7625*5113495bSYour Name  *
7626*5113495bSYour Name  * This function does initial processing of wlan device ioctls.
7627*5113495bSYour Name  * Currently two flavors of ioctls are supported.  The primary ioctl
7628*5113495bSYour Name  * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7629*5113495bSYour Name  * for Android "DRIVER" commands.  The other ioctl that is
7630*5113495bSYour Name  * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7631*5113495bSYour Name  * for FTM on some platforms.  This function simply verifies that the
7632*5113495bSYour Name  * driver is in a sane state, and that the ioctl is one of the
7633*5113495bSYour Name  * supported flavors, in which case flavor-specific handlers are
7634*5113495bSYour Name  * dispatched.
7635*5113495bSYour Name  *
7636*5113495bSYour Name  * Return: 0 on success, non-zero on error
7637*5113495bSYour Name  */
__hdd_ioctl(struct net_device * dev,void __user * data,int cmd)7638*5113495bSYour Name static int __hdd_ioctl(struct net_device *dev, void __user *data, int cmd)
7639*5113495bSYour Name {
7640*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7641*5113495bSYour Name 	struct hdd_context *hdd_ctx;
7642*5113495bSYour Name 	int ret;
7643*5113495bSYour Name 
7644*5113495bSYour Name 	hdd_enter_dev(dev);
7645*5113495bSYour Name 
7646*5113495bSYour Name 	if (dev != adapter->dev) {
7647*5113495bSYour Name 		hdd_err("HDD adapter/dev inconsistency");
7648*5113495bSYour Name 		ret = -ENODEV;
7649*5113495bSYour Name 		goto exit;
7650*5113495bSYour Name 	}
7651*5113495bSYour Name 
7652*5113495bSYour Name 	if (!data) {
7653*5113495bSYour Name 		hdd_err("invalid data cmd: %d", cmd);
7654*5113495bSYour Name 		ret = -EINVAL;
7655*5113495bSYour Name 		goto exit;
7656*5113495bSYour Name 	}
7657*5113495bSYour Name #if  defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
7658*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
7659*5113495bSYour Name 		if (SIOCIOCTLTX99 == cmd) {
7660*5113495bSYour Name 			ret = wlan_hdd_qcmbr_unified_ioctl(adapter, data);
7661*5113495bSYour Name 			goto exit;
7662*5113495bSYour Name 		}
7663*5113495bSYour Name 	}
7664*5113495bSYour Name #endif
7665*5113495bSYour Name 
7666*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7667*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
7668*5113495bSYour Name 	if (ret)
7669*5113495bSYour Name 		goto exit;
7670*5113495bSYour Name 
7671*5113495bSYour Name 	switch (cmd) {
7672*5113495bSYour Name 	case (SIOCDEVPRIVATE + 1):
7673*5113495bSYour Name 		if (in_compat_syscall())
7674*5113495bSYour Name 			ret = hdd_driver_compat_ioctl(adapter->deflink, data);
7675*5113495bSYour Name 		else
7676*5113495bSYour Name 			ret = hdd_driver_ioctl(adapter->deflink, data);
7677*5113495bSYour Name 		break;
7678*5113495bSYour Name 	default:
7679*5113495bSYour Name 		hdd_warn("unknown ioctl %d", cmd);
7680*5113495bSYour Name 		ret = -EINVAL;
7681*5113495bSYour Name 		break;
7682*5113495bSYour Name 	}
7683*5113495bSYour Name exit:
7684*5113495bSYour Name 	hdd_exit();
7685*5113495bSYour Name 	return ret;
7686*5113495bSYour Name }
7687*5113495bSYour Name 
hdd_ioctl(struct net_device * net_dev,struct ifreq * ifr,int cmd)7688*5113495bSYour Name int hdd_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
7689*5113495bSYour Name {
7690*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
7691*5113495bSYour Name 	int errno;
7692*5113495bSYour Name 
7693*5113495bSYour Name 	errno = osif_vdev_sync_op_start(net_dev, &vdev_sync);
7694*5113495bSYour Name 	if (errno)
7695*5113495bSYour Name 		return errno;
7696*5113495bSYour Name 
7697*5113495bSYour Name 	errno = __hdd_ioctl(net_dev, ifr->ifr_data, cmd);
7698*5113495bSYour Name 
7699*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
7700*5113495bSYour Name 
7701*5113495bSYour Name 	return errno;
7702*5113495bSYour Name }
7703*5113495bSYour Name 
hdd_dev_private_ioctl(struct net_device * dev,struct ifreq * ifr,void __user * data,int cmd)7704*5113495bSYour Name int hdd_dev_private_ioctl(struct net_device *dev, struct ifreq *ifr,
7705*5113495bSYour Name 			  void __user *data, int cmd)
7706*5113495bSYour Name {
7707*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
7708*5113495bSYour Name 	int errno;
7709*5113495bSYour Name 
7710*5113495bSYour Name 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
7711*5113495bSYour Name 	if (errno)
7712*5113495bSYour Name 		return errno;
7713*5113495bSYour Name 
7714*5113495bSYour Name 	errno = __hdd_ioctl(dev, data, cmd);
7715*5113495bSYour Name 
7716*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
7717*5113495bSYour Name 
7718*5113495bSYour Name 	return errno;
7719*5113495bSYour Name }
7720