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