xref: /wlan-dirver/qcacld-3.0/core/wma/src/wma_scan_roam.c (revision 83d3c5b7b2a13fc3107d3d4bcef3de58e5c17777)
1  /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 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 /**
21  *  DOC:    wma_scan_roam.c
22  *  This file contains functions related to scan and
23  *  roaming functionality.
24  */
25 
26 /* Header files */
27 
28 #include "wma.h"
29 #include "wma_api.h"
30 #include "cds_api.h"
31 #include "wmi_unified_api.h"
32 #include "wlan_qct_sys.h"
33 #include "wni_api.h"
34 #include "ani_global.h"
35 #include "wmi_unified.h"
36 #include "wni_cfg.h"
37 #include <cdp_txrx_peer_ops.h>
38 #include <cdp_txrx_cfg.h>
39 #include <cdp_txrx_ctrl.h>
40 
41 #include "qdf_nbuf.h"
42 #include "qdf_types.h"
43 #include "qdf_mem.h"
44 #include "wlan_dlm_api.h"
45 
46 #include "wma_types.h"
47 #include "lim_api.h"
48 #include "lim_session_utils.h"
49 
50 #include "cds_utils.h"
51 #include "wlan_policy_mgr_api.h"
52 #include <wlan_utility.h>
53 
54 #if !defined(REMOVE_PKT_LOG)
55 #include "pktlog_ac.h"
56 #endif /* REMOVE_PKT_LOG */
57 
58 #include "dbglog_host.h"
59 #include "csr_api.h"
60 #include "ol_fw.h"
61 
62 #include "wma_internal.h"
63 #if defined(CONFIG_HL_SUPPORT)
64 #include "wlan_tgt_def_config_hl.h"
65 #else
66 #include "wlan_tgt_def_config.h"
67 #endif
68 #include "wlan_reg_services_api.h"
69 #include "wlan_roam_debug.h"
70 #include "wlan_mlme_public_struct.h"
71 #include "wlan_mgmt_txrx_utils_api.h"
72 
73 /* This is temporary, should be removed */
74 #include "ol_htt_api.h"
75 #include <cdp_txrx_handle.h>
76 #include "wma_he.h"
77 #include <wlan_scan_public_structs.h>
78 #include <wlan_scan_ucfg_api.h>
79 #include "wma_nan_datapath.h"
80 #include "wlan_mlme_api.h"
81 #include <wlan_mlme_main.h>
82 #include <wlan_crypto_global_api.h>
83 #include <cdp_txrx_mon.h>
84 #include <cdp_txrx_ctrl.h>
85 #include "wlan_dlm_api.h"
86 #include "wlan_cm_roam_api.h"
87 #ifdef FEATURE_WLAN_DIAG_SUPPORT    /* FEATURE_WLAN_DIAG_SUPPORT */
88 #include "host_diag_core_log.h"
89 #endif /* FEATURE_WLAN_DIAG_SUPPORT */
90 #include <../../core/src/wlan_cm_roam_i.h>
91 #include "wlan_cm_roam_api.h"
92 #include "wlan_mlo_mgr_roam.h"
93 #include "lim_mlo.h"
94 #ifdef FEATURE_WLAN_EXTSCAN
95 #define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED
96 
97 /*
98  * Maximum number of entries that could be present in the
99  * WMI_EXTSCAN_HOTLIST_MATCH_EVENT buffer from the firmware
100  */
101 #define WMA_EXTSCAN_MAX_HOTLIST_ENTRIES 10
102 #endif
103 
104 static inline wmi_host_channel_width
105 wma_map_phy_ch_bw_to_wmi_channel_width(enum phy_ch_width ch_width)
106 {
107 	switch (ch_width) {
108 	case CH_WIDTH_20MHZ:
109 		return WMI_HOST_CHAN_WIDTH_20;
110 	case CH_WIDTH_40MHZ:
111 		return WMI_HOST_CHAN_WIDTH_40;
112 	case CH_WIDTH_80MHZ:
113 		return WMI_HOST_CHAN_WIDTH_80;
114 	case CH_WIDTH_160MHZ:
115 		return WMI_HOST_CHAN_WIDTH_160;
116 	case CH_WIDTH_5MHZ:
117 		return WMI_HOST_CHAN_WIDTH_5;
118 	case CH_WIDTH_10MHZ:
119 		return WMI_HOST_CHAN_WIDTH_10;
120 	case CH_WIDTH_320MHZ:
121 		return WMI_HOST_CHAN_WIDTH_320;
122 	default:
123 		return WMI_HOST_CHAN_WIDTH_20;
124 	}
125 }
126 
127 #define WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ      0
128 #define WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ         1
129 #define WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ        2
130 #define WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ 3
131 
132 #if defined(WLAN_FEATURE_11BE)
133 static void wma_update_ch_list_11be_params(struct ch_params *ch)
134 {
135 	ch->ch_width = CH_WIDTH_320MHZ;
136 }
137 #else /* !WLAN_FEATURE_11BE */
138 static void wma_update_ch_list_11be_params(struct ch_params *ch)
139 {
140 	ch->ch_width = CH_WIDTH_160MHZ;
141 }
142 #endif /* WLAN_FEATURE_11BE */
143 
144 /**
145  * wma_update_channel_list() - update channel list
146  * @handle: wma handle
147  * @chan_list: channel list
148  *
149  * Function is used to update the support channel list in fw.
150  *
151  * Return: QDF status
152  */
153 QDF_STATUS wma_update_channel_list(WMA_HANDLE handle,
154 				   tSirUpdateChanList *chan_list)
155 {
156 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
157 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
158 	int i, len;
159 	struct scan_chan_list_params *scan_ch_param;
160 	struct channel_param *chan_p;
161 	struct ch_params ch_params = {0};
162 
163 	len = sizeof(struct channel_param) * chan_list->numChan +
164 		offsetof(struct scan_chan_list_params, ch_param[0]);
165 	scan_ch_param = qdf_mem_malloc(len);
166 	if (!scan_ch_param)
167 		return QDF_STATUS_E_NOMEM;
168 
169 	qdf_mem_zero(scan_ch_param, len);
170 	wma_debug("no of channels = %d", chan_list->numChan);
171 	chan_p = &scan_ch_param->ch_param[0];
172 	scan_ch_param->nallchans = chan_list->numChan;
173 	scan_ch_param->max_bw_support_present = true;
174 	wma_handle->saved_chan.num_channels = chan_list->numChan;
175 	wma_debug("ht %d, vht %d, vht_24 %d", chan_list->ht_en,
176 		  chan_list->vht_en, chan_list->vht_24_en);
177 
178 	for (i = 0; i < chan_list->numChan; ++i) {
179 		chan_p->mhz = chan_list->chanParam[i].freq;
180 		chan_p->cfreq1 = chan_p->mhz;
181 		chan_p->cfreq2 = 0;
182 		wma_handle->saved_chan.ch_freq_list[i] =
183 					chan_list->chanParam[i].freq;
184 
185 		if (chan_list->chanParam[i].dfsSet) {
186 			chan_p->is_chan_passive = 1;
187 			chan_p->dfs_set = 1;
188 		}
189 
190 		if (chan_list->chanParam[i].nan_disabled)
191 			chan_p->nan_disabled = 1;
192 
193 		if (chan_p->mhz < WMA_2_4_GHZ_MAX_FREQ) {
194 			chan_p->phy_mode = MODE_11G;
195 			if (chan_list->vht_en && chan_list->vht_24_en)
196 				chan_p->allow_vht = 1;
197 		} else {
198 			chan_p->phy_mode = MODE_11A;
199 			if (chan_list->vht_en &&
200 			    !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz)))
201 				chan_p->allow_vht = 1;
202 		}
203 
204 		if (chan_list->ht_en &&
205 		    !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz)))
206 			chan_p->allow_ht = 1;
207 
208 		if (chan_list->he_en)
209 			chan_p->allow_he = 1;
210 
211 		if (chan_list->eht_en)
212 			chan_p->allow_eht = 1;
213 
214 		if (chan_list->chanParam[i].half_rate)
215 			chan_p->half_rate = 1;
216 		else if (chan_list->chanParam[i].quarter_rate)
217 			chan_p->quarter_rate = 1;
218 
219 		if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz) &&
220 		    wlan_reg_is_6ghz_psc_chan_freq(chan_p->mhz))
221 			chan_p->psc_channel = 1;
222 
223 		/*TODO: Set WMI_SET_CHANNEL_MIN_POWER */
224 		/*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */
225 		/*TODO: WMI_SET_CHANNEL_REG_CLASSID */
226 		chan_p->maxregpower = chan_list->chanParam[i].pwr;
227 
228 		wma_update_ch_list_11be_params(&ch_params);
229 
230 		wlan_reg_set_channel_params_for_pwrmode(wma_handle->pdev,
231 							chan_p->mhz, 0,
232 							&ch_params,
233 							REG_CURRENT_PWR_MODE);
234 
235 		chan_p->max_bw_supported =
236 		     wma_map_phy_ch_bw_to_wmi_channel_width(ch_params.ch_width);
237 		chan_p++;
238 	}
239 
240 	qdf_status = wmi_unified_scan_chan_list_cmd_send(wma_handle->wmi_handle,
241 				scan_ch_param);
242 
243 	if (QDF_IS_STATUS_ERROR(qdf_status))
244 		wma_err("Failed to send WMI_SCAN_CHAN_LIST_CMDID");
245 
246 	qdf_mem_free(scan_ch_param);
247 
248 	return qdf_status;
249 }
250 
251 /**
252  * wma_handle_disconnect_reason() - Send del sta msg to lim on receiving
253  * @wma_handle: wma handle
254  * @vdev_id: vdev id
255  * @reason: disconnection reason from fw
256  *
257  * Return: None
258  */
259 static void wma_handle_disconnect_reason(tp_wma_handle wma_handle,
260 					 uint32_t vdev_id, uint32_t reason)
261 {
262 	tpDeleteStaContext del_sta_ctx;
263 
264 	del_sta_ctx = qdf_mem_malloc(sizeof(tDeleteStaContext));
265 	if (!del_sta_ctx)
266 		return;
267 
268 	del_sta_ctx->vdev_id = vdev_id;
269 	del_sta_ctx->reasonCode = reason;
270 	wma_send_msg(wma_handle, SIR_LIM_DELETE_STA_CONTEXT_IND,
271 		     (void *)del_sta_ctx, 0);
272 }
273 
274 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
275 QDF_STATUS
276 cm_handle_auth_offload(struct auth_offload_event *auth_event)
277 {
278 	QDF_STATUS status;
279 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
280 	struct mac_context *mac_ctx;
281 
282 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
283 	if (!mac_ctx || !wma) {
284 		QDF_ASSERT(0);
285 		return QDF_STATUS_E_FAILURE;
286 	}
287 
288 	cds_host_diag_log_work(&wma->roam_preauth_wl,
289 			       WMA_ROAM_PREAUTH_WAKE_LOCK_DURATION,
290 			       WIFI_POWER_EVENT_WAKELOCK_WOW);
291 
292 	qdf_wake_lock_timeout_acquire(&wma->roam_ho_wl,
293 			       WMA_ROAM_HO_WAKE_LOCK_DURATION);
294 
295 	lim_sae_auth_cleanup_retry(mac_ctx, auth_event->vdev_id);
296 	wlan_cm_set_sae_auth_ta(mac_ctx->pdev,
297 				auth_event->vdev_id,
298 				auth_event->ta);
299 
300 	wlan_cm_store_mlo_roam_peer_address(mac_ctx->pdev, auth_event);
301 
302 	status =
303 		wlan_cm_update_offload_ssid_from_candidate(mac_ctx->pdev,
304 							   auth_event->vdev_id,
305 							   &auth_event->ap_bssid);
306 
307 	if (QDF_IS_STATUS_ERROR(status)) {
308 		wma_err_rl("Set offload ssid failed %d", status);
309 		return QDF_STATUS_E_FAILURE;
310 	}
311 
312 	status = wma->csr_roam_auth_event_handle_cb(mac_ctx, auth_event->vdev_id,
313 						    auth_event->ap_bssid,
314 						    auth_event->akm);
315 	if (QDF_IS_STATUS_ERROR(status)) {
316 		wma_err_rl("Trigger pre-auth failed");
317 		return QDF_STATUS_E_FAILURE;
318 	}
319 	return QDF_STATUS_SUCCESS;
320 }
321 
322 QDF_STATUS
323 cm_handle_disconnect_reason(struct vdev_disconnect_event_data *data)
324 {
325 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
326 
327 	if (!wma) {
328 		QDF_ASSERT(0);
329 		return QDF_STATUS_E_FAILURE;
330 	}
331 	switch (data->reason) {
332 	case CM_DISCONNECT_REASON_CSA_SA_QUERY_TIMEOUT:
333 		wma_handle_disconnect_reason(wma, data->vdev_id,
334 			HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT);
335 		break;
336 	case CM_DISCONNECT_REASON_MOVE_TO_CELLULAR:
337 		wma_handle_disconnect_reason(wma, data->vdev_id,
338 			HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT);
339 		break;
340 	default:
341 		return QDF_STATUS_SUCCESS;
342 	}
343 
344 	return QDF_STATUS_SUCCESS;
345 }
346 
347 QDF_STATUS
348 cm_handle_scan_ch_list_data(struct cm_roam_scan_ch_resp *data)
349 {
350 	struct scheduler_msg sme_msg = {0};
351 
352 	sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT;
353 	sme_msg.bodyptr = data;
354 
355 	if (scheduler_post_message(QDF_MODULE_ID_WMA,
356 				   QDF_MODULE_ID_SME,
357 				   QDF_MODULE_ID_SME, &sme_msg)) {
358 		wma_err("Failed to post msg to SME");
359 		qdf_mem_free(sme_msg.bodyptr);
360 		return -EINVAL;
361 	}
362 
363 	return QDF_STATUS_SUCCESS;
364 }
365 
366 #endif
367 
368 /**
369  * wma_process_set_pdev_ie_req() - process the pdev set IE req
370  * @wma: Pointer to wma handle
371  * @ie_params: Pointer to IE data.
372  *
373  * Sends the WMI req to set the IE to FW.
374  *
375  * Return: None
376  */
377 void wma_process_set_pdev_ie_req(tp_wma_handle wma,
378 				 struct set_ie_param *ie_params)
379 {
380 	if (ie_params->ie_type == DOT11_HT_IE)
381 		wma_process_set_pdev_ht_ie_req(wma, ie_params);
382 	if (ie_params->ie_type == DOT11_VHT_IE)
383 		wma_process_set_pdev_vht_ie_req(wma, ie_params);
384 
385 	qdf_mem_free(ie_params->ie_ptr);
386 }
387 
388 /**
389  * wma_process_set_pdev_ht_ie_req() - sends HT IE data to FW
390  * @wma: Pointer to wma handle
391  * @ie_params: Pointer to IE data.
392  * @nss: Nss values to prepare the HT IE.
393  *
394  * Sends the WMI req to set the HT IE to FW.
395  *
396  * Return: None
397  */
398 void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma,
399 				    struct set_ie_param *ie_params)
400 {
401 	QDF_STATUS status;
402 	wmi_pdev_set_ht_ie_cmd_fixed_param *cmd;
403 	wmi_buf_t buf;
404 	uint16_t len;
405 	uint16_t ie_len_pad;
406 	uint8_t *buf_ptr;
407 
408 	len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
409 	ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t));
410 	len += ie_len_pad;
411 
412 	buf = wmi_buf_alloc(wma->wmi_handle, len);
413 	if (!buf)
414 		return;
415 
416 	cmd = (wmi_pdev_set_ht_ie_cmd_fixed_param *)wmi_buf_data(buf);
417 	WMITLV_SET_HDR(&cmd->tlv_header,
418 		       WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param,
419 		       WMITLV_GET_STRUCT_TLVLEN(
420 			       wmi_pdev_set_ht_ie_cmd_fixed_param));
421 	cmd->reserved0 = 0;
422 	cmd->ie_len = ie_params->ie_len;
423 	cmd->tx_streams = ie_params->nss;
424 	cmd->rx_streams = ie_params->nss;
425 	wma_debug("Setting pdev HT ie with Nss = %u", ie_params->nss);
426 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
427 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad);
428 	if (ie_params->ie_len) {
429 		qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
430 			     (uint8_t *)ie_params->ie_ptr,
431 			     ie_params->ie_len);
432 	}
433 
434 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
435 				      WMI_PDEV_SET_HT_CAP_IE_CMDID);
436 	if (QDF_IS_STATUS_ERROR(status))
437 		wmi_buf_free(buf);
438 }
439 
440 /**
441  * wma_process_set_pdev_vht_ie_req() - sends VHT IE data to FW
442  * @wma: Pointer to wma handle
443  * @ie_params: Pointer to IE data.
444  * @nss: Nss values to prepare the VHT IE.
445  *
446  * Sends the WMI req to set the VHT IE to FW.
447  *
448  * Return: None
449  */
450 void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma,
451 				     struct set_ie_param *ie_params)
452 {
453 	QDF_STATUS status;
454 	wmi_pdev_set_vht_ie_cmd_fixed_param *cmd;
455 	wmi_buf_t buf;
456 	uint16_t len;
457 	uint16_t ie_len_pad;
458 	uint8_t *buf_ptr;
459 
460 	len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
461 	ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t));
462 	len += ie_len_pad;
463 
464 	buf = wmi_buf_alloc(wma->wmi_handle, len);
465 	if (!buf)
466 		return;
467 
468 	cmd = (wmi_pdev_set_vht_ie_cmd_fixed_param *)wmi_buf_data(buf);
469 	WMITLV_SET_HDR(&cmd->tlv_header,
470 		       WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param,
471 		       WMITLV_GET_STRUCT_TLVLEN(
472 					wmi_pdev_set_vht_ie_cmd_fixed_param));
473 	cmd->reserved0 = 0;
474 	cmd->ie_len = ie_params->ie_len;
475 	cmd->tx_streams = ie_params->nss;
476 	cmd->rx_streams = ie_params->nss;
477 	wma_debug("Setting pdev VHT ie with Nss = %u", ie_params->nss);
478 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
479 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad);
480 	if (ie_params->ie_len) {
481 		qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
482 			     (uint8_t *)ie_params->ie_ptr, ie_params->ie_len);
483 	}
484 
485 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
486 				      WMI_PDEV_SET_VHT_CAP_IE_CMDID);
487 	if (QDF_IS_STATUS_ERROR(status))
488 		wmi_buf_free(buf);
489 }
490 
491 #define MAX_VDEV_ROAM_SCAN_PARAMS 2
492 /* params being sent:
493  * wmi_vdev_param_bmiss_first_bcnt
494  * wmi_vdev_param_bmiss_final_bcnt
495  */
496 
497 /**
498  * wma_roam_scan_bmiss_cnt() - set bmiss count to fw
499  * @wma_handle: wma handle
500  * @first_bcnt: first bmiss count
501  * @final_bcnt: final bmiss count
502  * @vdev_id: vdev id
503  *
504  * set first & final biss count to fw.
505  *
506  * Return: QDF status
507  */
508 QDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle,
509 				   A_INT32 first_bcnt,
510 				   A_UINT32 final_bcnt, uint32_t vdev_id)
511 {
512 	QDF_STATUS status = QDF_STATUS_SUCCESS;
513 	struct dev_set_param setparam[MAX_VDEV_ROAM_SCAN_PARAMS] = {};
514 	uint8_t index = 0;
515 
516 	wma_debug("first_bcnt: %d, final_bcnt: %d", first_bcnt, final_bcnt);
517 
518 	status = mlme_check_index_setparam(setparam,
519 					   wmi_vdev_param_bmiss_first_bcnt,
520 					   first_bcnt, index++,
521 					   MAX_VDEV_ROAM_SCAN_PARAMS);
522 	if (QDF_IS_STATUS_ERROR(status)) {
523 		wma_err("failed to set wmi_vdev_param_bmiss_first_bcnt");
524 		goto error;
525 	}
526 	status = mlme_check_index_setparam(setparam,
527 					   wmi_vdev_param_bmiss_final_bcnt,
528 					   final_bcnt, index++,
529 					   MAX_VDEV_ROAM_SCAN_PARAMS);
530 	if (QDF_IS_STATUS_ERROR(status)) {
531 		wma_err("failed to set wmi_vdev_param_bmiss_final_bcnt");
532 		goto error;
533 	}
534 	status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM,
535 						     vdev_id, setparam, index);
536 	if (QDF_IS_STATUS_ERROR(status))
537 		wma_err("Failed to set BMISS FIRST and FINAL vdev set params");
538 error:
539 	return status;
540 }
541 
542 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
543 void
544 wma_send_roam_preauth_status(tp_wma_handle wma_handle,
545 			     struct wmi_roam_auth_status_params *params)
546 {
547 	QDF_STATUS status;
548 	struct wmi_unified *wmi_handle;
549 
550 	if (wma_validate_handle(wma_handle))
551 		return;
552 
553 	wmi_handle = wma_handle->wmi_handle;
554 	if (wmi_validate_handle(wmi_handle))
555 		return;
556 
557 	status = wmi_unified_send_roam_preauth_status(wmi_handle, params);
558 	if (QDF_IS_STATUS_ERROR(status))
559 		wma_err("failed to send disconnect roam preauth status");
560 }
561 #endif
562 
563 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
564 /**
565  * wma_delete_bss_peer() Delete bss peer/s for Non ML interface
566  * @wma: Global WMA Handle
567  * @vdev_id: vdev id
568  *
569  * This function will perform cleanup of the peer corresponds
570  * to given vdev_id
571  *
572  * Return: QDF status
573  */
574 static
575 QDF_STATUS wma_delete_bss_peer(tp_wma_handle wma,
576 			       uint8_t vdev_id)
577 {
578 	tDeleteStaParams *del_sta_params;
579 
580 	del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params));
581 	if (!del_sta_params)
582 		return QDF_STATUS_E_NOMEM;
583 
584 	del_sta_params->smesessionId = vdev_id;
585 	wma_delete_sta(wma, del_sta_params);
586 	wma_delete_bss(wma, vdev_id);
587 
588 	return QDF_STATUS_SUCCESS;
589 }
590 
591 #ifdef WLAN_FEATURE_11BE_MLO
592 /**
593  * wma_delete_all_peers() - Delete all bss peer/s
594  * @wma: Global WMA Handle
595  * @vdev_id: vdev id
596  * @del_sta_params: parameters required for del sta request
597  *
598  * This function will perform deleting of all the link peers
599  * after self roaming.
600  *
601  * Return: None
602  */
603 static QDF_STATUS
604 wma_delete_all_peers(tp_wma_handle wma,
605 		     uint8_t vdev_id)
606 {
607 	struct wlan_objmgr_vdev *vdev;
608 	struct wlan_mlo_dev_context *mlo_dev_ctx;
609 	uint8_t i;
610 	uint8_t link_vdev_id;
611 	tDeleteStaParams *del_sta_params;
612 	QDF_STATUS status = QDF_STATUS_SUCCESS;
613 	struct qdf_mac_addr bssid;
614 	struct qdf_mac_addr *mld_addr;
615 
616 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id,
617 						    WLAN_MLME_OBJMGR_ID);
618 	if (!vdev) {
619 		mlme_err("vdev object is NULL for vdev %d", vdev_id);
620 		return QDF_STATUS_E_NULL_VALUE;
621 	}
622 
623 	mlo_dev_ctx = vdev->mlo_dev_ctx;
624 	if (!mlo_dev_ctx) {
625 		mld_addr =
626 		    (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
627 		/* It's not a ML interface*/
628 		if (qdf_is_macaddr_zero(mld_addr)) {
629 			mlme_debug("Non-ML STA vdev_id: %d", vdev_id);
630 			status = wma_delete_bss_peer(wma, vdev_id);
631 			goto end;
632 		}
633 
634 		mlme_err("mlo_dev_ctx object is NULL for vdev %d", vdev_id);
635 		status = QDF_STATUS_E_NULL_VALUE;
636 		goto end;
637 	}
638 
639 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
640 		if (!mlo_dev_ctx->wlan_vdev_list[i])
641 			continue;
642 
643 		if (QDF_IS_STATUS_ERROR(wlan_vdev_get_bss_peer_mac(
644 			mlo_dev_ctx->wlan_vdev_list[i],
645 			&bssid))) {
646 			pe_debug("bss peer is not present on vdev id %d, no need to cleanup",
647 				 wlan_vdev_get_id(
648 				 mlo_dev_ctx->wlan_vdev_list[i]));
649 			continue;
650 		}
651 
652 		del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params));
653 		if (!del_sta_params) {
654 			status = QDF_STATUS_E_NOMEM;
655 			goto end;
656 		}
657 		lim_mlo_roam_peer_disconn_del(mlo_dev_ctx->wlan_vdev_list[i]);
658 		qdf_mem_zero(del_sta_params, sizeof(*del_sta_params));
659 		link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
660 		if (link_vdev_id == WLAN_INVALID_VDEV_ID) {
661 			mlme_err("invalid vdev id");
662 			status = QDF_STATUS_E_INVAL;
663 			goto end;
664 		}
665 		del_sta_params->smesessionId = link_vdev_id;
666 		wma_delete_sta(wma, del_sta_params);
667 		wma_delete_bss(wma, link_vdev_id);
668 	}
669 
670 end:
671 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
672 	return status;
673 }
674 #else
675 static inline  QDF_STATUS
676 wma_delete_all_peers(tp_wma_handle wma,
677 		     uint8_t vdev_id)
678 {
679 	return wma_delete_bss_peer(wma, vdev_id);
680 }
681 #endif
682 /**
683  * wma_roam_update_vdev() - Update the STA and BSS
684  * @wma: Global WMA Handle
685  * @roam_synch_ind_ptr: Information needed for roam sync propagation
686  *
687  * This function will perform all the vdev related operations with
688  * respect to the self sta and the peer after roaming and completes
689  * the roam synch propagation with respect to WMA layer.
690  *
691  * Return: None
692  */
693 static void
694 wma_roam_update_vdev(tp_wma_handle wma,
695 		     struct roam_offload_synch_ind *roam_synch_ind_ptr,
696 		     uint8_t roamed_vdev_id)
697 {
698 	tAddStaParams *add_sta_params;
699 	uint8_t vdev_id, *bssid;
700 	int32_t uc_cipher, cipher_cap;
701 	bool is_assoc_peer = false;
702 	struct qdf_mac_addr mac_addr;
703 	QDF_STATUS status = QDF_STATUS_SUCCESS;
704 
705 	vdev_id = roamed_vdev_id;
706 	wma->interfaces[vdev_id].nss = roam_synch_ind_ptr->nss;
707 
708 	/* update channel width */
709 	wma->interfaces[vdev_id].chan_width =
710 		roam_synch_ind_ptr->chan_width;
711 	/* Fill link freq from roam_synch_ind */
712 	if (is_multi_link_roam(roam_synch_ind_ptr))
713 		wma->interfaces[vdev_id].ch_freq =
714 			mlo_roam_get_chan_freq(vdev_id, roam_synch_ind_ptr);
715 	else
716 		wma->interfaces[vdev_id].ch_freq =
717 			roam_synch_ind_ptr->chan_freq;
718 
719 	add_sta_params = qdf_mem_malloc(sizeof(*add_sta_params));
720 	if (!add_sta_params) {
721 		return;
722 	}
723 
724 	if (is_multi_link_roam(roam_synch_ind_ptr))
725 		mlo_get_sta_link_mac_addr(vdev_id, roam_synch_ind_ptr,
726 					  &mac_addr);
727 	else
728 		mac_addr = roam_synch_ind_ptr->bssid;
729 
730 	qdf_mem_zero(add_sta_params, sizeof(*add_sta_params));
731 
732 	/* With self roaming on multi link AP, as the same
733 	 * peer already exists, new peer creation fails
734 	 * To handle this delete all link peers,
735 	 * while doing roam sync on first link.
736 	 */
737 	if (!is_multi_link_roam(roam_synch_ind_ptr) ||
738 	    wlan_vdev_mlme_get_is_mlo_link(wma->psoc, vdev_id) ||
739 	    mlo_get_single_link_ml_roaming(wma->psoc, vdev_id)) {
740 		status = wma_delete_all_peers(wma, vdev_id);
741 		if (QDF_IS_STATUS_ERROR(status))
742 			goto end;
743 	}
744 
745 	add_sta_params->staType = STA_ENTRY_SELF;
746 	add_sta_params->smesessionId = vdev_id;
747 	qdf_mem_copy(&add_sta_params->bssId, &mac_addr,
748 			 QDF_MAC_ADDR_SIZE);
749 	add_sta_params->assocId = roam_synch_ind_ptr->aid;
750 
751 	bssid = wma_get_vdev_bssid(wma->interfaces[vdev_id].vdev);
752 	if (!bssid) {
753 		wma_err("Failed to get bssid for vdev_%d", vdev_id);
754 		return;
755 	}
756 
757 	is_assoc_peer = wlan_vdev_mlme_get_is_mlo_vdev(wma->psoc, vdev_id);
758 	if (is_multi_link_roam(roam_synch_ind_ptr)) {
759 		wma_create_peer(wma, mac_addr.bytes,
760 				WMI_PEER_TYPE_DEFAULT, vdev_id,
761 				roam_synch_ind_ptr->bssid.bytes,
762 				is_assoc_peer);
763 	} else {
764 		wma_create_peer(wma, mac_addr.bytes,
765 				WMI_PEER_TYPE_DEFAULT,
766 				vdev_id,
767 				NULL,
768 				is_assoc_peer);
769 	}
770 
771 	if (is_multi_link_roam(roam_synch_ind_ptr))
772 		lim_roam_mlo_create_peer(wma->mac_context,
773 					 roam_synch_ind_ptr,
774 					 vdev_id,
775 					 mac_addr.bytes);
776 
777 	if (wlan_vdev_mlme_get_opmode(wma->interfaces[vdev_id].vdev) ==
778 								QDF_STA_MODE)
779 		wlan_cdp_set_peer_freq(wma->psoc, mac_addr.bytes,
780 				       wma->interfaces[vdev_id].ch_freq,
781 				       vdev_id);
782 
783 	/* Update new peer's uc cipher */
784 	uc_cipher = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev,
785 					   WLAN_CRYPTO_PARAM_UCAST_CIPHER);
786 	cipher_cap = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev,
787 					   WLAN_CRYPTO_PARAM_CIPHER_CAP);
788 	wma_set_peer_ucast_cipher(mac_addr.bytes, uc_cipher,
789 				  cipher_cap);
790 	wma_add_bss_lfr3(wma, roam_synch_ind_ptr->add_bss_params);
791 	wma_add_sta(wma, add_sta_params);
792 	qdf_mem_copy(bssid, mac_addr.bytes,
793 		     QDF_MAC_ADDR_SIZE);
794 	lim_fill_roamed_peer_twt_caps(wma->mac_context, vdev_id,
795 				      roam_synch_ind_ptr);
796 end:
797 	qdf_mem_free(add_sta_params);
798 }
799 
800 static void wma_update_phymode_on_roam(tp_wma_handle wma,
801 				       struct qdf_mac_addr *bssid,
802 				       wmi_channel *chan,
803 				       struct wma_txrx_node *iface)
804 {
805 	enum wlan_phymode bss_phymode;
806 	struct wlan_channel *des_chan;
807 	struct wlan_channel *bss_chan;
808 	struct vdev_mlme_obj *vdev_mlme;
809 	uint8_t channel;
810 	struct wlan_objmgr_pdev *pdev = NULL;
811 	qdf_freq_t sec_ch_2g_freq = 0;
812 	struct ch_params ch_params = {0};
813 
814 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev);
815 	if (!vdev_mlme)
816 		return;
817 
818 	pdev = wlan_vdev_get_pdev(vdev_mlme->vdev);
819 
820 	channel = wlan_reg_freq_to_chan(pdev, iface->ch_freq);
821 	if (chan)
822 		bss_phymode =
823 			wma_fw_to_host_phymode(WMI_GET_CHANNEL_MODE(chan));
824 	else
825 		wma_get_phy_mode_cb(iface->ch_freq,
826 				    iface->chan_width, &bss_phymode);
827 
828 	/* Update vdev mlme channel info after roaming */
829 	des_chan = wlan_vdev_mlme_get_des_chan(iface->vdev);
830 	bss_chan = wlan_vdev_mlme_get_bss_chan(iface->vdev);
831 	des_chan->ch_phymode = bss_phymode;
832 	des_chan->ch_width = iface->chan_width;
833 	if (chan) {
834 		des_chan->ch_freq = chan->mhz;
835 		ch_params.ch_width = des_chan->ch_width;
836 		if (wlan_reg_is_24ghz_ch_freq(des_chan->ch_freq) &&
837 		    des_chan->ch_width == CH_WIDTH_40MHZ &&
838 		    chan->band_center_freq1) {
839 			if (des_chan->ch_freq < chan->band_center_freq1)
840 				sec_ch_2g_freq = des_chan->ch_freq + 20;
841 			else
842 				sec_ch_2g_freq = des_chan->ch_freq - 20;
843 		}
844 		wlan_reg_set_channel_params_for_pwrmode(pdev, des_chan->ch_freq,
845 							sec_ch_2g_freq,
846 							&ch_params,
847 							REG_CURRENT_PWR_MODE);
848 		if (ch_params.ch_width != des_chan->ch_width ||
849 		    ch_params.mhz_freq_seg0 != chan->band_center_freq1 ||
850 		    ch_params.mhz_freq_seg1 != chan->band_center_freq2)
851 			wma_err("ch mismatch host & fw bw (%d %d) seg0 (%d, %d) seg1 (%d, %d)",
852 				ch_params.ch_width, des_chan->ch_width,
853 				ch_params.mhz_freq_seg0,
854 				chan->band_center_freq1,
855 				ch_params.mhz_freq_seg1,
856 				chan->band_center_freq2);
857 		des_chan->ch_cfreq1 = ch_params.mhz_freq_seg0;
858 		des_chan->ch_cfreq2 = ch_params.mhz_freq_seg1;
859 		des_chan->ch_width = ch_params.ch_width;
860 	} else {
861 		wma_err("LFR3: invalid chan");
862 	}
863 	qdf_mem_copy(bss_chan, des_chan, sizeof(struct wlan_channel));
864 
865 	/* Till conversion is not done in WMI we need to fill fw phy mode */
866 	vdev_mlme->mgmt.generic.phy_mode = wmi_host_to_fw_phymode(bss_phymode);
867 
868 	/* update new phymode to peer */
869 	wma_objmgr_set_peer_mlme_phymode(wma, bssid->bytes, bss_phymode);
870 
871 	wma_debug("LFR3: new phymode %d freq %d (bw %d, %d %d)",
872 		  bss_phymode, des_chan->ch_freq, des_chan->ch_width,
873 		  des_chan->ch_cfreq1, des_chan->ch_cfreq2);
874 }
875 
876 /**
877  * wma_set_ric_req() - set ric request element
878  * @wma: wma handle
879  * @msg: message
880  * @is_add_ts: is addts required
881  *
882  * This function sets ric request element for 11r roaming.
883  *
884  * Return: none
885  */
886 void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts)
887 {
888 	if (!wma) {
889 		wma_err("wma handle is NULL");
890 		return;
891 	}
892 
893 	wmi_unified_set_ric_req_cmd(wma->wmi_handle, msg, is_add_ts);
894 }
895 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
896 
897 #ifdef FEATURE_RSSI_MONITOR
898 QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma,
899 				   struct rssi_monitor_param *req)
900 {
901 	if (!wma) {
902 		wma_err("wma handle is NULL");
903 		return QDF_STATUS_E_INVAL;
904 	}
905 
906 	return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, req);
907 }
908 
909 /**
910  * wma_rssi_breached_event_handler() - rssi breached event handler
911  * @handle: wma handle
912  * @cmd_param_info: event handler data
913  * @len: length of @cmd_param_info
914  *
915  * Return: 0 on success; error number otherwise
916  */
917 int wma_rssi_breached_event_handler(void *handle,
918 				u_int8_t  *cmd_param_info, u_int32_t len)
919 {
920 	WMI_RSSI_BREACH_EVENTID_param_tlvs *param_buf;
921 	wmi_rssi_breach_event_fixed_param  *event;
922 	struct rssi_breach_event  rssi;
923 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
924 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
925 
926 	if (!mac || !wma) {
927 		wma_err("Invalid mac/wma context");
928 		return -EINVAL;
929 	}
930 	if (!mac->sme.rssi_threshold_breached_cb) {
931 		wma_err("Callback not registered");
932 		return -EINVAL;
933 	}
934 	param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info;
935 	if (!param_buf) {
936 		wma_err("Invalid rssi breached event");
937 		return -EINVAL;
938 	}
939 	event = param_buf->fixed_param;
940 
941 	rssi.request_id = event->request_id;
942 	rssi.session_id = event->vdev_id;
943 	if (wmi_service_enabled(wma->wmi_handle,
944 				wmi_service_hw_db2dbm_support))
945 		rssi.curr_rssi = event->rssi;
946 	else
947 		rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM;
948 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes);
949 
950 	wma_debug("req_id: %u vdev_id: %d curr_rssi: %d",
951 		 rssi.request_id, rssi.session_id, rssi.curr_rssi);
952 	wma_debug("curr_bssid: "QDF_MAC_ADDR_FMT,
953 		  QDF_MAC_ADDR_REF(rssi.curr_bssid.bytes));
954 
955 	mac->sme.rssi_threshold_breached_cb(mac->hdd_handle, &rssi);
956 	wma_debug("Invoke HDD rssi breached callback");
957 	return 0;
958 }
959 #endif /* FEATURE_RSSI_MONITOR */
960 
961 QDF_STATUS wma_pre_chan_switch_setup(uint8_t vdev_id)
962 {
963 	QDF_STATUS status = QDF_STATUS_SUCCESS;
964 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
965 	struct wma_txrx_node *intr;
966 	uint16_t beacon_interval_ori;
967 	bool restart;
968 	uint16_t reduced_beacon_interval;
969 	struct vdev_mlme_obj *mlme_obj;
970 	struct wlan_objmgr_vdev *vdev;
971 
972 	if (!wma) {
973 		pe_err("wma is NULL");
974 		return QDF_STATUS_E_FAILURE;
975 	}
976 	intr = &wma->interfaces[vdev_id];
977 	if (!intr) {
978 		pe_err("wma txrx node is NULL");
979 		return QDF_STATUS_E_FAILURE;
980 	}
981 	vdev = intr->vdev;
982 	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev);
983 	if (!mlme_obj) {
984 		pe_err("vdev component object is NULL");
985 		return QDF_STATUS_E_FAILURE;
986 	}
987 
988 	restart =
989 		wma_get_channel_switch_in_progress(intr);
990 	if (restart && intr->beacon_filter_enabled)
991 		wma_remove_beacon_filter(wma, &intr->beacon_filter);
992 
993 	reduced_beacon_interval =
994 		wma->mac_context->sap.SapDfsInfo.reduced_beacon_interval;
995 	if (wma_is_vdev_in_ap_mode(wma, vdev_id) && reduced_beacon_interval) {
996 
997 
998 		/* Reduce the beacon interval just before the channel switch.
999 		 * This would help in reducing the downtime on the STA side
1000 		 * (which is waiting for beacons from the AP to resume back
1001 		 * transmission). Switch back the beacon_interval to its
1002 		 * original value after the channel switch based on the
1003 		 * timeout. This would ensure there are atleast some beacons
1004 		 * sent with increased frequency.
1005 		 */
1006 
1007 		wma_debug("Changing beacon interval to %d",
1008 			 reduced_beacon_interval);
1009 
1010 		/* Add a timer to reset the beacon interval back*/
1011 		beacon_interval_ori = mlme_obj->proto.generic.beacon_interval;
1012 		mlme_obj->proto.generic.beacon_interval =
1013 			reduced_beacon_interval;
1014 		if (wma_fill_beacon_interval_reset_req(wma,
1015 			vdev_id,
1016 			beacon_interval_ori,
1017 			RESET_BEACON_INTERVAL_TIMEOUT)) {
1018 
1019 			wma_debug("Failed to fill beacon interval reset req");
1020 		}
1021 	}
1022 
1023 	status = wma_vdev_pre_start(vdev_id, restart);
1024 
1025 	return status;
1026 }
1027 
1028 QDF_STATUS wma_post_chan_switch_setup(uint8_t vdev_id)
1029 {
1030 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
1031 	struct wma_txrx_node *intr;
1032 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1033 	struct wlan_channel *des_chan;
1034 	cdp_config_param_type val;
1035 
1036 	if (!wma) {
1037 		pe_err("wma is NULL");
1038 		return QDF_STATUS_E_FAILURE;
1039 	}
1040 	intr = &wma->interfaces[vdev_id];
1041 	if (!intr) {
1042 		pe_err("wma txrx node is NULL");
1043 		return QDF_STATUS_E_FAILURE;
1044 	}
1045 	/*
1046 	 * Record monitor mode channel here in case HW
1047 	 * indicate RX PPDU TLV with invalid channel number.
1048 	 */
1049 	if (intr->type == WMI_VDEV_TYPE_MONITOR) {
1050 		des_chan = intr->vdev->vdev_mlme.des_chan;
1051 		val.cdp_pdev_param_monitor_chan = des_chan->ch_ieee;
1052 		cdp_txrx_set_pdev_param(soc,
1053 					wlan_objmgr_pdev_get_pdev_id(wma->pdev),
1054 					CDP_MONITOR_CHANNEL, val);
1055 		val.cdp_pdev_param_mon_freq = des_chan->ch_freq;
1056 		cdp_txrx_set_pdev_param(soc,
1057 					wlan_objmgr_pdev_get_pdev_id(wma->pdev),
1058 					CDP_MONITOR_FREQUENCY, val);
1059 	}
1060 	return QDF_STATUS_SUCCESS;
1061 }
1062 
1063 #ifdef FEATURE_WLAN_ESE
1064 /**
1065  * wma_plm_start() - plm start request
1066  * @wma: wma handle
1067  * @params: plm request parameters
1068  *
1069  * This function request FW to start PLM.
1070  *
1071  * Return: QDF status
1072  */
1073 static QDF_STATUS wma_plm_start(tp_wma_handle wma,
1074 				struct plm_req_params *params)
1075 {
1076 	QDF_STATUS status;
1077 
1078 	wma_debug("PLM Start");
1079 
1080 	status = wmi_unified_plm_start_cmd(wma->wmi_handle, params);
1081 	if (QDF_IS_STATUS_ERROR(status))
1082 		return status;
1083 
1084 	wma->interfaces[params->vdev_id].plm_in_progress = true;
1085 
1086 	wma_debug("Plm start request sent successfully for vdev %d",
1087 		 params->vdev_id);
1088 
1089 	return status;
1090 }
1091 
1092 /**
1093  * wma_plm_stop() - plm stop request
1094  * @wma: wma handle
1095  * @params: plm request parameters
1096  *
1097  * This function request FW to stop PLM.
1098  *
1099  * Return: QDF status
1100  */
1101 static QDF_STATUS wma_plm_stop(tp_wma_handle wma,
1102 			       struct plm_req_params *params)
1103 {
1104 	QDF_STATUS status;
1105 
1106 	if (!wma->interfaces[params->vdev_id].plm_in_progress) {
1107 		wma_err("No active plm req found, skip plm stop req");
1108 		return QDF_STATUS_E_FAILURE;
1109 	}
1110 
1111 	wma_debug("PLM Stop");
1112 
1113 	status = wmi_unified_plm_stop_cmd(wma->wmi_handle, params);
1114 	if (QDF_IS_STATUS_ERROR(status))
1115 		return status;
1116 
1117 	wma->interfaces[params->vdev_id].plm_in_progress = false;
1118 
1119 	wma_debug("Plm stop request sent successfully for vdev %d",
1120 		 params->vdev_id);
1121 
1122 	return status;
1123 }
1124 
1125 /**
1126  * wma_config_plm() - config PLM
1127  * @wma: wma handle
1128  * @params: plm request parameters
1129  *
1130  * Return: none
1131  */
1132 void wma_config_plm(tp_wma_handle wma, struct plm_req_params *params)
1133 {
1134 	QDF_STATUS ret;
1135 
1136 	if (!params || !wma)
1137 		return;
1138 
1139 	if (params->enable)
1140 		ret = wma_plm_start(wma, params);
1141 	else
1142 		ret = wma_plm_stop(wma, params);
1143 
1144 	if (ret)
1145 		wma_err("PLM %s failed %d",
1146 			params->enable ? "start" : "stop", ret);
1147 }
1148 #endif
1149 
1150 #ifdef FEATURE_WLAN_EXTSCAN
1151 /**
1152  * wma_extscan_wow_event_callback() - extscan wow event callback
1153  * @handle: WMA handle
1154  * @event: event buffer
1155  * @len: length of @event buffer
1156  *
1157  * In wow case, the wow event is followed by the payload of the event
1158  * which generated the wow event.
1159  * payload is 4 bytes of length followed by event buffer. the first 4 bytes
1160  * of event buffer is common tlv header, which is a combination
1161  * of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to
1162  * identify the event which triggered wow event.
1163  * Payload is extracted and converted into generic tlv structure before
1164  * being passed to this function.
1165  *
1166  * @Return: Errno
1167  */
1168 int wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len)
1169 {
1170 	uint32_t tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(event));
1171 
1172 	switch (tag) {
1173 	case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param:
1174 		return wma_extscan_start_stop_event_handler(handle, event, len);
1175 
1176 	case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param:
1177 		return wma_extscan_operations_event_handler(handle, event, len);
1178 
1179 	case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param:
1180 		return wma_extscan_table_usage_event_handler(handle, event,
1181 							     len);
1182 
1183 	case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param:
1184 		return wma_extscan_cached_results_event_handler(handle, event,
1185 								len);
1186 
1187 	case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param:
1188 		return wma_extscan_change_results_event_handler(handle, event,
1189 								len);
1190 
1191 	case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param:
1192 		return wma_extscan_hotlist_match_event_handler(handle,	event,
1193 							       len);
1194 
1195 	case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param:
1196 		return wma_extscan_capabilities_event_handler(handle, event,
1197 							      len);
1198 
1199 	default:
1200 		wma_err("Unknown tag: %d", tag);
1201 		return 0;
1202 	}
1203 }
1204 
1205 /**
1206  * wma_register_extscan_event_handler() - register extscan event handler
1207  * @wma_handle: wma handle
1208  *
1209  * This function register extscan related event handlers.
1210  *
1211  * Return: none
1212  */
1213 void wma_register_extscan_event_handler(tp_wma_handle wma_handle)
1214 {
1215 	if (wma_validate_handle(wma_handle))
1216 		return;
1217 
1218 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1219 					   wmi_extscan_start_stop_event_id,
1220 					   wma_extscan_start_stop_event_handler,
1221 					   WMA_RX_SERIALIZER_CTX);
1222 
1223 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1224 					wmi_extscan_capabilities_event_id,
1225 					wma_extscan_capabilities_event_handler,
1226 					WMA_RX_SERIALIZER_CTX);
1227 
1228 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1229 				wmi_extscan_hotlist_match_event_id,
1230 				wma_extscan_hotlist_match_event_handler,
1231 				WMA_RX_SERIALIZER_CTX);
1232 
1233 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1234 				wmi_extscan_wlan_change_results_event_id,
1235 				wma_extscan_change_results_event_handler,
1236 				WMA_RX_SERIALIZER_CTX);
1237 
1238 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1239 				wmi_extscan_operation_event_id,
1240 				wma_extscan_operations_event_handler,
1241 				WMA_RX_SERIALIZER_CTX);
1242 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1243 				wmi_extscan_table_usage_event_id,
1244 				wma_extscan_table_usage_event_handler,
1245 				WMA_RX_SERIALIZER_CTX);
1246 
1247 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1248 				wmi_extscan_cached_results_event_id,
1249 				wma_extscan_cached_results_event_handler,
1250 				WMA_RX_SERIALIZER_CTX);
1251 
1252 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1253 			wmi_passpoint_match_event_id,
1254 			wma_passpoint_match_event_handler,
1255 			WMA_RX_SERIALIZER_CTX);
1256 }
1257 
1258 /**
1259  * wma_extscan_start_stop_event_handler() -  extscan start/stop event handler
1260  * @handle: wma handle
1261  * @cmd_param_info: event buffer
1262  * @len: data length
1263  *
1264  * This function handles different extscan related commands
1265  * like start/stop/get results etc and indicate to upper layers.
1266  *
1267  * Return: 0 for success or error code.
1268  */
1269 int wma_extscan_start_stop_event_handler(void *handle,
1270 					 uint8_t *cmd_param_info,
1271 					 uint32_t len)
1272 {
1273 	WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *param_buf;
1274 	wmi_extscan_start_stop_event_fixed_param *event;
1275 	struct sir_extscan_generic_response   *extscan_ind;
1276 	uint16_t event_type;
1277 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1278 
1279 	if (!mac)
1280 		return -EINVAL;
1281 
1282 	if (!mac->sme.ext_scan_ind_cb) {
1283 		wma_err("Callback not registered");
1284 		return -EINVAL;
1285 	}
1286 	param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *)
1287 		    cmd_param_info;
1288 	if (!param_buf) {
1289 		wma_err("Invalid extscan event");
1290 		return -EINVAL;
1291 	}
1292 	event = param_buf->fixed_param;
1293 	extscan_ind = qdf_mem_malloc(sizeof(*extscan_ind));
1294 	if (!extscan_ind)
1295 		return -ENOMEM;
1296 
1297 	switch (event->command) {
1298 	case WMI_EXTSCAN_START_CMDID:
1299 		event_type = eSIR_EXTSCAN_START_RSP;
1300 		extscan_ind->status = event->status;
1301 		extscan_ind->request_id = event->request_id;
1302 		break;
1303 	case WMI_EXTSCAN_STOP_CMDID:
1304 		event_type = eSIR_EXTSCAN_STOP_RSP;
1305 		extscan_ind->status = event->status;
1306 		extscan_ind->request_id = event->request_id;
1307 		break;
1308 	case WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID:
1309 		extscan_ind->status = event->status;
1310 		extscan_ind->request_id = event->request_id;
1311 		if (event->mode == WMI_EXTSCAN_MODE_STOP)
1312 			event_type =
1313 				eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP;
1314 		else
1315 			event_type =
1316 				eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP;
1317 		break;
1318 	case WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID:
1319 		extscan_ind->status = event->status;
1320 		extscan_ind->request_id = event->request_id;
1321 		if (event->mode == WMI_EXTSCAN_MODE_STOP)
1322 			event_type = eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP;
1323 		else
1324 			event_type = eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP;
1325 		break;
1326 	case WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID:
1327 		extscan_ind->status = event->status;
1328 		extscan_ind->request_id = event->request_id;
1329 		event_type = eSIR_EXTSCAN_CACHED_RESULTS_RSP;
1330 		break;
1331 	case WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID:
1332 		extscan_ind->status = event->status;
1333 		extscan_ind->request_id = event->request_id;
1334 		if (event->mode == WMI_EXTSCAN_MODE_STOP)
1335 			event_type =
1336 				eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP;
1337 		else
1338 			event_type =
1339 				eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP;
1340 		break;
1341 	default:
1342 		wma_err("Unknown event(%d) from target", event->status);
1343 		qdf_mem_free(extscan_ind);
1344 		return -EINVAL;
1345 	}
1346 	mac->sme.ext_scan_ind_cb(mac->hdd_handle, event_type, extscan_ind);
1347 	wma_debug("sending event to umac for requestid %u with status %d",
1348 		 extscan_ind->request_id, extscan_ind->status);
1349 	qdf_mem_free(extscan_ind);
1350 	return 0;
1351 }
1352 
1353 /**
1354  * wma_extscan_operations_event_handler() - extscan operation event handler
1355  * @handle: wma handle
1356  * @cmd_param_info: event buffer
1357  * @len: length
1358  *
1359  * This function handles different operations related event and indicate
1360  * upper layers with appropriate callback.
1361  *
1362  * Return: 0 for success or error code.
1363  */
1364 int wma_extscan_operations_event_handler(void *handle,
1365 					 uint8_t *cmd_param_info,
1366 					 uint32_t len)
1367 {
1368 	tp_wma_handle wma = (tp_wma_handle) handle;
1369 	WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *param_buf;
1370 	wmi_extscan_operation_event_fixed_param *oprn_event;
1371 	tSirExtScanOnScanEventIndParams *oprn_ind;
1372 	uint32_t cnt;
1373 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1374 
1375 	if (!mac)
1376 		return -EINVAL;
1377 
1378 	if (!mac->sme.ext_scan_ind_cb) {
1379 		wma_err("Callback not registered");
1380 		return -EINVAL;
1381 	}
1382 	param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *)
1383 		    cmd_param_info;
1384 	if (!param_buf) {
1385 		wma_err("Invalid scan operation event");
1386 		return -EINVAL;
1387 	}
1388 	oprn_event = param_buf->fixed_param;
1389 	oprn_ind = qdf_mem_malloc(sizeof(*oprn_ind));
1390 	if (!oprn_ind)
1391 		return -ENOMEM;
1392 
1393 	oprn_ind->requestId = oprn_event->request_id;
1394 
1395 	switch (oprn_event->event) {
1396 	case WMI_EXTSCAN_BUCKET_COMPLETED_EVENT:
1397 		oprn_ind->status = 0;
1398 		goto exit_handler;
1399 	case WMI_EXTSCAN_CYCLE_STARTED_EVENT:
1400 		wma_debug("received WMI_EXTSCAN_CYCLE_STARTED_EVENT");
1401 
1402 		if (oprn_event->num_buckets > param_buf->num_bucket_id) {
1403 			wma_err("FW mesg num_buk %d more than TLV hdr %d",
1404 				 oprn_event->num_buckets,
1405 				 param_buf->num_bucket_id);
1406 			qdf_mem_free(oprn_ind);
1407 			return -EINVAL;
1408 		}
1409 
1410 		cds_host_diag_log_work(&wma->extscan_wake_lock,
1411 				       WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION,
1412 				       WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN);
1413 		qdf_wake_lock_timeout_acquire(&wma->extscan_wake_lock,
1414 				      WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION);
1415 		oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_STARTED_EVENT;
1416 		oprn_ind->status = 0;
1417 		oprn_ind->buckets_scanned = 0;
1418 		for (cnt = 0; cnt < oprn_event->num_buckets; cnt++)
1419 			oprn_ind->buckets_scanned |=
1420 				(1 << param_buf->bucket_id[cnt]);
1421 		wma_debug("num_buckets %u request_id %u buckets_scanned %u",
1422 			oprn_event->num_buckets, oprn_ind->requestId,
1423 			oprn_ind->buckets_scanned);
1424 		break;
1425 	case WMI_EXTSCAN_CYCLE_COMPLETED_EVENT:
1426 		wma_debug("received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT");
1427 		qdf_wake_lock_release(&wma->extscan_wake_lock,
1428 				      WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN);
1429 		oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT;
1430 		oprn_ind->status = 0;
1431 		/* Set bucket scanned mask to zero on cycle complete */
1432 		oprn_ind->buckets_scanned = 0;
1433 		break;
1434 	case WMI_EXTSCAN_BUCKET_STARTED_EVENT:
1435 		wma_debug("received WMI_EXTSCAN_BUCKET_STARTED_EVENT");
1436 		oprn_ind->scanEventType = WIFI_EXTSCAN_BUCKET_STARTED_EVENT;
1437 		oprn_ind->status = 0;
1438 		goto exit_handler;
1439 	case WMI_EXTSCAN_THRESHOLD_NUM_SCANS:
1440 		wma_debug("received WMI_EXTSCAN_THRESHOLD_NUM_SCANS");
1441 		oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_NUM_SCANS;
1442 		oprn_ind->status = 0;
1443 		break;
1444 	case WMI_EXTSCAN_THRESHOLD_PERCENT:
1445 		wma_debug("received WMI_EXTSCAN_THRESHOLD_PERCENT");
1446 		oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_PERCENT;
1447 		oprn_ind->status = 0;
1448 		break;
1449 	default:
1450 		wma_err("Unknown event(%d) from target", oprn_event->event);
1451 		qdf_mem_free(oprn_ind);
1452 		return -EINVAL;
1453 	}
1454 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
1455 				eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, oprn_ind);
1456 	wma_debug("sending scan progress event to hdd");
1457 exit_handler:
1458 	qdf_mem_free(oprn_ind);
1459 	return 0;
1460 }
1461 
1462 /**
1463  * wma_extscan_table_usage_event_handler() - extscan table usage event handler
1464  * @handle: wma handle
1465  * @cmd_param_info: event buffer
1466  * @len: length
1467  *
1468  * This function handles table usage related event and indicate
1469  * upper layers with appropriate callback.
1470  *
1471  * Return: 0 for success or error code.
1472  */
1473 int wma_extscan_table_usage_event_handler(void *handle,
1474 					  uint8_t *cmd_param_info,
1475 					  uint32_t len)
1476 {
1477 	WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *param_buf;
1478 	wmi_extscan_table_usage_event_fixed_param *event;
1479 	tSirExtScanResultsAvailableIndParams *tbl_usg_ind;
1480 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1481 
1482 	if (!mac)
1483 		return -EINVAL;
1484 
1485 	if (!mac->sme.ext_scan_ind_cb) {
1486 		wma_err("Callback not registered");
1487 		return -EINVAL;
1488 	}
1489 	param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *)
1490 		    cmd_param_info;
1491 	if (!param_buf) {
1492 		wma_err("Invalid table usage event");
1493 		return -EINVAL;
1494 	}
1495 	event = param_buf->fixed_param;
1496 	tbl_usg_ind = qdf_mem_malloc(sizeof(*tbl_usg_ind));
1497 	if (!tbl_usg_ind)
1498 		return -ENOMEM;
1499 
1500 	tbl_usg_ind->requestId = event->request_id;
1501 	tbl_usg_ind->numResultsAvailable = event->entries_in_use;
1502 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
1503 				eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND,
1504 				tbl_usg_ind);
1505 	wma_debug("sending scan_res available event to hdd");
1506 	qdf_mem_free(tbl_usg_ind);
1507 	return 0;
1508 }
1509 
1510 /**
1511  * wma_extscan_capabilities_event_handler() - extscan capabilities event handler
1512  * @handle: wma handle
1513  * @cmd_param_info: event buffer
1514  * @len: length
1515  *
1516  * This function handles capabilities event and indicate
1517  * upper layers with registered callback.
1518  *
1519  * Return: 0 for success or error code.
1520  */
1521 int wma_extscan_capabilities_event_handler(void *handle,
1522 					   uint8_t *cmd_param_info,
1523 					   uint32_t len)
1524 {
1525 	WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *param_buf;
1526 	wmi_extscan_capabilities_event_fixed_param *event;
1527 	wmi_extscan_cache_capabilities *src_cache;
1528 	wmi_extscan_hotlist_monitor_capabilities *src_hotlist;
1529 	wmi_extscan_wlan_change_monitor_capabilities *src_change;
1530 	struct ext_scan_capabilities_response  *dest_capab;
1531 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1532 
1533 	if (!mac)
1534 		return -EINVAL;
1535 
1536 	if (!mac->sme.ext_scan_ind_cb) {
1537 		wma_err("Callback not registered");
1538 		return -EINVAL;
1539 	}
1540 	param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *)
1541 		    cmd_param_info;
1542 	if (!param_buf) {
1543 		wma_err("Invalid capabilities event");
1544 		return -EINVAL;
1545 	}
1546 	event = param_buf->fixed_param;
1547 	src_cache = param_buf->extscan_cache_capabilities;
1548 	src_hotlist = param_buf->hotlist_capabilities;
1549 	src_change = param_buf->wlan_change_capabilities;
1550 
1551 	if (!src_cache || !src_hotlist || !src_change) {
1552 		wma_err("Invalid capabilities list");
1553 		return -EINVAL;
1554 	}
1555 	dest_capab = qdf_mem_malloc(sizeof(*dest_capab));
1556 	if (!dest_capab)
1557 		return -ENOMEM;
1558 
1559 	dest_capab->requestId = event->request_id;
1560 	dest_capab->max_scan_buckets = src_cache->max_buckets;
1561 	dest_capab->max_scan_cache_size = src_cache->scan_cache_entry_size;
1562 	dest_capab->max_ap_cache_per_scan = src_cache->max_bssid_per_scan;
1563 	dest_capab->max_scan_reporting_threshold =
1564 		src_cache->max_table_usage_threshold;
1565 
1566 	dest_capab->max_hotlist_bssids = src_hotlist->max_hotlist_entries;
1567 	dest_capab->max_rssi_sample_size =
1568 					src_change->max_rssi_averaging_samples;
1569 	dest_capab->max_bssid_history_entries =
1570 		src_change->max_rssi_history_entries;
1571 	dest_capab->max_significant_wifi_change_aps =
1572 		src_change->max_wlan_change_entries;
1573 	dest_capab->max_hotlist_ssids =
1574 				event->num_extscan_hotlist_ssid;
1575 	dest_capab->max_number_epno_networks =
1576 				event->num_epno_networks;
1577 	dest_capab->max_number_epno_networks_by_ssid =
1578 				event->num_epno_networks;
1579 	dest_capab->max_number_of_allow_listed_ssid =
1580 				event->num_roam_ssid_whitelist;
1581 	dest_capab->max_number_of_deny_listed_bssid =
1582 				event->num_roam_bssid_blacklist;
1583 	dest_capab->status = 0;
1584 
1585 	wma_debug("request_id: %u status: %d",
1586 		 dest_capab->requestId, dest_capab->status);
1587 
1588 	wma_debug("Capabilities: max_scan_buckets: %d, max_hotlist_bssids: %d, max_scan_cache_size: %d, max_ap_cache_per_scan: %d",
1589 		 dest_capab->max_scan_buckets,
1590 		 dest_capab->max_hotlist_bssids, dest_capab->max_scan_cache_size,
1591 		 dest_capab->max_ap_cache_per_scan);
1592 	wma_debug("max_scan_reporting_threshold: %d, max_rssi_sample_size: %d, max_bssid_history_entries: %d, max_significant_wifi_change_aps: %d",
1593 		 dest_capab->max_scan_reporting_threshold,
1594 		 dest_capab->max_rssi_sample_size,
1595 		 dest_capab->max_bssid_history_entries,
1596 		 dest_capab->max_significant_wifi_change_aps);
1597 
1598 	wma_debug("Capabilities: max_hotlist_ssids: %d, max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d",
1599 		 dest_capab->max_hotlist_ssids,
1600 		 dest_capab->max_number_epno_networks,
1601 		 dest_capab->max_number_epno_networks_by_ssid);
1602 	wma_debug("max_number_of_allow_listed_ssid: %d, max_number_of_deny_listed_bssid: %d",
1603 		  dest_capab->max_number_of_allow_listed_ssid,
1604 		  dest_capab->max_number_of_deny_listed_bssid);
1605 
1606 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
1607 				eSIR_EXTSCAN_GET_CAPABILITIES_IND, dest_capab);
1608 	qdf_mem_free(dest_capab);
1609 	return 0;
1610 }
1611 
1612 /**
1613  * wma_extscan_hotlist_match_event_handler() - hotlist match event handler
1614  * @handle: wma handle
1615  * @cmd_param_info: event buffer
1616  * @len: length
1617  *
1618  * This function handles hotlist match event and indicate
1619  * upper layers with registered callback.
1620  *
1621  * Return: 0 for success or error code.
1622  */
1623 int wma_extscan_hotlist_match_event_handler(void *handle,
1624 					    uint8_t *cmd_param_info,
1625 					    uint32_t len)
1626 {
1627 	WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *param_buf;
1628 	wmi_extscan_hotlist_match_event_fixed_param *event;
1629 	struct extscan_hotlist_match *dest_hotlist;
1630 	tSirWifiScanResult *dest_ap;
1631 	wmi_extscan_wlan_descriptor *src_hotlist;
1632 	uint32_t numap;
1633 	int j, ap_found = 0;
1634 	uint32_t buf_len;
1635 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1636 
1637 	if (!mac)
1638 		return -EINVAL;
1639 
1640 	if (!mac->sme.ext_scan_ind_cb) {
1641 		wma_err("Callback not registered");
1642 		return -EINVAL;
1643 	}
1644 	param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *)
1645 		    cmd_param_info;
1646 	if (!param_buf) {
1647 		wma_err("Invalid hotlist match event");
1648 		return -EINVAL;
1649 	}
1650 	event = param_buf->fixed_param;
1651 	src_hotlist = param_buf->hotlist_match;
1652 	numap = event->total_entries;
1653 
1654 	if (!src_hotlist || !numap) {
1655 		wma_err("Hotlist AP's list invalid");
1656 		return -EINVAL;
1657 	}
1658 	if (numap > param_buf->num_hotlist_match) {
1659 		wma_err("Invalid no of total enteries %d", numap);
1660 		return -EINVAL;
1661 	}
1662 	if (numap > WMA_EXTSCAN_MAX_HOTLIST_ENTRIES) {
1663 		wma_err("Total Entries %u greater than max", numap);
1664 		numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES;
1665 	}
1666 
1667 	buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) +
1668 		  WMI_TLV_HDR_SIZE +
1669 		  (numap * sizeof(wmi_extscan_wlan_descriptor));
1670 
1671 	if (buf_len > len) {
1672 		wma_err("Invalid buf len from FW %d numap %d", len, numap);
1673 		return -EINVAL;
1674 	}
1675 
1676 	dest_hotlist = qdf_mem_malloc(sizeof(*dest_hotlist) +
1677 				      sizeof(*dest_ap) * numap);
1678 	if (!dest_hotlist)
1679 		return -ENOMEM;
1680 
1681 	dest_ap = &dest_hotlist->ap[0];
1682 	dest_hotlist->numOfAps = numap;
1683 	dest_hotlist->requestId = event->config_request_id;
1684 
1685 	if (event->first_entry_index +
1686 		event->num_entries_in_page < event->total_entries)
1687 		dest_hotlist->moreData = 1;
1688 	else
1689 		dest_hotlist->moreData = 0;
1690 
1691 	wma_debug("Hotlist match: requestId: %u numOfAps: %d",
1692 		 dest_hotlist->requestId, dest_hotlist->numOfAps);
1693 
1694 	/*
1695 	 * Currently firmware sends only one bss information in-case
1696 	 * of both hotlist ap found and lost.
1697 	 */
1698 	for (j = 0; j < numap; j++) {
1699 		dest_ap->rssi = 0;
1700 		dest_ap->channel = src_hotlist->channel;
1701 		dest_ap->ts = src_hotlist->tstamp;
1702 		ap_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE;
1703 		dest_ap->rtt = src_hotlist->rtt;
1704 		dest_ap->rtt_sd = src_hotlist->rtt_sd;
1705 		dest_ap->beaconPeriod = src_hotlist->beacon_interval;
1706 		dest_ap->capability = src_hotlist->capabilities;
1707 		dest_ap->ieLength = src_hotlist->ie_length;
1708 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid,
1709 					   dest_ap->bssid.bytes);
1710 		if (src_hotlist->ssid.ssid_len > WLAN_SSID_MAX_LEN) {
1711 			wma_err("Invalid SSID len %d, truncating",
1712 				src_hotlist->ssid.ssid_len);
1713 			src_hotlist->ssid.ssid_len = WLAN_SSID_MAX_LEN;
1714 		}
1715 		qdf_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid,
1716 			     src_hotlist->ssid.ssid_len);
1717 		dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0';
1718 		dest_ap++;
1719 		src_hotlist++;
1720 	}
1721 	dest_hotlist->ap_found = ap_found;
1722 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
1723 				eSIR_EXTSCAN_HOTLIST_MATCH_IND, dest_hotlist);
1724 	wma_debug("sending hotlist match event to hdd");
1725 	qdf_mem_free(dest_hotlist);
1726 	return 0;
1727 }
1728 
1729 /** wma_extscan_find_unique_scan_ids() - find unique scan ids
1730  * @cmd_param_info: event data.
1731  *
1732  * This utility function parses the input bss table of information
1733  * and find the unique number of scan ids
1734  *
1735  * Return: 0 on success; error number otherwise
1736  */
1737 static int wma_extscan_find_unique_scan_ids(const u_int8_t *cmd_param_info)
1738 {
1739 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
1740 	wmi_extscan_cached_results_event_fixed_param  *event;
1741 	wmi_extscan_wlan_descriptor  *src_hotlist;
1742 	wmi_extscan_rssi_info  *src_rssi;
1743 	int prev_scan_id, scan_ids_cnt, i;
1744 
1745 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
1746 						cmd_param_info;
1747 	event = param_buf->fixed_param;
1748 	src_hotlist = param_buf->bssid_list;
1749 	src_rssi = param_buf->rssi_list;
1750 
1751 	/* Find the unique number of scan_id's for grouping */
1752 	prev_scan_id = src_rssi->scan_cycle_id;
1753 	scan_ids_cnt = 1;
1754 	for (i = 1; i < param_buf->num_rssi_list; i++) {
1755 		src_rssi++;
1756 
1757 		if (prev_scan_id != src_rssi->scan_cycle_id) {
1758 			scan_ids_cnt++;
1759 			prev_scan_id = src_rssi->scan_cycle_id;
1760 		}
1761 	}
1762 
1763 	return scan_ids_cnt;
1764 }
1765 
1766 /** wma_fill_num_results_per_scan_id() - fill number of bss per scan id
1767  * @cmd_param_info: event data.
1768  * @scan_id_group: pointer to scan id group.
1769  *
1770  * This utility function parses the input bss table of information
1771  * and finds how many bss are there per unique scan id.
1772  *
1773  * Return: 0 on success; error number otherwise
1774  */
1775 static int wma_fill_num_results_per_scan_id(const u_int8_t *cmd_param_info,
1776 			struct extscan_cached_scan_result *scan_id_group)
1777 {
1778 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
1779 	wmi_extscan_cached_results_event_fixed_param  *event;
1780 	wmi_extscan_wlan_descriptor  *src_hotlist;
1781 	wmi_extscan_rssi_info  *src_rssi;
1782 	struct extscan_cached_scan_result *t_scan_id_grp;
1783 	int i, prev_scan_id;
1784 
1785 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
1786 						cmd_param_info;
1787 	event = param_buf->fixed_param;
1788 	src_hotlist = param_buf->bssid_list;
1789 	src_rssi = param_buf->rssi_list;
1790 	t_scan_id_grp = scan_id_group;
1791 
1792 	prev_scan_id = src_rssi->scan_cycle_id;
1793 
1794 	t_scan_id_grp->scan_id = src_rssi->scan_cycle_id;
1795 	t_scan_id_grp->flags = src_rssi->flags;
1796 	t_scan_id_grp->buckets_scanned = src_rssi->buckets_scanned;
1797 	t_scan_id_grp->num_results = 1;
1798 	for (i = 1; i < param_buf->num_rssi_list; i++) {
1799 		src_rssi++;
1800 		if (prev_scan_id == src_rssi->scan_cycle_id) {
1801 			t_scan_id_grp->num_results++;
1802 		} else {
1803 			t_scan_id_grp++;
1804 			prev_scan_id = t_scan_id_grp->scan_id =
1805 				src_rssi->scan_cycle_id;
1806 			t_scan_id_grp->flags = src_rssi->flags;
1807 			t_scan_id_grp->buckets_scanned =
1808 				src_rssi->buckets_scanned;
1809 			t_scan_id_grp->num_results = 1;
1810 		}
1811 	}
1812 	return 0;
1813 }
1814 
1815 /** wma_group_num_bss_to_scan_id() - group bss to scan id table
1816  * @cmd_param_info: event data.
1817  * @cached_result: pointer to cached table.
1818  *
1819  * This function reads the bss information from the format
1820  * ------------------------------------------------------------------------
1821  * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_1 | flags |
1822  * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_2 | flags |
1823  * ........................................................................
1824  * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_N | flags |
1825  * ------------------------------------------------------------------------
1826  *
1827  * and converts it into the below format and store it
1828  *
1829  * ------------------------------------------------------------------------
1830  * | scan id_1 | -> bss info_1 -> bss info_2 -> .... bss info_M1
1831  * | scan id_2 | -> bss info_1 -> bss info_2 -> .... bss info_M2
1832  * ......................
1833  * | scan id_N | -> bss info_1 -> bss info_2 -> .... bss info_Mn
1834  * ------------------------------------------------------------------------
1835  *
1836  * Return: 0 on success; error number otherwise
1837  */
1838 static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info,
1839 			struct extscan_cached_scan_results *cached_result)
1840 {
1841 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
1842 	wmi_extscan_cached_results_event_fixed_param  *event;
1843 	wmi_extscan_wlan_descriptor  *src_hotlist;
1844 	wmi_extscan_rssi_info  *src_rssi;
1845 	struct extscan_cached_scan_results *t_cached_result;
1846 	struct extscan_cached_scan_result *t_scan_id_grp;
1847 	int i, j;
1848 	uint32_t total_scan_num_results = 0;
1849 	tSirWifiScanResult *ap;
1850 
1851 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
1852 						cmd_param_info;
1853 	event = param_buf->fixed_param;
1854 	src_hotlist = param_buf->bssid_list;
1855 	src_rssi = param_buf->rssi_list;
1856 	t_cached_result = cached_result;
1857 	t_scan_id_grp = &t_cached_result->result[0];
1858 
1859 	for (i = 0; i < t_cached_result->num_scan_ids; i++) {
1860 		total_scan_num_results += t_scan_id_grp->num_results;
1861 		t_scan_id_grp++;
1862 	}
1863 
1864 	if (total_scan_num_results > param_buf->num_bssid_list) {
1865 		wma_err("total_scan_num_results %d, num_bssid_list %d",
1866 			total_scan_num_results,
1867 			param_buf->num_bssid_list);
1868 		return -EINVAL;
1869 	}
1870 
1871 	t_scan_id_grp = &t_cached_result->result[0];
1872 	wma_debug("num_scan_ids:%d",
1873 			t_cached_result->num_scan_ids);
1874 	for (i = 0; i < t_cached_result->num_scan_ids; i++) {
1875 		wma_debug("num_results:%d", t_scan_id_grp->num_results);
1876 		t_scan_id_grp->ap = qdf_mem_malloc(t_scan_id_grp->num_results *
1877 						sizeof(*ap));
1878 		if (!t_scan_id_grp->ap)
1879 			return -ENOMEM;
1880 
1881 		ap = &t_scan_id_grp->ap[0];
1882 		for (j = 0; j < t_scan_id_grp->num_results; j++) {
1883 			ap->channel = src_hotlist->channel;
1884 			ap->ts = WMA_MSEC_TO_USEC(src_rssi->tstamp);
1885 			ap->rtt = src_hotlist->rtt;
1886 			ap->rtt_sd = src_hotlist->rtt_sd;
1887 			ap->beaconPeriod = src_hotlist->beacon_interval;
1888 			ap->capability = src_hotlist->capabilities;
1889 			ap->ieLength = src_hotlist->ie_length;
1890 
1891 			/* Firmware already applied noise floor adjustment and
1892 			 * due to WMI interface "UINT32 rssi", host driver
1893 			 * receives a positive value, hence convert to
1894 			 * signed char to get the absolute rssi.
1895 			 */
1896 			ap->rssi = (signed char) src_rssi->rssi;
1897 			WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid,
1898 						   ap->bssid.bytes);
1899 
1900 			if (src_hotlist->ssid.ssid_len >
1901 			    WLAN_SSID_MAX_LEN) {
1902 				wma_debug("Invalid SSID len %d, truncating",
1903 					 src_hotlist->ssid.ssid_len);
1904 				src_hotlist->ssid.ssid_len =
1905 						WLAN_SSID_MAX_LEN;
1906 			}
1907 			qdf_mem_copy(ap->ssid, src_hotlist->ssid.ssid,
1908 					src_hotlist->ssid.ssid_len);
1909 			ap->ssid[src_hotlist->ssid.ssid_len] = '\0';
1910 			ap++;
1911 			src_rssi++;
1912 			src_hotlist++;
1913 		}
1914 		t_scan_id_grp++;
1915 	}
1916 	return 0;
1917 }
1918 
1919 /**
1920  * wma_extscan_cached_results_event_handler() - cached results event handler
1921  * @handle: wma handle
1922  * @cmd_param_info: event buffer
1923  * @len: length of @cmd_param_info
1924  *
1925  * This function handles cached results event and indicate
1926  * cached results to upper layer.
1927  *
1928  * Return: 0 for success or error code.
1929  */
1930 int wma_extscan_cached_results_event_handler(void *handle,
1931 					     uint8_t *cmd_param_info,
1932 					     uint32_t len)
1933 {
1934 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
1935 	wmi_extscan_cached_results_event_fixed_param *event;
1936 	struct extscan_cached_scan_results *dest_cachelist;
1937 	struct extscan_cached_scan_result *dest_result;
1938 	struct extscan_cached_scan_results empty_cachelist;
1939 	wmi_extscan_wlan_descriptor *src_hotlist;
1940 	wmi_extscan_rssi_info *src_rssi;
1941 	int i, moredata, scan_ids_cnt, buf_len, status;
1942 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1943 	uint32_t total_len;
1944 	bool excess_data = false;
1945 
1946 	if (!mac) {
1947 		wma_err("Invalid mac");
1948 		return -EINVAL;
1949 	}
1950 	if (!mac->sme.ext_scan_ind_cb) {
1951 		wma_err("Callback not registered");
1952 		return -EINVAL;
1953 	}
1954 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
1955 		    cmd_param_info;
1956 	if (!param_buf) {
1957 		wma_err("Invalid cached results event");
1958 		return -EINVAL;
1959 	}
1960 	event = param_buf->fixed_param;
1961 	src_hotlist = param_buf->bssid_list;
1962 	src_rssi = param_buf->rssi_list;
1963 	wma_debug("Total_entries: %u first_entry_index: %u num_entries_in_page: %d",
1964 		 event->total_entries,
1965 		 event->first_entry_index,
1966 		 event->num_entries_in_page);
1967 
1968 	if (!src_hotlist || !src_rssi || !event->num_entries_in_page) {
1969 		wma_warn("Cached results empty, send 0 results");
1970 		goto noresults;
1971 	}
1972 
1973 	if (event->num_entries_in_page >
1974 	    (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist) ||
1975 	    event->num_entries_in_page > param_buf->num_bssid_list) {
1976 		wma_err("excess num_entries_in_page %d in WMI event. num_bssid_list %d",
1977 			 event->num_entries_in_page, param_buf->num_bssid_list);
1978 		return -EINVAL;
1979 	} else {
1980 		total_len = sizeof(*event) +
1981 			(event->num_entries_in_page * sizeof(*src_hotlist));
1982 	}
1983 	for (i = 0; i < event->num_entries_in_page; i++) {
1984 		if (src_hotlist[i].ie_length >
1985 		    WMI_SVC_MSG_MAX_SIZE - total_len) {
1986 			excess_data = true;
1987 			break;
1988 		} else {
1989 			total_len += src_hotlist[i].ie_length;
1990 			wma_debug("total len IE: %d", total_len);
1991 		}
1992 
1993 		if (src_hotlist[i].number_rssi_samples >
1994 		    (WMI_SVC_MSG_MAX_SIZE - total_len) / sizeof(*src_rssi)) {
1995 			excess_data = true;
1996 			break;
1997 		} else {
1998 			total_len += (src_hotlist[i].number_rssi_samples *
1999 					sizeof(*src_rssi));
2000 			wma_debug("total len RSSI samples: %d", total_len);
2001 		}
2002 	}
2003 	if (excess_data) {
2004 		wma_err("excess data in WMI event");
2005 		return -EINVAL;
2006 	}
2007 
2008 	if (event->first_entry_index +
2009 	    event->num_entries_in_page < event->total_entries)
2010 		moredata = 1;
2011 	else
2012 		moredata = 0;
2013 
2014 	dest_cachelist = qdf_mem_malloc(sizeof(*dest_cachelist));
2015 	if (!dest_cachelist)
2016 		return -ENOMEM;
2017 
2018 	qdf_mem_zero(dest_cachelist, sizeof(*dest_cachelist));
2019 	dest_cachelist->request_id = event->request_id;
2020 	dest_cachelist->more_data = moredata;
2021 
2022 	scan_ids_cnt = wma_extscan_find_unique_scan_ids(cmd_param_info);
2023 	wma_debug("scan_ids_cnt %d", scan_ids_cnt);
2024 	dest_cachelist->num_scan_ids = scan_ids_cnt;
2025 
2026 	buf_len = sizeof(*dest_result) * scan_ids_cnt;
2027 	dest_cachelist->result = qdf_mem_malloc(buf_len);
2028 	if (!dest_cachelist->result) {
2029 		qdf_mem_free(dest_cachelist);
2030 		return -ENOMEM;
2031 	}
2032 
2033 	dest_result = dest_cachelist->result;
2034 	wma_fill_num_results_per_scan_id(cmd_param_info, dest_result);
2035 
2036 	status = wma_group_num_bss_to_scan_id(cmd_param_info, dest_cachelist);
2037 	if (!status)
2038 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
2039 				eSIR_EXTSCAN_CACHED_RESULTS_IND,
2040 				dest_cachelist);
2041 	else
2042 		wma_debug("wma_group_num_bss_to_scan_id failed, not calling callback");
2043 
2044 	dest_result = dest_cachelist->result;
2045 	for (i = 0; i < dest_cachelist->num_scan_ids; i++) {
2046 		if (dest_result->ap)
2047 		qdf_mem_free(dest_result->ap);
2048 		dest_result++;
2049 	}
2050 	qdf_mem_free(dest_cachelist->result);
2051 	qdf_mem_free(dest_cachelist);
2052 	return status;
2053 
2054 noresults:
2055 	empty_cachelist.request_id = event->request_id;
2056 	empty_cachelist.more_data = 0;
2057 	empty_cachelist.num_scan_ids = 0;
2058 
2059 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
2060 				eSIR_EXTSCAN_CACHED_RESULTS_IND,
2061 				&empty_cachelist);
2062 	return 0;
2063 }
2064 
2065 /**
2066  * wma_extscan_change_results_event_handler() - change results event handler
2067  * @handle: wma handle
2068  * @cmd_param_info: event buffer
2069  * @len: length
2070  *
2071  * This function handles change results event and indicate
2072  * change results to upper layer.
2073  *
2074  * Return: 0 for success or error code.
2075  */
2076 int wma_extscan_change_results_event_handler(void *handle,
2077 					     uint8_t *cmd_param_info,
2078 					     uint32_t len)
2079 {
2080 	WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *param_buf;
2081 	wmi_extscan_wlan_change_results_event_fixed_param *event;
2082 	tSirWifiSignificantChangeEvent *dest_chglist;
2083 	tSirWifiSignificantChange *dest_ap;
2084 	wmi_extscan_wlan_change_result_bssid *src_chglist;
2085 
2086 	uint32_t numap;
2087 	int i, k;
2088 	uint8_t *src_rssi;
2089 	int count = 0;
2090 	int moredata;
2091 	uint32_t rssi_num = 0;
2092 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
2093 	uint32_t buf_len;
2094 	bool excess_data = false;
2095 
2096 	if (!mac) {
2097 		wma_err("Invalid mac");
2098 		return -EINVAL;
2099 	}
2100 	if (!mac->sme.ext_scan_ind_cb) {
2101 		wma_err("Callback not registered");
2102 		return -EINVAL;
2103 	}
2104 	param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *)
2105 		    cmd_param_info;
2106 	if (!param_buf) {
2107 		wma_err("Invalid change monitor event");
2108 		return -EINVAL;
2109 	}
2110 	event = param_buf->fixed_param;
2111 	src_chglist = param_buf->bssid_signal_descriptor_list;
2112 	src_rssi = param_buf->rssi_list;
2113 	numap = event->num_entries_in_page;
2114 
2115 	if (!src_chglist || !numap) {
2116 		wma_err("Results invalid");
2117 		return -EINVAL;
2118 	}
2119 	if (numap > param_buf->num_bssid_signal_descriptor_list) {
2120 		wma_err("Invalid num of entries in page: %d", numap);
2121 		return -EINVAL;
2122 	}
2123 	for (i = 0; i < numap; i++) {
2124 		if (src_chglist->num_rssi_samples > (UINT_MAX - rssi_num)) {
2125 			wma_err("Invalid num of rssi samples %d numap %d rssi_num %d",
2126 				 src_chglist->num_rssi_samples,
2127 				 numap, rssi_num);
2128 			return -EINVAL;
2129 		}
2130 		rssi_num += src_chglist->num_rssi_samples;
2131 		src_chglist++;
2132 	}
2133 	src_chglist = param_buf->bssid_signal_descriptor_list;
2134 
2135 	if (event->first_entry_index +
2136 	    event->num_entries_in_page < event->total_entries) {
2137 		moredata = 1;
2138 	} else {
2139 		moredata = 0;
2140 	}
2141 
2142 	do {
2143 		if (event->num_entries_in_page >
2144 			(WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/
2145 			sizeof(*src_chglist)) {
2146 			excess_data = true;
2147 			break;
2148 		} else {
2149 			buf_len =
2150 				sizeof(*event) + (event->num_entries_in_page *
2151 						sizeof(*src_chglist));
2152 		}
2153 		if (rssi_num >
2154 			(WMI_SVC_MSG_MAX_SIZE - buf_len)/sizeof(int32_t)) {
2155 			excess_data = true;
2156 			break;
2157 		}
2158 	} while (0);
2159 
2160 	if (excess_data) {
2161 		wma_err("buffer len exceeds WMI payload,numap:%d, rssi_num:%d",
2162 			numap, rssi_num);
2163 		QDF_ASSERT(0);
2164 		return -EINVAL;
2165 	}
2166 	dest_chglist = qdf_mem_malloc(sizeof(*dest_chglist) +
2167 				      sizeof(*dest_ap) * numap +
2168 				      sizeof(int32_t) * rssi_num);
2169 	if (!dest_chglist)
2170 		return -ENOMEM;
2171 
2172 	dest_ap = &dest_chglist->ap[0];
2173 	for (i = 0; i < numap; i++) {
2174 		dest_ap->channel = src_chglist->channel;
2175 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_chglist->bssid,
2176 					   dest_ap->bssid.bytes);
2177 		dest_ap->numOfRssi = src_chglist->num_rssi_samples;
2178 		if (dest_ap->numOfRssi) {
2179 			if ((dest_ap->numOfRssi + count) >
2180 			    param_buf->num_rssi_list) {
2181 				wma_err("Invalid num in rssi list: %d",
2182 					dest_ap->numOfRssi);
2183 				qdf_mem_free(dest_chglist);
2184 				return -EINVAL;
2185 			}
2186 			for (k = 0; k < dest_ap->numOfRssi; k++) {
2187 				dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM +
2188 						   src_rssi[count++];
2189 			}
2190 		}
2191 		dest_ap = (tSirWifiSignificantChange *)((char *)dest_ap +
2192 					dest_ap->numOfRssi * sizeof(int32_t) +
2193 					sizeof(*dest_ap));
2194 		src_chglist++;
2195 	}
2196 	dest_chglist->requestId = event->request_id;
2197 	dest_chglist->moreData = moredata;
2198 	dest_chglist->numResults = numap;
2199 
2200 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
2201 			eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND,
2202 			dest_chglist);
2203 	wma_debug("sending change monitor results");
2204 	qdf_mem_free(dest_chglist);
2205 	return 0;
2206 }
2207 
2208 /**
2209  * wma_passpoint_match_event_handler() - passpoint match found event handler
2210  * @handle: WMA handle
2211  * @cmd_param_info: event data
2212  * @len: event data length
2213  *
2214  * This is the passpoint match found event handler; it reads event data from
2215  * @cmd_param_info and fill in the destination buffer and sends indication
2216  * up layer.
2217  *
2218  * Return: 0 on success; error number otherwise
2219  */
2220 int wma_passpoint_match_event_handler(void *handle,
2221 				     uint8_t  *cmd_param_info,
2222 				     uint32_t len)
2223 {
2224 	WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *param_buf;
2225 	wmi_passpoint_event_hdr  *event;
2226 	struct wifi_passpoint_match  *dest_match;
2227 	tSirWifiScanResult      *dest_ap;
2228 	uint8_t *buf_ptr;
2229 	uint32_t buf_len = 0;
2230 	bool excess_data = false;
2231 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
2232 
2233 	if (!mac) {
2234 		wma_err("Invalid mac");
2235 		return -EINVAL;
2236 	}
2237 	if (!mac->sme.ext_scan_ind_cb) {
2238 		wma_err("Callback not registered");
2239 		return -EINVAL;
2240 	}
2241 
2242 	param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info;
2243 	if (!param_buf) {
2244 		wma_err("Invalid passpoint match event");
2245 		return -EINVAL;
2246 	}
2247 	event = param_buf->fixed_param;
2248 	buf_ptr = (uint8_t *)param_buf->fixed_param;
2249 
2250 	do {
2251 		if (event->ie_length > (WMI_SVC_MSG_MAX_SIZE)) {
2252 			excess_data = true;
2253 			break;
2254 		} else {
2255 			buf_len = event->ie_length;
2256 		}
2257 
2258 		if (event->anqp_length > (WMI_SVC_MSG_MAX_SIZE)) {
2259 			excess_data = true;
2260 			break;
2261 		} else {
2262 			buf_len += event->anqp_length;
2263 		}
2264 
2265 	} while (0);
2266 
2267 	if (excess_data || buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*event)) ||
2268 	    buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*dest_match)) ||
2269 	    (event->ie_length + event->anqp_length) > param_buf->num_bufp) {
2270 		wma_err("IE Length: %u or ANQP Length: %u is huge, num_bufp: %u",
2271 			event->ie_length, event->anqp_length,
2272 			param_buf->num_bufp);
2273 		return -EINVAL;
2274 	}
2275 
2276 	if (event->ssid.ssid_len > WLAN_SSID_MAX_LEN) {
2277 		wma_debug("Invalid ssid len %d, truncating",
2278 			 event->ssid.ssid_len);
2279 		event->ssid.ssid_len = WLAN_SSID_MAX_LEN;
2280 	}
2281 
2282 	dest_match = qdf_mem_malloc(sizeof(*dest_match) + buf_len);
2283 	if (!dest_match)
2284 		return -EINVAL;
2285 
2286 	dest_ap = &dest_match->ap;
2287 	dest_match->request_id = 0;
2288 	dest_match->id = event->id;
2289 	dest_match->anqp_len = event->anqp_length;
2290 	wma_info("passpoint match: id: %u anqp length %u",
2291 		 dest_match->id, dest_match->anqp_len);
2292 
2293 	dest_ap->channel = event->channel_mhz;
2294 	dest_ap->ts = event->timestamp;
2295 	dest_ap->rtt = event->rtt;
2296 	dest_ap->rssi = event->rssi;
2297 	dest_ap->rtt_sd = event->rtt_sd;
2298 	dest_ap->beaconPeriod = event->beacon_period;
2299 	dest_ap->capability = event->capability;
2300 	dest_ap->ieLength = event->ie_length;
2301 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, dest_ap->bssid.bytes);
2302 	qdf_mem_copy(dest_ap->ssid, event->ssid.ssid,
2303 				event->ssid.ssid_len);
2304 	dest_ap->ssid[event->ssid.ssid_len] = '\0';
2305 	qdf_mem_copy(dest_ap->ieData, buf_ptr + sizeof(*event) +
2306 			WMI_TLV_HDR_SIZE, dest_ap->ieLength);
2307 	qdf_mem_copy(dest_match->anqp, buf_ptr + sizeof(*event) +
2308 			WMI_TLV_HDR_SIZE + dest_ap->ieLength,
2309 			dest_match->anqp_len);
2310 
2311 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
2312 				eSIR_PASSPOINT_NETWORK_FOUND_IND,
2313 				dest_match);
2314 	wma_debug("sending passpoint match event to hdd");
2315 	qdf_mem_free(dest_match);
2316 	return 0;
2317 }
2318 
2319 QDF_STATUS wma_start_extscan(tp_wma_handle wma,
2320 			     struct wifi_scan_cmd_req_params *params)
2321 {
2322 	QDF_STATUS status;
2323 	struct wmi_unified *wmi_handle;
2324 
2325 	if (wma_validate_handle(wma))
2326 		return QDF_STATUS_E_INVAL;
2327 
2328 	wmi_handle = wma->wmi_handle;
2329 	if (wmi_validate_handle(wmi_handle))
2330 		return QDF_STATUS_E_INVAL;
2331 
2332 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2333 		wma_err("extscan not enabled");
2334 		return QDF_STATUS_E_FAILURE;
2335 	}
2336 
2337 	if (!params) {
2338 		wma_err("NULL param");
2339 		return QDF_STATUS_E_NOMEM;
2340 	}
2341 
2342 	status = wmi_unified_start_extscan_cmd(wmi_handle, params);
2343 	if (QDF_IS_STATUS_SUCCESS(status))
2344 		wma->interfaces[params->vdev_id].extscan_in_progress = true;
2345 
2346 	wma_debug("Exit, vdev %d, status %d", params->vdev_id, status);
2347 
2348 	return status;
2349 }
2350 
2351 QDF_STATUS wma_stop_extscan(tp_wma_handle wma,
2352 			    struct extscan_stop_req_params *params)
2353 {
2354 	QDF_STATUS status;
2355 	struct wmi_unified *wmi_handle;
2356 
2357 	if (wma_validate_handle(wma))
2358 		return QDF_STATUS_E_INVAL;
2359 
2360 	wmi_handle = wma->wmi_handle;
2361 	if (wmi_validate_handle(wmi_handle))
2362 		return QDF_STATUS_E_INVAL;
2363 
2364 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2365 		wma_err("extscan not enabled");
2366 		return QDF_STATUS_E_FAILURE;
2367 	}
2368 
2369 	status = wmi_unified_stop_extscan_cmd(wmi_handle, params);
2370 	if (QDF_IS_STATUS_ERROR(status))
2371 		return status;
2372 
2373 	wma->interfaces[params->vdev_id].extscan_in_progress = false;
2374 	wma_debug("Extscan stop request sent successfully for vdev %d",
2375 		 params->vdev_id);
2376 
2377 	return status;
2378 }
2379 
2380 QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma,
2381 			struct extscan_bssid_hotlist_set_params *params)
2382 {
2383 	struct wmi_unified *wmi_handle;
2384 
2385 	if (wma_validate_handle(wma))
2386 		return QDF_STATUS_E_INVAL;
2387 
2388 	wmi_handle = wma->wmi_handle;
2389 	if (wmi_validate_handle(wmi_handle))
2390 		return QDF_STATUS_E_INVAL;
2391 
2392 	if (!params) {
2393 		wma_err("Invalid params");
2394 		return QDF_STATUS_E_INVAL;
2395 	}
2396 
2397 	return wmi_unified_extscan_start_hotlist_monitor_cmd(wmi_handle,
2398 							     params);
2399 }
2400 
2401 QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma,
2402 		    struct extscan_bssid_hotlist_reset_params *params)
2403 {
2404 	struct wmi_unified *wmi_handle;
2405 
2406 	if (wma_validate_handle(wma))
2407 		return QDF_STATUS_E_INVAL;
2408 
2409 	wmi_handle = wma->wmi_handle;
2410 	if (wmi_validate_handle(wmi_handle))
2411 		return QDF_STATUS_E_INVAL;
2412 
2413 	if (!params) {
2414 		wma_err("Invalid params");
2415 		return QDF_STATUS_E_INVAL;
2416 	}
2417 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2418 		wma_err("extscan not enabled");
2419 		return QDF_STATUS_E_FAILURE;
2420 	}
2421 
2422 	return wmi_unified_extscan_stop_hotlist_monitor_cmd(wmi_handle,
2423 							    params);
2424 }
2425 
2426 QDF_STATUS
2427 wma_extscan_start_change_monitor(tp_wma_handle wma,
2428 			struct extscan_set_sig_changereq_params *params)
2429 {
2430 	QDF_STATUS status;
2431 	struct wmi_unified *wmi_handle;
2432 
2433 	if (wma_validate_handle(wma))
2434 		return QDF_STATUS_E_INVAL;
2435 
2436 	wmi_handle = wma->wmi_handle;
2437 	if (wmi_validate_handle(wmi_handle))
2438 		return QDF_STATUS_E_INVAL;
2439 
2440 	if (!params) {
2441 		wma_err("NULL params");
2442 		return QDF_STATUS_E_NOMEM;
2443 	}
2444 
2445 	status = wmi_unified_extscan_start_change_monitor_cmd(wmi_handle,
2446 							      params);
2447 	return status;
2448 }
2449 
2450 QDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma,
2451 			struct extscan_capabilities_reset_params *params)
2452 {
2453 	struct wmi_unified *wmi_handle;
2454 
2455 	if (wma_validate_handle(wma))
2456 		return QDF_STATUS_E_INVAL;
2457 
2458 	wmi_handle = wma->wmi_handle;
2459 	if (wmi_validate_handle(wmi_handle))
2460 		return QDF_STATUS_E_INVAL;
2461 
2462 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2463 		wma_err("ext scan not enabled");
2464 		return QDF_STATUS_E_FAILURE;
2465 	}
2466 
2467 	return wmi_unified_extscan_stop_change_monitor_cmd(wmi_handle,
2468 							   params);
2469 }
2470 
2471 QDF_STATUS
2472 wma_extscan_get_cached_results(tp_wma_handle wma,
2473 			       struct extscan_cached_result_params *params)
2474 {
2475 	struct wmi_unified *wmi_handle;
2476 
2477 	if (wma_validate_handle(wma))
2478 		return QDF_STATUS_E_INVAL;
2479 
2480 	wmi_handle = wma->wmi_handle;
2481 	if (wmi_validate_handle(wmi_handle))
2482 		return QDF_STATUS_E_INVAL;
2483 
2484 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2485 		wma_err("extscan not enabled");
2486 		return QDF_STATUS_E_FAILURE;
2487 	}
2488 
2489 	return wmi_unified_extscan_get_cached_results_cmd(wmi_handle,
2490 							  params);
2491 }
2492 
2493 QDF_STATUS
2494 wma_extscan_get_capabilities(tp_wma_handle wma,
2495 			     struct extscan_capabilities_params *params)
2496 {
2497 	struct wmi_unified *wmi_handle;
2498 
2499 	if (wma_validate_handle(wma))
2500 		return QDF_STATUS_E_INVAL;
2501 
2502 	wmi_handle = wma->wmi_handle;
2503 	if (wmi_validate_handle(wmi_handle))
2504 		return QDF_STATUS_E_INVAL;
2505 
2506 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2507 		wma_err("extscan not enabled");
2508 		return QDF_STATUS_E_FAILURE;
2509 	}
2510 
2511 	return wmi_unified_extscan_get_capabilities_cmd(wmi_handle,
2512 							params);
2513 }
2514 
2515 QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma,
2516 				     struct wifi_enhanced_pno_params *req)
2517 {
2518 	QDF_STATUS status;
2519 	struct wmi_unified *wmi_handle;
2520 
2521 	wma_debug("Enter");
2522 
2523 	if (wma_validate_handle(wma))
2524 		return QDF_STATUS_E_FAILURE;
2525 
2526 	wmi_handle = wma->wmi_handle;
2527 	if (wmi_validate_handle(wmi_handle))
2528 		return QDF_STATUS_E_FAILURE;
2529 
2530 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2531 		wma_err("extscan not enabled");
2532 		return QDF_STATUS_E_NOSUPPORT;
2533 	}
2534 
2535 	status = wmi_unified_set_epno_network_list_cmd(wmi_handle, req);
2536 	wma_debug("Exit, vdev %d, status %d", req->vdev_id, status);
2537 
2538 	return status;
2539 }
2540 
2541 QDF_STATUS
2542 wma_set_passpoint_network_list(tp_wma_handle wma,
2543 			       struct wifi_passpoint_req_param *params)
2544 {
2545 	QDF_STATUS status;
2546 	struct wmi_unified *wmi_handle;
2547 
2548 	wma_debug("Enter");
2549 
2550 	if (wma_validate_handle(wma))
2551 		return QDF_STATUS_E_FAILURE;
2552 
2553 	wmi_handle = wma->wmi_handle;
2554 	if (wmi_validate_handle(wmi_handle))
2555 		return QDF_STATUS_E_FAILURE;
2556 
2557 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2558 		wma_err("extscan not enabled");
2559 		return QDF_STATUS_E_NOSUPPORT;
2560 	}
2561 
2562 	status = wmi_unified_set_passpoint_network_list_cmd(wmi_handle,
2563 							    params);
2564 	wma_debug("Exit, vdev %d, status %d", params->vdev_id, status);
2565 
2566 	return status;
2567 }
2568 
2569 QDF_STATUS
2570 wma_reset_passpoint_network_list(tp_wma_handle wma,
2571 				 struct wifi_passpoint_req_param *params)
2572 {
2573 	QDF_STATUS status;
2574 	struct wmi_unified *wmi_handle;
2575 
2576 	wma_debug("Enter");
2577 
2578 	if (wma_validate_handle(wma))
2579 		return QDF_STATUS_E_FAILURE;
2580 
2581 	wmi_handle = wma->wmi_handle;
2582 	if (wmi_validate_handle(wmi_handle))
2583 		return QDF_STATUS_E_FAILURE;
2584 
2585 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2586 		wma_err("extscan not enabled");
2587 		return QDF_STATUS_E_NOSUPPORT;
2588 	}
2589 
2590 	status = wmi_unified_reset_passpoint_network_list_cmd(wmi_handle,
2591 							      params);
2592 	wma_debug("Exit, vdev %d, status %d", params->vdev_id, status);
2593 
2594 	return status;
2595 }
2596 
2597 #endif
2598 
2599 QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma,
2600 				 struct scan_mac_oui *set_oui)
2601 {
2602 	struct wmi_unified *wmi_handle;
2603 
2604 	if (wma_validate_handle(wma))
2605 		return QDF_STATUS_E_INVAL;
2606 
2607 	wmi_handle = wma->wmi_handle;
2608 	if (wmi_validate_handle(wmi_handle))
2609 		return QDF_STATUS_E_INVAL;
2610 
2611 	if (!wma_is_vdev_valid(set_oui->vdev_id)) {
2612 		wma_err("vdev_id: %d is not active", set_oui->vdev_id);
2613 		return QDF_STATUS_E_INVAL;
2614 	}
2615 
2616 	return wmi_unified_scan_probe_setoui_cmd(wmi_handle, set_oui);
2617 }
2618 
2619 /**
2620  * wma_roam_better_ap_handler() - better ap event handler
2621  * @wma: wma handle
2622  * @vdev_id: vdev id
2623  *
2624  * Handler for WMI_ROAM_REASON_BETTER_AP event from roam firmware in Rome.
2625  * This event means roam algorithm in Rome has found a better matching
2626  * candidate AP. The indication is sent to SME.
2627  *
2628  * Return: none
2629  */
2630 void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id)
2631 {
2632 	struct scheduler_msg msg = {0};
2633 	QDF_STATUS status;
2634 	struct cm_host_roam_start_ind *ind;
2635 
2636 	ind = qdf_mem_malloc(sizeof(*ind));
2637 	if (!ind)
2638 		return;
2639 
2640 	ind->pdev = wma->pdev;
2641 	ind->vdev_id = vdev_id;
2642 	msg.bodyptr = ind;
2643 	msg.callback = wlan_cm_host_roam_start;
2644 	wma_debug("Posting ROam start ind to connection manager, vdev %d",
2645 		  vdev_id);
2646 	status = scheduler_post_message(QDF_MODULE_ID_WMA,
2647 					QDF_MODULE_ID_OS_IF,
2648 					QDF_MODULE_ID_SCAN, &msg);
2649 
2650 	if (QDF_IS_STATUS_ERROR(status))
2651 		qdf_mem_free(msg.bodyptr);
2652 }
2653 
2654 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
2655 /**
2656  * wma_invalid_roam_reason_handler() - Handle Invalid roam notification
2657  * @wma: wma handle
2658  * @vdev_id: vdev id
2659  * @op_code: Operation to be done by the callback
2660  *
2661  * This function calls pe and csr callbacks with proper op_code
2662  *
2663  * Return: None
2664  */
2665 static void wma_invalid_roam_reason_handler(tp_wma_handle wma_handle,
2666 					    uint32_t vdev_id,
2667 					    enum cm_roam_notif notif)
2668 {
2669 	struct roam_offload_synch_ind *roam_synch_data;
2670 	enum sir_roam_op_code op_code;
2671 
2672 	if (notif == CM_ROAM_NOTIF_ROAM_START) {
2673 		op_code = SIR_ROAMING_START;
2674 	} else if (notif == CM_ROAM_NOTIF_ROAM_ABORT) {
2675 		op_code = SIR_ROAMING_ABORT;
2676 		lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id);
2677 	} else {
2678 		wma_debug("Invalid notif %d", notif);
2679 		return;
2680 	}
2681 	roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data));
2682 	if (!roam_synch_data)
2683 		return;
2684 
2685 	roam_synch_data->roamed_vdev_id = vdev_id;
2686 	if (notif != CM_ROAM_NOTIF_ROAM_START)
2687 		wma_handle->pe_roam_synch_cb(wma_handle->mac_context,
2688 					     roam_synch_data->roamed_vdev_id,
2689 					     roam_synch_data, 0, op_code);
2690 
2691 	if (notif == CM_ROAM_NOTIF_ROAM_START)
2692 		cm_fw_roam_start_req(wma_handle->psoc, vdev_id);
2693 	else
2694 		cm_fw_roam_abort_req(wma_handle->psoc, vdev_id);
2695 
2696 	qdf_mem_free(roam_synch_data);
2697 }
2698 
2699 void wma_handle_roam_sync_timeout(tp_wma_handle wma_handle,
2700 				  struct roam_sync_timeout_timer_info *info)
2701 {
2702 	wma_invalid_roam_reason_handler(wma_handle, info->vdev_id,
2703 					CM_ROAM_NOTIF_ROAM_ABORT);
2704 }
2705 
2706 void cm_invalid_roam_reason_handler(uint32_t vdev_id, enum cm_roam_notif notif,
2707 				    uint32_t reason)
2708 {
2709 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2710 
2711 	if (!wma_handle) {
2712 		QDF_ASSERT(0);
2713 		return;
2714 	}
2715 	wma_invalid_roam_reason_handler(wma_handle, vdev_id, notif);
2716 
2717 	if (notif == CM_ROAM_NOTIF_SCAN_START ||
2718 	    notif == CM_ROAM_NOTIF_SCAN_END)
2719 		cm_report_roam_rt_stats(wma_handle->psoc, vdev_id,
2720 					ROAM_RT_STATS_TYPE_SCAN_STATE,
2721 					NULL, notif, 0, reason);
2722 }
2723 #endif
2724 
2725 static void
2726 wma_handle_roam_reason_invoke_roam_fail(tp_wma_handle wma_handle,
2727 					uint8_t vdev_id, uint32_t notif_params)
2728 {
2729 	struct roam_offload_synch_ind *roam_synch_data;
2730 
2731 	roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data));
2732 	if (!roam_synch_data)
2733 		return;
2734 
2735 	lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id);
2736 	roam_synch_data->roamed_vdev_id = vdev_id;
2737 	cm_fw_roam_invoke_fail(wma_handle->psoc, vdev_id);
2738 	wlan_cm_update_roam_states(wma_handle->psoc, vdev_id,
2739 				   notif_params,
2740 				   ROAM_INVOKE_FAIL_REASON);
2741 	qdf_mem_free(roam_synch_data);
2742 }
2743 
2744 static void wma_handle_roam_reason_btm(uint8_t vdev_id)
2745 {
2746 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2747 
2748 	if (!wma_handle) {
2749 		QDF_ASSERT(0);
2750 		return;
2751 	}
2752 	/*
2753 	 * This event is received from firmware if firmware is unable to
2754 	 * find candidate AP after roam scan and BTM request from AP
2755 	 * has disassoc imminent bit set.
2756 	 */
2757 	wma_debug("Kickout due to btm request");
2758 	wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BTM, vdev_id, NULL);
2759 	wma_handle_disconnect_reason(wma_handle, vdev_id,
2760 			HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT);
2761 }
2762 
2763 static void wma_handle_roam_reason_bmiss(uint8_t vdev_id, uint32_t rssi)
2764 {
2765 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2766 
2767 	if (!wma_handle) {
2768 		QDF_ASSERT(0);
2769 		return;
2770 	}
2771 	/*
2772 	 * WMI_ROAM_REASON_BMISS can get called in soft IRQ context, so
2773 	 * avoid using CSR/PE structure directly
2774 	 */
2775 	wma_debug("Beacon Miss for vdevid %x", vdev_id);
2776 	mlme_set_hb_ap_rssi(wma_handle->interfaces[vdev_id].vdev, rssi);
2777 	wma_beacon_miss_handler(wma_handle, vdev_id, rssi);
2778 	wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BMISS, vdev_id, NULL);
2779 }
2780 
2781 static void wma_handle_roam_reason_better_ap(uint8_t vdev_id, uint32_t rssi)
2782 {
2783 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2784 
2785 	if (!wma_handle) {
2786 		QDF_ASSERT(0);
2787 		return;
2788 	}
2789 	/*
2790 	 * WMI_ROAM_REASON_BETTER_AP can get called in soft IRQ context,
2791 	 * so avoid using CSR/PE structure directly.
2792 	 */
2793 	wma_debug("Better AP found for vdevid %x, rssi %d", vdev_id, rssi);
2794 	mlme_set_roam_reason_better_ap(wma_handle->interfaces[vdev_id].vdev,
2795 				       false);
2796 	wma_roam_better_ap_handler(wma_handle, vdev_id);
2797 }
2798 
2799 static void wma_handle_roam_reason_suitable_ap(uint8_t vdev_id, uint32_t rssi)
2800 {
2801 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2802 
2803 	if (!wma_handle) {
2804 		QDF_ASSERT(0);
2805 		return;
2806 	}
2807 	/*
2808 	 * WMI_ROAM_REASON_SUITABLE_AP can get called in soft IRQ
2809 	 * context, so avoid using CSR/PE structure directly.
2810 	 */
2811 	mlme_set_roam_reason_better_ap(wma_handle->interfaces[vdev_id].vdev,
2812 				       true);
2813 	mlme_set_hb_ap_rssi(wma_handle->interfaces[vdev_id].vdev, rssi);
2814 	wma_debug("Bmiss scan AP found for vdevid %x, rssi %d", vdev_id, rssi);
2815 	wma_roam_better_ap_handler(wma_handle, vdev_id);
2816 }
2817 
2818 static void
2819 wma_update_pdev_hw_mode_trans_ind(tp_wma_handle wma,
2820 				  struct cm_hw_mode_trans_ind *trans_ind)
2821 {
2822 	uint32_t i;
2823 
2824 	/* Store the vdev-mac map in WMA and send to policy manager */
2825 	for (i = 0; i < trans_ind->num_vdev_mac_entries; i++)
2826 		wma_update_intf_hw_mode_params(
2827 				trans_ind->vdev_mac_map[i].vdev_id,
2828 				trans_ind->vdev_mac_map[i].mac_id,
2829 				trans_ind->new_hw_mode_index);
2830 
2831 	wma->old_hw_mode_index = trans_ind->old_hw_mode_index;
2832 	wma->new_hw_mode_index = trans_ind->new_hw_mode_index;
2833 	policy_mgr_update_new_hw_mode_index(wma->psoc,
2834 					    trans_ind->new_hw_mode_index);
2835 	policy_mgr_update_old_hw_mode_index(wma->psoc,
2836 					    trans_ind->old_hw_mode_index);
2837 
2838 	wma_debug("Updated: old_hw_mode_index:%d new_hw_mode_index:%d",
2839 		  wma->old_hw_mode_index, wma->new_hw_mode_index);
2840 }
2841 
2842 static void
2843 wma_handle_hw_mode_trans_ind(tp_wma_handle wma_handle,
2844 			     struct cm_hw_mode_trans_ind *hw_mode_trans_ind)
2845 {
2846 	struct scheduler_msg sme_msg = {0};
2847 	QDF_STATUS status;
2848 
2849 	if (hw_mode_trans_ind) {
2850 		wma_update_pdev_hw_mode_trans_ind(wma_handle,
2851 						  hw_mode_trans_ind);
2852 		wma_debug("Update HW mode");
2853 		sme_msg.type = eWNI_SME_HW_MODE_TRANS_IND;
2854 		sme_msg.bodyptr = hw_mode_trans_ind;
2855 
2856 		status = scheduler_post_message(QDF_MODULE_ID_WMA,
2857 						QDF_MODULE_ID_SME,
2858 						QDF_MODULE_ID_SME, &sme_msg);
2859 		if (QDF_IS_STATUS_ERROR(status))
2860 			qdf_mem_free(hw_mode_trans_ind);
2861 	} else {
2862 		wma_debug("hw_mode transition fixed param is NULL");
2863 	}
2864 }
2865 
2866 int cm_rso_cmd_status_event_handler(uint8_t vdev_id, enum cm_roam_notif notif)
2867 {
2868 	return wma_rso_cmd_status_event_handler(vdev_id, notif);
2869 }
2870 
2871 void
2872 cm_handle_roam_reason_invoke_roam_fail(uint8_t vdev_id,	uint32_t notif_params,
2873 				       struct cm_hw_mode_trans_ind *trans_ind)
2874 {
2875 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2876 
2877 	if (!wma_handle) {
2878 		QDF_ASSERT(0);
2879 		return;
2880 	}
2881 	wma_handle_hw_mode_trans_ind(wma_handle, trans_ind);
2882 	wma_handle_roam_reason_invoke_roam_fail(wma_handle, vdev_id,
2883 						notif_params);
2884 	cm_report_roam_rt_stats(wma_handle->psoc, vdev_id,
2885 				ROAM_RT_STATS_TYPE_INVOKE_FAIL_REASON,
2886 				NULL, notif_params, 0, 0);
2887 }
2888 
2889 void
2890 cm_handle_roam_sync_update_hw_mode(struct cm_hw_mode_trans_ind *trans_ind)
2891 {
2892 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2893 	struct cm_hw_mode_trans_ind *trans_ind_data;
2894 
2895 	if (!wma_handle) {
2896 		wma_err("invalid wma handle");
2897 		return;
2898 	}
2899 	trans_ind_data = qdf_mem_malloc(sizeof(*trans_ind_data));
2900 	if (!trans_ind_data)
2901 		return;
2902 	qdf_mem_copy(trans_ind_data, trans_ind, sizeof(*trans_ind_data));
2903 	wma_handle_hw_mode_trans_ind(wma_handle, trans_ind_data);
2904 }
2905 
2906 static void
2907 wma_handle_roam_reason_deauth(uint8_t vdev_id, uint32_t notif_params,
2908 			      uint32_t notif_params1,
2909 			      uint8_t *deauth_disassoc_frame)
2910 {
2911 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2912 	struct roam_offload_synch_ind *roam_synch_data;
2913 
2914 	if (!wma_handle) {
2915 		QDF_ASSERT(0);
2916 		return;
2917 	}
2918 	wma_debug("Received disconnect roam event reason:%d", notif_params);
2919 	wma_handle->pe_disconnect_cb(wma_handle->mac_context,
2920 				     vdev_id,
2921 				     deauth_disassoc_frame, notif_params1,
2922 				     notif_params);
2923 	roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data));
2924 	if (!roam_synch_data)
2925 		return;
2926 
2927 	roam_synch_data->roamed_vdev_id = vdev_id;
2928 	qdf_mem_free(roam_synch_data);
2929 }
2930 
2931 void cm_handle_roam_reason_deauth(uint8_t vdev_id, uint32_t notif_params,
2932 				  uint8_t *deauth_disassoc_frame,
2933 				  uint32_t frame_len)
2934 {
2935 	wma_handle_roam_reason_deauth(vdev_id, notif_params, frame_len,
2936 				      deauth_disassoc_frame);
2937 }
2938 
2939 void cm_handle_roam_reason_btm(uint8_t vdev_id)
2940 {
2941 	wma_handle_roam_reason_btm(vdev_id);
2942 }
2943 
2944 void cm_handle_roam_reason_bmiss(uint8_t vdev_id, uint32_t rssi)
2945 {
2946 	wma_handle_roam_reason_bmiss(vdev_id, rssi);
2947 }
2948 
2949 void cm_handle_roam_reason_better_ap(uint8_t vdev_id, uint32_t rssi)
2950 {
2951 	wma_handle_roam_reason_better_ap(vdev_id, rssi);
2952 }
2953 
2954 void cm_handle_roam_reason_suitable_ap(uint8_t vdev_id, uint32_t rssi)
2955 {
2956 	wma_handle_roam_reason_suitable_ap(vdev_id, rssi);
2957 }
2958 
2959 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
2960 static void
2961 wma_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid,
2962 				 struct cm_hw_mode_trans_ind *hw_mode_trans_ind)
2963 {
2964 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2965 
2966 	if (!wma_handle) {
2967 		QDF_ASSERT(0);
2968 		return;
2969 	}
2970 	/*
2971 	 * WMI_ROAM_REASON_HO_FAILED can get called in soft IRQ context,
2972 	 * so avoid using CSR/PE structure directly.
2973 	 */
2974 	wma_err("LFR3:Hand-Off Failed for vdevid %x", vdev_id);
2975 	wma_debug("mac addr to avoid " QDF_MAC_ADDR_FMT,
2976 		  QDF_MAC_ADDR_REF(bssid.bytes));
2977 	wma_handle_hw_mode_trans_ind(wma_handle, hw_mode_trans_ind);
2978 	cm_fw_ho_fail_req(wma_handle->psoc, vdev_id, bssid);
2979 	lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id);
2980 }
2981 
2982 void
2983 cm_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid,
2984 				struct cm_hw_mode_trans_ind *hw_mode_trans_ind)
2985 {
2986 	wma_handle_roam_reason_ho_failed(vdev_id, bssid, hw_mode_trans_ind);
2987 }
2988 #endif
2989 
2990 #ifdef FEATURE_LFR_SUBNET_DETECTION
2991 QDF_STATUS wma_set_gateway_params(tp_wma_handle wma,
2992 				  struct gateway_update_req_param *req)
2993 {
2994 	if (wma_validate_handle(wma))
2995 		return QDF_STATUS_E_INVAL;
2996 
2997 	return wmi_unified_set_gateway_params_cmd(wma->wmi_handle, req);
2998 }
2999 #endif /* FEATURE_LFR_SUBNET_DETECTION */
3000 
3001 /**
3002  * wma_ht40_stop_obss_scan() - ht40 obss stop scan
3003  * @wma: WMA handle
3004  * @vdev_id: vdev identifier
3005  *
3006  * Return: Return QDF_STATUS, otherwise appropriate failure code
3007  */
3008 QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma, int32_t vdev_id)
3009 {
3010 	QDF_STATUS status;
3011 	wmi_buf_t buf;
3012 	wmi_obss_scan_disable_cmd_fixed_param *cmd;
3013 	int len = sizeof(*cmd);
3014 
3015 	buf = wmi_buf_alloc(wma->wmi_handle, len);
3016 	if (!buf)
3017 		return QDF_STATUS_E_NOMEM;
3018 
3019 	wma_debug("cmd %x vdev_id %d", WMI_OBSS_SCAN_DISABLE_CMDID, vdev_id);
3020 
3021 	cmd = (wmi_obss_scan_disable_cmd_fixed_param *) wmi_buf_data(buf);
3022 	WMITLV_SET_HDR(&cmd->tlv_header,
3023 		WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param,
3024 		WMITLV_GET_STRUCT_TLVLEN(
3025 			wmi_obss_scan_disable_cmd_fixed_param));
3026 
3027 	cmd->vdev_id = vdev_id;
3028 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
3029 				      WMI_OBSS_SCAN_DISABLE_CMDID);
3030 	if (QDF_IS_STATUS_ERROR(status))
3031 		wmi_buf_free(buf);
3032 
3033 	return status;
3034 }
3035 
3036 /**
3037  * wma_send_ht40_obss_scanind() - ht40 obss start scan indication
3038  * @wma: WMA handle
3039  * @req: start scan request
3040  *
3041  * Return: Return QDF_STATUS, otherwise appropriate failure code
3042  */
3043 QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma,
3044 				struct obss_ht40_scanind *req)
3045 {
3046 	QDF_STATUS status;
3047 	wmi_buf_t buf;
3048 	wmi_obss_scan_enable_cmd_fixed_param *cmd;
3049 	int len = 0;
3050 	uint8_t *buf_ptr, i;
3051 	uint8_t *channel_list;
3052 	uint32_t *chan_freq_list;
3053 
3054 	len += sizeof(wmi_obss_scan_enable_cmd_fixed_param);
3055 
3056 	len += WMI_TLV_HDR_SIZE;
3057 	len += qdf_roundup(sizeof(uint8_t) * req->channel_count,
3058 				sizeof(uint32_t));
3059 
3060 	len += WMI_TLV_HDR_SIZE;
3061 	len += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t));
3062 
3063 	/* length calculation for chan_freqs */
3064 	len += WMI_TLV_HDR_SIZE;
3065 	len += sizeof(uint32_t) * req->channel_count;
3066 
3067 	wma_debug("cmdlen %d vdev_id %d channel count %d iefield_len %d",
3068 		 len, req->bss_id, req->channel_count, req->iefield_len);
3069 
3070 	wma_debug("scantype %d active_time %d passive %d Obss interval %d",
3071 		 req->scan_type, req->obss_active_dwelltime,
3072 		 req->obss_passive_dwelltime,
3073 		 req->obss_width_trigger_interval);
3074 
3075 	buf = wmi_buf_alloc(wma->wmi_handle, len);
3076 	if (!buf)
3077 		return QDF_STATUS_E_NOMEM;
3078 
3079 	cmd = (wmi_obss_scan_enable_cmd_fixed_param *) wmi_buf_data(buf);
3080 	WMITLV_SET_HDR(&cmd->tlv_header,
3081 		WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param,
3082 		WMITLV_GET_STRUCT_TLVLEN(wmi_obss_scan_enable_cmd_fixed_param));
3083 
3084 	buf_ptr = (uint8_t *) cmd;
3085 
3086 	cmd->vdev_id = req->bss_id;
3087 	cmd->scan_type = req->scan_type;
3088 	cmd->obss_scan_active_dwell =
3089 		req->obss_active_dwelltime;
3090 	cmd->obss_scan_passive_dwell =
3091 		req->obss_passive_dwelltime;
3092 	cmd->bss_channel_width_trigger_scan_interval =
3093 		req->obss_width_trigger_interval;
3094 	cmd->bss_width_channel_transition_delay_factor =
3095 		req->bsswidth_ch_trans_delay;
3096 	cmd->obss_scan_active_total_per_channel =
3097 		req->obss_active_total_per_channel;
3098 	cmd->obss_scan_passive_total_per_channel =
3099 		req->obss_passive_total_per_channel;
3100 	cmd->obss_scan_activity_threshold =
3101 		req->obss_activity_threshold;
3102 
3103 	cmd->channel_len = req->channel_count;
3104 	cmd->forty_mhz_intolerant =  req->fortymhz_intolerent;
3105 	cmd->current_operating_class = req->current_operatingclass;
3106 	cmd->ie_len = req->iefield_len;
3107 
3108 	buf_ptr += sizeof(wmi_obss_scan_enable_cmd_fixed_param);
3109 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
3110 		qdf_roundup(req->channel_count, sizeof(uint32_t)));
3111 
3112 	buf_ptr += WMI_TLV_HDR_SIZE;
3113 	channel_list = (uint8_t *) buf_ptr;
3114 
3115 	for (i = 0; i < req->channel_count; i++) {
3116 		channel_list[i] =
3117 		  wlan_reg_freq_to_chan(wma->pdev, req->chan_freq_list[i]);
3118 		wma_nofl_debug("Ch[%d]: %d ", i, channel_list[i]);
3119 	}
3120 
3121 	buf_ptr += qdf_roundup(sizeof(uint8_t) * req->channel_count,
3122 				sizeof(uint32_t));
3123 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
3124 			qdf_roundup(1, sizeof(uint32_t)));
3125 	buf_ptr += WMI_TLV_HDR_SIZE;
3126 
3127 	buf_ptr += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t));
3128 
3129 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
3130 		       sizeof(uint32_t) * req->channel_count);
3131 	buf_ptr += WMI_TLV_HDR_SIZE;
3132 
3133 	chan_freq_list = (uint32_t *)buf_ptr;
3134 	for (i = 0; i < req->channel_count; i++) {
3135 		chan_freq_list[i] = req->chan_freq_list[i];
3136 		wma_nofl_debug("freq[%u]: %u ", i, chan_freq_list[i]);
3137 	}
3138 
3139 	buf_ptr += sizeof(uint32_t) * req->channel_count;
3140 
3141 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
3142 				      WMI_OBSS_SCAN_ENABLE_CMDID);
3143 	if (QDF_IS_STATUS_ERROR(status))
3144 		wmi_buf_free(buf);
3145 
3146 	return status;
3147 }
3148 
3149 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
3150 void cm_roam_update_vdev(struct roam_offload_synch_ind *sync_ind,
3151 			 uint8_t vdev_id)
3152 {
3153 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3154 
3155 	if (!wma)
3156 		return;
3157 
3158 	wma_roam_update_vdev(wma, sync_ind, vdev_id);
3159 }
3160 
3161 QDF_STATUS
3162 cm_roam_pe_sync_callback(struct roam_offload_synch_ind *sync_ind,
3163 			 uint8_t vdev_id, uint16_t ie_len)
3164 {
3165 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3166 	struct pe_session *pe_session;
3167 	bool new_link_session = false;
3168 	QDF_STATUS status;
3169 
3170 	if (!wma)
3171 		return QDF_STATUS_E_INVAL;
3172 
3173 	pe_session = pe_find_session_by_vdev_id(wma->mac_context, vdev_id);
3174 	if (!pe_session) {
3175 		new_link_session = true;
3176 		/* Legacy to MLO roaming: create new pe session */
3177 		status = lim_create_and_fill_link_session(wma->mac_context,
3178 							  vdev_id,
3179 							  sync_ind, ie_len);
3180 
3181 		if (QDF_IS_STATUS_ERROR(status)) {
3182 			wma_err("MLO ROAM: pe session creation failed vdev id %d",
3183 				vdev_id);
3184 			return status;
3185 		}
3186 	}
3187 	status = wma->pe_roam_synch_cb(wma->mac_context,
3188 				vdev_id, sync_ind, ie_len,
3189 				SIR_ROAM_SYNCH_PROPAGATION);
3190 
3191 	/* delete newly added pe session in case of failure */
3192 	if (new_link_session && QDF_IS_STATUS_ERROR(status)) {
3193 		pe_session = pe_find_session_by_vdev_id(wma->mac_context,
3194 							vdev_id);
3195 		if (pe_session)
3196 			pe_delete_session(wma->mac_context, pe_session);
3197 	}
3198 	return status;
3199 }
3200 
3201 void cm_update_phymode_on_roam(uint8_t vdev_id,
3202 			       struct roam_offload_synch_ind *sync_ind)
3203 {
3204 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3205 	struct qdf_mac_addr link_bssid;
3206 	wmi_channel link_chan;
3207 
3208 	if (!wma)
3209 		return;
3210 
3211 	if (is_multi_link_roam(sync_ind)) {
3212 		mlo_roam_get_bssid_chan_for_link(vdev_id, sync_ind,
3213 						 &link_bssid,
3214 						 &link_chan);
3215 		wma_update_phymode_on_roam(wma, &link_bssid,
3216 					   &link_chan,
3217 					   &wma->interfaces[vdev_id]);
3218 	} else {
3219 		wma_update_phymode_on_roam(wma, &sync_ind->bssid,
3220 					   &sync_ind->chan,
3221 					   &wma->interfaces[vdev_id]);
3222 	}
3223 }
3224 
3225 enum wlan_phymode
3226 wlan_cm_fw_to_host_phymode(WMI_HOST_WLAN_PHY_MODE phymode)
3227 {
3228 	return wma_fw_to_host_phymode(phymode);
3229 }
3230 #endif
3231 
3232 QDF_STATUS
3233 wlan_update_peer_phy_mode(struct wlan_channel *des_chan,
3234 			  struct wlan_objmgr_vdev *vdev)
3235 {
3236 	return wma_update_bss_peer_phy_mode(des_chan, vdev);
3237 }
3238