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