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