xref: /wlan-dirver/qcacld-3.0/core/wma/src/wma_scan_roam.c (revision 63d7e2a202b3cd37d6c1c20a39582b297a267b6b)
1  /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  *  DOC:    wma_scan_roam.c
21  *  This file contains functions related to scan and
22  *  roaming functionality.
23  */
24 
25 /* Header files */
26 
27 #include "wma.h"
28 #include "wma_api.h"
29 #include "cds_api.h"
30 #include "wmi_unified_api.h"
31 #include "wlan_qct_sys.h"
32 #include "wni_api.h"
33 #include "ani_global.h"
34 #include "wmi_unified.h"
35 #include "wni_cfg.h"
36 #include <cdp_txrx_peer_ops.h>
37 #include <cdp_txrx_cfg.h>
38 #include <cdp_txrx_ctrl.h>
39 
40 #include "qdf_nbuf.h"
41 #include "qdf_types.h"
42 #include "qdf_mem.h"
43 #include "wlan_blm_api.h"
44 
45 #include "wma_types.h"
46 #include "lim_api.h"
47 #include "lim_session_utils.h"
48 
49 #include "cds_utils.h"
50 #include "wlan_policy_mgr_api.h"
51 #include <wlan_utility.h>
52 
53 #if !defined(REMOVE_PKT_LOG)
54 #include "pktlog_ac.h"
55 #endif /* REMOVE_PKT_LOG */
56 
57 #include "dbglog_host.h"
58 #include "csr_api.h"
59 #include "ol_fw.h"
60 
61 #include "wma_internal.h"
62 #if defined(CONFIG_HL_SUPPORT)
63 #include "wlan_tgt_def_config_hl.h"
64 #else
65 #include "wlan_tgt_def_config.h"
66 #endif
67 #include "wlan_reg_services_api.h"
68 #include "wlan_roam_debug.h"
69 #include "wlan_mlme_public_struct.h"
70 
71 /* This is temporary, should be removed */
72 #include "ol_htt_api.h"
73 #include <cdp_txrx_handle.h>
74 #include "wma_he.h"
75 #include <wlan_scan_public_structs.h>
76 #include <wlan_scan_ucfg_api.h>
77 #include "wma_nan_datapath.h"
78 #include "wlan_mlme_api.h"
79 #include <wlan_mlme_main.h>
80 #include <wlan_crypto_global_api.h>
81 #include <cdp_txrx_mon.h>
82 #include <cdp_txrx_ctrl.h>
83 #include "wlan_blm_api.h"
84 #include "wlan_cm_roam_api.h"
85 #ifdef FEATURE_WLAN_DIAG_SUPPORT    /* FEATURE_WLAN_DIAG_SUPPORT */
86 #include "host_diag_core_log.h"
87 #endif /* FEATURE_WLAN_DIAG_SUPPORT */
88 #ifdef FEATURE_CM_ENABLE
89 #include <../../core/src/wlan_cm_roam_i.h>
90 #endif
91 
92 #ifdef FEATURE_WLAN_EXTSCAN
93 #define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED
94 
95 /*
96  * Maximum number of entires that could be present in the
97  * WMI_EXTSCAN_HOTLIST_MATCH_EVENT buffer from the firmware
98  */
99 #define WMA_EXTSCAN_MAX_HOTLIST_ENTRIES 10
100 #endif
101 
102 static inline wmi_host_channel_width
103 wma_map_phy_ch_bw_to_wmi_channel_width(enum phy_ch_width ch_width)
104 {
105 	switch (ch_width) {
106 	case CH_WIDTH_20MHZ:
107 		return WMI_HOST_CHAN_WIDTH_20;
108 	case CH_WIDTH_40MHZ:
109 		return WMI_HOST_CHAN_WIDTH_40;
110 	case CH_WIDTH_80MHZ:
111 		return WMI_HOST_CHAN_WIDTH_80;
112 	case CH_WIDTH_160MHZ:
113 		return WMI_HOST_CHAN_WIDTH_160;
114 	case CH_WIDTH_5MHZ:
115 		return WMI_HOST_CHAN_WIDTH_5;
116 	case CH_WIDTH_10MHZ:
117 		return WMI_HOST_CHAN_WIDTH_10;
118 #ifdef WLAN_FEATURE_11BE
119 	case CH_WIDTH_320MHZ:
120 		return WMI_HOST_CHAN_WIDTH_320;
121 #endif
122 	default:
123 		return WMI_HOST_CHAN_WIDTH_20;
124 	}
125 }
126 
127 #define WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ      0
128 #define WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ         1
129 #define WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ        2
130 #define WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ 3
131 
132 #ifdef WLAN_FEATURE_11BE
133 static void wma_update_ch_list_11be_params(struct ch_params *ch)
134 {
135 	ch->ch_width = CH_WIDTH_320MHZ;
136 }
137 #else /* !WLAN_FEATURE_11BE */
138 static void wma_update_ch_list_11be_params(struct ch_params *ch)
139 {
140 	ch->ch_width = CH_WIDTH_160MHZ;
141 }
142 #endif /* WLAN_FEATURE_11BE */
143 
144 /**
145  * wma_update_channel_list() - update channel list
146  * @handle: wma handle
147  * @chan_list: channel list
148  *
149  * Function is used to update the support channel list in fw.
150  *
151  * Return: QDF status
152  */
153 QDF_STATUS wma_update_channel_list(WMA_HANDLE handle,
154 				   tSirUpdateChanList *chan_list)
155 {
156 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
157 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
158 	int i, len;
159 	struct scan_chan_list_params *scan_ch_param;
160 	struct channel_param *chan_p;
161 	struct ch_params ch_params;
162 
163 	len = sizeof(struct channel_param) * chan_list->numChan +
164 		offsetof(struct scan_chan_list_params, ch_param[0]);
165 	scan_ch_param = qdf_mem_malloc(len);
166 	if (!scan_ch_param)
167 		return QDF_STATUS_E_NOMEM;
168 
169 	qdf_mem_zero(scan_ch_param, len);
170 	wma_debug("no of channels = %d", chan_list->numChan);
171 	chan_p = &scan_ch_param->ch_param[0];
172 	scan_ch_param->nallchans = chan_list->numChan;
173 	scan_ch_param->max_bw_support_present = true;
174 	wma_handle->saved_chan.num_channels = chan_list->numChan;
175 	wma_debug("ht %d, vht %d, vht_24 %d", chan_list->ht_en,
176 		  chan_list->vht_en, chan_list->vht_24_en);
177 
178 	for (i = 0; i < chan_list->numChan; ++i) {
179 		chan_p->mhz = chan_list->chanParam[i].freq;
180 		chan_p->cfreq1 = chan_p->mhz;
181 		chan_p->cfreq2 = 0;
182 		wma_handle->saved_chan.ch_freq_list[i] =
183 					chan_list->chanParam[i].freq;
184 
185 		if (chan_list->chanParam[i].dfsSet) {
186 			chan_p->is_chan_passive = 1;
187 			chan_p->dfs_set = 1;
188 		}
189 
190 		if (chan_list->chanParam[i].nan_disabled)
191 			chan_p->nan_disabled = 1;
192 
193 		if (chan_p->mhz < WMA_2_4_GHZ_MAX_FREQ) {
194 			chan_p->phy_mode = MODE_11G;
195 			if (chan_list->vht_en && chan_list->vht_24_en)
196 				chan_p->allow_vht = 1;
197 		} else {
198 			chan_p->phy_mode = MODE_11A;
199 			if (chan_list->vht_en &&
200 			    !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz)))
201 				chan_p->allow_vht = 1;
202 		}
203 
204 		if (chan_list->ht_en &&
205 		    !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz)))
206 			chan_p->allow_ht = 1;
207 
208 		if (chan_list->he_en)
209 			chan_p->allow_he = 1;
210 
211 		if (chan_list->chanParam[i].half_rate)
212 			chan_p->half_rate = 1;
213 		else if (chan_list->chanParam[i].quarter_rate)
214 			chan_p->quarter_rate = 1;
215 
216 		if (wlan_reg_is_6ghz_psc_chan_freq(
217 			    chan_p->mhz))
218 			chan_p->psc_channel = 1;
219 
220 		/*TODO: Set WMI_SET_CHANNEL_MIN_POWER */
221 		/*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */
222 		/*TODO: WMI_SET_CHANNEL_REG_CLASSID */
223 		chan_p->maxregpower = chan_list->chanParam[i].pwr;
224 
225 		wma_update_ch_list_11be_params(&ch_params);
226 
227 		wlan_reg_set_channel_params_for_freq(wma_handle->pdev,
228 						     chan_p->mhz, 0,
229 						     &ch_params);
230 
231 		chan_p->max_bw_supported =
232 		     wma_map_phy_ch_bw_to_wmi_channel_width(ch_params.ch_width);
233 		chan_p++;
234 	}
235 
236 	qdf_status = wmi_unified_scan_chan_list_cmd_send(wma_handle->wmi_handle,
237 				scan_ch_param);
238 
239 	if (QDF_IS_STATUS_ERROR(qdf_status))
240 		wma_err("Failed to send WMI_SCAN_CHAN_LIST_CMDID");
241 
242 	qdf_mem_free(scan_ch_param);
243 
244 	return qdf_status;
245 }
246 
247 /**
248  * wma_handle_disconnect_reason() - Send del sta msg to lim on receiving
249  * @wma_handle: wma handle
250  * @vdev_id: vdev id
251  * @reason: disconnection reason from fw
252  *
253  * Return: None
254  */
255 static void wma_handle_disconnect_reason(tp_wma_handle wma_handle,
256 					 uint32_t vdev_id, uint32_t reason)
257 {
258 	tpDeleteStaContext del_sta_ctx;
259 
260 	del_sta_ctx = qdf_mem_malloc(sizeof(tDeleteStaContext));
261 	if (!del_sta_ctx)
262 		return;
263 
264 	del_sta_ctx->vdev_id = vdev_id;
265 	del_sta_ctx->reasonCode = reason;
266 	wma_send_msg(wma_handle, SIR_LIM_DELETE_STA_CONTEXT_IND,
267 		     (void *)del_sta_ctx, 0);
268 }
269 
270 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
271 int wma_roam_vdev_disconnect_event_handler(void *handle, uint8_t *event,
272 					   uint32_t len)
273 {
274 	WMI_VDEV_DISCONNECT_EVENTID_param_tlvs *param_buf;
275 	wmi_vdev_disconnect_event_fixed_param *roam_vdev_disc_ev;
276 	tp_wma_handle wma = (tp_wma_handle)handle;
277 
278 	if (!event) {
279 		wma_err("received null event from target");
280 		return -EINVAL;
281 	}
282 
283 	param_buf = (WMI_VDEV_DISCONNECT_EVENTID_param_tlvs *)event;
284 
285 	roam_vdev_disc_ev = param_buf->fixed_param;
286 	if (!roam_vdev_disc_ev) {
287 		wma_err("roam cap event is NULL");
288 		return -EINVAL;
289 	}
290 	if (roam_vdev_disc_ev->vdev_id >= wma->max_bssid) {
291 		wma_err("Invalid vdev id %d", roam_vdev_disc_ev->vdev_id);
292 		return -EINVAL;
293 	}
294 
295 	wma_debug("Received disconnect roam event on vdev_id : %d, reason:%d",
296 		 roam_vdev_disc_ev->vdev_id, roam_vdev_disc_ev->reason);
297 
298 	switch (roam_vdev_disc_ev->reason) {
299 	case WLAN_DISCONNECT_REASON_CSA_SA_QUERY_TIMEOUT:
300 		wma_handle_disconnect_reason(wma, roam_vdev_disc_ev->vdev_id,
301 			HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT);
302 		break;
303 	case WLAN_DISCONNECT_REASON_MOVE_TO_CELLULAR:
304 		wma_handle_disconnect_reason(wma, roam_vdev_disc_ev->vdev_id,
305 			HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT);
306 		break;
307 	default:
308 		return 0;
309 	}
310 
311 	return 0;
312 }
313 #endif
314 
315 /**
316  * wma_process_set_pdev_ie_req() - process the pdev set IE req
317  * @wma: Pointer to wma handle
318  * @ie_params: Pointer to IE data.
319  *
320  * Sends the WMI req to set the IE to FW.
321  *
322  * Return: None
323  */
324 void wma_process_set_pdev_ie_req(tp_wma_handle wma,
325 				 struct set_ie_param *ie_params)
326 {
327 	if (ie_params->ie_type == DOT11_HT_IE)
328 		wma_process_set_pdev_ht_ie_req(wma, ie_params);
329 	if (ie_params->ie_type == DOT11_VHT_IE)
330 		wma_process_set_pdev_vht_ie_req(wma, ie_params);
331 
332 	qdf_mem_free(ie_params->ie_ptr);
333 }
334 
335 /**
336  * wma_process_set_pdev_ht_ie_req() - sends HT IE data to FW
337  * @wma: Pointer to wma handle
338  * @ie_params: Pointer to IE data.
339  * @nss: Nss values to prepare the HT IE.
340  *
341  * Sends the WMI req to set the HT IE to FW.
342  *
343  * Return: None
344  */
345 void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma,
346 				    struct set_ie_param *ie_params)
347 {
348 	QDF_STATUS status;
349 	wmi_pdev_set_ht_ie_cmd_fixed_param *cmd;
350 	wmi_buf_t buf;
351 	uint16_t len;
352 	uint16_t ie_len_pad;
353 	uint8_t *buf_ptr;
354 
355 	len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
356 	ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t));
357 	len += ie_len_pad;
358 
359 	buf = wmi_buf_alloc(wma->wmi_handle, len);
360 	if (!buf)
361 		return;
362 
363 	cmd = (wmi_pdev_set_ht_ie_cmd_fixed_param *)wmi_buf_data(buf);
364 	WMITLV_SET_HDR(&cmd->tlv_header,
365 		       WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param,
366 		       WMITLV_GET_STRUCT_TLVLEN(
367 			       wmi_pdev_set_ht_ie_cmd_fixed_param));
368 	cmd->reserved0 = 0;
369 	cmd->ie_len = ie_params->ie_len;
370 	cmd->tx_streams = ie_params->nss;
371 	cmd->rx_streams = ie_params->nss;
372 	wma_debug("Setting pdev HT ie with Nss = %u", ie_params->nss);
373 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
374 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad);
375 	if (ie_params->ie_len) {
376 		qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
377 			     (uint8_t *)ie_params->ie_ptr,
378 			     ie_params->ie_len);
379 	}
380 
381 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
382 				      WMI_PDEV_SET_HT_CAP_IE_CMDID);
383 	if (QDF_IS_STATUS_ERROR(status))
384 		wmi_buf_free(buf);
385 }
386 
387 /**
388  * wma_process_set_pdev_vht_ie_req() - sends VHT IE data to FW
389  * @wma: Pointer to wma handle
390  * @ie_params: Pointer to IE data.
391  * @nss: Nss values to prepare the VHT IE.
392  *
393  * Sends the WMI req to set the VHT IE to FW.
394  *
395  * Return: None
396  */
397 void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma,
398 				     struct set_ie_param *ie_params)
399 {
400 	QDF_STATUS status;
401 	wmi_pdev_set_vht_ie_cmd_fixed_param *cmd;
402 	wmi_buf_t buf;
403 	uint16_t len;
404 	uint16_t ie_len_pad;
405 	uint8_t *buf_ptr;
406 
407 	len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
408 	ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t));
409 	len += ie_len_pad;
410 
411 	buf = wmi_buf_alloc(wma->wmi_handle, len);
412 	if (!buf)
413 		return;
414 
415 	cmd = (wmi_pdev_set_vht_ie_cmd_fixed_param *)wmi_buf_data(buf);
416 	WMITLV_SET_HDR(&cmd->tlv_header,
417 		       WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param,
418 		       WMITLV_GET_STRUCT_TLVLEN(
419 					wmi_pdev_set_vht_ie_cmd_fixed_param));
420 	cmd->reserved0 = 0;
421 	cmd->ie_len = ie_params->ie_len;
422 	cmd->tx_streams = ie_params->nss;
423 	cmd->rx_streams = ie_params->nss;
424 	wma_debug("Setting pdev VHT ie with Nss = %u", ie_params->nss);
425 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
426 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad);
427 	if (ie_params->ie_len) {
428 		qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
429 			     (uint8_t *)ie_params->ie_ptr, ie_params->ie_len);
430 	}
431 
432 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
433 				      WMI_PDEV_SET_VHT_CAP_IE_CMDID);
434 	if (QDF_IS_STATUS_ERROR(status))
435 		wmi_buf_free(buf);
436 }
437 
438 /**
439  * wma_roam_scan_bmiss_cnt() - set bmiss count to fw
440  * @wma_handle: wma handle
441  * @first_bcnt: first bmiss count
442  * @final_bcnt: final bmiss count
443  * @vdev_id: vdev id
444  *
445  * set first & final biss count to fw.
446  *
447  * Return: QDF status
448  */
449 QDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle,
450 				   A_INT32 first_bcnt,
451 				   A_UINT32 final_bcnt, uint32_t vdev_id)
452 {
453 	QDF_STATUS status;
454 
455 	wma_debug("first_bcnt: %d, final_bcnt: %d", first_bcnt, final_bcnt);
456 
457 	status = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id,
458 				    WMI_VDEV_PARAM_BMISS_FIRST_BCNT,
459 				    first_bcnt);
460 	if (QDF_IS_STATUS_ERROR(status)) {
461 		wma_err("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FIRST_BCNT returned Error %d",
462 			status);
463 		return status;
464 	}
465 
466 	status = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id,
467 				    WMI_VDEV_PARAM_BMISS_FINAL_BCNT,
468 				    final_bcnt);
469 	if (QDF_IS_STATUS_ERROR(status)) {
470 		wma_err("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FINAL_BCNT returned Error %d",
471 			status);
472 		return status;
473 	}
474 
475 	return status;
476 }
477 
478 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
479 void
480 wma_send_roam_preauth_status(tp_wma_handle wma_handle,
481 			     struct wmi_roam_auth_status_params *params)
482 {
483 	QDF_STATUS status;
484 	struct wmi_unified *wmi_handle;
485 
486 	if (wma_validate_handle(wma_handle))
487 		return;
488 
489 	wmi_handle = wma_handle->wmi_handle;
490 	if (wmi_validate_handle(wmi_handle))
491 		return;
492 
493 	status = wmi_unified_send_roam_preauth_status(wmi_handle, params);
494 	if (QDF_IS_STATUS_ERROR(status))
495 		wma_err("failed to send disconnect roam preauth status");
496 }
497 #endif
498 
499 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
500 #ifndef FEATURE_CM_ENABLE
501 /**
502  * wma_process_roam_invoke() - send roam invoke command to fw.
503  * @handle: wma handle
504  * @roaminvoke: roam invoke command
505  *
506  * Send roam invoke command to fw for fastreassoc.
507  *
508  * Return: none
509  */
510 void wma_process_roam_invoke(WMA_HANDLE handle,
511 		struct roam_invoke_req *roaminvoke)
512 {
513 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
514 	struct wmi_unified *wmi_handle;
515 
516 	if (wma_validate_handle(wma_handle))
517 		goto free_frame_buf;
518 
519 	wmi_handle = wma_handle->wmi_handle;
520 	if (wmi_validate_handle(wmi_handle))
521 		goto free_frame_buf;
522 
523 	if (!wma_is_vdev_valid(roaminvoke->vdev_id)) {
524 		wma_err("Invalid vdev id:%d", roaminvoke->vdev_id);
525 		goto free_frame_buf;
526 	}
527 	wma_err("Sending ROAM INVOKE CMD vdev id:%d", roaminvoke->vdev_id);
528 
529 	wmi_unified_roam_invoke_cmd(wmi_handle,
530 				(struct roam_invoke_req *)roaminvoke);
531 free_frame_buf:
532 	if (roaminvoke->frame_len) {
533 		qdf_mem_free(roaminvoke->frame_buf);
534 		roaminvoke->frame_buf = NULL;
535 	}
536 }
537 
538 /**
539  * wma_process_roam_synch_fail() -roam synch failure handle
540  * @handle: wma handle
541  * @synch_fail: roam synch fail parameters
542  *
543  * Return: none
544  */
545 void wma_process_roam_synch_fail(WMA_HANDLE handle,
546 				 struct roam_offload_synch_fail *synch_fail)
547 {
548 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
549 	struct wmi_unified *wmi_handle;
550 
551 	if (wma_validate_handle(wma_handle))
552 		return;
553 
554 	wmi_handle = wma_handle->wmi_handle;
555 	if (wmi_validate_handle(wmi_handle))
556 		return;
557 
558 	wlan_roam_debug_log(synch_fail->session_id,
559 			    DEBUG_ROAM_SYNCH_FAIL,
560 			    DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0);
561 }
562 #endif
563 
564 /**
565  * wma_free_roam_synch_frame_ind() - Free the bcn_probe_rsp, reassoc_req,
566  * reassoc_rsp received as part of the ROAM_SYNC_FRAME event
567  *
568  * @iface - interaface corresponding to a vdev
569  *
570  * This API is used to free the buffer allocated during the ROAM_SYNC_FRAME
571  * event
572  *
573  */
574 static void wma_free_roam_synch_frame_ind(struct wma_txrx_node *iface)
575 {
576 	if (iface->roam_synch_frame_ind.bcn_probe_rsp) {
577 		qdf_mem_free(iface->roam_synch_frame_ind.bcn_probe_rsp);
578 		iface->roam_synch_frame_ind.bcn_probe_rsp_len = 0;
579 		iface->roam_synch_frame_ind.bcn_probe_rsp = NULL;
580 	}
581 	if (iface->roam_synch_frame_ind.reassoc_req) {
582 		qdf_mem_free(iface->roam_synch_frame_ind.reassoc_req);
583 		iface->roam_synch_frame_ind.reassoc_req_len = 0;
584 		iface->roam_synch_frame_ind.reassoc_req = NULL;
585 	}
586 	if (iface->roam_synch_frame_ind.reassoc_rsp) {
587 		qdf_mem_free(iface->roam_synch_frame_ind.reassoc_rsp);
588 		iface->roam_synch_frame_ind.reassoc_rsp_len = 0;
589 		iface->roam_synch_frame_ind.reassoc_rsp = NULL;
590 	}
591 }
592 
593 /**
594  * wma_fill_data_synch_frame_event() - Fill the the roam sync data buffer using
595  * synch frame event data
596  * @wma: Global WMA Handle
597  * @roam_synch_ind_ptr: Buffer to be filled
598  * @param_buf: Source buffer
599  *
600  * Firmware sends all the required information required for roam
601  * synch propagation as TLV's and stored in param_buf. These
602  * parameters are parsed and filled into the roam synch indication
603  * buffer which will be used at different layers for propagation.
604  *
605  * Return: None
606  */
607 static void wma_fill_data_synch_frame_event(tp_wma_handle wma,
608 				struct roam_offload_synch_ind *roam_synch_ind_ptr,
609 				struct wma_txrx_node *iface)
610 {
611 	uint8_t *bcn_probersp_ptr;
612 	uint8_t *reassoc_rsp_ptr;
613 	uint8_t *reassoc_req_ptr;
614 
615 	/* Beacon/Probe Rsp data */
616 	roam_synch_ind_ptr->beaconProbeRespOffset =
617 		sizeof(struct roam_offload_synch_ind);
618 	bcn_probersp_ptr = (uint8_t *) roam_synch_ind_ptr +
619 		roam_synch_ind_ptr->beaconProbeRespOffset;
620 	roam_synch_ind_ptr->beaconProbeRespLength =
621 		iface->roam_synch_frame_ind.bcn_probe_rsp_len;
622 	qdf_mem_copy(bcn_probersp_ptr,
623 		iface->roam_synch_frame_ind.bcn_probe_rsp,
624 		roam_synch_ind_ptr->beaconProbeRespLength);
625 	qdf_mem_free(iface->roam_synch_frame_ind.bcn_probe_rsp);
626 		iface->roam_synch_frame_ind.bcn_probe_rsp = NULL;
627 
628 	/* ReAssoc Rsp data */
629 	roam_synch_ind_ptr->reassocRespOffset =
630 		sizeof(struct roam_offload_synch_ind) +
631 		roam_synch_ind_ptr->beaconProbeRespLength;
632 	roam_synch_ind_ptr->reassocRespLength =
633 		iface->roam_synch_frame_ind.reassoc_rsp_len;
634 	reassoc_rsp_ptr = (uint8_t *) roam_synch_ind_ptr +
635 			  roam_synch_ind_ptr->reassocRespOffset;
636 	qdf_mem_copy(reassoc_rsp_ptr,
637 		     iface->roam_synch_frame_ind.reassoc_rsp,
638 		     roam_synch_ind_ptr->reassocRespLength);
639 	qdf_mem_free(iface->roam_synch_frame_ind.reassoc_rsp);
640 	iface->roam_synch_frame_ind.reassoc_rsp = NULL;
641 
642 	/* ReAssoc Req data */
643 	roam_synch_ind_ptr->reassoc_req_offset =
644 		sizeof(struct roam_offload_synch_ind) +
645 		roam_synch_ind_ptr->beaconProbeRespLength +
646 		roam_synch_ind_ptr->reassocRespLength;
647 	roam_synch_ind_ptr->reassoc_req_length =
648 		iface->roam_synch_frame_ind.reassoc_req_len;
649 	reassoc_req_ptr = (uint8_t *) roam_synch_ind_ptr +
650 			  roam_synch_ind_ptr->reassoc_req_offset;
651 	qdf_mem_copy(reassoc_req_ptr,
652 		     iface->roam_synch_frame_ind.reassoc_req,
653 		     roam_synch_ind_ptr->reassoc_req_length);
654 	qdf_mem_free(iface->roam_synch_frame_ind.reassoc_req);
655 	iface->roam_synch_frame_ind.reassoc_req = NULL;
656 }
657 
658 /**
659  * wma_fill_data_synch_event() - Fill the the roam sync data buffer using synch
660  * event data
661  * @wma: Global WMA Handle
662  * @roam_synch_ind_ptr: Buffer to be filled
663  * @param_buf: Source buffer
664  *
665  * Firmware sends all the required information required for roam
666  * synch propagation as TLV's and stored in param_buf. These
667  * parameters are parsed and filled into the roam synch indication
668  * buffer which will be used at different layers for propagation.
669  *
670  * Return: None
671  */
672 static void wma_fill_data_synch_event(tp_wma_handle wma,
673 				struct roam_offload_synch_ind *roam_synch_ind_ptr,
674 				WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf)
675 {
676 	uint8_t *bcn_probersp_ptr;
677 	uint8_t *reassoc_rsp_ptr;
678 	uint8_t *reassoc_req_ptr;
679 	wmi_roam_synch_event_fixed_param *synch_event;
680 
681 	synch_event = param_buf->fixed_param;
682 
683 	/* Beacon/Probe Rsp data */
684 	roam_synch_ind_ptr->beaconProbeRespOffset =
685 		sizeof(struct roam_offload_synch_ind);
686 	bcn_probersp_ptr = (uint8_t *) roam_synch_ind_ptr +
687 		roam_synch_ind_ptr->beaconProbeRespOffset;
688 	roam_synch_ind_ptr->beaconProbeRespLength =
689 		synch_event->bcn_probe_rsp_len;
690 	qdf_mem_copy(bcn_probersp_ptr, param_buf->bcn_probe_rsp_frame,
691 		     roam_synch_ind_ptr->beaconProbeRespLength);
692 	/* ReAssoc Rsp data */
693 	roam_synch_ind_ptr->reassocRespOffset =
694 		sizeof(struct roam_offload_synch_ind) +
695 		roam_synch_ind_ptr->beaconProbeRespLength;
696 	roam_synch_ind_ptr->reassocRespLength = synch_event->reassoc_rsp_len;
697 	reassoc_rsp_ptr = (uint8_t *) roam_synch_ind_ptr +
698 			  roam_synch_ind_ptr->reassocRespOffset;
699 	qdf_mem_copy(reassoc_rsp_ptr,
700 		     param_buf->reassoc_rsp_frame,
701 		     roam_synch_ind_ptr->reassocRespLength);
702 
703 	/* ReAssoc Req data */
704 	roam_synch_ind_ptr->reassoc_req_offset =
705 		sizeof(struct roam_offload_synch_ind) +
706 		roam_synch_ind_ptr->beaconProbeRespLength +
707 		roam_synch_ind_ptr->reassocRespLength;
708 	roam_synch_ind_ptr->reassoc_req_length = synch_event->reassoc_req_len;
709 	reassoc_req_ptr = (uint8_t *) roam_synch_ind_ptr +
710 			  roam_synch_ind_ptr->reassoc_req_offset;
711 	qdf_mem_copy(reassoc_req_ptr, param_buf->reassoc_req_frame,
712 		     roam_synch_ind_ptr->reassoc_req_length);
713 }
714 
715 /**
716  * wma_fill_roam_synch_buffer() - Fill the the roam sync buffer
717  * @wma: Global WMA Handle
718  * @roam_synch_ind_ptr: Buffer to be filled
719  * @param_buf: Source buffer
720  *
721  * Firmware sends all the required information required for roam
722  * synch propagation as TLV's and stored in param_buf. These
723  * parameters are parsed and filled into the roam synch indication
724  * buffer which will be used at different layers for propagation.
725  *
726  * Return: Success or Failure
727  */
728 static int wma_fill_roam_synch_buffer(tp_wma_handle wma,
729 				struct roam_offload_synch_ind *roam_synch_ind_ptr,
730 				WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf)
731 {
732 	wmi_roam_synch_event_fixed_param *synch_event;
733 	wmi_channel *chan;
734 	wmi_key_material *key;
735 	wmi_key_material_ext *key_ft;
736 	struct wma_txrx_node *iface = NULL;
737 	wmi_roam_fils_synch_tlv_param *fils_info;
738 	wmi_roam_pmk_cache_synch_tlv_param *pmk_cache_info;
739 	int status = -EINVAL;
740 	uint8_t kck_len;
741 	uint8_t kek_len;
742 
743 	synch_event = param_buf->fixed_param;
744 	roam_synch_ind_ptr->roamed_vdev_id = synch_event->vdev_id;
745 	roam_synch_ind_ptr->auth_status = synch_event->auth_status;
746 	roam_synch_ind_ptr->roam_reason = synch_event->roam_reason;
747 	roam_synch_ind_ptr->rssi = synch_event->rssi;
748 	iface = &wma->interfaces[synch_event->vdev_id];
749 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&synch_event->bssid,
750 				   roam_synch_ind_ptr->bssid.bytes);
751 	wma_debug("roamedVdevId %d authStatus %d roamReason %d rssi %d isBeacon %d",
752 		 roam_synch_ind_ptr->roamed_vdev_id,
753 		 roam_synch_ind_ptr->auth_status,
754 		 roam_synch_ind_ptr->roam_reason,
755 		 roam_synch_ind_ptr->rssi,
756 		 roam_synch_ind_ptr->isBeacon);
757 
758 #ifdef FEATURE_CM_ENABLE
759 	if (!QDF_IS_STATUS_SUCCESS(
760 		cm_fw_roam_sync_start_ind(iface->vdev,
761 					  roam_synch_ind_ptr)))
762 #else
763 	if (!QDF_IS_STATUS_SUCCESS(
764 		wma->csr_roam_synch_cb(wma->mac_context, roam_synch_ind_ptr,
765 				       NULL, SIR_ROAMING_DEREGISTER_STA)))
766 #endif
767 	{
768 		wma_err("LFR3: CSR Roam synch cb failed");
769 		wma_free_roam_synch_frame_ind(iface);
770 		return status;
771 	}
772 
773 	/*
774 	 * If lengths of bcn_probe_rsp, reassoc_req and reassoc_rsp are zero in
775 	 * synch_event driver would have received bcn_probe_rsp, reassoc_req
776 	 * and reassoc_rsp via the event WMI_ROAM_SYNCH_FRAME_EVENTID
777 	 */
778 	if ((!synch_event->bcn_probe_rsp_len) &&
779 		(!synch_event->reassoc_req_len) &&
780 		(!synch_event->reassoc_rsp_len)) {
781 		if (!iface->roam_synch_frame_ind.bcn_probe_rsp) {
782 			wma_err("LFR3: bcn_probe_rsp is NULL");
783 			QDF_ASSERT(iface->roam_synch_frame_ind.
784 				   bcn_probe_rsp);
785 			wma_free_roam_synch_frame_ind(iface);
786 			return status;
787 		}
788 		if (!iface->roam_synch_frame_ind.reassoc_rsp) {
789 			wma_err("LFR3: reassoc_rsp is NULL");
790 			QDF_ASSERT(iface->roam_synch_frame_ind.
791 				   reassoc_rsp);
792 			wma_free_roam_synch_frame_ind(iface);
793 			return status;
794 		}
795 		if (!iface->roam_synch_frame_ind.reassoc_req) {
796 			wma_err("LFR3: reassoc_req is NULL");
797 			QDF_ASSERT(iface->roam_synch_frame_ind.
798 				   reassoc_req);
799 			wma_free_roam_synch_frame_ind(iface);
800 			return status;
801 		}
802 		wma_fill_data_synch_frame_event(wma, roam_synch_ind_ptr, iface);
803 	} else {
804 		wma_fill_data_synch_event(wma, roam_synch_ind_ptr, param_buf);
805 	}
806 	chan = param_buf->chan;
807 	if (chan) {
808 		roam_synch_ind_ptr->chan_freq = chan->mhz;
809 		roam_synch_ind_ptr->phy_mode =
810 			wma_fw_to_host_phymode(WMI_GET_CHANNEL_MODE(chan));
811 	} else {
812 		roam_synch_ind_ptr->phy_mode = WLAN_PHYMODE_AUTO;
813 	}
814 
815 	key = param_buf->key;
816 	key_ft = param_buf->key_ext;
817 	if (key) {
818 		roam_synch_ind_ptr->kck_len = KCK_KEY_LEN;
819 		qdf_mem_copy(roam_synch_ind_ptr->kck, key->kck,
820 			     KCK_KEY_LEN);
821 		roam_synch_ind_ptr->kek_len = SIR_KEK_KEY_LEN;
822 		qdf_mem_copy(roam_synch_ind_ptr->kek, key->kek,
823 			     SIR_KEK_KEY_LEN);
824 		qdf_mem_copy(roam_synch_ind_ptr->replay_ctr,
825 			     key->replay_counter, REPLAY_CTR_LEN);
826 	} else if (key_ft) {
827 		/*
828 		 * For AKM 00:0F:AC (FT suite-B-SHA384)
829 		 * KCK-bits:192 KEK-bits:256
830 		 * Firmware sends wmi_key_material_ext tlv now only if
831 		 * auth is FT Suite-B SHA-384 auth. If further new suites
832 		 * are added, add logic to get kck, kek bits based on
833 		 * akm protocol
834 		 */
835 		kck_len = KCK_192BIT_KEY_LEN;
836 		kek_len = KEK_256BIT_KEY_LEN;
837 
838 		roam_synch_ind_ptr->kck_len = kck_len;
839 		qdf_mem_copy(roam_synch_ind_ptr->kck,
840 			     key_ft->key_buffer, kck_len);
841 
842 		roam_synch_ind_ptr->kek_len = kek_len;
843 		qdf_mem_copy(roam_synch_ind_ptr->kek,
844 			     (key_ft->key_buffer + kck_len),
845 			     kek_len);
846 
847 		qdf_mem_copy(roam_synch_ind_ptr->replay_ctr,
848 			     (key_ft->key_buffer + kek_len + kck_len),
849 			     REPLAY_CTR_LEN);
850 	}
851 
852 	if (param_buf->hw_mode_transition_fixed_param)
853 		wma_process_pdev_hw_mode_trans_ind(wma,
854 		    param_buf->hw_mode_transition_fixed_param,
855 		    param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping,
856 		    &roam_synch_ind_ptr->hw_mode_trans_ind);
857 	else
858 		wma_debug("hw_mode transition fixed param is NULL");
859 
860 	fils_info = param_buf->roam_fils_synch_info;
861 	if (fils_info) {
862 		if ((fils_info->kek_len > MAX_KEK_LENGTH) ||
863 		    (fils_info->pmk_len > MAX_PMK_LEN)) {
864 			wma_err("Invalid kek_len %d or pmk_len %d",
865 				 fils_info->kek_len,
866 				 fils_info->pmk_len);
867 			wma_free_roam_synch_frame_ind(iface);
868 			return status;
869 		}
870 
871 		roam_synch_ind_ptr->kek_len = fils_info->kek_len;
872 		qdf_mem_copy(roam_synch_ind_ptr->kek, fils_info->kek,
873 			     fils_info->kek_len);
874 
875 		roam_synch_ind_ptr->pmk_len = fils_info->pmk_len;
876 		qdf_mem_copy(roam_synch_ind_ptr->pmk, fils_info->pmk,
877 			     fils_info->pmk_len);
878 
879 		qdf_mem_copy(roam_synch_ind_ptr->pmkid, fils_info->pmkid,
880 			     PMKID_LEN);
881 
882 		roam_synch_ind_ptr->update_erp_next_seq_num =
883 				fils_info->update_erp_next_seq_num;
884 		roam_synch_ind_ptr->next_erp_seq_num =
885 				fils_info->next_erp_seq_num;
886 
887 		wma_debug("Update ERP Seq Num %d, Next ERP Seq Num %d",
888 			 roam_synch_ind_ptr->update_erp_next_seq_num,
889 			 roam_synch_ind_ptr->next_erp_seq_num);
890 	}
891 
892 	pmk_cache_info = param_buf->roam_pmk_cache_synch_info;
893 	if (pmk_cache_info && (pmk_cache_info->pmk_len)) {
894 		if (pmk_cache_info->pmk_len > MAX_PMK_LEN) {
895 			wma_err("Invalid pmk_len %d",
896 				 pmk_cache_info->pmk_len);
897 			wma_free_roam_synch_frame_ind(iface);
898 			return status;
899 		}
900 
901 		roam_synch_ind_ptr->pmk_len = pmk_cache_info->pmk_len;
902 		qdf_mem_copy(roam_synch_ind_ptr->pmk,
903 			     pmk_cache_info->pmk, pmk_cache_info->pmk_len);
904 		qdf_mem_copy(roam_synch_ind_ptr->pmkid,
905 			     pmk_cache_info->pmkid, PMKID_LEN);
906 	}
907 	wma_free_roam_synch_frame_ind(iface);
908 	return 0;
909 }
910 
911 /**
912  * wma_roam_update_vdev() - Update the STA and BSS
913  * @wma: Global WMA Handle
914  * @roam_synch_ind_ptr: Information needed for roam sync propagation
915  *
916  * This function will perform all the vdev related operations with
917  * respect to the self sta and the peer after roaming and completes
918  * the roam synch propagation with respect to WMA layer.
919  *
920  * Return: None
921  */
922 static void
923 wma_roam_update_vdev(tp_wma_handle wma,
924 		     struct roam_offload_synch_ind *roam_synch_ind_ptr)
925 {
926 	tDeleteStaParams *del_sta_params;
927 	tAddStaParams *add_sta_params;
928 	uint8_t vdev_id, *bssid;
929 	int32_t uc_cipher, cipher_cap;
930 
931 	vdev_id = roam_synch_ind_ptr->roamed_vdev_id;
932 	wma->interfaces[vdev_id].nss = roam_synch_ind_ptr->nss;
933 
934 	del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params));
935 	if (!del_sta_params) {
936 		return;
937 	}
938 
939 	add_sta_params = qdf_mem_malloc(sizeof(*add_sta_params));
940 	if (!add_sta_params) {
941 		qdf_mem_free(del_sta_params);
942 		return;
943 	}
944 
945 	qdf_mem_zero(del_sta_params, sizeof(*del_sta_params));
946 	qdf_mem_zero(add_sta_params, sizeof(*add_sta_params));
947 
948 	del_sta_params->smesessionId = vdev_id;
949 	add_sta_params->staType = STA_ENTRY_SELF;
950 	add_sta_params->smesessionId = vdev_id;
951 	qdf_mem_copy(&add_sta_params->bssId, &roam_synch_ind_ptr->bssid.bytes,
952 		     QDF_MAC_ADDR_SIZE);
953 	add_sta_params->assocId = roam_synch_ind_ptr->aid;
954 
955 	bssid = wma_get_vdev_bssid(wma->interfaces[vdev_id].vdev);
956 	if (!bssid) {
957 		wma_err("Failed to get bssid for vdev_%d", vdev_id);
958 		return;
959 	}
960 
961 	wma_delete_sta(wma, del_sta_params);
962 	wma_delete_bss(wma, vdev_id);
963 	wma_create_peer(wma, roam_synch_ind_ptr->bssid.bytes,
964 			WMI_PEER_TYPE_DEFAULT, vdev_id);
965 
966 	/* Update new peer's uc cipher */
967 	uc_cipher = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev,
968 					   WLAN_CRYPTO_PARAM_UCAST_CIPHER);
969 	cipher_cap = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev,
970 					   WLAN_CRYPTO_PARAM_CIPHER_CAP);
971 	wma_set_peer_ucast_cipher(roam_synch_ind_ptr->bssid.bytes, uc_cipher,
972 				  cipher_cap);
973 	wma_add_bss_lfr3(wma, roam_synch_ind_ptr->add_bss_params);
974 	wma_add_sta(wma, add_sta_params);
975 	qdf_mem_copy(bssid, roam_synch_ind_ptr->bssid.bytes,
976 		     QDF_MAC_ADDR_SIZE);
977 	lim_fill_roamed_peer_twt_caps(wma->mac_context, vdev_id,
978 				      roam_synch_ind_ptr);
979 	qdf_mem_free(add_sta_params);
980 }
981 
982 static void wma_update_phymode_on_roam(tp_wma_handle wma, uint8_t *bssid,
983 				       wmi_channel *chan,
984 				       struct wma_txrx_node *iface)
985 {
986 	enum wlan_phymode bss_phymode;
987 	struct wlan_channel *des_chan;
988 	struct wlan_channel *bss_chan;
989 	struct vdev_mlme_obj *vdev_mlme;
990 	uint8_t channel;
991 	struct wlan_objmgr_pdev *pdev = NULL;
992 
993 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev);
994 	if (!vdev_mlme)
995 		return;
996 
997 	pdev = wlan_vdev_get_pdev(vdev_mlme->vdev);
998 
999 	channel = wlan_reg_freq_to_chan(pdev, iface->ch_freq);
1000 	if (chan)
1001 		bss_phymode =
1002 			wma_fw_to_host_phymode(WMI_GET_CHANNEL_MODE(chan));
1003 	else
1004 		wma_get_phy_mode_cb(iface->ch_freq,
1005 				    iface->chan_width, &bss_phymode);
1006 
1007 	/* Update vdev mlme channel info after roaming */
1008 	des_chan = wlan_vdev_mlme_get_des_chan(iface->vdev);
1009 	bss_chan = wlan_vdev_mlme_get_bss_chan(iface->vdev);
1010 	des_chan->ch_phymode = bss_phymode;
1011 	des_chan->ch_width = iface->chan_width;
1012 	if (chan) {
1013 		des_chan->ch_freq = chan->mhz;
1014 		des_chan->ch_cfreq1 = chan->band_center_freq1;
1015 		des_chan->ch_cfreq2 = chan->band_center_freq2;
1016 	} else {
1017 		wma_err("LFR3: invalid chan");
1018 	}
1019 	qdf_mem_copy(bss_chan, des_chan, sizeof(struct wlan_channel));
1020 
1021 	/* Till conversion is not done in WMI we need to fill fw phy mode */
1022 	vdev_mlme->mgmt.generic.phy_mode = wma_host_to_fw_phymode(bss_phymode);
1023 
1024 	/* update new phymode to peer */
1025 	wma_objmgr_set_peer_mlme_phymode(wma, bssid, bss_phymode);
1026 
1027 	wma_debug("LFR3: new phymode %d", bss_phymode);
1028 }
1029 
1030 #ifndef FEATURE_CM_ENABLE
1031 static void wma_post_roam_sync_failure(tp_wma_handle wma, uint8_t vdev_id)
1032 {
1033 	wlan_cm_roam_stop_req(wma->psoc, vdev_id, REASON_ROAM_SYNCH_FAILED);
1034 	wma_debug("In cleanup: RSO Command:%d, reason %d vdev %d",
1035 		  ROAM_SCAN_OFFLOAD_STOP, REASON_ROAM_SYNCH_FAILED, vdev_id);
1036 }
1037 #endif
1038 
1039 int wma_mlme_roam_synch_event_handler_cb(void *handle, uint8_t *event,
1040 					 uint32_t len)
1041 {
1042 	WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf = NULL;
1043 	wmi_roam_synch_event_fixed_param *synch_event = NULL;
1044 	tp_wma_handle wma = (tp_wma_handle) handle;
1045 	struct roam_offload_synch_ind *roam_synch_ind_ptr = NULL;
1046 	struct bss_description *bss_desc_ptr = NULL;
1047 	uint16_t ie_len = 0;
1048 	int status = -EINVAL;
1049 	qdf_time_t roam_synch_received = qdf_get_system_timestamp();
1050 	uint32_t roam_synch_data_len;
1051 	A_UINT32 bcn_probe_rsp_len;
1052 	A_UINT32 reassoc_rsp_len;
1053 	A_UINT32 reassoc_req_len;
1054 
1055 	wma_debug("LFR3: Received WMA_ROAM_OFFLOAD_SYNCH_IND");
1056 	if (!event) {
1057 		wma_err("event param null");
1058 		goto cleanup_label;
1059 	}
1060 
1061 	param_buf = (WMI_ROAM_SYNCH_EVENTID_param_tlvs *) event;
1062 	if (!param_buf) {
1063 		wma_err("received null buf from target");
1064 		goto cleanup_label;
1065 	}
1066 
1067 	synch_event = param_buf->fixed_param;
1068 	if (!synch_event) {
1069 		wma_err("received null event data from target");
1070 		goto cleanup_label;
1071 	}
1072 
1073 	if (synch_event->vdev_id >= wma->max_bssid) {
1074 		wma_err("received invalid vdev_id %d", synch_event->vdev_id);
1075 		return status;
1076 	}
1077 
1078 	/*
1079 	 * This flag is set during ROAM_START and once this event is being
1080 	 * executed which is a run to completion, no other event can interrupt
1081 	 * this in MC thread context. So, it is OK to reset the flag here as
1082 	 * soon as we receive this event.
1083 	 */
1084 	wma->interfaces[synch_event->vdev_id].roaming_in_progress = false;
1085 
1086 	if (synch_event->bcn_probe_rsp_len >
1087 	    param_buf->num_bcn_probe_rsp_frame ||
1088 	    synch_event->reassoc_req_len >
1089 	    param_buf->num_reassoc_req_frame ||
1090 	    synch_event->reassoc_rsp_len >
1091 	    param_buf->num_reassoc_rsp_frame) {
1092 		wma_debug("Invalid synch payload: LEN bcn:%d, req:%d, rsp:%d",
1093 			synch_event->bcn_probe_rsp_len,
1094 			synch_event->reassoc_req_len,
1095 			synch_event->reassoc_rsp_len);
1096 		goto cleanup_label;
1097 	}
1098 
1099 	wlan_roam_debug_log(synch_event->vdev_id, DEBUG_ROAM_SYNCH_IND,
1100 			    DEBUG_INVALID_PEER_ID, NULL, NULL,
1101 			    synch_event->bssid.mac_addr31to0,
1102 			    synch_event->bssid.mac_addr47to32);
1103 	DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD,
1104 		synch_event->vdev_id, QDF_TRACE_DEFAULT_PDEV_ID,
1105 		QDF_PROTO_TYPE_EVENT, QDF_ROAM_SYNCH));
1106 
1107 	if (MLME_IS_ROAM_SYNCH_IN_PROGRESS(wma->psoc, synch_event->vdev_id)) {
1108 		wma_err("Ignoring RSI since one is already in progress");
1109 		goto cleanup_label;
1110 	}
1111 
1112 	/*
1113 	 * All below length fields are unsigned and hence positive numbers.
1114 	 * Maximum number during the addition would be (3 * MAX_LIMIT(UINT32) +
1115 	 * few fixed fields).
1116 	 */
1117 	wma_debug("synch payload: LEN bcn:%d, req:%d, rsp:%d",
1118 			synch_event->bcn_probe_rsp_len,
1119 			synch_event->reassoc_req_len,
1120 			synch_event->reassoc_rsp_len);
1121 
1122 	/*
1123 	 * If lengths of bcn_probe_rsp, reassoc_req and reassoc_rsp are zero in
1124 	 * synch_event driver would have received bcn_probe_rsp, reassoc_req
1125 	 * and reassoc_rsp via the event WMI_ROAM_SYNCH_FRAME_EVENTID
1126 	 */
1127 	if ((!synch_event->bcn_probe_rsp_len) &&
1128 		(!synch_event->reassoc_req_len) &&
1129 		(!synch_event->reassoc_rsp_len)) {
1130 		bcn_probe_rsp_len = wma->interfaces[synch_event->vdev_id].
1131 				      roam_synch_frame_ind.
1132 				      bcn_probe_rsp_len;
1133 		reassoc_req_len = wma->interfaces[synch_event->vdev_id].
1134 				      roam_synch_frame_ind.reassoc_req_len;
1135 		reassoc_rsp_len = wma->interfaces[synch_event->vdev_id].
1136 				      roam_synch_frame_ind.reassoc_rsp_len;
1137 
1138 		roam_synch_data_len = bcn_probe_rsp_len + reassoc_rsp_len +
1139 			reassoc_req_len + sizeof(struct roam_offload_synch_ind);
1140 
1141 		wma_debug("Updated synch payload: LEN bcn:%d, req:%d, rsp:%d",
1142 			 bcn_probe_rsp_len,
1143 			 reassoc_req_len,
1144 			 reassoc_rsp_len);
1145 	} else {
1146 		bcn_probe_rsp_len = synch_event->bcn_probe_rsp_len;
1147 		reassoc_req_len = synch_event->reassoc_req_len;
1148 		reassoc_rsp_len = synch_event->reassoc_rsp_len;
1149 
1150 		if (synch_event->bcn_probe_rsp_len > WMI_SVC_MSG_MAX_SIZE)
1151 			goto cleanup_label;
1152 		if (synch_event->reassoc_rsp_len >
1153 		    (WMI_SVC_MSG_MAX_SIZE - synch_event->bcn_probe_rsp_len))
1154 			goto cleanup_label;
1155 		if (synch_event->reassoc_req_len >
1156 		    WMI_SVC_MSG_MAX_SIZE - (synch_event->bcn_probe_rsp_len +
1157 			synch_event->reassoc_rsp_len))
1158 			goto cleanup_label;
1159 
1160 		roam_synch_data_len = bcn_probe_rsp_len +
1161 			reassoc_rsp_len + reassoc_req_len;
1162 
1163 		/*
1164 		 * Below is the check for the entire size of the message
1165 		 * received from the firmware.
1166 		 */
1167 		if (roam_synch_data_len > WMI_SVC_MSG_MAX_SIZE -
1168 			(sizeof(*synch_event) + sizeof(wmi_channel) +
1169 			 sizeof(wmi_key_material) + sizeof(uint32_t)))
1170 			goto cleanup_label;
1171 
1172 		roam_synch_data_len += sizeof(struct roam_offload_synch_ind);
1173 	}
1174 
1175 	cds_host_diag_log_work(&wma->roam_ho_wl,
1176 			       WMA_ROAM_HO_WAKE_LOCK_DURATION,
1177 			       WIFI_POWER_EVENT_WAKELOCK_WOW);
1178 	qdf_wake_lock_timeout_acquire(&wma->roam_ho_wl,
1179 				      WMA_ROAM_HO_WAKE_LOCK_DURATION);
1180 
1181 	roam_synch_ind_ptr = qdf_mem_malloc(roam_synch_data_len);
1182 	if (!roam_synch_ind_ptr) {
1183 		QDF_ASSERT(roam_synch_ind_ptr);
1184 		status = -ENOMEM;
1185 		goto cleanup_label;
1186 	}
1187 	qdf_mem_zero(roam_synch_ind_ptr, roam_synch_data_len);
1188 	status = wma_fill_roam_synch_buffer(wma,
1189 			roam_synch_ind_ptr, param_buf);
1190 	if (status != 0)
1191 		goto cleanup_label;
1192 	/* 24 byte MAC header and 12 byte to ssid IE */
1193 	if (roam_synch_ind_ptr->beaconProbeRespLength >
1194 			(SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) {
1195 		ie_len = roam_synch_ind_ptr->beaconProbeRespLength -
1196 			(SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET);
1197 	} else {
1198 		wma_err("LFR3: Invalid Beacon Length");
1199 		goto cleanup_label;
1200 	}
1201 	bss_desc_ptr = qdf_mem_malloc(sizeof(struct bss_description) + ie_len);
1202 	if (!bss_desc_ptr) {
1203 		QDF_ASSERT(bss_desc_ptr);
1204 		status = -ENOMEM;
1205 		goto cleanup_label;
1206 	}
1207 	qdf_mem_zero(bss_desc_ptr, sizeof(struct bss_description) + ie_len);
1208 	if (QDF_IS_STATUS_ERROR(wma->pe_roam_synch_cb(wma->mac_context,
1209 			roam_synch_ind_ptr, bss_desc_ptr,
1210 			SIR_ROAM_SYNCH_PROPAGATION))) {
1211 		wma_err("LFR3: PE roam synch cb failed");
1212 		status = -EBUSY;
1213 		goto cleanup_label;
1214 	}
1215 
1216 	wma_roam_update_vdev(wma, roam_synch_ind_ptr);
1217 	/* update freq and channel width */
1218 	wma->interfaces[synch_event->vdev_id].ch_freq =
1219 		roam_synch_ind_ptr->chan_freq;
1220 	wma->interfaces[synch_event->vdev_id].chan_width =
1221 		roam_synch_ind_ptr->chan_width;
1222 	/*
1223 	 * update phy_mode in wma to avoid mismatch in phymode between host and
1224 	 * firmware. The phymode stored in peer->peer_mlme.phymode is
1225 	 * sent to firmware as part of opmode update during either - vht opmode
1226 	 * action frame received or during opmode change detected while
1227 	 * processing beacon. Any mismatch of this value with firmware phymode
1228 	 * results in firmware assert.
1229 	 */
1230 	wma_update_phymode_on_roam(wma, roam_synch_ind_ptr->bssid.bytes,
1231 				   param_buf->chan,
1232 				   &wma->interfaces[synch_event->vdev_id]);
1233 #ifdef FEATURE_CM_ENABLE
1234 	cm_fw_roam_sync_propagation(wma->psoc,
1235 				    synch_event->vdev_id,
1236 				    roam_synch_ind_ptr);
1237 #else
1238 	wma->csr_roam_synch_cb(wma->mac_context, roam_synch_ind_ptr,
1239 			       bss_desc_ptr, SIR_ROAM_SYNCH_PROPAGATION);
1240 	wma_process_roam_synch_complete(wma, synch_event->vdev_id);
1241 	wma->csr_roam_synch_cb(wma->mac_context, roam_synch_ind_ptr,
1242 			       bss_desc_ptr, SIR_ROAM_SYNCH_COMPLETE);
1243 #endif
1244 
1245 	wma->interfaces[synch_event->vdev_id].roam_synch_delay =
1246 		qdf_get_system_timestamp() - roam_synch_received;
1247 	wma_debug("LFR3: roam_synch_delay:%d",
1248 		 wma->interfaces[synch_event->vdev_id].roam_synch_delay);
1249 #ifndef FEATURE_CM_ENABLE
1250 	wma->csr_roam_synch_cb(wma->mac_context, roam_synch_ind_ptr,
1251 			       bss_desc_ptr, SIR_ROAM_SYNCH_NAPI_OFF);
1252 #endif
1253 
1254 	status = 0;
1255 
1256 cleanup_label:
1257 	if (status != 0) {
1258 #ifdef FEATURE_CM_ENABLE
1259 		if (synch_event) {
1260 			cm_fw_roam_abort_req(wma->psoc, synch_event->vdev_id);
1261 			cm_roam_stop_req(wma->psoc, synch_event->vdev_id,
1262 					 REASON_ROAM_SYNCH_FAILED);
1263 		}
1264 #else
1265 		if (roam_synch_ind_ptr)
1266 			wma->csr_roam_synch_cb(wma->mac_context,
1267 					       roam_synch_ind_ptr, NULL,
1268 					       SIR_ROAMING_ABORT);
1269 		if (synch_event)
1270 			wma_post_roam_sync_failure(wma, synch_event->vdev_id);
1271 #endif
1272 	}
1273 
1274 	if (roam_synch_ind_ptr && roam_synch_ind_ptr->ric_tspec_data)
1275 		qdf_mem_free(roam_synch_ind_ptr->ric_tspec_data);
1276 	if (roam_synch_ind_ptr)
1277 		qdf_mem_free(roam_synch_ind_ptr);
1278 	if (bss_desc_ptr)
1279 		qdf_mem_free(bss_desc_ptr);
1280 
1281 	return status;
1282 }
1283 
1284 int wma_roam_synch_frame_event_handler(void *handle, uint8_t *event,
1285 					uint32_t len)
1286 {
1287 	WMI_ROAM_SYNCH_FRAME_EVENTID_param_tlvs *param_buf = NULL;
1288 	wmi_roam_synch_frame_event_fixed_param *synch_frame_event = NULL;
1289 	tp_wma_handle wma = (tp_wma_handle) handle;
1290 	A_UINT32 vdev_id;
1291 	struct wma_txrx_node *iface = NULL;
1292 	int status = -EINVAL;
1293 
1294 	if (!event) {
1295 		wma_err("event param null");
1296 		return status;
1297 	}
1298 
1299 	param_buf = (WMI_ROAM_SYNCH_FRAME_EVENTID_param_tlvs *) event;
1300 	if (!param_buf) {
1301 		wma_err("received null buf from target");
1302 		return status;
1303 	}
1304 
1305 	synch_frame_event = param_buf->fixed_param;
1306 	if (!synch_frame_event) {
1307 		wma_err("received null event data from target");
1308 		return status;
1309 	}
1310 
1311 	if (synch_frame_event->vdev_id >= wma->max_bssid) {
1312 		wma_err("received invalid vdev_id %d",
1313 			 synch_frame_event->vdev_id);
1314 		return status;
1315 	}
1316 
1317 	if (synch_frame_event->bcn_probe_rsp_len >
1318 	    param_buf->num_bcn_probe_rsp_frame ||
1319 	    synch_frame_event->reassoc_req_len >
1320 	    param_buf->num_reassoc_req_frame ||
1321 	    synch_frame_event->reassoc_rsp_len >
1322 	    param_buf->num_reassoc_rsp_frame) {
1323 		wma_err("fixed/actual len err: bcn:%d/%d req:%d/%d rsp:%d/%d",
1324 			 synch_frame_event->bcn_probe_rsp_len,
1325 			 param_buf->num_bcn_probe_rsp_frame,
1326 			 synch_frame_event->reassoc_req_len,
1327 			 param_buf->num_reassoc_req_frame,
1328 			 synch_frame_event->reassoc_rsp_len,
1329 			 param_buf->num_reassoc_rsp_frame);
1330 		return status;
1331 	}
1332 
1333 	vdev_id = synch_frame_event->vdev_id;
1334 	iface = &wma->interfaces[vdev_id];
1335 
1336 	if (MLME_IS_ROAM_SYNCH_IN_PROGRESS(wma->psoc, vdev_id)) {
1337 		wma_err("Ignoring this event as it is unexpected");
1338 		wma_free_roam_synch_frame_ind(iface);
1339 		return status;
1340 	}
1341 
1342 	wma_debug("LFR3: Roam synch frame payload: LEN bcn:%d, req:%d, rsp:%d morefrag: %d",
1343 		  synch_frame_event->bcn_probe_rsp_len,
1344 		  synch_frame_event->reassoc_req_len,
1345 		  synch_frame_event->reassoc_rsp_len,
1346 		  synch_frame_event->more_frag);
1347 
1348 	if (synch_frame_event->bcn_probe_rsp_len) {
1349 		iface->roam_synch_frame_ind.bcn_probe_rsp_len =
1350 				synch_frame_event->bcn_probe_rsp_len;
1351 		iface->roam_synch_frame_ind.is_beacon =
1352 				synch_frame_event->is_beacon;
1353 
1354 		if (iface->roam_synch_frame_ind.bcn_probe_rsp)
1355 			qdf_mem_free(iface->roam_synch_frame_ind.
1356 				     bcn_probe_rsp);
1357 		iface->roam_synch_frame_ind.bcn_probe_rsp =
1358 			qdf_mem_malloc(iface->roam_synch_frame_ind.
1359 				       bcn_probe_rsp_len);
1360 		if (!iface->roam_synch_frame_ind.bcn_probe_rsp) {
1361 			QDF_ASSERT(iface->roam_synch_frame_ind.
1362 				   bcn_probe_rsp);
1363 			status = -ENOMEM;
1364 			wma_free_roam_synch_frame_ind(iface);
1365 			return status;
1366 		}
1367 		qdf_mem_copy(iface->roam_synch_frame_ind.
1368 			bcn_probe_rsp,
1369 			param_buf->bcn_probe_rsp_frame,
1370 			iface->roam_synch_frame_ind.bcn_probe_rsp_len);
1371 	}
1372 
1373 	if (synch_frame_event->reassoc_req_len) {
1374 		iface->roam_synch_frame_ind.reassoc_req_len =
1375 				synch_frame_event->reassoc_req_len;
1376 
1377 		if (iface->roam_synch_frame_ind.reassoc_req)
1378 			qdf_mem_free(iface->roam_synch_frame_ind.reassoc_req);
1379 		iface->roam_synch_frame_ind.reassoc_req =
1380 			qdf_mem_malloc(iface->roam_synch_frame_ind.
1381 				       reassoc_req_len);
1382 		if (!iface->roam_synch_frame_ind.reassoc_req) {
1383 			QDF_ASSERT(iface->roam_synch_frame_ind.
1384 				   reassoc_req);
1385 			status = -ENOMEM;
1386 			wma_free_roam_synch_frame_ind(iface);
1387 			return status;
1388 		}
1389 		qdf_mem_copy(iface->roam_synch_frame_ind.reassoc_req,
1390 			     param_buf->reassoc_req_frame,
1391 			     iface->roam_synch_frame_ind.reassoc_req_len);
1392 	}
1393 
1394 	if (synch_frame_event->reassoc_rsp_len) {
1395 		iface->roam_synch_frame_ind.reassoc_rsp_len =
1396 				synch_frame_event->reassoc_rsp_len;
1397 
1398 		if (iface->roam_synch_frame_ind.reassoc_rsp)
1399 			qdf_mem_free(iface->roam_synch_frame_ind.reassoc_rsp);
1400 
1401 		iface->roam_synch_frame_ind.reassoc_rsp =
1402 			qdf_mem_malloc(iface->roam_synch_frame_ind.
1403 				       reassoc_rsp_len);
1404 		if (!iface->roam_synch_frame_ind.reassoc_rsp) {
1405 			QDF_ASSERT(iface->roam_synch_frame_ind.
1406 				   reassoc_rsp);
1407 			status = -ENOMEM;
1408 			wma_free_roam_synch_frame_ind(iface);
1409 			return status;
1410 		}
1411 		qdf_mem_copy(iface->roam_synch_frame_ind.reassoc_rsp,
1412 			     param_buf->reassoc_rsp_frame,
1413 			     iface->roam_synch_frame_ind.reassoc_rsp_len);
1414 	}
1415 	return 0;
1416 }
1417 
1418 /**
1419  * __wma_roam_synch_event_handler() - roam synch event handler
1420  * @handle: wma handle
1421  * @event: event data
1422  * @len: length of data
1423  *
1424  * This function is roam synch event handler.It sends roam
1425  * indication for upper layer.
1426  *
1427  * Return: Success or Failure status
1428  */
1429 int wma_roam_synch_event_handler(void *handle, uint8_t *event,
1430 				 uint32_t len)
1431 {
1432 	int status = -EINVAL;
1433 	wmi_roam_synch_event_fixed_param *synch_event = NULL;
1434 	WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf = NULL;
1435 	tp_wma_handle wma = (tp_wma_handle)handle;
1436 #ifndef FEATURE_CM_ENABLE
1437 	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
1438 	struct wma_txrx_node *iface = NULL;
1439 	struct vdev_mlme_obj *mlme_obj;
1440 #endif
1441 	if (!event) {
1442 		wma_err_rl("event param null");
1443 		return status;
1444 	}
1445 
1446 	param_buf = (WMI_ROAM_SYNCH_EVENTID_param_tlvs *)event;
1447 	if (!param_buf) {
1448 		wma_err_rl("received null buf from target");
1449 		return status;
1450 	}
1451 	synch_event = param_buf->fixed_param;
1452 	if (!synch_event) {
1453 		wma_err_rl("received null event data from target");
1454 		return status;
1455 	}
1456 
1457 	if (synch_event->vdev_id >= wma->max_bssid) {
1458 		wma_err_rl("received invalid vdev_id %d",
1459 			   synch_event->vdev_id);
1460 		return status;
1461 	}
1462 #ifdef FEATURE_CM_ENABLE
1463 	cm_fw_roam_sync_req(wma->psoc, synch_event->vdev_id, event, len);
1464 #else
1465 	iface = &wma->interfaces[synch_event->vdev_id];
1466 	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(iface->vdev);
1467 	if (mlme_obj)
1468 		mlme_obj->mgmt.generic.tx_pwrlimit =
1469 				synch_event->max_allowed_tx_power;
1470 
1471 	qdf_status = wlan_vdev_mlme_sm_deliver_evt(iface->vdev,
1472 						   WLAN_VDEV_SM_EV_ROAM,
1473 						   len,
1474 						   event);
1475 	if (QDF_IS_STATUS_ERROR(qdf_status)) {
1476 		wma_err("Failed to send the EV_ROAM");
1477 		wma_post_roam_sync_failure(wma, synch_event->vdev_id);
1478 		return status;
1479 	}
1480 	wma_debug("Posted EV_ROAM to VDEV SM");
1481 #endif
1482 	return 0;
1483 }
1484 
1485 int wma_roam_auth_offload_event_handler(WMA_HANDLE handle, uint8_t *event,
1486 					uint32_t len)
1487 {
1488 	QDF_STATUS status;
1489 	tp_wma_handle wma = (tp_wma_handle) handle;
1490 	struct mac_context *mac_ctx;
1491 	wmi_roam_preauth_start_event_fixed_param *rso_auth_start_ev;
1492 	WMI_ROAM_PREAUTH_START_EVENTID_param_tlvs *param_buf;
1493 	struct qdf_mac_addr ap_bssid;
1494 	uint8_t vdev_id;
1495 
1496 	if (!event) {
1497 		wma_err_rl("received null event from target");
1498 		return -EINVAL;
1499 	}
1500 
1501 	param_buf = (WMI_ROAM_PREAUTH_START_EVENTID_param_tlvs *) event;
1502 	if (!param_buf) {
1503 		wma_err_rl("received null buf from target");
1504 		return -EINVAL;
1505 	}
1506 
1507 	rso_auth_start_ev = param_buf->fixed_param;
1508 	if (!rso_auth_start_ev) {
1509 		wma_err_rl("received null event data from target");
1510 		return -EINVAL;
1511 	}
1512 
1513 	if (rso_auth_start_ev->vdev_id > wma->max_bssid) {
1514 		wma_err_rl("received invalid vdev_id %d",
1515 			   rso_auth_start_ev->vdev_id);
1516 		return -EINVAL;
1517 	}
1518 
1519 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
1520 	if (!mac_ctx) {
1521 		wma_err("NULL mac ptr");
1522 		QDF_ASSERT(0);
1523 		return -EINVAL;
1524 	}
1525 
1526 	cds_host_diag_log_work(&wma->roam_preauth_wl,
1527 			       WMA_ROAM_PREAUTH_WAKE_LOCK_DURATION,
1528 			       WIFI_POWER_EVENT_WAKELOCK_WOW);
1529 	qdf_wake_lock_timeout_acquire(&wma->roam_ho_wl,
1530 				      WMA_ROAM_HO_WAKE_LOCK_DURATION);
1531 
1532 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&rso_auth_start_ev->candidate_ap_bssid,
1533 				   ap_bssid.bytes);
1534 	if (qdf_is_macaddr_zero(&ap_bssid) ||
1535 	    qdf_is_macaddr_broadcast(&ap_bssid) ||
1536 	    qdf_is_macaddr_group(&ap_bssid)) {
1537 		wma_err_rl("Invalid bssid");
1538 		return -EINVAL;
1539 	}
1540 
1541 	vdev_id = rso_auth_start_ev->vdev_id;
1542 	wma_debug("Received Roam auth offload event for bss:"QDF_MAC_ADDR_FMT" vdev_id:%d",
1543 		  QDF_MAC_ADDR_REF(ap_bssid.bytes), vdev_id);
1544 
1545 	lim_sae_auth_cleanup_retry(mac_ctx, vdev_id);
1546 	status = wma->csr_roam_auth_event_handle_cb(mac_ctx, vdev_id, ap_bssid);
1547 	if (QDF_IS_STATUS_ERROR(status)) {
1548 		wma_err_rl("Trigger pre-auth failed");
1549 		return -EINVAL;
1550 	}
1551 
1552 	return 0;
1553 }
1554 
1555 int wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle,
1556 					  uint8_t *event,
1557 					  uint32_t len)
1558 {
1559 	tp_wma_handle wma = (tp_wma_handle)handle;
1560 	WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *param_buf;
1561 	wmi_roam_scan_channel_list_event_fixed_param *fixed_param;
1562 	uint8_t vdev_id, i = 0, num_ch = 0;
1563 	struct roam_scan_ch_resp *resp;
1564 	struct scheduler_msg sme_msg = {0};
1565 
1566 	param_buf = (WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *)event;
1567 	if (!param_buf) {
1568 		wma_err_rl("NULL event received from target");
1569 		return -EINVAL;
1570 	}
1571 
1572 	fixed_param = param_buf->fixed_param;
1573 	if (!fixed_param) {
1574 		wma_err_rl(" NULL fixed param");
1575 		return -EINVAL;
1576 	}
1577 
1578 	vdev_id = fixed_param->vdev_id;
1579 	if (vdev_id >= wma->max_bssid) {
1580 		wma_err_rl("Invalid vdev_id %d", vdev_id);
1581 		return -EINVAL;
1582 	}
1583 
1584 	num_ch = (param_buf->num_channel_list <
1585 		WNI_CFG_VALID_CHANNEL_LIST_LEN) ?
1586 		param_buf->num_channel_list :
1587 		WNI_CFG_VALID_CHANNEL_LIST_LEN;
1588 
1589 	resp = qdf_mem_malloc(sizeof(struct roam_scan_ch_resp) +
1590 		num_ch * sizeof(param_buf->channel_list[0]));
1591 	if (!resp)
1592 		return -EINVAL;
1593 
1594 	resp->chan_list = (uint32_t *)(resp + 1);
1595 	resp->vdev_id = vdev_id;
1596 	resp->command_resp = fixed_param->command_response;
1597 	resp->num_channels = param_buf->num_channel_list;
1598 
1599 	for (i = 0; i < num_ch; i++)
1600 		resp->chan_list[i] = param_buf->channel_list[i];
1601 
1602 	sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT;
1603 	sme_msg.bodyptr = resp;
1604 
1605 	if (scheduler_post_message(QDF_MODULE_ID_WMA,
1606 				   QDF_MODULE_ID_SME,
1607 				   QDF_MODULE_ID_SME, &sme_msg)) {
1608 		wma_err("Failed to post msg to SME");
1609 		qdf_mem_free(sme_msg.bodyptr);
1610 		return -EINVAL;
1611 	}
1612 
1613 	return 0;
1614 }
1615 
1616 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
1617 /**
1618  * wma_get_trigger_detail_str  - Return roam trigger string from the
1619  * enum WMI_ROAM_TRIGGER_REASON
1620  * @roam_info: Pointer to the roam trigger info
1621  * @buf:       Destination buffer to write the reason string
1622  *
1623  * Return: None
1624  */
1625 static void
1626 wma_get_trigger_detail_str(struct wmi_roam_trigger_info *roam_info, char *buf)
1627 {
1628 	uint16_t buf_cons, buf_left = MAX_ROAM_DEBUG_BUF_SIZE;
1629 	char *temp = buf;
1630 
1631 	buf_cons = qdf_snprint(temp, buf_left, "Reason: \"%s\" ",
1632 			mlme_get_roam_trigger_str(roam_info->trigger_reason));
1633 	temp += buf_cons;
1634 	buf_left -= buf_cons;
1635 
1636 	if (roam_info->trigger_sub_reason) {
1637 		buf_cons = qdf_snprint(
1638 			    temp, buf_left, "Sub-Reason: %s",
1639 			    mlme_get_sub_reason_str(roam_info->trigger_sub_reason));
1640 		temp += buf_cons;
1641 		buf_left -= buf_cons;
1642 	}
1643 
1644 	switch (roam_info->trigger_reason) {
1645 	case WMI_ROAM_TRIGGER_REASON_PER:
1646 	case WMI_ROAM_TRIGGER_REASON_BMISS:
1647 	case WMI_ROAM_TRIGGER_REASON_HIGH_RSSI:
1648 	case WMI_ROAM_TRIGGER_REASON_MAWC:
1649 	case WMI_ROAM_TRIGGER_REASON_DENSE:
1650 	case WMI_ROAM_TRIGGER_REASON_BACKGROUND:
1651 	case WMI_ROAM_TRIGGER_REASON_IDLE:
1652 	case WMI_ROAM_TRIGGER_REASON_FORCED:
1653 	case WMI_ROAM_TRIGGER_REASON_UNIT_TEST:
1654 		return;
1655 	case WMI_ROAM_TRIGGER_REASON_BTM:
1656 		buf_cons = qdf_snprint(temp, buf_left,
1657 				       "Req_mode: %d Disassoc_timer: %d",
1658 				       roam_info->btm_trig_data.btm_request_mode,
1659 				       roam_info->btm_trig_data.disassoc_timer);
1660 		temp += buf_cons;
1661 		buf_left -= buf_cons;
1662 
1663 		buf_cons = qdf_snprint(temp, buf_left,
1664 			    "validity_interval: %d candidate_list_cnt: %d resp_status: %d, bss_termination_timeout: %d, mbo_assoc_retry_timeout: %d",
1665 			    roam_info->btm_trig_data.validity_interval,
1666 			    roam_info->btm_trig_data.candidate_list_count,
1667 			    roam_info->btm_trig_data.btm_resp_status,
1668 			    roam_info->btm_trig_data.
1669 					btm_bss_termination_timeout,
1670 			    roam_info->btm_trig_data.
1671 					btm_mbo_assoc_retry_timeout);
1672 		buf_left -= buf_cons;
1673 		temp += buf_cons;
1674 		return;
1675 	case WMI_ROAM_TRIGGER_REASON_BSS_LOAD:
1676 		buf_cons = qdf_snprint(temp, buf_left, "CU: %d %% ",
1677 				       roam_info->cu_trig_data.cu_load);
1678 		temp += buf_cons;
1679 		buf_left -= buf_cons;
1680 		return;
1681 	case WMI_ROAM_TRIGGER_REASON_DEAUTH:
1682 		buf_cons = qdf_snprint(temp, buf_left, "Type: %d Reason: %d ",
1683 				       roam_info->deauth_trig_data.type,
1684 				       roam_info->deauth_trig_data.reason);
1685 		temp += buf_cons;
1686 		buf_left -= buf_cons;
1687 		return;
1688 	case WMI_ROAM_TRIGGER_REASON_LOW_RSSI:
1689 	case WMI_ROAM_TRIGGER_REASON_PERIODIC:
1690 		/*
1691 		 * Use roam_info->current_rssi get the RSSI of current AP after
1692 		 * roam scan is triggered. This avoids discrepency with the
1693 		 * next rssi threshold value printed in roam scan details.
1694 		 * roam_info->rssi_trig_data.threshold gives the rssi threshold
1695 		 * for the Low Rssi/Periodic scan trigger.
1696 		 */
1697 		buf_cons = qdf_snprint(temp, buf_left,
1698 				       " Cur_Rssi threshold:%d Current AP RSSI: %d",
1699 				       roam_info->rssi_trig_data.threshold,
1700 				       roam_info->current_rssi);
1701 		temp += buf_cons;
1702 		buf_left -= buf_cons;
1703 		return;
1704 	case WMI_ROAM_TRIGGER_REASON_WTC_BTM:
1705 		buf_cons =
1706 		  qdf_snprint(temp, buf_left, "Roaming Mode: %d, Trigger Reason: %d, Sub code:%d, wtc mode:%d, wtc scan mode:%d, wtc rssi th:%d, wtc candi rssi th:%d",
1707 			      roam_info->wtc_btm_trig_data.roaming_mode,
1708 			      roam_info->wtc_btm_trig_data.vsie_trigger_reason,
1709 			      roam_info->wtc_btm_trig_data.sub_code,
1710 			      roam_info->wtc_btm_trig_data.wtc_mode,
1711 			      roam_info->wtc_btm_trig_data.wtc_scan_mode,
1712 			      roam_info->wtc_btm_trig_data.wtc_rssi_th,
1713 			      roam_info->wtc_btm_trig_data.wtc_candi_rssi_th);
1714 		temp += buf_cons;
1715 		buf_left -= buf_cons;
1716 		return;
1717 	default:
1718 		return;
1719 	}
1720 }
1721 
1722 /**
1723  * wma_rso_print_trigger_info  - Roam trigger related details
1724  * @data:    Pointer to the roam trigger data
1725  * @vdev_id: Vdev ID
1726  *
1727  * Prints the vdev, roam trigger reason, time of the day at which roaming
1728  * was triggered.
1729  *
1730  * Return: None
1731  */
1732 static void
1733 wma_rso_print_trigger_info(struct wmi_roam_trigger_info *data, uint8_t vdev_id)
1734 {
1735 	char *buf;
1736 	char time[TIME_STRING_LEN];
1737 
1738 	buf = qdf_mem_malloc(MAX_ROAM_DEBUG_BUF_SIZE);
1739 	if (!buf)
1740 		return;
1741 
1742 	wma_get_trigger_detail_str(data, buf);
1743 	mlme_get_converted_timestamp(data->timestamp, time);
1744 	wma_nofl_info("%s [ROAM_TRIGGER]: VDEV[%d] %s", time, vdev_id, buf);
1745 
1746 	qdf_mem_free(buf);
1747 }
1748 
1749 /**
1750  * wma_rso_print_btm_rsp_info - BTM RSP related details
1751  * @data:    Pointer to the btm rsp data
1752  * @vdev_id: vdev id
1753  *
1754  * Prints the vdev, btm status, target_bssid and vsie reason
1755  *
1756  * Return: None
1757  */
1758 static void
1759 wma_rso_print_btm_rsp_info(struct roam_btm_response_data *data,
1760 			   uint8_t vdev_id)
1761 {
1762 	char time[TIME_STRING_LEN];
1763 
1764 	mlme_get_converted_timestamp(data->timestamp, time);
1765 	wma_nofl_info("%s [BTM RSP]: VDEV[%d], Status: %d, VSIE reason: %d, BSSID: " QDF_MAC_ADDR_FMT,
1766 		      time, vdev_id, data->btm_status, data->vsie_reason,
1767 		      QDF_MAC_ADDR_REF(data->target_bssid.bytes));
1768 }
1769 
1770 /**
1771  * wma_rso_print_roam_initial_info - Roaming related initial details
1772  * @data:    Pointer to the btm rsp data
1773  * @vdev_id: vdev id
1774  *
1775  * Prints the vdev, roam_full_scan_count, channel and rssi
1776  * utilization threhold and timer
1777  *
1778  * Return: None
1779  */
1780 static void
1781 wma_rso_print_roam_initial_info(struct roam_initial_data *data,
1782 				uint8_t vdev_id)
1783 {
1784 	wma_nofl_info("[ROAM INIT INFO]: VDEV[%d], roam_full_scan_count: %d, rssi_th: %d, cu_th: %d, fw_cancel_timer_bitmap: %d",
1785 		      vdev_id, data->roam_full_scan_count, data->rssi_th,
1786 		      data->cu_th, data->fw_cancel_timer_bitmap);
1787 }
1788 
1789 /**
1790  * wma_rso_print_roam_msg_info - Roaming related message details
1791  * @data:    Pointer to the btm rsp data
1792  * @vdev_id: vdev id
1793  *
1794  * Prints the vdev, msg_id, msg_param1, msg_param2 and timer
1795  *
1796  * Return: None
1797  */
1798 static void wma_rso_print_roam_msg_info(struct roam_msg_info *data,
1799 					uint8_t vdev_id)
1800 {
1801 	char time[TIME_STRING_LEN];
1802 	static const char msg_id1_str[] = "Roam RSSI TH Reset";
1803 
1804 	if (data->msg_id == WMI_ROAM_MSG_RSSI_RECOVERED) {
1805 		mlme_get_converted_timestamp(data->timestamp, time);
1806 		wma_info("%s [ROAM MSG INFO]: VDEV[%d] %s, Current rssi: %d dbm, next_rssi_threshold: %d dbm",
1807 			 time, vdev_id, msg_id1_str, data->msg_param1,
1808 			 data->msg_param2);
1809 	}
1810 }
1811 
1812 /**
1813  * wma_log_roam_scan_candidates  - Print roam scan candidate AP info
1814  * @ap:           Pointer to the candidate AP list
1815  * @num_entries:  Number of candidate APs
1816  *
1817  * Print the RSSI, CU load, Cu score, RSSI score, total score, BSSID
1818  * and time stamp at which the candidate was found details.
1819  *
1820  * Return: None
1821  */
1822 static void
1823 wma_log_roam_scan_candidates(struct wmi_roam_candidate_info *ap,
1824 			     uint8_t num_entries)
1825 {
1826 	uint16_t i;
1827 	char time[TIME_STRING_LEN], time2[TIME_STRING_LEN];
1828 
1829 	wma_nofl_info("%62s%62s", LINE_STR, LINE_STR);
1830 	wma_nofl_info("%13s %16s %8s %4s %4s %5s/%3s %3s/%3s %7s %7s %6s %12s %20s",
1831 		      "AP BSSID", "TSTAMP", "CH", "TY", "ETP", "RSSI",
1832 		      "SCR", "CU%", "SCR", "TOT_SCR", "BL_RSN", "BL_SRC",
1833 		      "BL_TSTAMP", "BL_TIMEOUT(ms)");
1834 	wma_nofl_info("%62s%62s", LINE_STR, LINE_STR);
1835 
1836 	if (num_entries > MAX_ROAM_CANDIDATE_AP)
1837 		num_entries = MAX_ROAM_CANDIDATE_AP;
1838 
1839 	for (i = 0; i < num_entries; i++) {
1840 		mlme_get_converted_timestamp(ap->timestamp, time);
1841 		mlme_get_converted_timestamp(ap->bl_timestamp, time2);
1842 		wma_nofl_info(QDF_MAC_ADDR_FMT " %17s %4d %-4s %4d %3d/%-4d %2d/%-4d %5d %7d %7d   %17s %9d",
1843 			      QDF_MAC_ADDR_REF(ap->bssid.bytes), time,
1844 			      ap->freq,
1845 			      ((ap->type == 0) ? "C_AP" :
1846 			       ((ap->type == 2) ? "R_AP" : "P_AP")),
1847 			      ap->etp, ap->rssi, ap->rssi_score, ap->cu_load,
1848 			      ap->cu_score, ap->total_score, ap->bl_reason,
1849 			      ap->bl_source, time2, ap->bl_original_timeout);
1850 		ap++;
1851 	}
1852 }
1853 
1854 /**
1855  * wma_rso_print_scan_info  - Print the roam scan details and candidate AP
1856  * details
1857  * @scan:      Pointer to the received tlv after sanitization
1858  * @vdev_id:   Vdev ID
1859  * @trigger:   Roam scan trigger reason
1860  * @timestamp: Host timestamp in millisecs
1861  *
1862  * Prinst the roam scan details with time of the day when the scan was
1863  * triggered and roam candidate AP with score details
1864  *
1865  * Return: None
1866  */
1867 static void
1868 wma_rso_print_scan_info(struct wmi_roam_scan_data *scan, uint8_t vdev_id,
1869 			uint32_t trigger, uint32_t timestamp)
1870 {
1871 	uint16_t num_ch = scan->num_chan;
1872 	uint16_t buf_cons = 0, buf_left = ROAM_CHANNEL_BUF_SIZE;
1873 	uint8_t i;
1874 	char *buf, *buf1, *tmp;
1875 	char time[TIME_STRING_LEN];
1876 
1877 	buf = qdf_mem_malloc(ROAM_CHANNEL_BUF_SIZE);
1878 	if (!buf)
1879 		return;
1880 
1881 	tmp = buf;
1882 	/* For partial scans, print the channel info */
1883 	if (!scan->type) {
1884 		buf_cons = qdf_snprint(tmp, buf_left, "{");
1885 		buf_left -= buf_cons;
1886 		tmp += buf_cons;
1887 
1888 		for (i = 0; i < num_ch; i++) {
1889 			buf_cons = qdf_snprint(tmp, buf_left, "%d ",
1890 					       scan->chan_freq[i]);
1891 			buf_left -= buf_cons;
1892 			tmp += buf_cons;
1893 		}
1894 		buf_cons = qdf_snprint(tmp, buf_left, "}");
1895 		buf_left -= buf_cons;
1896 		tmp += buf_cons;
1897 	}
1898 
1899 	buf1 = qdf_mem_malloc(ROAM_FAILURE_BUF_SIZE);
1900 	if (!buf1) {
1901 		qdf_mem_free(buf);
1902 		return;
1903 	}
1904 
1905 	if (WMI_ROAM_TRIGGER_REASON_LOW_RSSI == trigger ||
1906 	    WMI_ROAM_TRIGGER_REASON_PERIODIC == trigger)
1907 		qdf_snprint(buf1, ROAM_FAILURE_BUF_SIZE,
1908 			    "next_rssi_threshold: %d dBm",
1909 			    scan->next_rssi_threshold);
1910 
1911 	mlme_get_converted_timestamp(timestamp, time);
1912 	wma_nofl_info("%s [ROAM_SCAN]: VDEV[%d] Scan_type: %s %s %s",
1913 		      time, vdev_id, mlme_get_roam_scan_type_str(scan->type),
1914 		      buf1, buf);
1915 	wma_log_roam_scan_candidates(scan->ap, scan->num_ap);
1916 
1917 	qdf_mem_free(buf);
1918 	qdf_mem_free(buf1);
1919 }
1920 
1921 /**
1922  * wma_rso_print_roam_result()  - Print roam result related info
1923  * @res:     Roam result strucure pointer
1924  * @vdev_id: Vdev id
1925  *
1926  * Print roam result and failure reason if roaming failed.
1927  *
1928  * Return: None
1929  */
1930 static void
1931 wma_rso_print_roam_result(struct wmi_roam_result *res,
1932 			  uint8_t vdev_id)
1933 {
1934 	char *buf;
1935 	char time[TIME_STRING_LEN];
1936 
1937 	buf = qdf_mem_malloc(ROAM_FAILURE_BUF_SIZE);
1938 	if (!buf)
1939 		return;
1940 
1941 	if (res->status == 1)
1942 		qdf_snprint(buf, ROAM_FAILURE_BUF_SIZE, "Reason: %s",
1943 			    mlme_get_roam_fail_reason_str(res->fail_reason));
1944 
1945 	mlme_get_converted_timestamp(res->timestamp, time);
1946 	wma_nofl_info("%s [ROAM_RESULT]: VDEV[%d] %s %s",
1947 		      time, vdev_id, mlme_get_roam_status_str(res->status),
1948 		      buf);
1949 
1950 	qdf_mem_free(buf);
1951 }
1952 
1953 /**
1954  * wma_rso_print_11kv_info  - Print neighbor report/BTM related data
1955  * @neigh_rpt: Pointer to the extracted TLV structure
1956  * @vdev_id:   Vdev ID
1957  *
1958  * Print BTM/neighbor report info that is sent by firmware after
1959  * connection/roaming to an AP.
1960  *
1961  * Return: none
1962  */
1963 static void
1964 wma_rso_print_11kv_info(struct wmi_neighbor_report_data *neigh_rpt,
1965 			uint8_t vdev_id)
1966 {
1967 	char time[TIME_STRING_LEN], time1[TIME_STRING_LEN];
1968 	char *buf, *tmp;
1969 	uint8_t type = neigh_rpt->req_type, i;
1970 	uint16_t buf_left = ROAM_CHANNEL_BUF_SIZE, buf_cons;
1971 	uint8_t num_ch = neigh_rpt->num_freq;
1972 
1973 	if (!type)
1974 		return;
1975 
1976 	buf = qdf_mem_malloc(ROAM_CHANNEL_BUF_SIZE);
1977 	if (!buf)
1978 		return;
1979 
1980 	tmp = buf;
1981 	if (num_ch) {
1982 		buf_cons = qdf_snprint(tmp, buf_left, "{ ");
1983 		buf_left -= buf_cons;
1984 		tmp += buf_cons;
1985 
1986 		for (i = 0; i < num_ch; i++) {
1987 			buf_cons = qdf_snprint(tmp, buf_left, "%d ",
1988 					       neigh_rpt->freq[i]);
1989 			buf_left -= buf_cons;
1990 			tmp += buf_cons;
1991 		}
1992 
1993 		buf_cons = qdf_snprint(tmp, buf_left, "}");
1994 		buf_left -= buf_cons;
1995 		tmp += buf_cons;
1996 	}
1997 
1998 	mlme_get_converted_timestamp(neigh_rpt->req_time, time);
1999 	wma_nofl_info("%s [%s] VDEV[%d]", time,
2000 		      (type == 1) ? "BTM_QUERY" : "NEIGH_RPT_REQ", vdev_id);
2001 
2002 	if (neigh_rpt->resp_time) {
2003 		mlme_get_converted_timestamp(neigh_rpt->resp_time, time1);
2004 		wma_nofl_info("%s [%s] VDEV[%d] %s", time1,
2005 			      (type == 1) ? "BTM_REQ" : "NEIGH_RPT_RSP",
2006 			      vdev_id,
2007 			      (num_ch > 0) ? buf : "NO Ch update");
2008 	} else {
2009 		wma_nofl_info("%s No response received from AP",
2010 			      (type == 1) ? "BTM" : "NEIGH_RPT");
2011 	}
2012 	qdf_mem_free(buf);
2013 }
2014 
2015 int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
2016 				 uint32_t len)
2017 {
2018 	tp_wma_handle wma = (tp_wma_handle) handle;
2019 	WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf;
2020 	wmi_roam_stats_event_fixed_param *fixed_param;
2021 	struct mlme_roam_debug_info *roam_info = NULL;
2022 	uint8_t vdev_id, i;
2023 	uint8_t num_tlv = 0, num_chan = 0, num_ap = 0, num_rpt = 0, rem_tlv = 0;
2024 	uint32_t rem_len;
2025 	QDF_STATUS status;
2026 
2027 	param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)event;
2028 	if (!param_buf) {
2029 		wma_err_rl("NULL event received from target");
2030 		goto err;
2031 	}
2032 
2033 	fixed_param = param_buf->fixed_param;
2034 	if (!fixed_param) {
2035 		wma_err_rl(" NULL fixed param");
2036 		goto err;
2037 	}
2038 
2039 	vdev_id = fixed_param->vdev_id;
2040 	if (vdev_id >= wma->max_bssid) {
2041 		wma_err_rl("Invalid vdev_id %d", vdev_id);
2042 		goto err;
2043 	}
2044 
2045 	num_tlv = fixed_param->roam_scan_trigger_count;
2046 	if (num_tlv > MAX_ROAM_SCAN_STATS_TLV) {
2047 		wma_err_rl("Limiting roam triggers to 5");
2048 		num_tlv = MAX_ROAM_SCAN_STATS_TLV;
2049 	}
2050 
2051 	rem_len = WMI_SVC_MSG_MAX_SIZE - sizeof(*fixed_param);
2052 	if (rem_len < num_tlv * sizeof(wmi_roam_trigger_reason)) {
2053 		wma_err_rl("Invalid roam trigger data");
2054 		goto err;
2055 	}
2056 
2057 	rem_len -= num_tlv * sizeof(wmi_roam_trigger_reason);
2058 	if (rem_len < num_tlv * sizeof(wmi_roam_scan_info)) {
2059 		wma_err_rl("Invalid roam scan data");
2060 		goto err;
2061 	}
2062 
2063 	rem_len -= num_tlv * sizeof(wmi_roam_scan_info);
2064 	if (rem_len < num_tlv * sizeof(wmi_roam_result)) {
2065 		wma_err_rl("Invalid roam result data");
2066 		goto err;
2067 	}
2068 
2069 	rem_len -= num_tlv * sizeof(wmi_roam_result);
2070 	if (rem_len < (num_tlv * sizeof(wmi_roam_neighbor_report_info))) {
2071 		wma_err_rl("Invalid roam neighbor report data");
2072 		goto err;
2073 	}
2074 
2075 	rem_len -= num_tlv * sizeof(wmi_roam_neighbor_report_info);
2076 	if (rem_len < (param_buf->num_roam_scan_chan_info *
2077 		       sizeof(wmi_roam_scan_channel_info))) {
2078 		wma_err_rl("Invalid roam chan data num_tlv:%d",
2079 			   param_buf->num_roam_scan_chan_info);
2080 		goto err;
2081 	}
2082 
2083 	rem_len -= param_buf->num_roam_scan_chan_info *
2084 		   sizeof(wmi_roam_scan_channel_info);
2085 
2086 	if (rem_len < (param_buf->num_roam_ap_info *
2087 		       sizeof(wmi_roam_ap_info))) {
2088 		wma_err_rl("Invalid roam ap data num_tlv:%d",
2089 			   param_buf->num_roam_ap_info);
2090 		goto err;
2091 	}
2092 
2093 	rem_len -= param_buf->num_roam_ap_info * sizeof(wmi_roam_ap_info);
2094 	if (rem_len < (param_buf->num_roam_neighbor_report_chan_info *
2095 		       sizeof(wmi_roam_neighbor_report_channel_info))) {
2096 		wma_err_rl("Invalid roam neigb rpt chan data num_tlv:%d",
2097 			   param_buf->num_roam_neighbor_report_chan_info);
2098 		goto err;
2099 	}
2100 
2101 	rem_len -= param_buf->num_roam_neighbor_report_chan_info *
2102 			sizeof(wmi_roam_neighbor_report_channel_info);
2103 	if (rem_len < param_buf->num_roam_btm_response_info *
2104 	    sizeof(wmi_roam_btm_response_info)) {
2105 		wma_err_rl("Invalid btm rsp data");
2106 		goto err;
2107 	}
2108 
2109 	rem_len -= param_buf->num_roam_btm_response_info *
2110 			sizeof(wmi_roam_btm_response_info);
2111 	if (rem_len < param_buf->num_roam_initial_info *
2112 	    sizeof(wmi_roam_initial_info)) {
2113 		wma_err_rl("Invalid Initial roam info");
2114 		goto err;
2115 	}
2116 
2117 	rem_len -= param_buf->num_roam_initial_info *
2118 			sizeof(wmi_roam_initial_info);
2119 	if (rem_len < param_buf->num_roam_msg_info *
2120 	    sizeof(wmi_roam_msg_info)) {
2121 		wma_err_rl("Invalid roam msg info");
2122 		goto err;
2123 	}
2124 
2125 	for (i = 0; i < num_tlv; i++) {
2126 		roam_info = qdf_mem_malloc(sizeof(*roam_info));
2127 		if (!roam_info)
2128 			return -ENOMEM;
2129 
2130 		/*
2131 		 * Roam Trigger id and that specific roam trigger related
2132 		 * details.
2133 		 */
2134 		status = wmi_unified_extract_roam_trigger_stats(
2135 						wma->wmi_handle, event,
2136 						&roam_info->trigger, i);
2137 		if (QDF_IS_STATUS_ERROR(status)) {
2138 			wma_debug_rl("Extract roam trigger stats failed vdev %d at %d iteration",
2139 				     vdev_id, i);
2140 			qdf_mem_free(roam_info);
2141 			return -EINVAL;
2142 		}
2143 
2144 		if (roam_info->trigger.present) {
2145 			wma_rso_print_trigger_info(&roam_info->trigger,
2146 						   vdev_id);
2147 			wlan_cm_update_roam_states(wma->psoc, vdev_id,
2148 					roam_info->trigger.trigger_reason,
2149 					ROAM_TRIGGER_REASON);
2150 		}
2151 
2152 		/* Roam scan related details - Scan channel, scan type .. */
2153 		status = wmi_unified_extract_roam_scan_stats(
2154 							wma->wmi_handle, event,
2155 							&roam_info->scan, i,
2156 							num_chan, num_ap);
2157 		if (QDF_IS_STATUS_ERROR(status)) {
2158 			wma_debug_rl("Roam scan stats extract failed vdev %d at %d iteration",
2159 				     vdev_id, i);
2160 			qdf_mem_free(roam_info);
2161 			return -EINVAL;
2162 		}
2163 		num_chan += roam_info->scan.num_chan;
2164 		num_ap += roam_info->scan.num_ap;
2165 
2166 		if (roam_info->scan.present && roam_info->trigger.present)
2167 			wma_rso_print_scan_info(&roam_info->scan, vdev_id,
2168 					roam_info->trigger.trigger_reason,
2169 					roam_info->trigger.timestamp);
2170 
2171 		/* Roam result - Success/Failure status, failure reason */
2172 		status = wmi_unified_extract_roam_result_stats(
2173 							wma->wmi_handle, event,
2174 							&roam_info->result, i);
2175 		if (QDF_IS_STATUS_ERROR(status)) {
2176 			wma_debug_rl("Roam result stats extract failed vdev %d at %d iteration",
2177 				     vdev_id, i);
2178 			qdf_mem_free(roam_info);
2179 			return -EINVAL;
2180 		}
2181 		if (roam_info->result.present) {
2182 			wma_rso_print_roam_result(&roam_info->result, vdev_id);
2183 			wlan_cm_update_roam_states(wma->psoc, vdev_id,
2184 						roam_info->result.fail_reason,
2185 						ROAM_FAIL_REASON);
2186 		}
2187 		/* BTM resp info */
2188 		status = wlan_cm_roam_extract_btm_response(wma->wmi_handle,
2189 							   event,
2190 							   &roam_info->btm_rsp,
2191 							   i);
2192 		if (QDF_IS_STATUS_ERROR(status)) {
2193 			wma_debug_rl("Roam btm rsp stats extract fail vdev %d at %d iteration",
2194 				     vdev_id, i);
2195 			qdf_mem_free(roam_info);
2196 			return -EINVAL;
2197 		}
2198 
2199 		/*
2200 		 * Print BTM resp TLV info (wmi_roam_btm_response_info) only
2201 		 * when trigger reason is BTM or WTC_BTM. As for other roam
2202 		 * triggers this TLV contains zeros, so host should not print.
2203 		 */
2204 		if ((roam_info->btm_rsp.present) &&
2205 		    (roam_info->trigger.present &&
2206 		    (roam_info->trigger.trigger_reason ==
2207 		     WMI_ROAM_TRIGGER_REASON_WTC_BTM ||
2208 		     roam_info->trigger.trigger_reason ==
2209 		     WMI_ROAM_TRIGGER_REASON_BTM)))
2210 			wma_rso_print_btm_rsp_info(&roam_info->btm_rsp,
2211 						   vdev_id);
2212 
2213 		/* Initial Roam info */
2214 		status = wlan_cm_roam_extract_roam_initial_info(
2215 				wma->wmi_handle, event,
2216 				&roam_info->roam_init_info, i);
2217 		if (QDF_IS_STATUS_ERROR(status)) {
2218 			wma_debug_rl("Initial roam stats extract fail vdev %d at %d iteration",
2219 				     vdev_id, i);
2220 			qdf_mem_free(roam_info);
2221 			return -EINVAL;
2222 		}
2223 		if (roam_info->roam_init_info.present)
2224 			wma_rso_print_roam_initial_info(
2225 					&roam_info->roam_init_info, vdev_id);
2226 
2227 		/* Roam message info */
2228 		status = wlan_cm_roam_extract_roam_msg_info(
2229 				wma->wmi_handle, event,
2230 				&roam_info->roam_msg_info, i);
2231 		if (QDF_IS_STATUS_ERROR(status)) {
2232 			wma_err("roam msg stats extract fail vdev %d",
2233 				vdev_id);
2234 			qdf_mem_free(roam_info);
2235 			return -EINVAL;
2236 		}
2237 		if (roam_info->roam_msg_info.present) {
2238 			rem_tlv++;
2239 			wma_rso_print_roam_msg_info(
2240 					&roam_info->roam_msg_info, vdev_id);
2241 
2242 		/* BTM req/resp or Neighbor report/response info */
2243 		status = wmi_unified_extract_roam_11kv_stats(
2244 				wma->wmi_handle, event,
2245 				&roam_info->data_11kv, i, num_rpt);
2246 		if (QDF_IS_STATUS_ERROR(status)) {
2247 			wma_debug_rl("Roam 11kv stats extract failed vdev %d at %d iteration",
2248 				     vdev_id, i);
2249 			qdf_mem_free(roam_info);
2250 			return -EINVAL;
2251 		}
2252 		num_rpt += roam_info->data_11kv.num_freq;
2253 		if (roam_info->data_11kv.present)
2254 			wma_rso_print_11kv_info(&roam_info->data_11kv, vdev_id);
2255 		}
2256 
2257 		qdf_mem_free(roam_info);
2258 	}
2259 
2260 	if (!num_tlv) {
2261 		roam_info = qdf_mem_malloc(sizeof(*roam_info));
2262 		if (!roam_info)
2263 			return -ENOMEM;
2264 
2265 		status = wmi_unified_extract_roam_11kv_stats(
2266 					wma->wmi_handle, event,
2267 					&roam_info->data_11kv, 0, 0);
2268 		if (QDF_IS_STATUS_ERROR(status)) {
2269 			wma_err("Roam 11kv stats extract failed vdev %d",
2270 				vdev_id);
2271 			qdf_mem_free(roam_info);
2272 			return -EINVAL;
2273 		}
2274 
2275 		if (roam_info->data_11kv.present)
2276 			wma_rso_print_11kv_info(&roam_info->data_11kv, vdev_id);
2277 
2278 		status = wmi_unified_extract_roam_trigger_stats(
2279 						wma->wmi_handle, event,
2280 						&roam_info->trigger, 0);
2281 		if (QDF_IS_STATUS_ERROR(status)) {
2282 			wma_debug_rl("Extract roam trigger stats failed vdev %d",
2283 				     vdev_id);
2284 			qdf_mem_free(roam_info);
2285 			return -EINVAL;
2286 		}
2287 
2288 		if (roam_info->trigger.present)
2289 			wma_rso_print_trigger_info(&roam_info->trigger,
2290 						   vdev_id);
2291 
2292 		status = wmi_unified_extract_roam_scan_stats(wma->wmi_handle,
2293 							     event,
2294 							     &roam_info->scan,
2295 							     0, 0, 0);
2296 		if (QDF_IS_STATUS_ERROR(status)) {
2297 			wma_debug_rl("Roam scan stats extract failed vdev %d",
2298 				     vdev_id);
2299 			qdf_mem_free(roam_info);
2300 			return -EINVAL;
2301 		}
2302 
2303 		if (roam_info->scan.present && roam_info->trigger.present)
2304 			wma_rso_print_scan_info(&roam_info->scan, vdev_id,
2305 					roam_info->trigger.trigger_reason,
2306 					roam_info->trigger.timestamp);
2307 
2308 		status = wlan_cm_roam_extract_btm_response(wma->wmi_handle,
2309 							   event,
2310 							   &roam_info->btm_rsp,
2311 							   0);
2312 		if (QDF_IS_STATUS_ERROR(status)) {
2313 			wma_debug_rl("Roam btm rsp stats extract fail vdev %d",
2314 				     vdev_id);
2315 			qdf_mem_free(roam_info);
2316 			return -EINVAL;
2317 		}
2318 
2319 		if (roam_info->btm_rsp.present)
2320 			wma_rso_print_btm_rsp_info(&roam_info->btm_rsp,
2321 						   vdev_id);
2322 
2323 		qdf_mem_free(roam_info);
2324 	}
2325 
2326 	if (param_buf->roam_msg_info && param_buf->num_roam_msg_info &&
2327 	    param_buf->num_roam_msg_info - rem_tlv) {
2328 		for (i = 0; i < (param_buf->num_roam_msg_info - rem_tlv); i++) {
2329 			roam_info = qdf_mem_malloc(sizeof(*roam_info));
2330 			if (!roam_info)
2331 				return -ENOMEM;
2332 			status = wlan_cm_roam_extract_roam_msg_info(
2333 					wma->wmi_handle, event,
2334 					&roam_info->roam_msg_info, rem_tlv + i);
2335 			if (QDF_IS_STATUS_ERROR(status)) {
2336 				wma_err("roam msg stats extract fail vdev %d",
2337 					vdev_id);
2338 				qdf_mem_free(roam_info);
2339 				return -EINVAL;
2340 			}
2341 
2342 			if (roam_info->roam_msg_info.present)
2343 				wma_rso_print_roam_msg_info(
2344 						&roam_info->roam_msg_info,
2345 						vdev_id);
2346 			qdf_mem_free(roam_info);
2347 		}
2348 	}
2349 
2350 	return 0;
2351 
2352 err:
2353 	return -EINVAL;
2354 }
2355 #endif
2356 
2357 /**
2358  * wma_set_ric_req() - set ric request element
2359  * @wma: wma handle
2360  * @msg: message
2361  * @is_add_ts: is addts required
2362  *
2363  * This function sets ric request element for 11r roaming.
2364  *
2365  * Return: none
2366  */
2367 void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts)
2368 {
2369 	if (!wma) {
2370 		wma_err("wma handle is NULL");
2371 		return;
2372 	}
2373 
2374 	wmi_unified_set_ric_req_cmd(wma->wmi_handle, msg, is_add_ts);
2375 }
2376 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
2377 
2378 #ifdef FEATURE_RSSI_MONITOR
2379 QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma,
2380 				   struct rssi_monitor_param *req)
2381 {
2382 	if (!wma) {
2383 		wma_err("wma handle is NULL");
2384 		return QDF_STATUS_E_INVAL;
2385 	}
2386 
2387 	return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, req);
2388 }
2389 
2390 /**
2391  * wma_rssi_breached_event_handler() - rssi breached event handler
2392  * @handle: wma handle
2393  * @cmd_param_info: event handler data
2394  * @len: length of @cmd_param_info
2395  *
2396  * Return: 0 on success; error number otherwise
2397  */
2398 int wma_rssi_breached_event_handler(void *handle,
2399 				u_int8_t  *cmd_param_info, u_int32_t len)
2400 {
2401 	WMI_RSSI_BREACH_EVENTID_param_tlvs *param_buf;
2402 	wmi_rssi_breach_event_fixed_param  *event;
2403 	struct rssi_breach_event  rssi;
2404 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
2405 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
2406 
2407 	if (!mac || !wma) {
2408 		wma_err("Invalid mac/wma context");
2409 		return -EINVAL;
2410 	}
2411 	if (!mac->sme.rssi_threshold_breached_cb) {
2412 		wma_err("Callback not registered");
2413 		return -EINVAL;
2414 	}
2415 	param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info;
2416 	if (!param_buf) {
2417 		wma_err("Invalid rssi breached event");
2418 		return -EINVAL;
2419 	}
2420 	event = param_buf->fixed_param;
2421 
2422 	rssi.request_id = event->request_id;
2423 	rssi.session_id = event->vdev_id;
2424 	if (wmi_service_enabled(wma->wmi_handle,
2425 				wmi_service_hw_db2dbm_support))
2426 		rssi.curr_rssi = event->rssi;
2427 	else
2428 		rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM;
2429 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes);
2430 
2431 	wma_debug("req_id: %u vdev_id: %d curr_rssi: %d",
2432 		 rssi.request_id, rssi.session_id, rssi.curr_rssi);
2433 	wma_debug("curr_bssid: "QDF_MAC_ADDR_FMT,
2434 		  QDF_MAC_ADDR_REF(rssi.curr_bssid.bytes));
2435 
2436 	mac->sme.rssi_threshold_breached_cb(mac->hdd_handle, &rssi);
2437 	wma_debug("Invoke HDD rssi breached callback");
2438 	return 0;
2439 }
2440 #endif /* FEATURE_RSSI_MONITOR */
2441 
2442 #ifndef FEATURE_CM_ENABLE
2443 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
2444 /**
2445  * wma_roam_ho_fail_handler() - LFR3.0 roam hand off failed handler
2446  * @wma: wma handle
2447  * @vdev_id: vdev id
2448  *
2449  * Return: none
2450  */
2451 static void
2452 wma_roam_ho_fail_handler(tp_wma_handle wma, uint32_t vdev_id,
2453 			 struct qdf_mac_addr bssid)
2454 {
2455 	struct handoff_failure_ind *ho_failure_ind;
2456 	struct scheduler_msg sme_msg = { 0 };
2457 	QDF_STATUS qdf_status;
2458 
2459 	ho_failure_ind = qdf_mem_malloc(sizeof(*ho_failure_ind));
2460 	if (!ho_failure_ind)
2461 		return;
2462 
2463 	ho_failure_ind->vdev_id = vdev_id;
2464 	ho_failure_ind->bssid = bssid;
2465 
2466 	sme_msg.type = eWNI_SME_HO_FAIL_IND;
2467 	sme_msg.bodyptr = ho_failure_ind;
2468 	sme_msg.bodyval = 0;
2469 
2470 	qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA,
2471 					    QDF_MODULE_ID_SME,
2472 					    QDF_MODULE_ID_SME, &sme_msg);
2473 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
2474 		wma_err("Fail to post eWNI_SME_HO_FAIL_IND msg to SME");
2475 		qdf_mem_free(ho_failure_ind);
2476 		return;
2477 	}
2478 }
2479 
2480 /**
2481  * wma_process_roam_synch_complete() - roam synch complete command to fw.
2482  * @handle: wma handle
2483  * @synchcnf: offload synch confirmation params
2484  *
2485  * This function sends roam synch complete event to fw.
2486  *
2487  * Return: none
2488  */
2489 void wma_process_roam_synch_complete(WMA_HANDLE handle, uint8_t vdev_id)
2490 {
2491 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
2492 	struct wmi_unified *wmi_handle;
2493 
2494 	if (wma_validate_handle(wma_handle))
2495 		return;
2496 
2497 	wmi_handle = wma_handle->wmi_handle;
2498 	if (wmi_validate_handle(wmi_handle))
2499 		return;
2500 
2501 	if (!wma_is_vdev_valid(vdev_id))
2502 		return;
2503 
2504 	if (wmi_unified_roam_synch_complete_cmd(wmi_handle, vdev_id))
2505 		return;
2506 
2507 	DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD,
2508 		vdev_id, QDF_TRACE_DEFAULT_PDEV_ID,
2509 		QDF_PROTO_TYPE_EVENT, QDF_ROAM_COMPLETE));
2510 
2511 	wma_info("LFR3: vdev[%d] Sent ROAM_SYNCH_COMPLETE", vdev_id);
2512 	wlan_roam_debug_log(vdev_id, DEBUG_ROAM_SYNCH_CNF,
2513 			    DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0);
2514 
2515 }
2516 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
2517 #endif /* FEATURE_CM_ENABLE */
2518 
2519 QDF_STATUS wma_pre_chan_switch_setup(uint8_t vdev_id)
2520 {
2521 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2522 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
2523 	struct wma_txrx_node *intr;
2524 	uint16_t beacon_interval_ori;
2525 	bool restart;
2526 	uint16_t reduced_beacon_interval;
2527 	struct vdev_mlme_obj *mlme_obj;
2528 	struct wlan_objmgr_vdev *vdev;
2529 
2530 	if (!wma) {
2531 		pe_err("wma is NULL");
2532 		return QDF_STATUS_E_FAILURE;
2533 	}
2534 	intr = &wma->interfaces[vdev_id];
2535 	if (!intr) {
2536 		pe_err("wma txrx node is NULL");
2537 		return QDF_STATUS_E_FAILURE;
2538 	}
2539 	vdev = intr->vdev;
2540 	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev);
2541 	if (!mlme_obj) {
2542 		pe_err("vdev component object is NULL");
2543 		return QDF_STATUS_E_FAILURE;
2544 	}
2545 
2546 	restart =
2547 		wma_get_channel_switch_in_progress(intr);
2548 	if (restart && intr->beacon_filter_enabled)
2549 		wma_remove_beacon_filter(wma, &intr->beacon_filter);
2550 
2551 	reduced_beacon_interval =
2552 		wma->mac_context->sap.SapDfsInfo.reduced_beacon_interval;
2553 	if (wma_is_vdev_in_ap_mode(wma, vdev_id) && reduced_beacon_interval) {
2554 
2555 
2556 		/* Reduce the beacon interval just before the channel switch.
2557 		 * This would help in reducing the downtime on the STA side
2558 		 * (which is waiting for beacons from the AP to resume back
2559 		 * transmission). Switch back the beacon_interval to its
2560 		 * original value after the channel switch based on the
2561 		 * timeout. This would ensure there are atleast some beacons
2562 		 * sent with increased frequency.
2563 		 */
2564 
2565 		wma_debug("Changing beacon interval to %d",
2566 			 reduced_beacon_interval);
2567 
2568 		/* Add a timer to reset the beacon interval back*/
2569 		beacon_interval_ori = mlme_obj->proto.generic.beacon_interval;
2570 		mlme_obj->proto.generic.beacon_interval =
2571 			reduced_beacon_interval;
2572 		if (wma_fill_beacon_interval_reset_req(wma,
2573 			vdev_id,
2574 			beacon_interval_ori,
2575 			RESET_BEACON_INTERVAL_TIMEOUT)) {
2576 
2577 			wma_debug("Failed to fill beacon interval reset req");
2578 		}
2579 	}
2580 
2581 	status = wma_vdev_pre_start(vdev_id, restart);
2582 
2583 	return status;
2584 }
2585 
2586 QDF_STATUS wma_post_chan_switch_setup(uint8_t vdev_id)
2587 {
2588 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
2589 	struct wma_txrx_node *intr;
2590 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2591 	struct wlan_channel *des_chan;
2592 	cdp_config_param_type val;
2593 
2594 	if (!wma) {
2595 		pe_err("wma is NULL");
2596 		return QDF_STATUS_E_FAILURE;
2597 	}
2598 	intr = &wma->interfaces[vdev_id];
2599 	if (!intr) {
2600 		pe_err("wma txrx node is NULL");
2601 		return QDF_STATUS_E_FAILURE;
2602 	}
2603 	/*
2604 	 * Record monitor mode channel here in case HW
2605 	 * indicate RX PPDU TLV with invalid channel number.
2606 	 */
2607 	if (intr->type == WMI_VDEV_TYPE_MONITOR) {
2608 		des_chan = intr->vdev->vdev_mlme.des_chan;
2609 		val.cdp_pdev_param_monitor_chan = des_chan->ch_ieee;
2610 		cdp_txrx_set_pdev_param(soc,
2611 					wlan_objmgr_pdev_get_pdev_id(wma->pdev),
2612 					CDP_MONITOR_CHANNEL, val);
2613 		val.cdp_pdev_param_mon_freq = des_chan->ch_freq;
2614 		cdp_txrx_set_pdev_param(soc,
2615 					wlan_objmgr_pdev_get_pdev_id(wma->pdev),
2616 					CDP_MONITOR_FREQUENCY, val);
2617 	}
2618 	return QDF_STATUS_SUCCESS;
2619 }
2620 
2621 #ifdef FEATURE_WLAN_ESE
2622 /**
2623  * wma_plm_start() - plm start request
2624  * @wma: wma handle
2625  * @params: plm request parameters
2626  *
2627  * This function request FW to start PLM.
2628  *
2629  * Return: QDF status
2630  */
2631 static QDF_STATUS wma_plm_start(tp_wma_handle wma,
2632 				struct plm_req_params *params)
2633 {
2634 	QDF_STATUS status;
2635 
2636 	wma_debug("PLM Start");
2637 
2638 	status = wmi_unified_plm_start_cmd(wma->wmi_handle, params);
2639 	if (QDF_IS_STATUS_ERROR(status))
2640 		return status;
2641 
2642 	wma->interfaces[params->vdev_id].plm_in_progress = true;
2643 
2644 	wma_debug("Plm start request sent successfully for vdev %d",
2645 		 params->vdev_id);
2646 
2647 	return status;
2648 }
2649 
2650 /**
2651  * wma_plm_stop() - plm stop request
2652  * @wma: wma handle
2653  * @params: plm request parameters
2654  *
2655  * This function request FW to stop PLM.
2656  *
2657  * Return: QDF status
2658  */
2659 static QDF_STATUS wma_plm_stop(tp_wma_handle wma,
2660 			       struct plm_req_params *params)
2661 {
2662 	QDF_STATUS status;
2663 
2664 	if (!wma->interfaces[params->vdev_id].plm_in_progress) {
2665 		wma_err("No active plm req found, skip plm stop req");
2666 		return QDF_STATUS_E_FAILURE;
2667 	}
2668 
2669 	wma_debug("PLM Stop");
2670 
2671 	status = wmi_unified_plm_stop_cmd(wma->wmi_handle, params);
2672 	if (QDF_IS_STATUS_ERROR(status))
2673 		return status;
2674 
2675 	wma->interfaces[params->vdev_id].plm_in_progress = false;
2676 
2677 	wma_debug("Plm stop request sent successfully for vdev %d",
2678 		 params->vdev_id);
2679 
2680 	return status;
2681 }
2682 
2683 /**
2684  * wma_config_plm() - config PLM
2685  * @wma: wma handle
2686  * @params: plm request parameters
2687  *
2688  * Return: none
2689  */
2690 void wma_config_plm(tp_wma_handle wma, struct plm_req_params *params)
2691 {
2692 	QDF_STATUS ret;
2693 
2694 	if (!params || !wma)
2695 		return;
2696 
2697 	if (params->enable)
2698 		ret = wma_plm_start(wma, params);
2699 	else
2700 		ret = wma_plm_stop(wma, params);
2701 
2702 	if (ret)
2703 		wma_err("PLM %s failed %d",
2704 			params->enable ? "start" : "stop", ret);
2705 }
2706 #endif
2707 
2708 #ifdef FEATURE_WLAN_EXTSCAN
2709 /**
2710  * wma_extscan_wow_event_callback() - extscan wow event callback
2711  * @handle: WMA handle
2712  * @event: event buffer
2713  * @len: length of @event buffer
2714  *
2715  * In wow case, the wow event is followed by the payload of the event
2716  * which generated the wow event.
2717  * payload is 4 bytes of length followed by event buffer. the first 4 bytes
2718  * of event buffer is common tlv header, which is a combination
2719  * of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to
2720  * identify the event which triggered wow event.
2721  * Payload is extracted and converted into generic tlv structure before
2722  * being passed to this function.
2723  *
2724  * @Return: Errno
2725  */
2726 int wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len)
2727 {
2728 	uint32_t tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(event));
2729 
2730 	switch (tag) {
2731 	case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param:
2732 		return wma_extscan_start_stop_event_handler(handle, event, len);
2733 
2734 	case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param:
2735 		return wma_extscan_operations_event_handler(handle, event, len);
2736 
2737 	case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param:
2738 		return wma_extscan_table_usage_event_handler(handle, event,
2739 							     len);
2740 
2741 	case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param:
2742 		return wma_extscan_cached_results_event_handler(handle, event,
2743 								len);
2744 
2745 	case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param:
2746 		return wma_extscan_change_results_event_handler(handle, event,
2747 								len);
2748 
2749 	case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param:
2750 		return wma_extscan_hotlist_match_event_handler(handle,	event,
2751 							       len);
2752 
2753 	case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param:
2754 		return wma_extscan_capabilities_event_handler(handle, event,
2755 							      len);
2756 
2757 	default:
2758 		wma_err("Unknown tag: %d", tag);
2759 		return 0;
2760 	}
2761 }
2762 
2763 /**
2764  * wma_register_extscan_event_handler() - register extscan event handler
2765  * @wma_handle: wma handle
2766  *
2767  * This function register extscan related event handlers.
2768  *
2769  * Return: none
2770  */
2771 void wma_register_extscan_event_handler(tp_wma_handle wma_handle)
2772 {
2773 	if (wma_validate_handle(wma_handle))
2774 		return;
2775 
2776 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
2777 					   wmi_extscan_start_stop_event_id,
2778 					   wma_extscan_start_stop_event_handler,
2779 					   WMA_RX_SERIALIZER_CTX);
2780 
2781 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
2782 					wmi_extscan_capabilities_event_id,
2783 					wma_extscan_capabilities_event_handler,
2784 					WMA_RX_SERIALIZER_CTX);
2785 
2786 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
2787 				wmi_extscan_hotlist_match_event_id,
2788 				wma_extscan_hotlist_match_event_handler,
2789 				WMA_RX_SERIALIZER_CTX);
2790 
2791 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
2792 				wmi_extscan_wlan_change_results_event_id,
2793 				wma_extscan_change_results_event_handler,
2794 				WMA_RX_SERIALIZER_CTX);
2795 
2796 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
2797 				wmi_extscan_operation_event_id,
2798 				wma_extscan_operations_event_handler,
2799 				WMA_RX_SERIALIZER_CTX);
2800 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
2801 				wmi_extscan_table_usage_event_id,
2802 				wma_extscan_table_usage_event_handler,
2803 				WMA_RX_SERIALIZER_CTX);
2804 
2805 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
2806 				wmi_extscan_cached_results_event_id,
2807 				wma_extscan_cached_results_event_handler,
2808 				WMA_RX_SERIALIZER_CTX);
2809 
2810 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
2811 			wmi_passpoint_match_event_id,
2812 			wma_passpoint_match_event_handler,
2813 			WMA_RX_SERIALIZER_CTX);
2814 }
2815 
2816 /**
2817  * wma_extscan_start_stop_event_handler() -  extscan start/stop event handler
2818  * @handle: wma handle
2819  * @cmd_param_info: event buffer
2820  * @len: data length
2821  *
2822  * This function handles different extscan related commands
2823  * like start/stop/get results etc and indicate to upper layers.
2824  *
2825  * Return: 0 for success or error code.
2826  */
2827 int wma_extscan_start_stop_event_handler(void *handle,
2828 					 uint8_t *cmd_param_info,
2829 					 uint32_t len)
2830 {
2831 	WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *param_buf;
2832 	wmi_extscan_start_stop_event_fixed_param *event;
2833 	struct sir_extscan_generic_response   *extscan_ind;
2834 	uint16_t event_type;
2835 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
2836 
2837 	if (!mac)
2838 		return -EINVAL;
2839 
2840 	if (!mac->sme.ext_scan_ind_cb) {
2841 		wma_err("Callback not registered");
2842 		return -EINVAL;
2843 	}
2844 	param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *)
2845 		    cmd_param_info;
2846 	if (!param_buf) {
2847 		wma_err("Invalid extscan event");
2848 		return -EINVAL;
2849 	}
2850 	event = param_buf->fixed_param;
2851 	extscan_ind = qdf_mem_malloc(sizeof(*extscan_ind));
2852 	if (!extscan_ind)
2853 		return -ENOMEM;
2854 
2855 	switch (event->command) {
2856 	case WMI_EXTSCAN_START_CMDID:
2857 		event_type = eSIR_EXTSCAN_START_RSP;
2858 		extscan_ind->status = event->status;
2859 		extscan_ind->request_id = event->request_id;
2860 		break;
2861 	case WMI_EXTSCAN_STOP_CMDID:
2862 		event_type = eSIR_EXTSCAN_STOP_RSP;
2863 		extscan_ind->status = event->status;
2864 		extscan_ind->request_id = event->request_id;
2865 		break;
2866 	case WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID:
2867 		extscan_ind->status = event->status;
2868 		extscan_ind->request_id = event->request_id;
2869 		if (event->mode == WMI_EXTSCAN_MODE_STOP)
2870 			event_type =
2871 				eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP;
2872 		else
2873 			event_type =
2874 				eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP;
2875 		break;
2876 	case WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID:
2877 		extscan_ind->status = event->status;
2878 		extscan_ind->request_id = event->request_id;
2879 		if (event->mode == WMI_EXTSCAN_MODE_STOP)
2880 			event_type = eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP;
2881 		else
2882 			event_type = eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP;
2883 		break;
2884 	case WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID:
2885 		extscan_ind->status = event->status;
2886 		extscan_ind->request_id = event->request_id;
2887 		event_type = eSIR_EXTSCAN_CACHED_RESULTS_RSP;
2888 		break;
2889 	case WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID:
2890 		extscan_ind->status = event->status;
2891 		extscan_ind->request_id = event->request_id;
2892 		if (event->mode == WMI_EXTSCAN_MODE_STOP)
2893 			event_type =
2894 				eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP;
2895 		else
2896 			event_type =
2897 				eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP;
2898 		break;
2899 	default:
2900 		wma_err("Unknown event(%d) from target", event->status);
2901 		qdf_mem_free(extscan_ind);
2902 		return -EINVAL;
2903 	}
2904 	mac->sme.ext_scan_ind_cb(mac->hdd_handle, event_type, extscan_ind);
2905 	wma_debug("sending event to umac for requestid %u with status %d",
2906 		 extscan_ind->request_id, extscan_ind->status);
2907 	qdf_mem_free(extscan_ind);
2908 	return 0;
2909 }
2910 
2911 /**
2912  * wma_extscan_operations_event_handler() - extscan operation event handler
2913  * @handle: wma handle
2914  * @cmd_param_info: event buffer
2915  * @len: length
2916  *
2917  * This function handles different operations related event and indicate
2918  * upper layers with appropriate callback.
2919  *
2920  * Return: 0 for success or error code.
2921  */
2922 int wma_extscan_operations_event_handler(void *handle,
2923 					 uint8_t *cmd_param_info,
2924 					 uint32_t len)
2925 {
2926 	tp_wma_handle wma = (tp_wma_handle) handle;
2927 	WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *param_buf;
2928 	wmi_extscan_operation_event_fixed_param *oprn_event;
2929 	tSirExtScanOnScanEventIndParams *oprn_ind;
2930 	uint32_t cnt;
2931 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
2932 
2933 	if (!mac)
2934 		return -EINVAL;
2935 
2936 	if (!mac->sme.ext_scan_ind_cb) {
2937 		wma_err("Callback not registered");
2938 		return -EINVAL;
2939 	}
2940 	param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *)
2941 		    cmd_param_info;
2942 	if (!param_buf) {
2943 		wma_err("Invalid scan operation event");
2944 		return -EINVAL;
2945 	}
2946 	oprn_event = param_buf->fixed_param;
2947 	oprn_ind = qdf_mem_malloc(sizeof(*oprn_ind));
2948 	if (!oprn_ind)
2949 		return -ENOMEM;
2950 
2951 	oprn_ind->requestId = oprn_event->request_id;
2952 
2953 	switch (oprn_event->event) {
2954 	case WMI_EXTSCAN_BUCKET_COMPLETED_EVENT:
2955 		oprn_ind->status = 0;
2956 		goto exit_handler;
2957 	case WMI_EXTSCAN_CYCLE_STARTED_EVENT:
2958 		wma_debug("received WMI_EXTSCAN_CYCLE_STARTED_EVENT");
2959 
2960 		if (oprn_event->num_buckets > param_buf->num_bucket_id) {
2961 			wma_err("FW mesg num_buk %d more than TLV hdr %d",
2962 				 oprn_event->num_buckets,
2963 				 param_buf->num_bucket_id);
2964 			qdf_mem_free(oprn_ind);
2965 			return -EINVAL;
2966 		}
2967 
2968 		cds_host_diag_log_work(&wma->extscan_wake_lock,
2969 				       WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION,
2970 				       WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN);
2971 		qdf_wake_lock_timeout_acquire(&wma->extscan_wake_lock,
2972 				      WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION);
2973 		oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_STARTED_EVENT;
2974 		oprn_ind->status = 0;
2975 		oprn_ind->buckets_scanned = 0;
2976 		for (cnt = 0; cnt < oprn_event->num_buckets; cnt++)
2977 			oprn_ind->buckets_scanned |=
2978 				(1 << param_buf->bucket_id[cnt]);
2979 		wma_debug("num_buckets %u request_id %u buckets_scanned %u",
2980 			oprn_event->num_buckets, oprn_ind->requestId,
2981 			oprn_ind->buckets_scanned);
2982 		break;
2983 	case WMI_EXTSCAN_CYCLE_COMPLETED_EVENT:
2984 		wma_debug("received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT");
2985 		qdf_wake_lock_release(&wma->extscan_wake_lock,
2986 				      WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN);
2987 		oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT;
2988 		oprn_ind->status = 0;
2989 		/* Set bucket scanned mask to zero on cycle complete */
2990 		oprn_ind->buckets_scanned = 0;
2991 		break;
2992 	case WMI_EXTSCAN_BUCKET_STARTED_EVENT:
2993 		wma_debug("received WMI_EXTSCAN_BUCKET_STARTED_EVENT");
2994 		oprn_ind->scanEventType = WIFI_EXTSCAN_BUCKET_STARTED_EVENT;
2995 		oprn_ind->status = 0;
2996 		goto exit_handler;
2997 	case WMI_EXTSCAN_THRESHOLD_NUM_SCANS:
2998 		wma_debug("received WMI_EXTSCAN_THRESHOLD_NUM_SCANS");
2999 		oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_NUM_SCANS;
3000 		oprn_ind->status = 0;
3001 		break;
3002 	case WMI_EXTSCAN_THRESHOLD_PERCENT:
3003 		wma_debug("received WMI_EXTSCAN_THRESHOLD_PERCENT");
3004 		oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_PERCENT;
3005 		oprn_ind->status = 0;
3006 		break;
3007 	default:
3008 		wma_err("Unknown event(%d) from target", oprn_event->event);
3009 		qdf_mem_free(oprn_ind);
3010 		return -EINVAL;
3011 	}
3012 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
3013 				eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, oprn_ind);
3014 	wma_debug("sending scan progress event to hdd");
3015 exit_handler:
3016 	qdf_mem_free(oprn_ind);
3017 	return 0;
3018 }
3019 
3020 /**
3021  * wma_extscan_table_usage_event_handler() - extscan table usage event handler
3022  * @handle: wma handle
3023  * @cmd_param_info: event buffer
3024  * @len: length
3025  *
3026  * This function handles table usage related event and indicate
3027  * upper layers with appropriate callback.
3028  *
3029  * Return: 0 for success or error code.
3030  */
3031 int wma_extscan_table_usage_event_handler(void *handle,
3032 					  uint8_t *cmd_param_info,
3033 					  uint32_t len)
3034 {
3035 	WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *param_buf;
3036 	wmi_extscan_table_usage_event_fixed_param *event;
3037 	tSirExtScanResultsAvailableIndParams *tbl_usg_ind;
3038 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
3039 
3040 	if (!mac)
3041 		return -EINVAL;
3042 
3043 	if (!mac->sme.ext_scan_ind_cb) {
3044 		wma_err("Callback not registered");
3045 		return -EINVAL;
3046 	}
3047 	param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *)
3048 		    cmd_param_info;
3049 	if (!param_buf) {
3050 		wma_err("Invalid table usage event");
3051 		return -EINVAL;
3052 	}
3053 	event = param_buf->fixed_param;
3054 	tbl_usg_ind = qdf_mem_malloc(sizeof(*tbl_usg_ind));
3055 	if (!tbl_usg_ind)
3056 		return -ENOMEM;
3057 
3058 	tbl_usg_ind->requestId = event->request_id;
3059 	tbl_usg_ind->numResultsAvailable = event->entries_in_use;
3060 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
3061 				eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND,
3062 				tbl_usg_ind);
3063 	wma_debug("sending scan_res available event to hdd");
3064 	qdf_mem_free(tbl_usg_ind);
3065 	return 0;
3066 }
3067 
3068 /**
3069  * wma_extscan_capabilities_event_handler() - extscan capabilities event handler
3070  * @handle: wma handle
3071  * @cmd_param_info: event buffer
3072  * @len: length
3073  *
3074  * This function handles capabilities event and indicate
3075  * upper layers with registered callback.
3076  *
3077  * Return: 0 for success or error code.
3078  */
3079 int wma_extscan_capabilities_event_handler(void *handle,
3080 					   uint8_t *cmd_param_info,
3081 					   uint32_t len)
3082 {
3083 	WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *param_buf;
3084 	wmi_extscan_capabilities_event_fixed_param *event;
3085 	wmi_extscan_cache_capabilities *src_cache;
3086 	wmi_extscan_hotlist_monitor_capabilities *src_hotlist;
3087 	wmi_extscan_wlan_change_monitor_capabilities *src_change;
3088 	struct ext_scan_capabilities_response  *dest_capab;
3089 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
3090 
3091 	if (!mac)
3092 		return -EINVAL;
3093 
3094 	if (!mac->sme.ext_scan_ind_cb) {
3095 		wma_err("Callback not registered");
3096 		return -EINVAL;
3097 	}
3098 	param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *)
3099 		    cmd_param_info;
3100 	if (!param_buf) {
3101 		wma_err("Invalid capabilities event");
3102 		return -EINVAL;
3103 	}
3104 	event = param_buf->fixed_param;
3105 	src_cache = param_buf->extscan_cache_capabilities;
3106 	src_hotlist = param_buf->hotlist_capabilities;
3107 	src_change = param_buf->wlan_change_capabilities;
3108 
3109 	if (!src_cache || !src_hotlist || !src_change) {
3110 		wma_err("Invalid capabilities list");
3111 		return -EINVAL;
3112 	}
3113 	dest_capab = qdf_mem_malloc(sizeof(*dest_capab));
3114 	if (!dest_capab)
3115 		return -ENOMEM;
3116 
3117 	dest_capab->requestId = event->request_id;
3118 	dest_capab->max_scan_buckets = src_cache->max_buckets;
3119 	dest_capab->max_scan_cache_size = src_cache->scan_cache_entry_size;
3120 	dest_capab->max_ap_cache_per_scan = src_cache->max_bssid_per_scan;
3121 	dest_capab->max_scan_reporting_threshold =
3122 		src_cache->max_table_usage_threshold;
3123 
3124 	dest_capab->max_hotlist_bssids = src_hotlist->max_hotlist_entries;
3125 	dest_capab->max_rssi_sample_size =
3126 					src_change->max_rssi_averaging_samples;
3127 	dest_capab->max_bssid_history_entries =
3128 		src_change->max_rssi_history_entries;
3129 	dest_capab->max_significant_wifi_change_aps =
3130 		src_change->max_wlan_change_entries;
3131 	dest_capab->max_hotlist_ssids =
3132 				event->num_extscan_hotlist_ssid;
3133 	dest_capab->max_number_epno_networks =
3134 				event->num_epno_networks;
3135 	dest_capab->max_number_epno_networks_by_ssid =
3136 				event->num_epno_networks;
3137 	dest_capab->max_number_of_white_listed_ssid =
3138 				event->num_roam_ssid_whitelist;
3139 	dest_capab->max_number_of_black_listed_bssid =
3140 				event->num_roam_bssid_blacklist;
3141 	dest_capab->status = 0;
3142 
3143 	wma_debug("request_id: %u status: %d",
3144 		 dest_capab->requestId, dest_capab->status);
3145 
3146 	wma_debug("Capabilities: max_scan_buckets: %d, max_hotlist_bssids: %d, max_scan_cache_size: %d, max_ap_cache_per_scan: %d",
3147 		 dest_capab->max_scan_buckets,
3148 		 dest_capab->max_hotlist_bssids, dest_capab->max_scan_cache_size,
3149 		 dest_capab->max_ap_cache_per_scan);
3150 	wma_debug("max_scan_reporting_threshold: %d, max_rssi_sample_size: %d, max_bssid_history_entries: %d, max_significant_wifi_change_aps: %d",
3151 		 dest_capab->max_scan_reporting_threshold,
3152 		 dest_capab->max_rssi_sample_size,
3153 		 dest_capab->max_bssid_history_entries,
3154 		 dest_capab->max_significant_wifi_change_aps);
3155 
3156 	wma_debug("Capabilities: max_hotlist_ssids: %d, max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d",
3157 		 dest_capab->max_hotlist_ssids,
3158 		 dest_capab->max_number_epno_networks,
3159 		 dest_capab->max_number_epno_networks_by_ssid);
3160 	wma_debug("max_number_of_white_listed_ssid: %d, max_number_of_black_listed_bssid: %d",
3161 		 dest_capab->max_number_of_white_listed_ssid,
3162 		 dest_capab->max_number_of_black_listed_bssid);
3163 
3164 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
3165 				eSIR_EXTSCAN_GET_CAPABILITIES_IND, dest_capab);
3166 	qdf_mem_free(dest_capab);
3167 	return 0;
3168 }
3169 
3170 /**
3171  * wma_extscan_hotlist_match_event_handler() - hotlist match event handler
3172  * @handle: wma handle
3173  * @cmd_param_info: event buffer
3174  * @len: length
3175  *
3176  * This function handles hotlist match event and indicate
3177  * upper layers with registered callback.
3178  *
3179  * Return: 0 for success or error code.
3180  */
3181 int wma_extscan_hotlist_match_event_handler(void *handle,
3182 					    uint8_t *cmd_param_info,
3183 					    uint32_t len)
3184 {
3185 	WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *param_buf;
3186 	wmi_extscan_hotlist_match_event_fixed_param *event;
3187 	struct extscan_hotlist_match *dest_hotlist;
3188 	tSirWifiScanResult *dest_ap;
3189 	wmi_extscan_wlan_descriptor *src_hotlist;
3190 	uint32_t numap;
3191 	int j, ap_found = 0;
3192 	uint32_t buf_len;
3193 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
3194 
3195 	if (!mac)
3196 		return -EINVAL;
3197 
3198 	if (!mac->sme.ext_scan_ind_cb) {
3199 		wma_err("Callback not registered");
3200 		return -EINVAL;
3201 	}
3202 	param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *)
3203 		    cmd_param_info;
3204 	if (!param_buf) {
3205 		wma_err("Invalid hotlist match event");
3206 		return -EINVAL;
3207 	}
3208 	event = param_buf->fixed_param;
3209 	src_hotlist = param_buf->hotlist_match;
3210 	numap = event->total_entries;
3211 
3212 	if (!src_hotlist || !numap) {
3213 		wma_err("Hotlist AP's list invalid");
3214 		return -EINVAL;
3215 	}
3216 	if (numap > param_buf->num_hotlist_match) {
3217 		wma_err("Invalid no of total enteries %d", numap);
3218 		return -EINVAL;
3219 	}
3220 	if (numap > WMA_EXTSCAN_MAX_HOTLIST_ENTRIES) {
3221 		wma_err("Total Entries %u greater than max", numap);
3222 		numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES;
3223 	}
3224 
3225 	buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) +
3226 		  WMI_TLV_HDR_SIZE +
3227 		  (numap * sizeof(wmi_extscan_wlan_descriptor));
3228 
3229 	if (buf_len > len) {
3230 		wma_err("Invalid buf len from FW %d numap %d", len, numap);
3231 		return -EINVAL;
3232 	}
3233 
3234 	dest_hotlist = qdf_mem_malloc(sizeof(*dest_hotlist) +
3235 				      sizeof(*dest_ap) * numap);
3236 	if (!dest_hotlist)
3237 		return -ENOMEM;
3238 
3239 	dest_ap = &dest_hotlist->ap[0];
3240 	dest_hotlist->numOfAps = event->total_entries;
3241 	dest_hotlist->requestId = event->config_request_id;
3242 
3243 	if (event->first_entry_index +
3244 		event->num_entries_in_page < event->total_entries)
3245 		dest_hotlist->moreData = 1;
3246 	else
3247 		dest_hotlist->moreData = 0;
3248 
3249 	wma_debug("Hotlist match: requestId: %u numOfAps: %d",
3250 		 dest_hotlist->requestId, dest_hotlist->numOfAps);
3251 
3252 	/*
3253 	 * Currently firmware sends only one bss information in-case
3254 	 * of both hotlist ap found and lost.
3255 	 */
3256 	for (j = 0; j < numap; j++) {
3257 		dest_ap->rssi = 0;
3258 		dest_ap->channel = src_hotlist->channel;
3259 		dest_ap->ts = src_hotlist->tstamp;
3260 		ap_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE;
3261 		dest_ap->rtt = src_hotlist->rtt;
3262 		dest_ap->rtt_sd = src_hotlist->rtt_sd;
3263 		dest_ap->beaconPeriod = src_hotlist->beacon_interval;
3264 		dest_ap->capability = src_hotlist->capabilities;
3265 		dest_ap->ieLength = src_hotlist->ie_length;
3266 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid,
3267 					   dest_ap->bssid.bytes);
3268 		if (src_hotlist->ssid.ssid_len > WLAN_SSID_MAX_LEN) {
3269 			wma_err("Invalid SSID len %d, truncating",
3270 				src_hotlist->ssid.ssid_len);
3271 			src_hotlist->ssid.ssid_len = WLAN_SSID_MAX_LEN;
3272 		}
3273 		qdf_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid,
3274 			     src_hotlist->ssid.ssid_len);
3275 		dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0';
3276 		dest_ap++;
3277 		src_hotlist++;
3278 	}
3279 	dest_hotlist->ap_found = ap_found;
3280 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
3281 				eSIR_EXTSCAN_HOTLIST_MATCH_IND, dest_hotlist);
3282 	wma_debug("sending hotlist match event to hdd");
3283 	qdf_mem_free(dest_hotlist);
3284 	return 0;
3285 }
3286 
3287 /** wma_extscan_find_unique_scan_ids() - find unique scan ids
3288  * @cmd_param_info: event data.
3289  *
3290  * This utility function parses the input bss table of information
3291  * and find the unique number of scan ids
3292  *
3293  * Return: 0 on success; error number otherwise
3294  */
3295 static int wma_extscan_find_unique_scan_ids(const u_int8_t *cmd_param_info)
3296 {
3297 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
3298 	wmi_extscan_cached_results_event_fixed_param  *event;
3299 	wmi_extscan_wlan_descriptor  *src_hotlist;
3300 	wmi_extscan_rssi_info  *src_rssi;
3301 	int prev_scan_id, scan_ids_cnt, i;
3302 
3303 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
3304 						cmd_param_info;
3305 	event = param_buf->fixed_param;
3306 	src_hotlist = param_buf->bssid_list;
3307 	src_rssi = param_buf->rssi_list;
3308 
3309 	/* Find the unique number of scan_id's for grouping */
3310 	prev_scan_id = src_rssi->scan_cycle_id;
3311 	scan_ids_cnt = 1;
3312 	for (i = 1; i < param_buf->num_rssi_list; i++) {
3313 		src_rssi++;
3314 
3315 		if (prev_scan_id != src_rssi->scan_cycle_id) {
3316 			scan_ids_cnt++;
3317 			prev_scan_id = src_rssi->scan_cycle_id;
3318 		}
3319 	}
3320 
3321 	return scan_ids_cnt;
3322 }
3323 
3324 /** wma_fill_num_results_per_scan_id() - fill number of bss per scan id
3325  * @cmd_param_info: event data.
3326  * @scan_id_group: pointer to scan id group.
3327  *
3328  * This utility function parses the input bss table of information
3329  * and finds how many bss are there per unique scan id.
3330  *
3331  * Return: 0 on success; error number otherwise
3332  */
3333 static int wma_fill_num_results_per_scan_id(const u_int8_t *cmd_param_info,
3334 			struct extscan_cached_scan_result *scan_id_group)
3335 {
3336 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
3337 	wmi_extscan_cached_results_event_fixed_param  *event;
3338 	wmi_extscan_wlan_descriptor  *src_hotlist;
3339 	wmi_extscan_rssi_info  *src_rssi;
3340 	struct extscan_cached_scan_result *t_scan_id_grp;
3341 	int i, prev_scan_id;
3342 
3343 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
3344 						cmd_param_info;
3345 	event = param_buf->fixed_param;
3346 	src_hotlist = param_buf->bssid_list;
3347 	src_rssi = param_buf->rssi_list;
3348 	t_scan_id_grp = scan_id_group;
3349 
3350 	prev_scan_id = src_rssi->scan_cycle_id;
3351 
3352 	t_scan_id_grp->scan_id = src_rssi->scan_cycle_id;
3353 	t_scan_id_grp->flags = src_rssi->flags;
3354 	t_scan_id_grp->buckets_scanned = src_rssi->buckets_scanned;
3355 	t_scan_id_grp->num_results = 1;
3356 	for (i = 1; i < param_buf->num_rssi_list; i++) {
3357 		src_rssi++;
3358 		if (prev_scan_id == src_rssi->scan_cycle_id) {
3359 			t_scan_id_grp->num_results++;
3360 		} else {
3361 			t_scan_id_grp++;
3362 			prev_scan_id = t_scan_id_grp->scan_id =
3363 				src_rssi->scan_cycle_id;
3364 			t_scan_id_grp->flags = src_rssi->flags;
3365 			t_scan_id_grp->buckets_scanned =
3366 				src_rssi->buckets_scanned;
3367 			t_scan_id_grp->num_results = 1;
3368 		}
3369 	}
3370 	return 0;
3371 }
3372 
3373 /** wma_group_num_bss_to_scan_id() - group bss to scan id table
3374  * @cmd_param_info: event data.
3375  * @cached_result: pointer to cached table.
3376  *
3377  * This function reads the bss information from the format
3378  * ------------------------------------------------------------------------
3379  * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_1 | flags |
3380  * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_2 | flags |
3381  * ........................................................................
3382  * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_N | flags |
3383  * ------------------------------------------------------------------------
3384  *
3385  * and converts it into the below format and store it
3386  *
3387  * ------------------------------------------------------------------------
3388  * | scan id_1 | -> bss info_1 -> bss info_2 -> .... bss info_M1
3389  * | scan id_2 | -> bss info_1 -> bss info_2 -> .... bss info_M2
3390  * ......................
3391  * | scan id_N | -> bss info_1 -> bss info_2 -> .... bss info_Mn
3392  * ------------------------------------------------------------------------
3393  *
3394  * Return: 0 on success; error number otherwise
3395  */
3396 static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info,
3397 			struct extscan_cached_scan_results *cached_result)
3398 {
3399 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
3400 	wmi_extscan_cached_results_event_fixed_param  *event;
3401 	wmi_extscan_wlan_descriptor  *src_hotlist;
3402 	wmi_extscan_rssi_info  *src_rssi;
3403 	struct extscan_cached_scan_results *t_cached_result;
3404 	struct extscan_cached_scan_result *t_scan_id_grp;
3405 	int i, j;
3406 	tSirWifiScanResult *ap;
3407 
3408 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
3409 						cmd_param_info;
3410 	event = param_buf->fixed_param;
3411 	src_hotlist = param_buf->bssid_list;
3412 	src_rssi = param_buf->rssi_list;
3413 	t_cached_result = cached_result;
3414 	t_scan_id_grp = &t_cached_result->result[0];
3415 
3416 	if ((t_cached_result->num_scan_ids *
3417 	     QDF_MIN(t_scan_id_grp->num_results,
3418 		     param_buf->num_bssid_list)) > param_buf->num_bssid_list) {
3419 		wma_err("num_scan_ids %d, num_results %d num_bssid_list %d",
3420 			 t_cached_result->num_scan_ids,
3421 			 t_scan_id_grp->num_results,
3422 			 param_buf->num_bssid_list);
3423 		return -EINVAL;
3424 	}
3425 
3426 	wma_debug("num_scan_ids:%d",
3427 			t_cached_result->num_scan_ids);
3428 	for (i = 0; i < t_cached_result->num_scan_ids; i++) {
3429 		wma_debug("num_results:%d", t_scan_id_grp->num_results);
3430 		t_scan_id_grp->ap = qdf_mem_malloc(t_scan_id_grp->num_results *
3431 						sizeof(*ap));
3432 		if (!t_scan_id_grp->ap)
3433 			return -ENOMEM;
3434 
3435 		ap = &t_scan_id_grp->ap[0];
3436 		for (j = 0; j < QDF_MIN(t_scan_id_grp->num_results,
3437 					param_buf->num_bssid_list); j++) {
3438 			ap->channel = src_hotlist->channel;
3439 			ap->ts = WMA_MSEC_TO_USEC(src_rssi->tstamp);
3440 			ap->rtt = src_hotlist->rtt;
3441 			ap->rtt_sd = src_hotlist->rtt_sd;
3442 			ap->beaconPeriod = src_hotlist->beacon_interval;
3443 			ap->capability = src_hotlist->capabilities;
3444 			ap->ieLength = src_hotlist->ie_length;
3445 
3446 			/* Firmware already applied noise floor adjustment and
3447 			 * due to WMI interface "UINT32 rssi", host driver
3448 			 * receives a positive value, hence convert to
3449 			 * signed char to get the absolute rssi.
3450 			 */
3451 			ap->rssi = (signed char) src_rssi->rssi;
3452 			WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid,
3453 						   ap->bssid.bytes);
3454 
3455 			if (src_hotlist->ssid.ssid_len >
3456 			    WLAN_SSID_MAX_LEN) {
3457 				wma_debug("Invalid SSID len %d, truncating",
3458 					 src_hotlist->ssid.ssid_len);
3459 				src_hotlist->ssid.ssid_len =
3460 						WLAN_SSID_MAX_LEN;
3461 			}
3462 			qdf_mem_copy(ap->ssid, src_hotlist->ssid.ssid,
3463 					src_hotlist->ssid.ssid_len);
3464 			ap->ssid[src_hotlist->ssid.ssid_len] = '\0';
3465 			ap++;
3466 			src_rssi++;
3467 			src_hotlist++;
3468 		}
3469 		t_scan_id_grp++;
3470 	}
3471 	return 0;
3472 }
3473 
3474 /**
3475  * wma_extscan_cached_results_event_handler() - cached results event handler
3476  * @handle: wma handle
3477  * @cmd_param_info: event buffer
3478  * @len: length of @cmd_param_info
3479  *
3480  * This function handles cached results event and indicate
3481  * cached results to upper layer.
3482  *
3483  * Return: 0 for success or error code.
3484  */
3485 int wma_extscan_cached_results_event_handler(void *handle,
3486 					     uint8_t *cmd_param_info,
3487 					     uint32_t len)
3488 {
3489 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
3490 	wmi_extscan_cached_results_event_fixed_param *event;
3491 	struct extscan_cached_scan_results *dest_cachelist;
3492 	struct extscan_cached_scan_result *dest_result;
3493 	struct extscan_cached_scan_results empty_cachelist;
3494 	wmi_extscan_wlan_descriptor *src_hotlist;
3495 	wmi_extscan_rssi_info *src_rssi;
3496 	int i, moredata, scan_ids_cnt, buf_len, status;
3497 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
3498 	uint32_t total_len;
3499 	bool excess_data = false;
3500 
3501 	if (!mac) {
3502 		wma_err("Invalid mac");
3503 		return -EINVAL;
3504 	}
3505 	if (!mac->sme.ext_scan_ind_cb) {
3506 		wma_err("Callback not registered");
3507 		return -EINVAL;
3508 	}
3509 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
3510 		    cmd_param_info;
3511 	if (!param_buf) {
3512 		wma_err("Invalid cached results event");
3513 		return -EINVAL;
3514 	}
3515 	event = param_buf->fixed_param;
3516 	src_hotlist = param_buf->bssid_list;
3517 	src_rssi = param_buf->rssi_list;
3518 	wma_debug("Total_entries: %u first_entry_index: %u num_entries_in_page: %d",
3519 		 event->total_entries,
3520 		 event->first_entry_index,
3521 		 event->num_entries_in_page);
3522 
3523 	if (!src_hotlist || !src_rssi || !event->num_entries_in_page) {
3524 		wma_warn("Cached results empty, send 0 results");
3525 		goto noresults;
3526 	}
3527 
3528 	if (event->num_entries_in_page >
3529 	    (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist) ||
3530 	    event->num_entries_in_page > param_buf->num_bssid_list) {
3531 		wma_err("excess num_entries_in_page %d in WMI event. num_bssid_list %d",
3532 			 event->num_entries_in_page, param_buf->num_bssid_list);
3533 		return -EINVAL;
3534 	} else {
3535 		total_len = sizeof(*event) +
3536 			(event->num_entries_in_page * sizeof(*src_hotlist));
3537 	}
3538 	for (i = 0; i < event->num_entries_in_page; i++) {
3539 		if (src_hotlist[i].ie_length >
3540 		    WMI_SVC_MSG_MAX_SIZE - total_len) {
3541 			excess_data = true;
3542 			break;
3543 		} else {
3544 			total_len += src_hotlist[i].ie_length;
3545 			wma_debug("total len IE: %d", total_len);
3546 		}
3547 
3548 		if (src_hotlist[i].number_rssi_samples >
3549 		    (WMI_SVC_MSG_MAX_SIZE - total_len) / sizeof(*src_rssi)) {
3550 			excess_data = true;
3551 			break;
3552 		} else {
3553 			total_len += (src_hotlist[i].number_rssi_samples *
3554 					sizeof(*src_rssi));
3555 			wma_debug("total len RSSI samples: %d", total_len);
3556 		}
3557 	}
3558 	if (excess_data) {
3559 		wma_err("excess data in WMI event");
3560 		return -EINVAL;
3561 	}
3562 
3563 	if (event->first_entry_index +
3564 	    event->num_entries_in_page < event->total_entries)
3565 		moredata = 1;
3566 	else
3567 		moredata = 0;
3568 
3569 	dest_cachelist = qdf_mem_malloc(sizeof(*dest_cachelist));
3570 	if (!dest_cachelist)
3571 		return -ENOMEM;
3572 
3573 	qdf_mem_zero(dest_cachelist, sizeof(*dest_cachelist));
3574 	dest_cachelist->request_id = event->request_id;
3575 	dest_cachelist->more_data = moredata;
3576 
3577 	scan_ids_cnt = wma_extscan_find_unique_scan_ids(cmd_param_info);
3578 	wma_debug("scan_ids_cnt %d", scan_ids_cnt);
3579 	dest_cachelist->num_scan_ids = scan_ids_cnt;
3580 
3581 	buf_len = sizeof(*dest_result) * scan_ids_cnt;
3582 	dest_cachelist->result = qdf_mem_malloc(buf_len);
3583 	if (!dest_cachelist->result) {
3584 		qdf_mem_free(dest_cachelist);
3585 		return -ENOMEM;
3586 	}
3587 
3588 	dest_result = dest_cachelist->result;
3589 	wma_fill_num_results_per_scan_id(cmd_param_info, dest_result);
3590 
3591 	status = wma_group_num_bss_to_scan_id(cmd_param_info, dest_cachelist);
3592 	if (!status)
3593 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
3594 				eSIR_EXTSCAN_CACHED_RESULTS_IND,
3595 				dest_cachelist);
3596 	else
3597 		wma_debug("wma_group_num_bss_to_scan_id failed, not calling callback");
3598 
3599 	dest_result = dest_cachelist->result;
3600 	for (i = 0; i < dest_cachelist->num_scan_ids; i++) {
3601 		if (dest_result->ap)
3602 		qdf_mem_free(dest_result->ap);
3603 		dest_result++;
3604 	}
3605 	qdf_mem_free(dest_cachelist->result);
3606 	qdf_mem_free(dest_cachelist);
3607 	return status;
3608 
3609 noresults:
3610 	empty_cachelist.request_id = event->request_id;
3611 	empty_cachelist.more_data = 0;
3612 	empty_cachelist.num_scan_ids = 0;
3613 
3614 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
3615 				eSIR_EXTSCAN_CACHED_RESULTS_IND,
3616 				&empty_cachelist);
3617 	return 0;
3618 }
3619 
3620 /**
3621  * wma_extscan_change_results_event_handler() - change results event handler
3622  * @handle: wma handle
3623  * @cmd_param_info: event buffer
3624  * @len: length
3625  *
3626  * This function handles change results event and indicate
3627  * change results to upper layer.
3628  *
3629  * Return: 0 for success or error code.
3630  */
3631 int wma_extscan_change_results_event_handler(void *handle,
3632 					     uint8_t *cmd_param_info,
3633 					     uint32_t len)
3634 {
3635 	WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *param_buf;
3636 	wmi_extscan_wlan_change_results_event_fixed_param *event;
3637 	tSirWifiSignificantChangeEvent *dest_chglist;
3638 	tSirWifiSignificantChange *dest_ap;
3639 	wmi_extscan_wlan_change_result_bssid *src_chglist;
3640 
3641 	uint32_t numap;
3642 	int i, k;
3643 	uint8_t *src_rssi;
3644 	int count = 0;
3645 	int moredata;
3646 	uint32_t rssi_num = 0;
3647 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
3648 	uint32_t buf_len;
3649 	bool excess_data = false;
3650 
3651 	if (!mac) {
3652 		wma_err("Invalid mac");
3653 		return -EINVAL;
3654 	}
3655 	if (!mac->sme.ext_scan_ind_cb) {
3656 		wma_err("Callback not registered");
3657 		return -EINVAL;
3658 	}
3659 	param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *)
3660 		    cmd_param_info;
3661 	if (!param_buf) {
3662 		wma_err("Invalid change monitor event");
3663 		return -EINVAL;
3664 	}
3665 	event = param_buf->fixed_param;
3666 	src_chglist = param_buf->bssid_signal_descriptor_list;
3667 	src_rssi = param_buf->rssi_list;
3668 	numap = event->num_entries_in_page;
3669 
3670 	if (!src_chglist || !numap) {
3671 		wma_err("Results invalid");
3672 		return -EINVAL;
3673 	}
3674 	if (numap > param_buf->num_bssid_signal_descriptor_list) {
3675 		wma_err("Invalid num of entries in page: %d", numap);
3676 		return -EINVAL;
3677 	}
3678 	for (i = 0; i < numap; i++) {
3679 		if (src_chglist->num_rssi_samples > (UINT_MAX - rssi_num)) {
3680 			wma_err("Invalid num of rssi samples %d numap %d rssi_num %d",
3681 				 src_chglist->num_rssi_samples,
3682 				 numap, rssi_num);
3683 			return -EINVAL;
3684 		}
3685 		rssi_num += src_chglist->num_rssi_samples;
3686 		src_chglist++;
3687 	}
3688 	src_chglist = param_buf->bssid_signal_descriptor_list;
3689 
3690 	if (event->first_entry_index +
3691 	    event->num_entries_in_page < event->total_entries) {
3692 		moredata = 1;
3693 	} else {
3694 		moredata = 0;
3695 	}
3696 
3697 	do {
3698 		if (event->num_entries_in_page >
3699 			(WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/
3700 			sizeof(*src_chglist)) {
3701 			excess_data = true;
3702 			break;
3703 		} else {
3704 			buf_len =
3705 				sizeof(*event) + (event->num_entries_in_page *
3706 						sizeof(*src_chglist));
3707 		}
3708 		if (rssi_num >
3709 			(WMI_SVC_MSG_MAX_SIZE - buf_len)/sizeof(int32_t)) {
3710 			excess_data = true;
3711 			break;
3712 		}
3713 	} while (0);
3714 
3715 	if (excess_data) {
3716 		wma_err("buffer len exceeds WMI payload,numap:%d, rssi_num:%d",
3717 			numap, rssi_num);
3718 		QDF_ASSERT(0);
3719 		return -EINVAL;
3720 	}
3721 	dest_chglist = qdf_mem_malloc(sizeof(*dest_chglist) +
3722 				      sizeof(*dest_ap) * numap +
3723 				      sizeof(int32_t) * rssi_num);
3724 	if (!dest_chglist)
3725 		return -ENOMEM;
3726 
3727 	dest_ap = &dest_chglist->ap[0];
3728 	for (i = 0; i < numap; i++) {
3729 		dest_ap->channel = src_chglist->channel;
3730 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_chglist->bssid,
3731 					   dest_ap->bssid.bytes);
3732 		dest_ap->numOfRssi = src_chglist->num_rssi_samples;
3733 		if (dest_ap->numOfRssi) {
3734 			if ((dest_ap->numOfRssi + count) >
3735 			    param_buf->num_rssi_list) {
3736 				wma_err("Invalid num in rssi list: %d",
3737 					dest_ap->numOfRssi);
3738 				qdf_mem_free(dest_chglist);
3739 				return -EINVAL;
3740 			}
3741 			for (k = 0; k < dest_ap->numOfRssi; k++) {
3742 				dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM +
3743 						   src_rssi[count++];
3744 			}
3745 		}
3746 		dest_ap = (tSirWifiSignificantChange *)((char *)dest_ap +
3747 					dest_ap->numOfRssi * sizeof(int32_t) +
3748 					sizeof(*dest_ap));
3749 		src_chglist++;
3750 	}
3751 	dest_chglist->requestId = event->request_id;
3752 	dest_chglist->moreData = moredata;
3753 	dest_chglist->numResults = numap;
3754 
3755 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
3756 			eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND,
3757 			dest_chglist);
3758 	wma_debug("sending change monitor results");
3759 	qdf_mem_free(dest_chglist);
3760 	return 0;
3761 }
3762 
3763 /**
3764  * wma_passpoint_match_event_handler() - passpoint match found event handler
3765  * @handle: WMA handle
3766  * @cmd_param_info: event data
3767  * @len: event data length
3768  *
3769  * This is the passpoint match found event handler; it reads event data from
3770  * @cmd_param_info and fill in the destination buffer and sends indication
3771  * up layer.
3772  *
3773  * Return: 0 on success; error number otherwise
3774  */
3775 int wma_passpoint_match_event_handler(void *handle,
3776 				     uint8_t  *cmd_param_info,
3777 				     uint32_t len)
3778 {
3779 	WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *param_buf;
3780 	wmi_passpoint_event_hdr  *event;
3781 	struct wifi_passpoint_match  *dest_match;
3782 	tSirWifiScanResult      *dest_ap;
3783 	uint8_t *buf_ptr;
3784 	uint32_t buf_len = 0;
3785 	bool excess_data = false;
3786 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
3787 
3788 	if (!mac) {
3789 		wma_err("Invalid mac");
3790 		return -EINVAL;
3791 	}
3792 	if (!mac->sme.ext_scan_ind_cb) {
3793 		wma_err("Callback not registered");
3794 		return -EINVAL;
3795 	}
3796 
3797 	param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info;
3798 	if (!param_buf) {
3799 		wma_err("Invalid passpoint match event");
3800 		return -EINVAL;
3801 	}
3802 	event = param_buf->fixed_param;
3803 	buf_ptr = (uint8_t *)param_buf->fixed_param;
3804 
3805 	do {
3806 		if (event->ie_length > (WMI_SVC_MSG_MAX_SIZE)) {
3807 			excess_data = true;
3808 			break;
3809 		} else {
3810 			buf_len = event->ie_length;
3811 		}
3812 
3813 		if (event->anqp_length > (WMI_SVC_MSG_MAX_SIZE)) {
3814 			excess_data = true;
3815 			break;
3816 		} else {
3817 			buf_len += event->anqp_length;
3818 		}
3819 
3820 	} while (0);
3821 
3822 	if (excess_data || buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*event)) ||
3823 	    buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*dest_match)) ||
3824 	    (event->ie_length + event->anqp_length) > param_buf->num_bufp) {
3825 		wma_err("IE Length: %u or ANQP Length: %u is huge, num_bufp: %u",
3826 			event->ie_length, event->anqp_length,
3827 			param_buf->num_bufp);
3828 		return -EINVAL;
3829 	}
3830 
3831 	if (event->ssid.ssid_len > WLAN_SSID_MAX_LEN) {
3832 		wma_debug("Invalid ssid len %d, truncating",
3833 			 event->ssid.ssid_len);
3834 		event->ssid.ssid_len = WLAN_SSID_MAX_LEN;
3835 	}
3836 
3837 	dest_match = qdf_mem_malloc(sizeof(*dest_match) + buf_len);
3838 	if (!dest_match)
3839 		return -EINVAL;
3840 
3841 	dest_ap = &dest_match->ap;
3842 	dest_match->request_id = 0;
3843 	dest_match->id = event->id;
3844 	dest_match->anqp_len = event->anqp_length;
3845 	wma_info("passpoint match: id: %u anqp length %u",
3846 		 dest_match->id, dest_match->anqp_len);
3847 
3848 	dest_ap->channel = event->channel_mhz;
3849 	dest_ap->ts = event->timestamp;
3850 	dest_ap->rtt = event->rtt;
3851 	dest_ap->rssi = event->rssi;
3852 	dest_ap->rtt_sd = event->rtt_sd;
3853 	dest_ap->beaconPeriod = event->beacon_period;
3854 	dest_ap->capability = event->capability;
3855 	dest_ap->ieLength = event->ie_length;
3856 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, dest_ap->bssid.bytes);
3857 	qdf_mem_copy(dest_ap->ssid, event->ssid.ssid,
3858 				event->ssid.ssid_len);
3859 	dest_ap->ssid[event->ssid.ssid_len] = '\0';
3860 	qdf_mem_copy(dest_ap->ieData, buf_ptr + sizeof(*event) +
3861 			WMI_TLV_HDR_SIZE, dest_ap->ieLength);
3862 	qdf_mem_copy(dest_match->anqp, buf_ptr + sizeof(*event) +
3863 			WMI_TLV_HDR_SIZE + dest_ap->ieLength,
3864 			dest_match->anqp_len);
3865 
3866 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
3867 				eSIR_PASSPOINT_NETWORK_FOUND_IND,
3868 				dest_match);
3869 	wma_debug("sending passpoint match event to hdd");
3870 	qdf_mem_free(dest_match);
3871 	return 0;
3872 }
3873 
3874 QDF_STATUS wma_start_extscan(tp_wma_handle wma,
3875 			     struct wifi_scan_cmd_req_params *params)
3876 {
3877 	QDF_STATUS status;
3878 	struct wmi_unified *wmi_handle;
3879 
3880 	if (wma_validate_handle(wma))
3881 		return QDF_STATUS_E_INVAL;
3882 
3883 	wmi_handle = wma->wmi_handle;
3884 	if (wmi_validate_handle(wmi_handle))
3885 		return QDF_STATUS_E_INVAL;
3886 
3887 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
3888 		wma_err("extscan not enabled");
3889 		return QDF_STATUS_E_FAILURE;
3890 	}
3891 
3892 	if (!params) {
3893 		wma_err("NULL param");
3894 		return QDF_STATUS_E_NOMEM;
3895 	}
3896 
3897 	status = wmi_unified_start_extscan_cmd(wmi_handle, params);
3898 	if (QDF_IS_STATUS_SUCCESS(status))
3899 		wma->interfaces[params->vdev_id].extscan_in_progress = true;
3900 
3901 	wma_debug("Exit, vdev %d, status %d", params->vdev_id, status);
3902 
3903 	return status;
3904 }
3905 
3906 QDF_STATUS wma_stop_extscan(tp_wma_handle wma,
3907 			    struct extscan_stop_req_params *params)
3908 {
3909 	QDF_STATUS status;
3910 	struct wmi_unified *wmi_handle;
3911 
3912 	if (wma_validate_handle(wma))
3913 		return QDF_STATUS_E_INVAL;
3914 
3915 	wmi_handle = wma->wmi_handle;
3916 	if (wmi_validate_handle(wmi_handle))
3917 		return QDF_STATUS_E_INVAL;
3918 
3919 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
3920 		wma_err("extscan not enabled");
3921 		return QDF_STATUS_E_FAILURE;
3922 	}
3923 
3924 	status = wmi_unified_stop_extscan_cmd(wmi_handle, params);
3925 	if (QDF_IS_STATUS_ERROR(status))
3926 		return status;
3927 
3928 	wma->interfaces[params->vdev_id].extscan_in_progress = false;
3929 	wma_debug("Extscan stop request sent successfully for vdev %d",
3930 		 params->vdev_id);
3931 
3932 	return status;
3933 }
3934 
3935 QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma,
3936 			struct extscan_bssid_hotlist_set_params *params)
3937 {
3938 	struct wmi_unified *wmi_handle;
3939 
3940 	if (wma_validate_handle(wma))
3941 		return QDF_STATUS_E_INVAL;
3942 
3943 	wmi_handle = wma->wmi_handle;
3944 	if (wmi_validate_handle(wmi_handle))
3945 		return QDF_STATUS_E_INVAL;
3946 
3947 	if (!params) {
3948 		wma_err("Invalid params");
3949 		return QDF_STATUS_E_INVAL;
3950 	}
3951 
3952 	return wmi_unified_extscan_start_hotlist_monitor_cmd(wmi_handle,
3953 							     params);
3954 }
3955 
3956 QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma,
3957 		    struct extscan_bssid_hotlist_reset_params *params)
3958 {
3959 	struct wmi_unified *wmi_handle;
3960 
3961 	if (wma_validate_handle(wma))
3962 		return QDF_STATUS_E_INVAL;
3963 
3964 	wmi_handle = wma->wmi_handle;
3965 	if (wmi_validate_handle(wmi_handle))
3966 		return QDF_STATUS_E_INVAL;
3967 
3968 	if (!params) {
3969 		wma_err("Invalid params");
3970 		return QDF_STATUS_E_INVAL;
3971 	}
3972 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
3973 		wma_err("extscan not enabled");
3974 		return QDF_STATUS_E_FAILURE;
3975 	}
3976 
3977 	return wmi_unified_extscan_stop_hotlist_monitor_cmd(wmi_handle,
3978 							    params);
3979 }
3980 
3981 QDF_STATUS
3982 wma_extscan_start_change_monitor(tp_wma_handle wma,
3983 			struct extscan_set_sig_changereq_params *params)
3984 {
3985 	QDF_STATUS status;
3986 	struct wmi_unified *wmi_handle;
3987 
3988 	if (wma_validate_handle(wma))
3989 		return QDF_STATUS_E_INVAL;
3990 
3991 	wmi_handle = wma->wmi_handle;
3992 	if (wmi_validate_handle(wmi_handle))
3993 		return QDF_STATUS_E_INVAL;
3994 
3995 	if (!params) {
3996 		wma_err("NULL params");
3997 		return QDF_STATUS_E_NOMEM;
3998 	}
3999 
4000 	status = wmi_unified_extscan_start_change_monitor_cmd(wmi_handle,
4001 							      params);
4002 	return status;
4003 }
4004 
4005 QDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma,
4006 			struct extscan_capabilities_reset_params *params)
4007 {
4008 	struct wmi_unified *wmi_handle;
4009 
4010 	if (wma_validate_handle(wma))
4011 		return QDF_STATUS_E_INVAL;
4012 
4013 	wmi_handle = wma->wmi_handle;
4014 	if (wmi_validate_handle(wmi_handle))
4015 		return QDF_STATUS_E_INVAL;
4016 
4017 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
4018 		wma_err("ext scan not enabled");
4019 		return QDF_STATUS_E_FAILURE;
4020 	}
4021 
4022 	return wmi_unified_extscan_stop_change_monitor_cmd(wmi_handle,
4023 							   params);
4024 }
4025 
4026 QDF_STATUS
4027 wma_extscan_get_cached_results(tp_wma_handle wma,
4028 			       struct extscan_cached_result_params *params)
4029 {
4030 	struct wmi_unified *wmi_handle;
4031 
4032 	if (wma_validate_handle(wma))
4033 		return QDF_STATUS_E_INVAL;
4034 
4035 	wmi_handle = wma->wmi_handle;
4036 	if (wmi_validate_handle(wmi_handle))
4037 		return QDF_STATUS_E_INVAL;
4038 
4039 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
4040 		wma_err("extscan not enabled");
4041 		return QDF_STATUS_E_FAILURE;
4042 	}
4043 
4044 	return wmi_unified_extscan_get_cached_results_cmd(wmi_handle,
4045 							  params);
4046 }
4047 
4048 QDF_STATUS
4049 wma_extscan_get_capabilities(tp_wma_handle wma,
4050 			     struct extscan_capabilities_params *params)
4051 {
4052 	struct wmi_unified *wmi_handle;
4053 
4054 	if (wma_validate_handle(wma))
4055 		return QDF_STATUS_E_INVAL;
4056 
4057 	wmi_handle = wma->wmi_handle;
4058 	if (wmi_validate_handle(wmi_handle))
4059 		return QDF_STATUS_E_INVAL;
4060 
4061 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
4062 		wma_err("extscan not enabled");
4063 		return QDF_STATUS_E_FAILURE;
4064 	}
4065 
4066 	return wmi_unified_extscan_get_capabilities_cmd(wmi_handle,
4067 							params);
4068 }
4069 
4070 QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma,
4071 				     struct wifi_enhanced_pno_params *req)
4072 {
4073 	QDF_STATUS status;
4074 	struct wmi_unified *wmi_handle;
4075 
4076 	wma_debug("Enter");
4077 
4078 	if (wma_validate_handle(wma))
4079 		return QDF_STATUS_E_FAILURE;
4080 
4081 	wmi_handle = wma->wmi_handle;
4082 	if (wmi_validate_handle(wmi_handle))
4083 		return QDF_STATUS_E_FAILURE;
4084 
4085 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
4086 		wma_err("extscan not enabled");
4087 		return QDF_STATUS_E_NOSUPPORT;
4088 	}
4089 
4090 	status = wmi_unified_set_epno_network_list_cmd(wmi_handle, req);
4091 	wma_debug("Exit, vdev %d, status %d", req->vdev_id, status);
4092 
4093 	return status;
4094 }
4095 
4096 QDF_STATUS
4097 wma_set_passpoint_network_list(tp_wma_handle wma,
4098 			       struct wifi_passpoint_req_param *params)
4099 {
4100 	QDF_STATUS status;
4101 	struct wmi_unified *wmi_handle;
4102 
4103 	wma_debug("Enter");
4104 
4105 	if (wma_validate_handle(wma))
4106 		return QDF_STATUS_E_FAILURE;
4107 
4108 	wmi_handle = wma->wmi_handle;
4109 	if (wmi_validate_handle(wmi_handle))
4110 		return QDF_STATUS_E_FAILURE;
4111 
4112 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
4113 		wma_err("extscan not enabled");
4114 		return QDF_STATUS_E_NOSUPPORT;
4115 	}
4116 
4117 	status = wmi_unified_set_passpoint_network_list_cmd(wmi_handle,
4118 							    params);
4119 	wma_debug("Exit, vdev %d, status %d", params->vdev_id, status);
4120 
4121 	return status;
4122 }
4123 
4124 QDF_STATUS
4125 wma_reset_passpoint_network_list(tp_wma_handle wma,
4126 				 struct wifi_passpoint_req_param *params)
4127 {
4128 	QDF_STATUS status;
4129 	struct wmi_unified *wmi_handle;
4130 
4131 	wma_debug("Enter");
4132 
4133 	if (wma_validate_handle(wma))
4134 		return QDF_STATUS_E_FAILURE;
4135 
4136 	wmi_handle = wma->wmi_handle;
4137 	if (wmi_validate_handle(wmi_handle))
4138 		return QDF_STATUS_E_FAILURE;
4139 
4140 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
4141 		wma_err("extscan not enabled");
4142 		return QDF_STATUS_E_NOSUPPORT;
4143 	}
4144 
4145 	status = wmi_unified_reset_passpoint_network_list_cmd(wmi_handle,
4146 							      params);
4147 	wma_debug("Exit, vdev %d, status %d", params->vdev_id, status);
4148 
4149 	return status;
4150 }
4151 
4152 #endif
4153 
4154 QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma,
4155 				 struct scan_mac_oui *set_oui)
4156 {
4157 	struct wmi_unified *wmi_handle;
4158 
4159 	if (wma_validate_handle(wma))
4160 		return QDF_STATUS_E_INVAL;
4161 
4162 	wmi_handle = wma->wmi_handle;
4163 	if (wmi_validate_handle(wmi_handle))
4164 		return QDF_STATUS_E_INVAL;
4165 
4166 	if (!wma_is_vdev_valid(set_oui->vdev_id)) {
4167 		wma_err("vdev_id: %d is not active", set_oui->vdev_id);
4168 		return QDF_STATUS_E_INVAL;
4169 	}
4170 
4171 	return wmi_unified_scan_probe_setoui_cmd(wmi_handle, set_oui);
4172 }
4173 
4174 /**
4175  * wma_roam_better_ap_handler() - better ap event handler
4176  * @wma: wma handle
4177  * @vdev_id: vdev id
4178  *
4179  * Handler for WMI_ROAM_REASON_BETTER_AP event from roam firmware in Rome.
4180  * This event means roam algorithm in Rome has found a better matching
4181  * candidate AP. The indication is sent to SME.
4182  *
4183  * Return: none
4184  */
4185 void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id)
4186 {
4187 	struct scheduler_msg msg = {0};
4188 	QDF_STATUS status;
4189 #ifdef FEATURE_CM_ENABLE
4190 	struct cm_host_roam_start_ind *ind;
4191 #else
4192 	tSirSmeCandidateFoundInd *candidate_ind;
4193 #endif
4194 
4195 #ifdef FEATURE_CM_ENABLE
4196 	ind = qdf_mem_malloc(sizeof(*ind));
4197 	if (!ind)
4198 		return;
4199 
4200 	wma->interfaces[vdev_id].roaming_in_progress = true;
4201 	ind->pdev = wma->pdev;
4202 	ind->vdev_id = vdev_id;
4203 	msg.bodyptr = ind;
4204 	msg.callback = wlan_cm_host_roam_start;
4205 	wma_debug("Posting ROam start ind to connection manager, vdev %d",
4206 		  vdev_id);
4207 	status = scheduler_post_message(QDF_MODULE_ID_WMA,
4208 					QDF_MODULE_ID_OS_IF,
4209 					QDF_MODULE_ID_SCAN, &msg);
4210 
4211 #else
4212 	candidate_ind = qdf_mem_malloc(sizeof(tSirSmeCandidateFoundInd));
4213 	if (!candidate_ind)
4214 		return;
4215 
4216 	wma->interfaces[vdev_id].roaming_in_progress = true;
4217 	candidate_ind->messageType = eWNI_SME_CANDIDATE_FOUND_IND;
4218 	candidate_ind->sessionId = vdev_id;
4219 	candidate_ind->length = sizeof(tSirSmeCandidateFoundInd);
4220 
4221 	msg.type = eWNI_SME_CANDIDATE_FOUND_IND;
4222 	msg.bodyptr = candidate_ind;
4223 	msg.callback = sme_mc_process_handler;
4224 	wma_debug("Posting candidate ind to SME, vdev %d", vdev_id);
4225 
4226 	status = scheduler_post_message(QDF_MODULE_ID_WMA, QDF_MODULE_ID_SME,
4227 					QDF_MODULE_ID_SCAN,  &msg);
4228 #endif
4229 	if (QDF_IS_STATUS_ERROR(status))
4230 		qdf_mem_free(msg.bodyptr);
4231 }
4232 
4233 /**
4234  * wma_handle_hw_mode_in_roam_fail() - Fill hw mode info if present in policy
4235  * manager.
4236  * @wma: wma handle
4237  * @param: roam event params
4238  *
4239  * Return: None
4240  */
4241 static int wma_handle_hw_mode_transition(tp_wma_handle wma,
4242 					 WMI_ROAM_EVENTID_param_tlvs *param)
4243 {
4244 	struct cm_hw_mode_trans_ind *hw_mode_trans_ind;
4245 	struct scheduler_msg sme_msg = {0};
4246 	QDF_STATUS status;
4247 
4248 	if (param->hw_mode_transition_fixed_param) {
4249 		hw_mode_trans_ind = qdf_mem_malloc(sizeof(*hw_mode_trans_ind));
4250 		if (!hw_mode_trans_ind)
4251 			return -ENOMEM;
4252 		wma_process_pdev_hw_mode_trans_ind(wma,
4253 		    param->hw_mode_transition_fixed_param,
4254 		    param->wmi_pdev_set_hw_mode_response_vdev_mac_mapping,
4255 		    hw_mode_trans_ind);
4256 
4257 		wma_debug("Update HW mode");
4258 		sme_msg.type = eWNI_SME_HW_MODE_TRANS_IND;
4259 		sme_msg.bodyptr = hw_mode_trans_ind;
4260 
4261 		status = scheduler_post_message(QDF_MODULE_ID_WMA,
4262 						QDF_MODULE_ID_SME,
4263 						QDF_MODULE_ID_SME, &sme_msg);
4264 		if (QDF_IS_STATUS_ERROR(status))
4265 			qdf_mem_free(hw_mode_trans_ind);
4266 	} else {
4267 		wma_debug("hw_mode transition fixed param is NULL");
4268 	}
4269 
4270 	return 0;
4271 }
4272 
4273 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
4274 /**
4275  * wma_invalid_roam_reason_handler() - Handle Invalid roam notification
4276  * @wma: wma handle
4277  * @vdev_id: vdev id
4278  * @op_code: Operation to be done by the callback
4279  *
4280  * This function calls pe and csr callbacks with proper op_code
4281  *
4282  * Return: None
4283  */
4284 static void wma_invalid_roam_reason_handler(tp_wma_handle wma_handle,
4285 					    uint32_t vdev_id,
4286 					    uint32_t notif)
4287 {
4288 	struct roam_offload_synch_ind *roam_synch_data;
4289 	enum sir_roam_op_code op_code;
4290 
4291 	if (notif == WMI_ROAM_NOTIF_ROAM_START) {
4292 		wma_handle->interfaces[vdev_id].roaming_in_progress = true;
4293 		op_code = SIR_ROAMING_START;
4294 	} else if (notif == WMI_ROAM_NOTIF_ROAM_ABORT) {
4295 		wma_handle->interfaces[vdev_id].roaming_in_progress = false;
4296 		op_code = SIR_ROAMING_ABORT;
4297 		lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id);
4298 	} else {
4299 		wma_debug("Invalid notif %d", notif);
4300 		return;
4301 	}
4302 	roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data));
4303 	if (!roam_synch_data)
4304 		return;
4305 
4306 	roam_synch_data->roamed_vdev_id = vdev_id;
4307 	if (notif != WMI_ROAM_NOTIF_ROAM_START)
4308 		wma_handle->pe_roam_synch_cb(wma_handle->mac_context,
4309 					     roam_synch_data, NULL, op_code);
4310 #ifdef FEATURE_CM_ENABLE
4311 	if (notif == WMI_ROAM_NOTIF_ROAM_START)
4312 		cm_fw_roam_start_req(wma_handle->psoc, vdev_id);
4313 	else
4314 		cm_fw_roam_abort_req(wma_handle->psoc, vdev_id);
4315 #else
4316 	wma_handle->csr_roam_synch_cb(wma_handle->mac_context, roam_synch_data,
4317 				      NULL, op_code);
4318 #endif
4319 	qdf_mem_free(roam_synch_data);
4320 }
4321 
4322 void wma_handle_roam_sync_timeout(tp_wma_handle wma_handle,
4323 				  struct roam_sync_timeout_timer_info *info)
4324 {
4325 	wma_invalid_roam_reason_handler(wma_handle, info->vdev_id,
4326 					WMI_ROAM_NOTIF_ROAM_ABORT);
4327 }
4328 #endif
4329 
4330 static char *wma_get_roam_event_reason_string(uint32_t reason)
4331 {
4332 	switch (reason) {
4333 	case WMI_ROAM_REASON_INVALID:
4334 		return "Default";
4335 	case WMI_ROAM_REASON_BETTER_AP:
4336 		return "Better AP";
4337 	case WMI_ROAM_REASON_BMISS:
4338 		return "BMISS";
4339 	case WMI_ROAM_REASON_LOW_RSSI:
4340 		return "Low Rssi";
4341 	case WMI_ROAM_REASON_SUITABLE_AP:
4342 		return "Suitable AP";
4343 	case WMI_ROAM_REASON_HO_FAILED:
4344 		return "Hand-off Failed";
4345 	case WMI_ROAM_REASON_INVOKE_ROAM_FAIL:
4346 		return "Roam Invoke failed";
4347 	case WMI_ROAM_REASON_RSO_STATUS:
4348 		return "RSO status";
4349 	case WMI_ROAM_REASON_BTM:
4350 		return "BTM";
4351 	case WMI_ROAM_REASON_DEAUTH:
4352 		return "Deauth";
4353 	default:
4354 		return "Invalid";
4355 	}
4356 
4357 	return "Invalid";
4358 }
4359 
4360 /**
4361  * wma_roam_event_callback() - roam event callback
4362  * @handle: wma handle
4363  * @event_buf: event buffer
4364  * @len: buffer length
4365  *
4366  * Handler for all events from roam engine in firmware
4367  *
4368  * Return: 0 for success or error code
4369  */
4370 int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf,
4371 				   uint32_t len)
4372 {
4373 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
4374 	WMI_ROAM_EVENTID_param_tlvs *param_buf;
4375 	wmi_roam_event_fixed_param *wmi_event;
4376 	struct roam_offload_synch_ind *roam_synch_data;
4377 	uint8_t *frame = NULL;
4378 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
4379 	struct qdf_mac_addr bssid;
4380 #endif
4381 
4382 	param_buf = (WMI_ROAM_EVENTID_param_tlvs *) event_buf;
4383 	if (!param_buf) {
4384 		wma_err("Invalid roam event buffer");
4385 		return -EINVAL;
4386 	}
4387 
4388 	wmi_event = param_buf->fixed_param;
4389 	if (wmi_event->vdev_id >= wma_handle->max_bssid) {
4390 		wma_err("Invalid vdev id from firmware");
4391 		return -EINVAL;
4392 	}
4393 	wlan_roam_debug_log(wmi_event->vdev_id, DEBUG_ROAM_EVENT,
4394 			    DEBUG_INVALID_PEER_ID, NULL, NULL,
4395 			    wmi_event->reason,
4396 			    (wmi_event->reason == WMI_ROAM_REASON_INVALID) ?
4397 				wmi_event->notif : wmi_event->rssi);
4398 
4399 	DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD,
4400 		wmi_event->vdev_id, QDF_TRACE_DEFAULT_PDEV_ID,
4401 		QDF_PROTO_TYPE_EVENT, QDF_ROAM_EVENTID));
4402 
4403 	wma_debug("FW_ROAM_EVT: Reason:%s[%d], Notif %x for vdevid %x, rssi %d",
4404 		  wma_get_roam_event_reason_string(wmi_event->reason),
4405 		  wmi_event->reason,
4406 		  wmi_event->notif, wmi_event->vdev_id, wmi_event->rssi);
4407 
4408 	switch (wmi_event->reason) {
4409 	case WMI_ROAM_REASON_BTM:
4410 		/*
4411 		 * This event is received from firmware if firmware is unable to
4412 		 * find candidate AP after roam scan and BTM request from AP
4413 		 * has disassoc imminent bit set.
4414 		 */
4415 		wma_debug("Kickout due to btm request");
4416 		wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BTM,
4417 				      wmi_event->vdev_id, NULL);
4418 		wma_handle_disconnect_reason(wma_handle, wmi_event->vdev_id,
4419 				HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT);
4420 		break;
4421 	case WMI_ROAM_REASON_BMISS:
4422 		/*
4423 		 * WMI_ROAM_REASON_BMISS can get called in soft IRQ context, so
4424 		 * avoid using CSR/PE structure directly
4425 		 */
4426 		wma_debug("Beacon Miss for vdevid %x", wmi_event->vdev_id);
4427 		wma_beacon_miss_handler(wma_handle, wmi_event->vdev_id,
4428 					wmi_event->rssi);
4429 		wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BMISS,
4430 						wmi_event->vdev_id, NULL);
4431 		break;
4432 	case WMI_ROAM_REASON_BETTER_AP:
4433 		/*
4434 		 * WMI_ROAM_REASON_BETTER_AP can get called in soft IRQ context,
4435 		 * so avoid using CSR/PE structure directly.
4436 		 */
4437 		wma_debug("Better AP found for vdevid %x, rssi %d",
4438 			 wmi_event->vdev_id, wmi_event->rssi);
4439 		mlme_set_roam_reason_better_ap(
4440 			wma_handle->interfaces[wmi_event->vdev_id].vdev, false);
4441 		wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id);
4442 		break;
4443 	case WMI_ROAM_REASON_SUITABLE_AP:
4444 		/*
4445 		 * WMI_ROAM_REASON_SUITABLE_AP can get called in soft IRQ
4446 		 * context, so avoid using CSR/PE structure directly.
4447 		 */
4448 		mlme_set_roam_reason_better_ap(
4449 			wma_handle->interfaces[wmi_event->vdev_id].vdev, true);
4450 		mlme_set_hb_ap_rssi(
4451 			wma_handle->interfaces[wmi_event->vdev_id].vdev,
4452 			wmi_event->rssi);
4453 		wma_debug("Bmiss scan AP found for vdevid %x, rssi %d",
4454 			 wmi_event->vdev_id, wmi_event->rssi);
4455 		wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id);
4456 		break;
4457 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
4458 	case WMI_ROAM_REASON_HO_FAILED:
4459 		/*
4460 		 * WMI_ROAM_REASON_HO_FAILED can get called in soft IRQ context,
4461 		 * so avoid using CSR/PE structure directly.
4462 		 */
4463 		wma_err("LFR3:Hand-Off Failed for vdevid %x",
4464 			 wmi_event->vdev_id);
4465 		bssid.bytes[0] = wmi_event->notif_params >> 0 & 0xFF;
4466 		bssid.bytes[1] = wmi_event->notif_params >> 8 & 0xFF;
4467 		bssid.bytes[2] = wmi_event->notif_params >> 16 & 0xFF;
4468 		bssid.bytes[3] = wmi_event->notif_params >> 24 & 0xFF;
4469 		bssid.bytes[4] = wmi_event->notif_params1 >> 0 & 0xFF;
4470 		bssid.bytes[5] = wmi_event->notif_params1 >> 8 & 0xFF;
4471 		wma_debug("mac addr to avoid "QDF_MAC_ADDR_FMT,
4472 			  QDF_MAC_ADDR_REF(bssid.bytes));
4473 		wma_handle_hw_mode_transition(wma_handle, param_buf);
4474 #ifdef FEATURE_CM_ENABLE
4475 		cm_fw_ho_fail_req(wma_handle->psoc, wmi_event->vdev_id, bssid);
4476 #else
4477 		wma_roam_ho_fail_handler(wma_handle, wmi_event->vdev_id, bssid);
4478 #endif
4479 		lim_sae_auth_cleanup_retry(wma_handle->mac_context,
4480 					   wmi_event->vdev_id);
4481 		break;
4482 	case WMI_ROAM_REASON_INVALID:
4483 		wma_invalid_roam_reason_handler(wma_handle, wmi_event->vdev_id,
4484 						wmi_event->notif);
4485 		break;
4486 #endif
4487 	case WMI_ROAM_REASON_RSO_STATUS:
4488 		wma_rso_cmd_status_event_handler(wmi_event);
4489 		break;
4490 	case WMI_ROAM_REASON_INVOKE_ROAM_FAIL:
4491 		wma_handle_hw_mode_transition(wma_handle, param_buf);
4492 		roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data));
4493 		if (!roam_synch_data)
4494 			return -ENOMEM;
4495 
4496 		lim_sae_auth_cleanup_retry(wma_handle->mac_context,
4497 					   wmi_event->vdev_id);
4498 		roam_synch_data->roamed_vdev_id = wmi_event->vdev_id;
4499 #ifdef FEATURE_CM_ENABLE
4500 		cm_fw_roam_invoke_fail(wma_handle->psoc, wmi_event->vdev_id);
4501 #else
4502 		wma_handle->csr_roam_synch_cb(wma_handle->mac_context,
4503 					      roam_synch_data, NULL,
4504 					      SIR_ROAMING_INVOKE_FAIL);
4505 #endif
4506 		wlan_cm_update_roam_states(wma_handle->psoc, wmi_event->vdev_id,
4507 					   wmi_event->notif_params,
4508 					   ROAM_INVOKE_FAIL_REASON);
4509 
4510 		qdf_mem_free(roam_synch_data);
4511 		break;
4512 	case WMI_ROAM_REASON_DEAUTH:
4513 		wma_debug("Received disconnect roam event reason:%d",
4514 			 wmi_event->notif_params);
4515 		if (wmi_event->notif_params1)
4516 			frame = param_buf->deauth_disassoc_frame;
4517 		wma_handle->pe_disconnect_cb(wma_handle->mac_context,
4518 					     wmi_event->vdev_id,
4519 					     frame, wmi_event->notif_params1,
4520 					     wmi_event->notif_params);
4521 		roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data));
4522 		if (!roam_synch_data)
4523 			return -ENOMEM;
4524 
4525 		roam_synch_data->roamed_vdev_id = wmi_event->vdev_id;
4526 #ifndef FEATURE_CM_ENABLE
4527 		wma_handle->csr_roam_synch_cb(
4528 				wma_handle->mac_context,
4529 				roam_synch_data, NULL, SIR_ROAMING_DEAUTH);
4530 #endif
4531 		qdf_mem_free(roam_synch_data);
4532 		break;
4533 	default:
4534 		wma_debug("Unhandled Roam Event %x for vdevid %x",
4535 			 wmi_event->reason, wmi_event->vdev_id);
4536 		break;
4537 	}
4538 	return 0;
4539 }
4540 
4541 #ifdef FEATURE_LFR_SUBNET_DETECTION
4542 QDF_STATUS wma_set_gateway_params(tp_wma_handle wma,
4543 				  struct gateway_update_req_param *req)
4544 {
4545 	if (wma_validate_handle(wma))
4546 		return QDF_STATUS_E_INVAL;
4547 
4548 	return wmi_unified_set_gateway_params_cmd(wma->wmi_handle, req);
4549 }
4550 #endif /* FEATURE_LFR_SUBNET_DETECTION */
4551 
4552 /**
4553  * wma_ht40_stop_obss_scan() - ht40 obss stop scan
4554  * @wma: WMA handel
4555  * @vdev_id: vdev identifier
4556  *
4557  * Return: Return QDF_STATUS, otherwise appropriate failure code
4558  */
4559 QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma, int32_t vdev_id)
4560 {
4561 	QDF_STATUS status;
4562 	wmi_buf_t buf;
4563 	wmi_obss_scan_disable_cmd_fixed_param *cmd;
4564 	int len = sizeof(*cmd);
4565 
4566 	buf = wmi_buf_alloc(wma->wmi_handle, len);
4567 	if (!buf)
4568 		return QDF_STATUS_E_NOMEM;
4569 
4570 	wma_debug("cmd %x vdev_id %d", WMI_OBSS_SCAN_DISABLE_CMDID, vdev_id);
4571 
4572 	cmd = (wmi_obss_scan_disable_cmd_fixed_param *) wmi_buf_data(buf);
4573 	WMITLV_SET_HDR(&cmd->tlv_header,
4574 		WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param,
4575 		WMITLV_GET_STRUCT_TLVLEN(
4576 			wmi_obss_scan_disable_cmd_fixed_param));
4577 
4578 	cmd->vdev_id = vdev_id;
4579 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
4580 				      WMI_OBSS_SCAN_DISABLE_CMDID);
4581 	if (QDF_IS_STATUS_ERROR(status))
4582 		wmi_buf_free(buf);
4583 
4584 	return status;
4585 }
4586 
4587 /**
4588  * wma_send_ht40_obss_scanind() - ht40 obss start scan indication
4589  * @wma: WMA handel
4590  * @req: start scan request
4591  *
4592  * Return: Return QDF_STATUS, otherwise appropriate failure code
4593  */
4594 QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma,
4595 				struct obss_ht40_scanind *req)
4596 {
4597 	QDF_STATUS status;
4598 	wmi_buf_t buf;
4599 	wmi_obss_scan_enable_cmd_fixed_param *cmd;
4600 	int len = 0;
4601 	uint8_t *buf_ptr, i;
4602 	uint8_t *channel_list;
4603 	uint32_t *chan_freq_list;
4604 
4605 	len += sizeof(wmi_obss_scan_enable_cmd_fixed_param);
4606 
4607 	len += WMI_TLV_HDR_SIZE;
4608 	len += qdf_roundup(sizeof(uint8_t) * req->channel_count,
4609 				sizeof(uint32_t));
4610 
4611 	len += WMI_TLV_HDR_SIZE;
4612 	len += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t));
4613 
4614 	/* length calculation for chan_freqs */
4615 	len += WMI_TLV_HDR_SIZE;
4616 	len += sizeof(uint32_t) * req->channel_count;
4617 
4618 	wma_debug("cmdlen %d vdev_id %d channel count %d iefield_len %d",
4619 		 len, req->bss_id, req->channel_count, req->iefield_len);
4620 
4621 	wma_debug("scantype %d active_time %d passive %d Obss interval %d",
4622 		 req->scan_type, req->obss_active_dwelltime,
4623 		 req->obss_passive_dwelltime,
4624 		 req->obss_width_trigger_interval);
4625 
4626 	buf = wmi_buf_alloc(wma->wmi_handle, len);
4627 	if (!buf)
4628 		return QDF_STATUS_E_NOMEM;
4629 
4630 	cmd = (wmi_obss_scan_enable_cmd_fixed_param *) wmi_buf_data(buf);
4631 	WMITLV_SET_HDR(&cmd->tlv_header,
4632 		WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param,
4633 		WMITLV_GET_STRUCT_TLVLEN(wmi_obss_scan_enable_cmd_fixed_param));
4634 
4635 	buf_ptr = (uint8_t *) cmd;
4636 
4637 	cmd->vdev_id = req->bss_id;
4638 	cmd->scan_type = req->scan_type;
4639 	cmd->obss_scan_active_dwell =
4640 		req->obss_active_dwelltime;
4641 	cmd->obss_scan_passive_dwell =
4642 		req->obss_passive_dwelltime;
4643 	cmd->bss_channel_width_trigger_scan_interval =
4644 		req->obss_width_trigger_interval;
4645 	cmd->bss_width_channel_transition_delay_factor =
4646 		req->bsswidth_ch_trans_delay;
4647 	cmd->obss_scan_active_total_per_channel =
4648 		req->obss_active_total_per_channel;
4649 	cmd->obss_scan_passive_total_per_channel =
4650 		req->obss_passive_total_per_channel;
4651 	cmd->obss_scan_activity_threshold =
4652 		req->obss_activity_threshold;
4653 
4654 	cmd->channel_len = req->channel_count;
4655 	cmd->forty_mhz_intolerant =  req->fortymhz_intolerent;
4656 	cmd->current_operating_class = req->current_operatingclass;
4657 	cmd->ie_len = req->iefield_len;
4658 
4659 	buf_ptr += sizeof(wmi_obss_scan_enable_cmd_fixed_param);
4660 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
4661 		qdf_roundup(req->channel_count, sizeof(uint32_t)));
4662 
4663 	buf_ptr += WMI_TLV_HDR_SIZE;
4664 	channel_list = (uint8_t *) buf_ptr;
4665 
4666 	for (i = 0; i < req->channel_count; i++) {
4667 		channel_list[i] =
4668 		  wlan_reg_freq_to_chan(wma->pdev, req->chan_freq_list[i]);
4669 		wma_nofl_debug("Ch[%d]: %d ", i, channel_list[i]);
4670 	}
4671 
4672 	buf_ptr += qdf_roundup(sizeof(uint8_t) * req->channel_count,
4673 				sizeof(uint32_t));
4674 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
4675 			qdf_roundup(1, sizeof(uint32_t)));
4676 	buf_ptr += WMI_TLV_HDR_SIZE;
4677 
4678 	buf_ptr += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t));
4679 
4680 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
4681 		       sizeof(uint32_t) * req->channel_count);
4682 	buf_ptr += WMI_TLV_HDR_SIZE;
4683 
4684 	chan_freq_list = (uint32_t *)buf_ptr;
4685 	for (i = 0; i < req->channel_count; i++) {
4686 		chan_freq_list[i] = req->chan_freq_list[i];
4687 		wma_nofl_debug("freq[%u]: %u ", i, chan_freq_list[i]);
4688 	}
4689 
4690 	buf_ptr += sizeof(uint32_t) * req->channel_count;
4691 
4692 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
4693 				      WMI_OBSS_SCAN_ENABLE_CMDID);
4694 	if (QDF_IS_STATUS_ERROR(status))
4695 		wmi_buf_free(buf);
4696 
4697 	return status;
4698 }
4699 
4700 static enum blm_reject_ap_reason wma_get_reject_reason(uint32_t reason)
4701 {
4702 	switch(reason) {
4703 	case WMI_BL_REASON_NUD_FAILURE:
4704 		return REASON_NUD_FAILURE;
4705 	case WMI_BL_REASON_STA_KICKOUT:
4706 		return REASON_STA_KICKOUT;
4707 	case WMI_BL_REASON_ROAM_HO_FAILURE:
4708 		return REASON_ROAM_HO_FAILURE;
4709 	case WMI_BL_REASON_ASSOC_REJECT_POOR_RSSI:
4710 		return REASON_ASSOC_REJECT_POOR_RSSI;
4711 	case WMI_BL_REASON_ASSOC_REJECT_OCE:
4712 		return REASON_ASSOC_REJECT_OCE;
4713 	case WMI_BL_REASON_USERSPACE_BL:
4714 		return REASON_USERSPACE_BL;
4715 	case WMI_BL_REASON_USERSPACE_AVOID_LIST:
4716 		return REASON_USERSPACE_AVOID_LIST;
4717 	case WMI_BL_REASON_BTM_DIASSOC_IMMINENT:
4718 		return REASON_BTM_DISASSOC_IMMINENT;
4719 	case WMI_BL_REASON_BTM_BSS_TERMINATION:
4720 		return REASON_BTM_BSS_TERMINATION;
4721 	case WMI_BL_REASON_BTM_MBO_RETRY:
4722 		return REASON_BTM_MBO_RETRY;
4723 	case WMI_BL_REASON_REASSOC_RSSI_REJECT:
4724 		return REASON_REASSOC_RSSI_REJECT;
4725 	case WMI_BL_REASON_REASSOC_NO_MORE_STAS:
4726 		return REASON_REASSOC_NO_MORE_STAS;
4727 	default:
4728 		return REASON_UNKNOWN;
4729 	}
4730 }
4731 
4732 int wma_handle_btm_blacklist_event(void *handle, uint8_t *cmd_param_info,
4733 				   uint32_t len)
4734 {
4735 	tp_wma_handle wma = (tp_wma_handle) handle;
4736 	WMI_ROAM_BLACKLIST_EVENTID_param_tlvs *param_buf;
4737 	wmi_roam_blacklist_event_fixed_param *resp_event;
4738 	wmi_roam_blacklist_with_timeout_tlv_param *src_list;
4739 	struct roam_blacklist_event *dst_list;
4740 	struct roam_blacklist_timeout *roam_blacklist;
4741 	uint32_t num_entries, i;
4742 
4743 	param_buf = (WMI_ROAM_BLACKLIST_EVENTID_param_tlvs *)cmd_param_info;
4744 	if (!param_buf) {
4745 		wma_err("Invalid event buffer");
4746 		return -EINVAL;
4747 	}
4748 
4749 	resp_event = param_buf->fixed_param;
4750 	if (!resp_event) {
4751 		wma_err("received null event data from target");
4752 		return -EINVAL;
4753 	}
4754 
4755 	if (resp_event->vdev_id >= wma->max_bssid) {
4756 		wma_err("received invalid vdev_id %d", resp_event->vdev_id);
4757 		return -EINVAL;
4758 	}
4759 
4760 	num_entries = param_buf->num_blacklist_with_timeout;
4761 	if (num_entries == 0) {
4762 		/* no aps to blacklist just return*/
4763 		wma_err("No APs in blacklist received");
4764 		return 0;
4765 	}
4766 
4767 	if (num_entries > MAX_RSSI_AVOID_BSSID_LIST) {
4768 		wma_err("num blacklist entries:%d exceeds maximum value",
4769 			num_entries);
4770 		return -EINVAL;
4771 	}
4772 
4773 	src_list = param_buf->blacklist_with_timeout;
4774 	if (len < (sizeof(*resp_event) + (num_entries * sizeof(*src_list)))) {
4775 		wma_err("Invalid length:%d", len);
4776 		return -EINVAL;
4777 	}
4778 
4779 	dst_list = qdf_mem_malloc(sizeof(struct roam_blacklist_event) +
4780 				 (sizeof(struct roam_blacklist_timeout) *
4781 				 num_entries));
4782 	if (!dst_list)
4783 		return -ENOMEM;
4784 
4785 	roam_blacklist = &dst_list->roam_blacklist[0];
4786 	for (i = 0; i < num_entries; i++) {
4787 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_list->bssid,
4788 					   roam_blacklist->bssid.bytes);
4789 		roam_blacklist->timeout = src_list->timeout;
4790 		roam_blacklist->received_time = src_list->timestamp;
4791 		roam_blacklist->original_timeout = src_list->original_timeout;
4792 		roam_blacklist->reject_reason =
4793 				wma_get_reject_reason(src_list->reason);
4794 		roam_blacklist->source = src_list->source;
4795 		roam_blacklist++;
4796 		src_list++;
4797 	}
4798 
4799 	dst_list->num_entries = num_entries;
4800 	wma_send_msg(wma, WMA_ROAM_BLACKLIST_MSG, (void *)dst_list, 0);
4801 	return 0;
4802 }
4803 
4804 #if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_FIPS)
4805 void wma_register_pmkid_req_event_handler(tp_wma_handle wma_handle)
4806 {
4807 	if (wma_validate_handle(wma_handle))
4808 		return;
4809 
4810 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
4811 					   wmi_roam_pmkid_request_event_id,
4812 					   wma_roam_pmkid_request_event_handler,
4813 					   WMA_RX_SERIALIZER_CTX);
4814 }
4815 
4816 int wma_roam_pmkid_request_event_handler(void *handle, uint8_t *event,
4817 					 uint32_t len)
4818 {
4819 	WMI_ROAM_PMKID_REQUEST_EVENTID_param_tlvs *param_buf;
4820 	wmi_roam_pmkid_request_event_fixed_param *roam_pmkid_req_ev;
4821 	wmi_roam_pmkid_request_tlv_param *src_list;
4822 	tp_wma_handle wma = (tp_wma_handle)handle;
4823 	struct roam_pmkid_req_event *dst_list;
4824 	struct qdf_mac_addr *roam_bsslist;
4825 	uint32_t num_entries, i;
4826 	QDF_STATUS status;
4827 
4828 	if (!event) {
4829 		wma_err("received null event from target");
4830 		return -EINVAL;
4831 	}
4832 
4833 	param_buf = (WMI_ROAM_PMKID_REQUEST_EVENTID_param_tlvs *)event;
4834 	if (!param_buf) {
4835 		wma_err("received null buf from target");
4836 		return -EINVAL;
4837 	}
4838 
4839 	roam_pmkid_req_ev = param_buf->fixed_param;
4840 	if (!roam_pmkid_req_ev) {
4841 		wma_err("received null event data from target");
4842 		return -EINVAL;
4843 	}
4844 
4845 	if (roam_pmkid_req_ev->vdev_id >= wma->max_bssid) {
4846 		wma_err("received invalid vdev_id %d", roam_pmkid_req_ev->vdev_id);
4847 		return -EINVAL;
4848 	}
4849 
4850 	num_entries = param_buf->num_pmkid_request;
4851 	if (num_entries > MAX_RSSI_AVOID_BSSID_LIST) {
4852 		wma_err("num bssid entries:%d exceeds maximum value",
4853 			num_entries);
4854 		return -EINVAL;
4855 	}
4856 
4857 	src_list = param_buf->pmkid_request;
4858 	if (len < (sizeof(*roam_pmkid_req_ev) +
4859 		(num_entries * sizeof(*src_list)))) {
4860 		wma_err("Invalid length: %d", len);
4861 		return -EINVAL;
4862 	}
4863 
4864 	dst_list = qdf_mem_malloc(sizeof(struct roam_pmkid_req_event) +
4865 				 (sizeof(struct qdf_mac_addr) * num_entries));
4866 	if (!dst_list)
4867 		return -ENOMEM;
4868 
4869 	for (i = 0; i < num_entries; i++) {
4870 		roam_bsslist = &dst_list->ap_bssid[i];
4871 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_list->bssid,
4872 					   roam_bsslist->bytes);
4873 		if (qdf_is_macaddr_zero(roam_bsslist) ||
4874 		    qdf_is_macaddr_broadcast(roam_bsslist) ||
4875 		    qdf_is_macaddr_group(roam_bsslist)) {
4876 			wma_err("Invalid bssid");
4877 			qdf_mem_free(dst_list);
4878 			return -EINVAL;
4879 		}
4880 		wma_debug("Received pmkid fallback for bssid: "QDF_MAC_ADDR_FMT" vdev_id:%d",
4881 			  QDF_MAC_ADDR_REF(roam_bsslist->bytes),
4882 			 roam_pmkid_req_ev->vdev_id);
4883 		src_list++;
4884 	}
4885 	dst_list->num_entries = num_entries;
4886 
4887 	status = cm_roam_pmkid_req_ind(wma->psoc, roam_pmkid_req_ev->vdev_id,
4888 				       dst_list);
4889 	if (QDF_IS_STATUS_ERROR(status)) {
4890 		wma_err("Pmkid request failed");
4891 		qdf_mem_free(dst_list);
4892 		return -EINVAL;
4893 	}
4894 
4895 	qdf_mem_free(dst_list);
4896 	return 0;
4897 }
4898 #endif
4899