xref: /wlan-dirver/qcacld-3.0/core/mac/src/pe/lim/lim_api.c (revision e686af65b6176b5b659333daaad8e170b9ef09bc)
1 /*
2  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * This file lim_api.cc contains the functions that are
22  * exported by LIM to other modules.
23  *
24  * Author:        Chandra Modumudi
25  * Date:          02/11/02
26  * History:-
27  * Date           Modified by    Modification Information
28  * --------------------------------------------------------------------
29  *
30  */
31 #include "cds_api.h"
32 #include "wni_cfg.h"
33 #include "wni_api.h"
34 #include "sir_common.h"
35 #include "sir_debug.h"
36 
37 #include "sch_api.h"
38 #include "utils_api.h"
39 #include "lim_api.h"
40 #include "lim_global.h"
41 #include "lim_types.h"
42 #include "lim_utils.h"
43 #include "lim_assoc_utils.h"
44 #include "lim_prop_exts_utils.h"
45 #include "lim_ser_des_utils.h"
46 #include "lim_admit_control.h"
47 #include "lim_send_sme_rsp_messages.h"
48 #include "lim_security_utils.h"
49 #include "wmm_apsd.h"
50 #include "lim_trace.h"
51 #include "lim_ft_defs.h"
52 #include "lim_session.h"
53 #include "wma_types.h"
54 #include "wlan_crypto_global_api.h"
55 #include "wlan_crypto_def_i.h"
56 
57 #include "rrm_api.h"
58 
59 #include <lim_ft.h>
60 #include "qdf_types.h"
61 #include "cds_packet.h"
62 #include "cds_utils.h"
63 #include "sys_startup.h"
64 #include "cds_api.h"
65 #include "wlan_policy_mgr_api.h"
66 #include "nan_datapath.h"
67 #include "wma.h"
68 #include "wlan_mgmt_txrx_utils_api.h"
69 #include "wlan_objmgr_psoc_obj.h"
70 #include "os_if_nan.h"
71 #include <wlan_scan_ucfg_api.h>
72 #include <wlan_scan_public_structs.h>
73 #include <wlan_p2p_ucfg_api.h>
74 #include "wlan_utility.h"
75 #include <wlan_tdls_cfg_api.h>
76 #include "cfg_ucfg_api.h"
77 #include "wlan_mlme_public_struct.h"
78 #include "wlan_mlme_twt_api.h"
79 #include "wlan_scan_utils_api.h"
80 #include <qdf_hang_event_notifier.h>
81 #include <qdf_notifier.h>
82 #include "wlan_pkt_capture_ucfg_api.h"
83 #include <lim_mlo.h>
84 #include "wlan_mlo_mgr_roam.h"
85 #include "utils_mlo.h"
86 #include "wlan_mlo_mgr_sta.h"
87 #include "wlan_mlo_mgr_peer.h"
88 #include <wlan_twt_api.h>
89 #include "wlan_tdls_api.h"
90 #include "wlan_mlo_mgr_link_switch.h"
91 #include "wlan_cm_api.h"
92 
93 struct pe_hang_event_fixed_param {
94 	uint16_t tlv_header;
95 	uint8_t vdev_id;
96 	uint8_t limmlmstate;
97 	uint8_t limprevmlmstate;
98 	uint8_t limsmestate;
99 	uint8_t limprevsmestate;
100 } qdf_packed;
101 
102 static void __lim_init_bss_vars(struct mac_context *mac)
103 {
104 	qdf_mem_zero((void *)mac->lim.gpSession,
105 		    sizeof(*mac->lim.gpSession) * mac->lim.maxBssId);
106 }
107 
108 static void __lim_init_stats_vars(struct mac_context *mac)
109 {
110 	/* / Variable to keep track of number of currently associated STAs */
111 	mac->lim.gLimNumOfAniSTAs = 0; /* count of ANI peers */
112 
113 	qdf_mem_zero(mac->lim.gLimHeartBeatApMac[0],
114 			sizeof(tSirMacAddr));
115 	qdf_mem_zero(mac->lim.gLimHeartBeatApMac[1],
116 			sizeof(tSirMacAddr));
117 	mac->lim.gLimHeartBeatApMacIndex = 0;
118 }
119 
120 static void __lim_init_states(struct mac_context *mac)
121 {
122 	/* Counts Heartbeat failures */
123 	mac->lim.gLimHBfailureCntInLinkEstState = 0;
124 	mac->lim.gLimProbeFailureAfterHBfailedCnt = 0;
125 	mac->lim.gLimHBfailureCntInOtherStates = 0;
126 	mac->lim.gLimRspReqd = 0;
127 	mac->lim.gLimPrevSmeState = eLIM_SME_OFFLINE_STATE;
128 
129 	/* / MLM State visible across all Sirius modules */
130 	MTRACE(mac_trace
131 		       (mac, TRACE_CODE_MLM_STATE, NO_SESSION, eLIM_MLM_IDLE_STATE));
132 	mac->lim.gLimMlmState = eLIM_MLM_IDLE_STATE;
133 
134 	/* / Previous MLM State */
135 	mac->lim.gLimPrevMlmState = eLIM_MLM_OFFLINE_STATE;
136 
137 	/**
138 	 * Initialize state to eLIM_SME_OFFLINE_STATE
139 	 */
140 	mac->lim.gLimSmeState = eLIM_SME_OFFLINE_STATE;
141 
142 	/**
143 	 * By default assume 'unknown' role. This will be updated
144 	 * when SME_START_BSS_REQ is received.
145 	 */
146 
147 	qdf_mem_zero(&mac->lim.gLimNoShortParams, sizeof(tLimNoShortParams));
148 	qdf_mem_zero(&mac->lim.gLimNoShortSlotParams,
149 		    sizeof(tLimNoShortSlotParams));
150 
151 	mac->lim.gLimPhyMode = 0;
152 }
153 
154 static void __lim_init_vars(struct mac_context *mac)
155 {
156 	/* Place holder for Measurement Req/Rsp/Ind related info */
157 
158 
159 	/* Deferred Queue Parameters */
160 	qdf_mem_zero(&mac->lim.gLimDeferredMsgQ, sizeof(tSirAddtsReq));
161 
162 	/* addts request if any - only one can be outstanding at any time */
163 	qdf_mem_zero(&mac->lim.gLimAddtsReq, sizeof(tSirAddtsReq));
164 	mac->lim.gLimAddtsSent = 0;
165 	mac->lim.gLimAddtsRspTimerCount = 0;
166 
167 	/* protection related config cache */
168 	qdf_mem_zero(&mac->lim.cfgProtection, sizeof(tCfgProtection));
169 	mac->lim.gLimProtectionControl = 0;
170 	SET_LIM_PROCESS_DEFD_MESGS(mac, true);
171 
172 	/* WMM Related Flag */
173 	mac->lim.gUapsdEnable = 0;
174 
175 	/* QoS-AC Downgrade: Initially, no AC is admitted */
176 	mac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] = 0;
177 	mac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] = 0;
178 
179 	/* dialogue token List head/tail for Action frames request sent. */
180 	mac->lim.pDialogueTokenHead = NULL;
181 	mac->lim.pDialogueTokenTail = NULL;
182 
183 	qdf_mem_zero(&mac->lim.tspecInfo,
184 		    sizeof(tLimTspecInfo) * LIM_NUM_TSPEC_MAX);
185 
186 	/* admission control policy information */
187 	qdf_mem_zero(&mac->lim.admitPolicyInfo, sizeof(tLimAdmitPolicyInfo));
188 }
189 
190 static void __lim_init_assoc_vars(struct mac_context *mac)
191 {
192 	mac->lim.gLimIbssStaLimit = 0;
193 	/* Place holder for current authentication request */
194 	/* being handled */
195 	mac->lim.gpLimMlmAuthReq = NULL;
196 
197 	/* / MAC level Pre-authentication related globals */
198 	mac->lim.gLimPreAuthChannelNumber = 0;
199 	mac->lim.gLimPreAuthType = eSIR_OPEN_SYSTEM;
200 	qdf_mem_zero(&mac->lim.gLimPreAuthPeerAddr, sizeof(tSirMacAddr));
201 	mac->lim.gLimNumPreAuthContexts = 0;
202 	qdf_mem_zero(&mac->lim.gLimPreAuthTimerTable, sizeof(tLimPreAuthTable));
203 
204 	/* Place holder for Pre-authentication node list */
205 	mac->lim.pLimPreAuthList = NULL;
206 
207 	/* One cache for each overlap and associated case. */
208 	qdf_mem_zero(mac->lim.protStaOverlapCache,
209 		    sizeof(tCacheParams) * LIM_PROT_STA_OVERLAP_CACHE_SIZE);
210 	qdf_mem_zero(mac->lim.protStaCache,
211 		    sizeof(tCacheParams) * LIM_PROT_STA_CACHE_SIZE);
212 
213 	mac->lim.pe_session = NULL;
214 	mac->lim.reAssocRetryAttempt = 0;
215 
216 }
217 
218 static void __lim_init_ht_vars(struct mac_context *mac)
219 {
220 	mac->lim.htCapabilityPresentInBeacon = 0;
221 	mac->lim.gHTGreenfield = 0;
222 	mac->lim.gHTShortGI40Mhz = 0;
223 	mac->lim.gHTShortGI20Mhz = 0;
224 	mac->lim.gHTMaxAmsduLength = 0;
225 	mac->lim.gHTDsssCckRate40MHzSupport = 0;
226 	mac->lim.gHTPSMPSupport = 0;
227 	mac->lim.gHTLsigTXOPProtection = 0;
228 	mac->lim.gHTMIMOPSState = eSIR_HT_MIMO_PS_STATIC;
229 	mac->lim.gHTAMpduDensity = 0;
230 
231 	mac->lim.gMaxAmsduSizeEnabled = false;
232 	mac->lim.gHTMaxRxAMpduFactor = 0;
233 	mac->lim.gHTServiceIntervalGranularity = 0;
234 	mac->lim.gHTControlledAccessOnly = 0;
235 	mac->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE;
236 	mac->lim.gHTPCOActive = 0;
237 
238 	mac->lim.gHTPCOPhase = 0;
239 	mac->lim.gHTSecondaryBeacon = 0;
240 	mac->lim.gHTDualCTSProtection = 0;
241 	mac->lim.gHTSTBCBasicMCS = 0;
242 }
243 
244 static QDF_STATUS __lim_init_config(struct mac_context *mac)
245 {
246 	struct mlme_ht_capabilities_info *ht_cap_info;
247 #ifdef FEATURE_WLAN_TDLS
248 	QDF_STATUS status;
249 	uint32_t val1;
250 	bool valb;
251 #endif
252 
253 	/* Read all the CFGs here that were updated before pe_start is called */
254 	/* All these CFG READS/WRITES are only allowed in init, at start when there is no session
255 	 * and they will be used throughout when there is no session
256 	 */
257 	mac->lim.gLimIbssStaLimit = mac->mlme_cfg->sap_cfg.assoc_sta_limit;
258 	ht_cap_info = &mac->mlme_cfg->ht_caps.ht_cap_info;
259 
260 	/* channel bonding mode could be set to anything from 0 to 4(Titan had these */
261 	/* modes But for Taurus we have only two modes: enable(>0) or disable(=0) */
262 	ht_cap_info->supported_channel_width_set =
263 			mac->mlme_cfg->feature_flags.channel_bonding_mode ?
264 			WNI_CFG_CHANNEL_BONDING_MODE_ENABLE :
265 			WNI_CFG_CHANNEL_BONDING_MODE_DISABLE;
266 
267 	mac->mlme_cfg->ht_caps.info_field_1.recommended_tx_width_set =
268 		ht_cap_info->supported_channel_width_set;
269 
270 	if (!mac->mlme_cfg->timeouts.heart_beat_threshold) {
271 		mac->sys.gSysEnableLinkMonitorMode = 0;
272 	} else {
273 		/* No need to activate the timer during init time. */
274 		mac->sys.gSysEnableLinkMonitorMode = 1;
275 	}
276 
277 	/* WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA - not needed */
278 
279 	/* This was initially done after resume notification from HAL. Now, DAL is
280 	   started before PE so this can be done here */
281 	handle_ht_capabilityand_ht_info(mac, NULL);
282 #ifdef FEATURE_WLAN_TDLS
283 	status = cfg_tdls_get_buffer_sta_enable(mac->psoc, &valb);
284 	if (QDF_STATUS_SUCCESS != status) {
285 		pe_err("cfg get LimTDLSBufStaEnabled failed");
286 		return QDF_STATUS_E_FAILURE;
287 	}
288 	mac->lim.gLimTDLSBufStaEnabled = (uint8_t)valb;
289 
290 	status = cfg_tdls_get_uapsd_mask(mac->psoc, &val1);
291 	if (QDF_STATUS_SUCCESS != status) {
292 		pe_err("cfg get LimTDLSUapsdMask failed");
293 		return QDF_STATUS_E_FAILURE;
294 	}
295 	mac->lim.gLimTDLSUapsdMask = (uint8_t)val1;
296 
297 	status = cfg_tdls_get_off_channel_enable(mac->psoc, &valb);
298 	if (QDF_STATUS_SUCCESS != status) {
299 		pe_err("cfg get LimTDLSUapsdMask failed");
300 		return QDF_STATUS_E_FAILURE;
301 	}
302 	mac->lim.gLimTDLSOffChannelEnabled = (uint8_t)valb;
303 
304 	status = cfg_tdls_get_wmm_mode_enable(mac->psoc, &valb);
305 	if (QDF_STATUS_SUCCESS != status) {
306 		pe_err("cfg get LimTDLSWmmMode failed");
307 		return QDF_STATUS_E_FAILURE;
308 	}
309 	mac->lim.gLimTDLSWmmMode = (uint8_t)valb;
310 #endif
311 
312 	return QDF_STATUS_SUCCESS;
313 }
314 
315 /*
316    lim_start
317    This function is to replace the __lim_process_sme_start_req since there is no
318    eWNI_SME_START_REQ post to PE.
319  */
320 QDF_STATUS lim_start(struct mac_context *mac)
321 {
322 	QDF_STATUS retCode = QDF_STATUS_SUCCESS;
323 
324 	pe_debug("enter");
325 
326 	if (mac->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) {
327 		mac->lim.gLimSmeState = eLIM_SME_IDLE_STATE;
328 
329 		MTRACE(mac_trace
330 			       (mac, TRACE_CODE_SME_STATE, NO_SESSION,
331 			       mac->lim.gLimSmeState));
332 
333 		/* Initialize MLM state machine */
334 		if (QDF_STATUS_SUCCESS != lim_init_mlm(mac)) {
335 			pe_err("Init MLM failed");
336 			return QDF_STATUS_E_FAILURE;
337 		}
338 	} else {
339 		/**
340 		 * Should not have received eWNI_SME_START_REQ in states
341 		 * other than OFFLINE. Return response to host and
342 		 * log error
343 		 */
344 		pe_warn("Invalid SME state: %X",
345 			mac->lim.gLimSmeState);
346 		retCode = QDF_STATUS_E_FAILURE;
347 	}
348 
349 	mac->lim.req_id =
350 		wlan_scan_register_requester(mac->psoc,
351 					     "LIM",
352 					     lim_process_rx_scan_handler,
353 					     mac);
354 	return retCode;
355 }
356 
357 /**
358  * lim_initialize()
359  *
360  ***FUNCTION:
361  * This function is called from LIM thread entry function.
362  * LIM related global data structures are initialized in this function.
363  *
364  ***LOGIC:
365  * NA
366  *
367  ***ASSUMPTIONS:
368  * NA
369  *
370  ***NOTE:
371  * NA
372  *
373  * @param  mac - Pointer to global MAC structure
374  * @return None
375  */
376 
377 QDF_STATUS lim_initialize(struct mac_context *mac)
378 {
379 	QDF_STATUS status = QDF_STATUS_SUCCESS;
380 
381 	mac->lim.tdls_frm_session_id = NO_SESSION;
382 	mac->lim.deferredMsgCnt = 0;
383 	mac->lim.retry_packet_cnt = 0;
384 	mac->lim.deauthMsgCnt = 0;
385 	mac->lim.disassocMsgCnt = 0;
386 
387 	__lim_init_assoc_vars(mac);
388 	__lim_init_vars(mac);
389 	__lim_init_states(mac);
390 	__lim_init_stats_vars(mac);
391 	__lim_init_bss_vars(mac);
392 	__lim_init_ht_vars(mac);
393 
394 	rrm_initialize(mac);
395 
396 	if (QDF_IS_STATUS_ERROR(qdf_mutex_create(
397 					&mac->lim.lim_frame_register_lock))) {
398 		pe_err("lim lock init failed!");
399 		return QDF_STATUS_E_FAILURE;
400 	}
401 
402 	qdf_list_create(&mac->lim.gLimMgmtFrameRegistratinQueue, 0);
403 
404 	/* initialize the TSPEC admission control table. */
405 	/* Note that this was initially done after resume notification from HAL. */
406 	/* Now, DAL is started before PE so this can be done here */
407 	lim_admit_control_init(mac);
408 	return status;
409 
410 } /*** end lim_initialize() ***/
411 
412 /**
413  * lim_cleanup()
414  *
415  ***FUNCTION:
416  * This function is called upon reset or persona change
417  * to cleanup LIM state
418  *
419  ***LOGIC:
420  * NA
421  *
422  ***ASSUMPTIONS:
423  * NA
424  *
425  ***NOTE:
426  * NA
427  *
428  * @param  mac - Pointer to Global MAC structure
429  * @return None
430  */
431 
432 void lim_cleanup(struct mac_context *mac)
433 {
434 	uint8_t i;
435 	qdf_list_node_t *lst_node;
436 
437 	/*
438 	 * Before destroying the list making sure all the nodes have been
439 	 * deleted
440 	 */
441 	while (qdf_list_remove_front(
442 			&mac->lim.gLimMgmtFrameRegistratinQueue,
443 			&lst_node) == QDF_STATUS_SUCCESS) {
444 		qdf_mem_free(lst_node);
445 	}
446 	qdf_list_destroy(&mac->lim.gLimMgmtFrameRegistratinQueue);
447 	qdf_mutex_destroy(&mac->lim.lim_frame_register_lock);
448 
449 	pe_deregister_mgmt_rx_frm_callback(mac);
450 
451 	/* free up preAuth table */
452 	if (mac->lim.gLimPreAuthTimerTable.pTable) {
453 		for (i = 0; i < mac->lim.gLimPreAuthTimerTable.numEntry; i++)
454 			qdf_mem_free(mac->lim.gLimPreAuthTimerTable.pTable[i]);
455 		qdf_mem_free(mac->lim.gLimPreAuthTimerTable.pTable);
456 		mac->lim.gLimPreAuthTimerTable.pTable = NULL;
457 		mac->lim.gLimPreAuthTimerTable.numEntry = 0;
458 	}
459 
460 	if (mac->lim.pDialogueTokenHead) {
461 		lim_delete_dialogue_token_list(mac);
462 	}
463 
464 	if (mac->lim.pDialogueTokenTail) {
465 		qdf_mem_free(mac->lim.pDialogueTokenTail);
466 		mac->lim.pDialogueTokenTail = NULL;
467 	}
468 
469 	if (mac->lim.gpLimMlmAuthReq) {
470 		qdf_mem_free(mac->lim.gpLimMlmAuthReq);
471 		mac->lim.gpLimMlmAuthReq = NULL;
472 	}
473 
474 	if (mac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq) {
475 		qdf_mem_free(mac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq);
476 		mac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = NULL;
477 	}
478 
479 	if (mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq) {
480 		qdf_mem_free(mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq);
481 		mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL;
482 	}
483 
484 	/* Now, finally reset the deferred message queue pointers */
485 	lim_reset_deferred_msg_q(mac);
486 
487 	for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++)
488 		rrm_cleanup(mac, i);
489 
490 	lim_ft_cleanup_all_ft_sessions(mac);
491 
492 	wlan_scan_unregister_requester(mac->psoc, mac->lim.req_id);
493 } /*** end lim_cleanup() ***/
494 
495 #ifdef WLAN_FEATURE_MEMDUMP_ENABLE
496 /**
497  * lim_state_info_dump() - print state information of lim layer
498  * @buf: buffer pointer
499  * @size: size of buffer to be filled
500  *
501  * This function is used to print state information of lim layer
502  *
503  * Return: None
504  */
505 static void lim_state_info_dump(char **buf_ptr, uint16_t *size)
506 {
507 	struct mac_context *mac;
508 	uint16_t len = 0;
509 	char *buf = *buf_ptr;
510 
511 	mac = cds_get_context(QDF_MODULE_ID_PE);
512 	if (!mac) {
513 		return;
514 	}
515 
516 	pe_debug("size of buffer: %d", *size);
517 
518 	len += qdf_scnprintf(buf + len, *size - len,
519 		"\n SmeState: %d", mac->lim.gLimSmeState);
520 	len += qdf_scnprintf(buf + len, *size - len,
521 		"\n PrevSmeState: %d", mac->lim.gLimPrevSmeState);
522 	len += qdf_scnprintf(buf + len, *size - len,
523 		"\n MlmState: %d", mac->lim.gLimMlmState);
524 	len += qdf_scnprintf(buf + len, *size - len,
525 		"\n PrevMlmState: %d", mac->lim.gLimPrevMlmState);
526 	len += qdf_scnprintf(buf + len, *size - len,
527 		"\n ProcessDefdMsgs: %d", mac->lim.gLimProcessDefdMsgs);
528 
529 	*size -= len;
530 	*buf_ptr += len;
531 }
532 
533 /**
534  * lim_register_debug_callback() - registration function for lim layer
535  * to print lim state information
536  *
537  * Return: None
538  */
539 static void lim_register_debug_callback(void)
540 {
541 	qdf_register_debug_callback(QDF_MODULE_ID_PE, &lim_state_info_dump);
542 }
543 #else /* WLAN_FEATURE_MEMDUMP_ENABLE */
544 static void lim_register_debug_callback(void)
545 {
546 }
547 #endif /* WLAN_FEATURE_MEMDUMP_ENABLE */
548 
549 #ifdef WLAN_FEATURE_NAN
550 static void lim_nan_register_callbacks(struct mac_context *mac_ctx)
551 {
552 	struct nan_callbacks cb_obj = {0};
553 
554 	cb_obj.add_ndi_peer = lim_add_ndi_peer_converged;
555 	cb_obj.ndp_delete_peers = lim_ndp_delete_peers_converged;
556 	cb_obj.delete_peers_by_addr = lim_ndp_delete_peers_by_addr_converged;
557 
558 	ucfg_nan_register_lim_callbacks(mac_ctx->psoc, &cb_obj);
559 }
560 #else
561 static inline void lim_nan_register_callbacks(struct mac_context *mac_ctx)
562 {
563 }
564 #endif
565 
566 void lim_stop_pmfcomeback_timer(struct pe_session *session)
567 {
568 	if (session->opmode != QDF_STA_MODE)
569 		return;
570 
571 	qdf_mc_timer_stop(&session->pmf_retry_timer);
572 	session->pmf_retry_timer_info.retried = false;
573 }
574 
575 /*
576  * pe_shutdown_notifier_cb - Shutdown notifier callback
577  * @ctx: Pointer to Global MAC structure
578  *
579  * Return: None
580  */
581 static void pe_shutdown_notifier_cb(void *ctx)
582 {
583 	struct mac_context *mac_ctx = (struct mac_context *)ctx;
584 	struct pe_session *session;
585 	uint8_t i;
586 
587 	lim_deactivate_timers(mac_ctx);
588 	for (i = 0; i < mac_ctx->lim.maxBssId; i++) {
589 		session = &mac_ctx->lim.gpSession[i];
590 		if (session->valid == true) {
591 			if (LIM_IS_AP_ROLE(session))
592 				qdf_mc_timer_stop(&session->
593 						 protection_fields_reset_timer);
594 			lim_stop_pmfcomeback_timer(session);
595 		}
596 	}
597 }
598 
599 bool is_mgmt_protected(uint32_t vdev_id,
600 		       const uint8_t *peer_mac_addr)
601 {
602 	uint16_t aid;
603 	tpDphHashNode sta_ds;
604 	struct pe_session *session;
605 	bool protected = false;
606 	struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
607 
608 	if (!mac_ctx)
609 		return false;
610 
611 	session = pe_find_session_by_vdev_id(mac_ctx, vdev_id);
612 	if (!session) {
613 		/* couldn't find session */
614 		pe_err("Session not found for vdev_id: %d", vdev_id);
615 		return false;
616 	}
617 
618 	sta_ds = dph_lookup_hash_entry(mac_ctx, (uint8_t *)peer_mac_addr, &aid,
619 				       &session->dph.dphHashTable);
620 	if (sta_ds) {
621 		/* rmfenabled will be set at the time of addbss.
622 		 * but sometimes EAP auth fails and keys are not
623 		 * installed then if we send any management frame
624 		 * like deauth/disassoc with this bit set then
625 		 * firmware crashes. so check for keys are
626 		 * installed or not also before setting the bit
627 		 */
628 		if (sta_ds->rmfEnabled && sta_ds->is_key_installed)
629 			protected = true;
630 	}
631 
632 	return protected;
633 }
634 
635 static void p2p_register_callbacks(struct mac_context *mac_ctx)
636 {
637 	struct p2p_protocol_callbacks p2p_cb = {0};
638 
639 	p2p_cb.is_mgmt_protected = is_mgmt_protected;
640 	ucfg_p2p_register_callbacks(mac_ctx->psoc, &p2p_cb);
641 }
642 
643 /*
644  * lim_register_sap_bcn_callback(): Register a callback with scan module for SAP
645  * @mac_ctx: pointer to the global mac context
646  *
647  * Registers the function lim_handle_sap_beacon as callback with the Scan
648  * module to handle beacon frames for SAP sessions
649  *
650  * Return: QDF Status
651  */
652 static QDF_STATUS lim_register_sap_bcn_callback(struct mac_context *mac_ctx)
653 {
654 	QDF_STATUS status;
655 
656 	status = ucfg_scan_register_bcn_cb(mac_ctx->psoc,
657 			lim_handle_sap_beacon,
658 			SCAN_CB_TYPE_UPDATE_BCN);
659 	if (!QDF_IS_STATUS_SUCCESS(status)) {
660 		pe_err("failed with status code %08d [x%08x]",
661 			status, status);
662 	}
663 
664 	return status;
665 }
666 
667 /*
668  * lim_unregister_sap_bcn_callback(): Unregister the callback with scan module
669  * @mac_ctx: pointer to the global mac context
670  *
671  * Unregisters the callback registered with the Scan
672  * module to handle beacon frames for SAP sessions
673  *
674  * Return: QDF Status
675  */
676 static QDF_STATUS lim_unregister_sap_bcn_callback(struct mac_context *mac_ctx)
677 {
678 	QDF_STATUS status;
679 
680 	status = ucfg_scan_register_bcn_cb(mac_ctx->psoc,
681 			NULL, SCAN_CB_TYPE_UPDATE_BCN);
682 	if (!QDF_IS_STATUS_SUCCESS(status)) {
683 		pe_err("failed with status code %08d [x%08x]",
684 			status, status);
685 	}
686 
687 	return status;
688 }
689 
690 /*
691  * lim_register_scan_mbssid_callback(): Register callback with scan module
692  * @mac_ctx: pointer to the global mac context
693  *
694  * Registers the function lim_register_scan_mbssid_callback as callback
695  * with the Scan module to handle generated frames by MBSSID IE
696  *
697  * Return: QDF Status
698  */
699 static QDF_STATUS
700 lim_register_scan_mbssid_callback(struct mac_context *mac_ctx)
701 {
702 	QDF_STATUS status;
703 
704 	status = wlan_scan_register_mbssid_cb(mac_ctx->psoc,
705 					      lim_handle_frame_genby_mbssid);
706 	if (!QDF_IS_STATUS_SUCCESS(status)) {
707 		pe_err("failed with status code %08d [x%08x]",
708 		       status, status);
709 	}
710 
711 	return status;
712 }
713 
714 /*
715  * lim_unregister_scan_mbssid_callback(): Unregister callback with scan module
716  * @mac_ctx: pointer to the global mac context
717  *
718  * Unregisters the callback registered with the Scan module to handle
719  * generated frames by MBSSID IE
720  *
721  * Return: QDF Status
722  */
723 static QDF_STATUS
724 lim_unregister_scan_mbssid_callback(struct mac_context *mac_ctx)
725 {
726 	QDF_STATUS status;
727 
728 	status = wlan_scan_register_mbssid_cb(mac_ctx->psoc, NULL);
729 	if (!QDF_IS_STATUS_SUCCESS(status)) {
730 		pe_err("failed with status code %08d [x%08x]",
731 		       status, status);
732 	}
733 
734 	return status;
735 }
736 
737 static void lim_register_policy_mgr_callback(struct wlan_objmgr_psoc *psoc)
738 {
739 	struct policy_mgr_conc_cbacks conc_cbacks;
740 
741 	qdf_mem_zero(&conc_cbacks, sizeof(conc_cbacks));
742 	conc_cbacks.connection_info_update = lim_send_conc_params_update;
743 
744 	if (QDF_STATUS_SUCCESS != policy_mgr_register_conc_cb(psoc,
745 							      &conc_cbacks)) {
746 		pe_err("failed to register policy manager callbacks");
747 	}
748 }
749 
750 static int pe_hang_event_notifier_call(struct notifier_block *block,
751 				       unsigned long state,
752 				       void *data)
753 {
754 	qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block,
755 							notif_block);
756 	struct mac_context *mac;
757 	struct pe_session *session;
758 	struct qdf_notifer_data *pe_hang_data = data;
759 	uint8_t *pe_data;
760 	uint8_t i;
761 	struct pe_hang_event_fixed_param *cmd;
762 	size_t size;
763 
764 	if (!data)
765 		return NOTIFY_STOP_MASK;
766 
767 	mac = notif_block->priv_data;
768 	if (!mac)
769 		return NOTIFY_STOP_MASK;
770 
771 	size = sizeof(*cmd);
772 	for (i = 0; i < mac->lim.maxBssId; i++) {
773 		session = &mac->lim.gpSession[i];
774 		if (!session->valid)
775 			continue;
776 		if (pe_hang_data->offset + size > QDF_WLAN_HANG_FW_OFFSET)
777 			return NOTIFY_STOP_MASK;
778 
779 		pe_data = (pe_hang_data->hang_data + pe_hang_data->offset);
780 		cmd = (struct pe_hang_event_fixed_param *)pe_data;
781 		QDF_HANG_EVT_SET_HDR(&cmd->tlv_header, HANG_EVT_TAG_LEGACY_MAC,
782 				     QDF_HANG_GET_STRUCT_TLVLEN(*cmd));
783 		cmd->vdev_id = session->vdev_id;
784 		cmd->limmlmstate = session->limMlmState;
785 		cmd->limprevmlmstate = session->limPrevMlmState;
786 		cmd->limsmestate = session->limSmeState;
787 		cmd->limprevsmestate = session->limPrevSmeState;
788 		pe_hang_data->offset += size;
789 	}
790 
791 	return NOTIFY_OK;
792 }
793 
794 static qdf_notif_block pe_hang_event_notifier = {
795 	.notif_block.notifier_call = pe_hang_event_notifier_call,
796 };
797 
798 /** -------------------------------------------------------------
799    \fn pe_open
800    \brief will be called in Open sequence from mac_open
801    \param   struct mac_context *mac
802    \param   tHalOpenParameters *pHalOpenParam
803    \return  QDF_STATUS
804    -------------------------------------------------------------*/
805 
806 QDF_STATUS pe_open(struct mac_context *mac, struct cds_config_info *cds_cfg)
807 {
808 	QDF_STATUS status = QDF_STATUS_SUCCESS;
809 
810 	if (QDF_DRIVER_TYPE_MFG == cds_cfg->driver_type)
811 		return QDF_STATUS_SUCCESS;
812 
813 	mac->lim.maxBssId = cds_cfg->max_bssid;
814 	mac->lim.maxStation = cds_cfg->max_station;
815 	mac->lim.max_sta_of_pe_session =
816 			(cds_cfg->max_station > SIR_SAP_MAX_NUM_PEERS) ?
817 				SIR_SAP_MAX_NUM_PEERS : cds_cfg->max_station;
818 	qdf_spinlock_create(&mac->sys.bbt_mgmt_lock);
819 
820 	if ((mac->lim.maxBssId == 0) || (mac->lim.maxStation == 0)) {
821 		pe_err("max number of Bssid or Stations cannot be zero!");
822 		return QDF_STATUS_E_FAILURE;
823 	}
824 
825 	if (!QDF_IS_STATUS_SUCCESS(pe_allocate_dph_node_array_buffer())) {
826 		pe_err("g_dph_node_array memory allocate failed!");
827 		return QDF_STATUS_E_NOMEM;
828 	}
829 
830 	mac->lim.lim_timers.gpLimCnfWaitTimer =
831 		qdf_mem_malloc(sizeof(TX_TIMER) * (mac->lim.maxStation + 1));
832 	if (!mac->lim.lim_timers.gpLimCnfWaitTimer) {
833 		status = QDF_STATUS_E_NOMEM;
834 		goto pe_open_timer_fail;
835 	}
836 
837 	mac->lim.gpSession =
838 		qdf_mem_common_alloc(sizeof(struct pe_session) * mac->lim.maxBssId);
839 	if (!mac->lim.gpSession) {
840 		status = QDF_STATUS_E_NOMEM;
841 		goto pe_open_psession_fail;
842 	}
843 
844 	status = lim_initialize(mac);
845 	if (QDF_STATUS_SUCCESS != status) {
846 		pe_err("lim_initialize failed!");
847 		status = QDF_STATUS_E_FAILURE;
848 		goto  pe_open_lock_fail;
849 	}
850 
851 	/*
852 	 * pe_open is successful by now, so it is right time to initialize
853 	 * MTRACE for PE module. if LIM_TRACE_RECORD is not defined in build
854 	 * file then nothing will be logged for PE module.
855 	 */
856 #ifdef LIM_TRACE_RECORD
857 	MTRACE(lim_trace_init(mac));
858 #endif
859 	lim_register_debug_callback();
860 	lim_nan_register_callbacks(mac);
861 	p2p_register_callbacks(mac);
862 	lim_register_scan_mbssid_callback(mac);
863 	lim_register_sap_bcn_callback(mac);
864 	wlan_reg_register_ctry_change_callback(
865 					mac->psoc,
866 					lim_update_tx_pwr_on_ctry_change_cb);
867 
868 	wlan_reg_register_is_chan_connected_callback(mac->psoc,
869 					lim_get_connected_chan_for_mode);
870 
871 	if (mac->mlme_cfg->edca_params.enable_edca_params)
872 		lim_register_policy_mgr_callback(mac->psoc);
873 
874 	if (!QDF_IS_STATUS_SUCCESS(
875 	    cds_shutdown_notifier_register(pe_shutdown_notifier_cb, mac))) {
876 		pe_err("Shutdown notifier register failed");
877 	}
878 
879 	pe_hang_event_notifier.priv_data = mac;
880 	qdf_hang_event_register_notifier(&pe_hang_event_notifier);
881 
882 	return status; /* status here will be QDF_STATUS_SUCCESS */
883 
884 pe_open_lock_fail:
885 	qdf_mem_common_free(mac->lim.gpSession);
886 	mac->lim.gpSession = NULL;
887 pe_open_psession_fail:
888 	qdf_mem_free(mac->lim.lim_timers.gpLimCnfWaitTimer);
889 	mac->lim.lim_timers.gpLimCnfWaitTimer = NULL;
890 pe_open_timer_fail:
891 	pe_free_dph_node_array_buffer();
892 
893 	return status;
894 }
895 
896 /** -------------------------------------------------------------
897    \fn pe_close
898    \brief will be called in close sequence from mac_close
899    \param   struct mac_context *mac
900    \return  QDF_STATUS
901    -------------------------------------------------------------*/
902 
903 QDF_STATUS pe_close(struct mac_context *mac)
904 {
905 	uint8_t i;
906 
907 	if (ANI_DRIVER_TYPE(mac) == QDF_DRIVER_TYPE_MFG)
908 		return QDF_STATUS_SUCCESS;
909 
910 	qdf_hang_event_unregister_notifier(&pe_hang_event_notifier);
911 	lim_cleanup(mac);
912 	lim_unregister_scan_mbssid_callback(mac);
913 	lim_unregister_sap_bcn_callback(mac);
914 	wlan_reg_unregister_ctry_change_callback(
915 					mac->psoc,
916 					lim_update_tx_pwr_on_ctry_change_cb);
917 
918 	wlan_reg_unregister_is_chan_connected_callback(mac->psoc,
919 					lim_get_connected_chan_for_mode);
920 
921 	if (mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq) {
922 		qdf_mem_free(mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq);
923 		mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL;
924 	}
925 
926 	qdf_spinlock_destroy(&mac->sys.bbt_mgmt_lock);
927 	for (i = 0; i < mac->lim.maxBssId; i++) {
928 		if (mac->lim.gpSession[i].valid == true)
929 			pe_delete_session(mac, &mac->lim.gpSession[i]);
930 	}
931 	qdf_mem_free(mac->lim.lim_timers.gpLimCnfWaitTimer);
932 	mac->lim.lim_timers.gpLimCnfWaitTimer = NULL;
933 
934 	qdf_mem_common_free(mac->lim.gpSession);
935 	mac->lim.gpSession = NULL;
936 
937 	pe_free_dph_node_array_buffer();
938 
939 	return QDF_STATUS_SUCCESS;
940 }
941 
942 /** -------------------------------------------------------------
943    \fn pe_start
944    \brief will be called in start sequence from mac_start
945    \param   struct mac_context *mac
946    \return QDF_STATUS_SUCCESS on success, other QDF_STATUS on error
947    -------------------------------------------------------------*/
948 
949 QDF_STATUS pe_start(struct mac_context *mac)
950 {
951 	QDF_STATUS status = QDF_STATUS_SUCCESS;
952 	status = lim_start(mac);
953 	if (QDF_STATUS_SUCCESS != status) {
954 		pe_err("lim_start failed!");
955 		return status;
956 	}
957 	/* Initialize the configurations needed by PE */
958 	if (QDF_STATUS_E_FAILURE == __lim_init_config(mac)) {
959 		pe_err("lim init config failed!");
960 		/* We need to undo everything in lim_start */
961 		lim_cleanup_mlm(mac);
962 		return QDF_STATUS_E_FAILURE;
963 	}
964 
965 	return status;
966 }
967 
968 /** -------------------------------------------------------------
969    \fn pe_stop
970    \brief will be called in stop sequence from mac_stop
971    \param   struct mac_context *mac
972    \return none
973    -------------------------------------------------------------*/
974 
975 void pe_stop(struct mac_context *mac)
976 {
977 	lim_cleanup_mlm(mac);
978 	pe_debug(" PE STOP: Set LIM state to eLIM_MLM_OFFLINE_STATE");
979 	SET_LIM_MLM_STATE(mac, eLIM_MLM_OFFLINE_STATE);
980 	return;
981 }
982 
983 static void pe_free_nested_messages(struct scheduler_msg *msg)
984 {
985 	switch (msg->type) {
986 	default:
987 		break;
988 	}
989 }
990 
991 /** -------------------------------------------------------------
992    \fn pe_free_msg
993    \brief Called by CDS scheduler (function cds_sched_flush_mc_mqs)
994  \      to free a given PE message on the TX and MC thread.
995  \      This happens when there are messages pending in the PE
996  \      queue when system is being stopped and reset.
997    \param   struct mac_context *mac
998    \param   struct scheduler_msg       pMsg
999    \return none
1000    -----------------------------------------------------------------*/
1001 void pe_free_msg(struct mac_context *mac, struct scheduler_msg *pMsg)
1002 {
1003 	if (pMsg) {
1004 		if (pMsg->bodyptr) {
1005 			if (SIR_BB_XPORT_MGMT_MSG == pMsg->type) {
1006 				cds_pkt_return_packet((cds_pkt_t *) pMsg->
1007 						      bodyptr);
1008 			} else {
1009 				pe_free_nested_messages(pMsg);
1010 				qdf_mem_free((void *)pMsg->bodyptr);
1011 			}
1012 		}
1013 		pMsg->bodyptr = 0;
1014 		pMsg->bodyval = 0;
1015 		pMsg->type = 0;
1016 	}
1017 	return;
1018 }
1019 
1020 QDF_STATUS lim_post_msg_api(struct mac_context *mac, struct scheduler_msg *msg)
1021 {
1022 	return scheduler_post_message(QDF_MODULE_ID_PE,
1023 				      QDF_MODULE_ID_PE,
1024 				      QDF_MODULE_ID_PE, msg);
1025 }
1026 
1027 QDF_STATUS lim_post_msg_high_priority(struct mac_context *mac,
1028 				      struct scheduler_msg *msg)
1029 {
1030 	return scheduler_post_msg_by_priority(QDF_MODULE_ID_PE,
1031 					       msg, true);
1032 }
1033 
1034 QDF_STATUS pe_mc_process_handler(struct scheduler_msg *msg)
1035 {
1036 	struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
1037 
1038 	if (!mac_ctx)
1039 		return QDF_STATUS_E_FAILURE;
1040 
1041 	if (ANI_DRIVER_TYPE(mac_ctx) == QDF_DRIVER_TYPE_MFG)
1042 		return QDF_STATUS_SUCCESS;
1043 
1044 	lim_message_processor(mac_ctx, msg);
1045 
1046 	return QDF_STATUS_SUCCESS;
1047 }
1048 
1049 /**
1050  * pe_drop_pending_rx_mgmt_frames: To drop pending RX mgmt frames
1051  * @mac_ctx: Pointer to global MAC structure
1052  * @hdr: Management header
1053  * @cds_pkt: Packet
1054  *
1055  * This function is used to drop RX pending mgmt frames if pe mgmt queue
1056  * reaches threshold
1057  *
1058  * Return: QDF_STATUS_SUCCESS on success or QDF_STATUS_E_FAILURE on failure
1059  */
1060 static QDF_STATUS pe_drop_pending_rx_mgmt_frames(struct mac_context *mac_ctx,
1061 				tpSirMacMgmtHdr hdr, cds_pkt_t *cds_pkt)
1062 {
1063 	qdf_spin_lock(&mac_ctx->sys.bbt_mgmt_lock);
1064 	if (mac_ctx->sys.sys_bbt_pending_mgmt_count >=
1065 	     MGMT_RX_PACKETS_THRESHOLD) {
1066 		qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock);
1067 		pe_debug("No.of pending RX management frames reaches to threshold, dropping management frames");
1068 		cds_pkt_return_packet(cds_pkt);
1069 		cds_pkt = NULL;
1070 		mac_ctx->rx_packet_drop_counter++;
1071 		return QDF_STATUS_E_FAILURE;
1072 	} else if (mac_ctx->sys.sys_bbt_pending_mgmt_count >
1073 		   (MGMT_RX_PACKETS_THRESHOLD / 2)) {
1074 		/* drop all probereq, proberesp and beacons */
1075 		if (hdr->fc.subType == SIR_MAC_MGMT_BEACON ||
1076 		    hdr->fc.subType == SIR_MAC_MGMT_PROBE_REQ ||
1077 		    hdr->fc.subType == SIR_MAC_MGMT_PROBE_RSP) {
1078 			qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock);
1079 			if (!(mac_ctx->rx_packet_drop_counter % 100))
1080 				pe_debug("No.of pending RX mgmt frames reaches 1/2 thresh, dropping frame subtype: %d rx_packet_drop_counter: %d",
1081 					hdr->fc.subType,
1082 					mac_ctx->rx_packet_drop_counter);
1083 			mac_ctx->rx_packet_drop_counter++;
1084 			cds_pkt_return_packet(cds_pkt);
1085 			cds_pkt = NULL;
1086 			return QDF_STATUS_E_FAILURE;
1087 		}
1088 	}
1089 	mac_ctx->sys.sys_bbt_pending_mgmt_count++;
1090 	qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock);
1091 	if (mac_ctx->sys.sys_bbt_pending_mgmt_count ==
1092 	    (MGMT_RX_PACKETS_THRESHOLD / 4)) {
1093 		if (!(mac_ctx->rx_packet_drop_counter % 100))
1094 			pe_debug("No.of pending RX management frames reaches to 1/4th of threshold, rx_packet_drop_counter: %d",
1095 				mac_ctx->rx_packet_drop_counter);
1096 			mac_ctx->rx_packet_drop_counter++;
1097 	}
1098 	return QDF_STATUS_SUCCESS;
1099 }
1100 
1101 /**
1102  * pe_is_ext_scan_bcn_probe_rsp - Check if the beacon or probe response
1103  * is from Ext or EPNO scan
1104  *
1105  * @hdr: pointer to the 802.11 header of the frame
1106  * @rx_pkt_info: pointer to the rx packet meta
1107  *
1108  * Checks if the beacon or probe response is from Ext Scan or EPNO scan
1109  *
1110  * Return: true or false
1111  */
1112 #ifdef FEATURE_WLAN_EXTSCAN
1113 static inline bool pe_is_ext_scan_bcn_probe_rsp(tpSirMacMgmtHdr hdr,
1114 				uint8_t *rx_pkt_info)
1115 {
1116 	if ((hdr->fc.subType == SIR_MAC_MGMT_BEACON ||
1117 	     hdr->fc.subType == SIR_MAC_MGMT_PROBE_RSP) &&
1118 	    (WMA_IS_EXTSCAN_SCAN_SRC(rx_pkt_info) ||
1119 	    WMA_IS_EPNO_SCAN_SRC(rx_pkt_info)))
1120 		return true;
1121 
1122 	return false;
1123 }
1124 #else
1125 static inline bool pe_is_ext_scan_bcn_probe_rsp(tpSirMacMgmtHdr hdr,
1126 				uint8_t *rx_pkt_info)
1127 {
1128 	return false;
1129 }
1130 #endif
1131 
1132 /**
1133  * pe_filter_drop_bcn_probe_frame - Apply filter on the received frame
1134  *
1135  * @mac_ctx: pointer to the global mac context
1136  * @hdr: pointer to the 802.11 header of the frame
1137  * @rx_pkt_info: pointer to the rx packet meta
1138  *
1139  * Applies the filter from global mac context on the received beacon/
1140  * probe response frame before posting it to the PE queue
1141  *
1142  * Return: true if frame is allowed, false if frame is to be dropped.
1143  */
1144 static bool pe_filter_bcn_probe_frame(struct mac_context *mac_ctx,
1145 					tpSirMacMgmtHdr hdr,
1146 					uint8_t *rx_pkt_info)
1147 {
1148 	uint8_t session_id;
1149 	struct mgmt_beacon_probe_filter *filter;
1150 
1151 	if (pe_is_ext_scan_bcn_probe_rsp(hdr, rx_pkt_info))
1152 		return true;
1153 
1154 	filter = &mac_ctx->bcn_filter;
1155 
1156 	/*
1157 	 * If any STA session exists and beacon source matches any of the
1158 	 * STA BSSIDs, allow the frame
1159 	 */
1160 	if (filter->num_sta_sessions) {
1161 		for (session_id = 0; session_id < WLAN_MAX_VDEVS;
1162 		     session_id++) {
1163 			if (sir_compare_mac_addr(filter->sta_bssid[session_id],
1164 			    hdr->bssId)) {
1165 				return true;
1166 			}
1167 		}
1168 	}
1169 
1170 	return false;
1171 }
1172 
1173 static QDF_STATUS pe_handle_probe_req_frames(struct mac_context *mac_ctx,
1174 					cds_pkt_t *pkt)
1175 {
1176 	QDF_STATUS status;
1177 	struct scheduler_msg msg = {0};
1178 	uint32_t scan_queue_size = 0;
1179 
1180 	/* Check if the probe request frame can be posted in the scan queue */
1181 	status = scheduler_get_queue_size(QDF_MODULE_ID_SCAN, &scan_queue_size);
1182 	if (!QDF_IS_STATUS_SUCCESS(status) ||
1183 	    scan_queue_size > MAX_BCN_PROBE_IN_SCAN_QUEUE) {
1184 		pe_debug_rl("Dropping probe req frame, queue size %d",
1185 			    scan_queue_size);
1186 		return QDF_STATUS_E_FAILURE;
1187 	}
1188 
1189 	/* Forward to MAC via mesg = SIR_BB_XPORT_MGMT_MSG */
1190 	msg.type = SIR_BB_XPORT_MGMT_MSG;
1191 	msg.bodyptr = pkt;
1192 	msg.bodyval = 0;
1193 	msg.callback = pe_mc_process_handler;
1194 
1195 	status = scheduler_post_message(QDF_MODULE_ID_PE,
1196 					QDF_MODULE_ID_PE,
1197 					QDF_MODULE_ID_SCAN, &msg);
1198 
1199 	return status;
1200 }
1201 
1202 /* --------------------------------------------------------------------------- */
1203 /**
1204  * pe_handle_mgmt_frame() - Process the Management frames from TXRX
1205  * @psoc: psoc context
1206  * @peer: peer
1207  * @buf: buffer
1208  * @mgmt_rx_params; rx event params
1209  * @frm_type: frame type
1210  *
1211  * This function handles the mgmt rx frame from mgmt txrx component and forms
1212  * a cds packet and schedule it in controller thread for further processing.
1213  *
1214  * Return: QDF_STATUS_SUCCESS - in case of success
1215  */
1216 static QDF_STATUS pe_handle_mgmt_frame(struct wlan_objmgr_psoc *psoc,
1217 			struct wlan_objmgr_peer *peer, qdf_nbuf_t buf,
1218 			struct mgmt_rx_event_params *mgmt_rx_params,
1219 			enum mgmt_frame_type frm_type)
1220 {
1221 	struct mac_context *mac;
1222 	tpSirMacMgmtHdr mHdr;
1223 	struct scheduler_msg msg = {0};
1224 	cds_pkt_t *pVosPkt;
1225 	QDF_STATUS qdf_status;
1226 	uint8_t *pRxPacketInfo;
1227 	int ret;
1228 
1229 	/* skip offload packets */
1230 	if ((ucfg_pkt_capture_get_mode(psoc) != PACKET_CAPTURE_MODE_DISABLE) &&
1231 	    mgmt_rx_params->status & WMI_RX_OFFLOAD_MON_MODE) {
1232 		qdf_nbuf_free(buf);
1233 		return QDF_STATUS_SUCCESS;
1234 	}
1235 
1236 	mac = cds_get_context(QDF_MODULE_ID_PE);
1237 	if (!mac) {
1238 		/* cannot log a failure without a valid mac */
1239 		qdf_nbuf_free(buf);
1240 		return QDF_STATUS_E_FAILURE;
1241 	}
1242 
1243 	if (mac->usr_cfg_disable_rsp_tx) {
1244 		pe_debug("Drop Rx pkt with user config");
1245 		qdf_nbuf_free(buf);
1246 		return QDF_STATUS_SUCCESS;
1247 	}
1248 	pVosPkt = qdf_mem_malloc_atomic(sizeof(*pVosPkt));
1249 	if (!pVosPkt) {
1250 		qdf_nbuf_free(buf);
1251 		return QDF_STATUS_E_NOMEM;
1252 	}
1253 
1254 	ret = wma_form_rx_packet(buf, mgmt_rx_params, pVosPkt);
1255 	if (ret) {
1256 		pe_debug_rl("Failed to fill cds packet from event buffer");
1257 		return QDF_STATUS_E_FAILURE;
1258 	}
1259 
1260 	qdf_status =
1261 		wma_ds_peek_rx_packet_info(pVosPkt, (void *)&pRxPacketInfo);
1262 
1263 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1264 		cds_pkt_return_packet(pVosPkt);
1265 		pVosPkt = NULL;
1266 		return QDF_STATUS_E_FAILURE;
1267 	}
1268 
1269 	/*
1270 	 * The MPDU header is now present at a certain "offset" in
1271 	 * the BD and is specified in the BD itself
1272 	 */
1273 
1274 	mHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
1275 
1276 	/*
1277 	 * Filter the beacon/probe response frames before posting it
1278 	 * on the PE queue
1279 	 */
1280 	if ((mHdr->fc.subType == SIR_MAC_MGMT_BEACON ||
1281 	    mHdr->fc.subType == SIR_MAC_MGMT_PROBE_RSP) &&
1282 	    !pe_filter_bcn_probe_frame(mac, mHdr, pRxPacketInfo)) {
1283 		cds_pkt_return_packet(pVosPkt);
1284 		pVosPkt = NULL;
1285 		return QDF_STATUS_SUCCESS;
1286 	}
1287 
1288 	/*
1289 	 * Post Probe Req frames to Scan queue and return
1290 	 */
1291 	if (mHdr->fc.subType == SIR_MAC_MGMT_PROBE_REQ) {
1292 		qdf_status = pe_handle_probe_req_frames(mac, pVosPkt);
1293 		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1294 			cds_pkt_return_packet(pVosPkt);
1295 			pVosPkt = NULL;
1296 		}
1297 		return qdf_status;
1298 	}
1299 
1300 	if (QDF_STATUS_SUCCESS !=
1301 	    pe_drop_pending_rx_mgmt_frames(mac, mHdr, pVosPkt))
1302 		return QDF_STATUS_E_FAILURE;
1303 
1304 	/* Forward to MAC via mesg = SIR_BB_XPORT_MGMT_MSG */
1305 	msg.type = SIR_BB_XPORT_MGMT_MSG;
1306 	msg.bodyptr = pVosPkt;
1307 	msg.bodyval = 0;
1308 
1309 	if (QDF_STATUS_SUCCESS != sys_bbt_process_message_core(mac,
1310 							 &msg,
1311 							 mHdr->fc.type,
1312 							 mHdr->fc.subType)) {
1313 		cds_pkt_return_packet(pVosPkt);
1314 		pVosPkt = NULL;
1315 		/*
1316 		 * Decrement sys_bbt_pending_mgmt_count if packet
1317 		 * is dropped before posting to LIM
1318 		 */
1319 		lim_decrement_pending_mgmt_count(mac);
1320 		return QDF_STATUS_E_FAILURE;
1321 	}
1322 
1323 	return QDF_STATUS_SUCCESS;
1324 }
1325 
1326 void pe_register_mgmt_rx_frm_callback(struct mac_context *mac_ctx)
1327 {
1328 	QDF_STATUS status;
1329 	struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info;
1330 
1331 	frm_cb_info.frm_type = MGMT_FRAME_TYPE_ALL;
1332 	frm_cb_info.mgmt_rx_cb = pe_handle_mgmt_frame;
1333 
1334 	status = wlan_mgmt_txrx_register_rx_cb(mac_ctx->psoc,
1335 					 WLAN_UMAC_COMP_MLME, &frm_cb_info, 1);
1336 	if (status != QDF_STATUS_SUCCESS)
1337 		pe_err("Registering the PE Handle with MGMT TXRX layer has failed");
1338 
1339 	wma_register_mgmt_frm_client();
1340 }
1341 
1342 void pe_deregister_mgmt_rx_frm_callback(struct mac_context *mac_ctx)
1343 {
1344 	QDF_STATUS status;
1345 	struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info;
1346 
1347 	frm_cb_info.frm_type = MGMT_FRAME_TYPE_ALL;
1348 	frm_cb_info.mgmt_rx_cb = pe_handle_mgmt_frame;
1349 
1350 	status = wlan_mgmt_txrx_deregister_rx_cb(mac_ctx->psoc,
1351 					 WLAN_UMAC_COMP_MLME, &frm_cb_info, 1);
1352 	if (status != QDF_STATUS_SUCCESS)
1353 		pe_err("Deregistering the PE Handle with MGMT TXRX layer has failed");
1354 
1355 	wma_de_register_mgmt_frm_client();
1356 }
1357 
1358 
1359 /**
1360  * pe_register_callbacks_with_wma() - register SME and PE callback functions to
1361  * WMA.
1362  * (function documentation in lim_api.h)
1363  */
1364 void pe_register_callbacks_with_wma(struct mac_context *mac,
1365 				    struct sme_ready_req *ready_req)
1366 {
1367 	QDF_STATUS status;
1368 
1369 	status = wma_register_roaming_callbacks(
1370 			ready_req->csr_roam_auth_event_handle_cb,
1371 			ready_req->pe_roam_synch_cb,
1372 			ready_req->pe_disconnect_cb,
1373 			ready_req->pe_roam_set_ie_cb);
1374 	if (status != QDF_STATUS_SUCCESS)
1375 		pe_err("Registering roaming callbacks with WMA failed");
1376 }
1377 
1378 void
1379 lim_received_hb_handler(struct mac_context *mac, uint32_t chan_freq,
1380 			struct pe_session *pe_session)
1381 {
1382 	if (chan_freq == 0 || chan_freq == pe_session->curr_op_freq)
1383 		pe_session->LimRxedBeaconCntDuringHB++;
1384 
1385 	pe_session->pmmOffloadInfo.bcnmiss = false;
1386 } /*** lim_init_wds_info_params() ***/
1387 
1388 /** -------------------------------------------------------------
1389    \fn lim_update_overlap_sta_param
1390    \brief Updates overlap cache and param data structure
1391    \param      struct mac_context *   mac
1392    \param      tSirMacAddr bssId
1393    \param      tpLimProtStaParams pStaParams
1394    \return      None
1395    -------------------------------------------------------------*/
1396 void
1397 lim_update_overlap_sta_param(struct mac_context *mac, tSirMacAddr bssId,
1398 			     tpLimProtStaParams pStaParams)
1399 {
1400 	int i;
1401 
1402 	if (!pStaParams->numSta) {
1403 		qdf_mem_copy(mac->lim.protStaOverlapCache[0].addr,
1404 			     bssId, sizeof(tSirMacAddr));
1405 		mac->lim.protStaOverlapCache[0].active = true;
1406 
1407 		pStaParams->numSta = 1;
1408 
1409 		return;
1410 	}
1411 
1412 	for (i = 0; i < LIM_PROT_STA_OVERLAP_CACHE_SIZE; i++) {
1413 		if (mac->lim.protStaOverlapCache[i].active) {
1414 			if (!qdf_mem_cmp
1415 				    (mac->lim.protStaOverlapCache[i].addr, bssId,
1416 				    sizeof(tSirMacAddr))) {
1417 				return;
1418 			}
1419 		} else
1420 			break;
1421 	}
1422 
1423 	if (i == LIM_PROT_STA_OVERLAP_CACHE_SIZE) {
1424 		pe_debug("Overlap cache is full");
1425 	} else {
1426 		qdf_mem_copy(mac->lim.protStaOverlapCache[i].addr,
1427 			     bssId, sizeof(tSirMacAddr));
1428 		mac->lim.protStaOverlapCache[i].active = true;
1429 
1430 		pStaParams->numSta++;
1431 	}
1432 }
1433 
1434 /**
1435  * lim_enc_type_matched() - matches security type of incoming beracon with
1436  * current
1437  * @mac_ctx      Pointer to Global MAC structure
1438  * @bcn          Pointer to parsed Beacon structure
1439  * @session      PE session entry
1440  *
1441  * This function matches security type of incoming beracon with current
1442  *
1443  * @return true if matched, false otherwise
1444  */
1445 static bool
1446 lim_enc_type_matched(struct mac_context *mac_ctx,
1447 		     tpSchBeaconStruct bcn,
1448 		     struct pe_session *session)
1449 {
1450 	if (!bcn || !session)
1451 		return false;
1452 
1453 	/*
1454 	 * This is handled by sending probe req due to IOT issues so
1455 	 * return TRUE
1456 	 */
1457 	if ((bcn->capabilityInfo.privacy) !=
1458 		SIR_MAC_GET_PRIVACY(session->limCurrentBssCaps)) {
1459 		pe_warn("Privacy bit miss match");
1460 		return true;
1461 	}
1462 
1463 	/* Open */
1464 	if ((bcn->capabilityInfo.privacy == 0) &&
1465 	    (session->encryptType == eSIR_ED_NONE))
1466 		return true;
1467 
1468 	/* WEP */
1469 	if ((bcn->capabilityInfo.privacy == 1) &&
1470 	    (bcn->wpaPresent == 0) && (bcn->rsnPresent == 0) &&
1471 	    ((session->encryptType == eSIR_ED_WEP40) ||
1472 		(session->encryptType == eSIR_ED_WEP104)
1473 #ifdef FEATURE_WLAN_WAPI
1474 		|| (session->encryptType == eSIR_ED_WPI)
1475 #endif
1476 	    ))
1477 		return true;
1478 
1479 	/* WPA OR RSN*/
1480 	if ((bcn->capabilityInfo.privacy == 1) &&
1481 	    ((bcn->wpaPresent == 1) || (bcn->rsnPresent == 1)) &&
1482 	    ((session->encryptType == eSIR_ED_TKIP) ||
1483 		(session->encryptType == eSIR_ED_CCMP) ||
1484 		(session->encryptType == eSIR_ED_GCMP) ||
1485 		(session->encryptType == eSIR_ED_GCMP_256) ||
1486 		(session->encryptType == eSIR_ED_AES_128_CMAC)))
1487 		return true;
1488 
1489 	/*
1490 	 * For HS2.0, RSN ie is not present
1491 	 * in beacon. Therefore no need to
1492 	 * check for security type in case
1493 	 * OSEN session.
1494 	 * For WPS registration session no need to detect
1495 	 * detect security mismatch as it won't match and
1496 	 * driver may end up sending probe request without
1497 	 * WPS IE during WPS registration process.
1498 	 */
1499 	if (session->isOSENConnection ||
1500 	   session->wps_registration)
1501 		return true;
1502 
1503 	pe_debug("AP:: Privacy %d WPA %d RSN %d, SELF:: Privacy %d Enc %d OSEN %d WPS %d",
1504 		 bcn->capabilityInfo.privacy, bcn->wpaPresent, bcn->rsnPresent,
1505 		 SIR_MAC_GET_PRIVACY(session->limCurrentBssCaps),
1506 		 session->encryptType, session->isOSENConnection,
1507 		 session->wps_registration);
1508 
1509 	return false;
1510 }
1511 
1512 void
1513 lim_detect_change_in_ap_capabilities(struct mac_context *mac,
1514 				     tpSirProbeRespBeacon pBeacon,
1515 				     struct pe_session *pe_session,
1516 				     bool is_bcn)
1517 {
1518 	uint8_t len;
1519 	uint32_t new_chan_freq;
1520 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1521 	bool security_caps_matched = true;
1522 	uint16_t ap_cap;
1523 
1524 	ap_cap = lim_get_u16((uint8_t *) &pBeacon->capabilityInfo);
1525 	new_chan_freq = pBeacon->chan_freq;
1526 
1527 	security_caps_matched = lim_enc_type_matched(mac, pBeacon,
1528 						     pe_session);
1529 	if ((false == pe_session->limSentCapsChangeNtf) &&
1530 	    (((!lim_is_null_ssid(&pBeacon->ssId)) &&
1531 	       lim_cmp_ssid(&pBeacon->ssId, pe_session)) ||
1532 	     ((SIR_MAC_GET_ESS(ap_cap) !=
1533 	       SIR_MAC_GET_ESS(pe_session->limCurrentBssCaps)) ||
1534 	      (SIR_MAC_GET_PRIVACY(ap_cap) !=
1535 	       SIR_MAC_GET_PRIVACY(pe_session->limCurrentBssCaps)) ||
1536 	      (SIR_MAC_GET_QOS(ap_cap) !=
1537 	       SIR_MAC_GET_QOS(pe_session->limCurrentBssCaps)) ||
1538 	      ((new_chan_freq != pe_session->curr_op_freq) &&
1539 		(new_chan_freq != 0)) ||
1540 	      (false == security_caps_matched)
1541 	     ))) {
1542 		if (!pe_session->fWaitForProbeRsp || is_bcn) {
1543 			/* If Beacon capabilities is not matching with the current capability,
1544 			 * then send unicast probe request to AP and take decision after
1545 			 * receiving probe response */
1546 			if (pe_session->fIgnoreCapsChange) {
1547 				pe_debug_rl("Ignore the Capability change as probe rsp Capability matched");
1548 				return;
1549 			}
1550 			pe_session->fWaitForProbeRsp = true;
1551 			pe_info(QDF_MAC_ADDR_FMT ": capabilities are not matching, sending directed probe request",
1552 				QDF_MAC_ADDR_REF(pe_session->bssId));
1553 			status =
1554 				lim_send_probe_req_mgmt_frame(
1555 					mac, &pe_session->ssId,
1556 					pe_session->bssId,
1557 					pe_session->curr_op_freq,
1558 					pe_session->self_mac_addr,
1559 					pe_session->dot11mode,
1560 					NULL, NULL);
1561 
1562 			if (QDF_STATUS_SUCCESS != status) {
1563 				pe_err("send ProbeReq failed");
1564 				pe_session->fWaitForProbeRsp = false;
1565 			}
1566 			return;
1567 		}
1568 		/**
1569 		 * BSS capabilities have changed.
1570 		 * Inform Roaming.
1571 		 */
1572 		len = sizeof(tSirMacCapabilityInfo) + sizeof(tSirMacAddr) + sizeof(uint8_t) + 3 * sizeof(uint8_t) + /* reserved fields */
1573 		      pBeacon->ssId.length + 1;
1574 
1575 		if (new_chan_freq != pe_session->curr_op_freq) {
1576 			pe_info(QDF_MAC_ADDR_FMT ": Channel freq Change from %d --> %d Ignoring beacon!",
1577 				QDF_MAC_ADDR_REF(pe_session->bssId),
1578 				pe_session->curr_op_freq, new_chan_freq);
1579 			return;
1580 		}
1581 
1582 		/**
1583 		 * When Cisco 1262 Enterprise APs are configured with WPA2-PSK with
1584 		 * AES+TKIP Pairwise ciphers and WEP-40 Group cipher, they do not set
1585 		 * the privacy bit in Beacons (wpa/rsnie is still present in beacons),
1586 		 * the privacy bit is set in Probe and association responses.
1587 		 * Due to this anomaly, we detect a change in
1588 		 * AP capabilities when we receive a beacon after association and
1589 		 * disconnect from the AP. The following check makes sure that we can
1590 		 * connect to such APs
1591 		 */
1592 		else if ((SIR_MAC_GET_PRIVACY(ap_cap) == 0) &&
1593 			 (pBeacon->rsnPresent || pBeacon->wpaPresent)) {
1594 			pe_info_rl(QDF_MAC_ADDR_FMT ": BSS Caps (Privacy) bit 0 in beacon, but WPA or RSN IE present, Ignore Beacon!",
1595 				   QDF_MAC_ADDR_REF(pe_session->bssId));
1596 			return;
1597 		}
1598 
1599 		pe_session->fIgnoreCapsChange = false;
1600 		pe_session->fWaitForProbeRsp = false;
1601 		pe_session->limSentCapsChangeNtf = true;
1602 		pe_info(QDF_MAC_ADDR_FMT ": initiate Disconnect due to cap mismatch!",
1603 			QDF_MAC_ADDR_REF(pe_session->bssId));
1604 		lim_send_deauth_mgmt_frame(mac, REASON_UNSPEC_FAILURE,
1605 					   pe_session->bssId, pe_session,
1606 					   false);
1607 		lim_tear_down_link_with_ap(mac, pe_session->peSessionId,
1608 					   REASON_UNSPEC_FAILURE,
1609 					   eLIM_HOST_DISASSOC);
1610 	} else if (pe_session->fWaitForProbeRsp) {
1611 		/* Only for probe response frames and matching capabilities the control
1612 		 * will come here. If beacon is with broadcast ssid then fWaitForProbeRsp
1613 		 * will be false, the control will not come here*/
1614 
1615 		pe_debug(QDF_MAC_ADDR_FMT ": capabilities in probe rsp are matching, so ignoring capability mismatch",
1616 			 QDF_MAC_ADDR_REF(pe_session->bssId));
1617 		pe_session->fIgnoreCapsChange = true;
1618 		pe_session->fWaitForProbeRsp = false;
1619 	}
1620 
1621 } /*** lim_detect_change_in_ap_capabilities() ***/
1622 
1623 /* --------------------------------------------------------------------- */
1624 /**
1625  * lim_update_short_slot
1626  *
1627  * FUNCTION:
1628  * Enable/Disable short slot
1629  *
1630  * LOGIC:
1631  *
1632  * ASSUMPTIONS:
1633  *
1634  * NOTE:
1635  *
1636  * @param enable        Flag to enable/disable short slot
1637  * @return None
1638  */
1639 
1640 QDF_STATUS lim_update_short_slot(struct mac_context *mac,
1641 				    tpSirProbeRespBeacon pBeacon,
1642 				    tpUpdateBeaconParams pBeaconParams,
1643 				    struct pe_session *pe_session)
1644 {
1645 
1646 	uint16_t ap_cap;
1647 	uint32_t nShortSlot;
1648 	uint32_t phyMode;
1649 
1650 	/* Check Admin mode first. If it is disabled just return */
1651 	if (!mac->mlme_cfg->feature_flags.enable_short_slot_time_11g)
1652 		return QDF_STATUS_SUCCESS;
1653 
1654 	/* Check for 11a mode or 11b mode. In both cases return since slot time is constant and cannot/should not change in beacon */
1655 	lim_get_phy_mode(mac, &phyMode, pe_session);
1656 	if ((phyMode == WNI_CFG_PHY_MODE_11A)
1657 	    || (phyMode == WNI_CFG_PHY_MODE_11B))
1658 		return QDF_STATUS_SUCCESS;
1659 
1660 	ap_cap = lim_get_u16((uint8_t *) &pBeacon->capabilityInfo);
1661 
1662 	/*  Earlier implementation: determine the appropriate short slot mode based on AP advertised modes */
1663 	/* when erp is present, apply short slot always unless, prot=on  && shortSlot=off */
1664 	/* if no erp present, use short slot based on current ap caps */
1665 
1666 	/* Issue with earlier implementation : Cisco 1231 BG has shortSlot = 0, erpIEPresent and useProtection = 0 (Case4); */
1667 
1668 	/* Resolution : always use the shortSlot setting the capability info to decide slot time. */
1669 	/* The difference between the earlier implementation and the new one is only Case4. */
1670 	/*
1671 	   ERP IE Present  |   useProtection   |   shortSlot   =   QC STA Short Slot
1672 	   Case1        1                                   1                       1                       1           //AP should not advertise this combination.
1673 	   Case2        1                                   1                       0                       0
1674 	   Case3        1                                   0                       1                       1
1675 	   Case4        1                                   0                       0                       0
1676 	   Case5        0                                   1                       1                       1
1677 	   Case6        0                                   1                       0                       0
1678 	   Case7        0                                   0                       1                       1
1679 	   Case8        0                                   0                       0                       0
1680 	 */
1681 	nShortSlot = SIR_MAC_GET_SHORT_SLOT_TIME(ap_cap);
1682 
1683 	if (nShortSlot != pe_session->shortSlotTimeSupported) {
1684 		/* Short slot time capability of AP has changed. Adopt to it. */
1685 		pe_debug("Shortslot capability of AP changed: %d",
1686 			       nShortSlot);
1687 			((tpSirMacCapabilityInfo) & pe_session->
1688 			limCurrentBssCaps)->shortSlotTime = (uint16_t) nShortSlot;
1689 		pe_session->shortSlotTimeSupported = nShortSlot;
1690 		pBeaconParams->fShortSlotTime = (uint8_t) nShortSlot;
1691 		pBeaconParams->paramChangeBitmap |=
1692 			PARAM_SHORT_SLOT_TIME_CHANGED;
1693 	}
1694 	return QDF_STATUS_SUCCESS;
1695 }
1696 
1697 
1698 void lim_send_heart_beat_timeout_ind(struct mac_context *mac,
1699 				     struct pe_session *pe_session)
1700 {
1701 	QDF_STATUS status;
1702 	struct scheduler_msg msg = {0};
1703 
1704 	/* Prepare and post message to LIM Message Queue */
1705 	msg.type = (uint16_t) SIR_LIM_HEART_BEAT_TIMEOUT;
1706 	msg.bodyptr = pe_session;
1707 	msg.bodyval = 0;
1708 	pe_err("Heartbeat failure from Fw");
1709 
1710 	status = lim_post_msg_api(mac, &msg);
1711 
1712 	if (status != QDF_STATUS_SUCCESS) {
1713 		pe_err("posting message: %X to LIM failed, reason: %d",
1714 			msg.type, status);
1715 	}
1716 }
1717 
1718 void lim_ps_offload_handle_missed_beacon_ind(struct mac_context *mac,
1719 					     struct scheduler_msg *msg)
1720 {
1721 	struct missed_beacon_ind *missed_beacon_ind = msg->bodyptr;
1722 	struct pe_session *pe_session =
1723 		pe_find_session_by_vdev_id(mac, missed_beacon_ind->bss_idx);
1724 
1725 	if (!pe_session) {
1726 		pe_err("session does not exist for vdev_id %d",
1727 			missed_beacon_ind->bss_idx);
1728 		return;
1729 	}
1730 
1731 	/* Set Beacon Miss in Powersave Offload */
1732 	pe_session->pmmOffloadInfo.bcnmiss = true;
1733 	pe_err("Received Heart Beat Failure");
1734 
1735 	/*  Do AP probing immediately */
1736 	lim_send_heart_beat_timeout_ind(mac, pe_session);
1737 }
1738 
1739 bool lim_is_sb_disconnect_allowed_fl(struct pe_session *session,
1740 				     const char *func, uint32_t line)
1741 {
1742 	if (session->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE &&
1743 	    session->limSmeState != eLIM_SME_WT_DISASSOC_STATE &&
1744 	    session->limSmeState != eLIM_SME_WT_DEAUTH_STATE)
1745 		return true;
1746 
1747 	pe_nofl_info("%s:%u: Vdev %d (%d): limMlmState %s(%x) limSmeState %s(%x)",
1748 		     func, line, session->vdev_id, session->peSessionId,
1749 		     lim_mlm_state_str(session->limMlmState),
1750 		     session->limMlmState,
1751 		     lim_sme_state_str(session->limSmeState),
1752 		     session->limSmeState);
1753 
1754 	return false;
1755 }
1756 
1757 #ifdef WLAN_SUPPORT_TWT
1758 #ifdef WLAN_TWT_CONV_SUPPORTED
1759 void lim_set_twt_peer_capabilities(struct mac_context *mac_ctx,
1760 				   struct qdf_mac_addr *peer_mac,
1761 				   tDot11fIEhe_cap *he_cap,
1762 				   tDot11fIEhe_op *he_op)
1763 {
1764 	uint8_t caps = 0;
1765 
1766 	if (he_cap->twt_request)
1767 		caps |= WLAN_TWT_CAPA_REQUESTOR;
1768 
1769 	if (he_cap->twt_responder)
1770 		caps |= WLAN_TWT_CAPA_RESPONDER;
1771 
1772 	if (he_cap->broadcast_twt)
1773 		caps |= WLAN_TWT_CAPA_BROADCAST;
1774 
1775 	if (he_cap->flex_twt_sched)
1776 		caps |= WLAN_TWT_CAPA_FLEXIBLE;
1777 
1778 	if (he_op->twt_required)
1779 		caps |= WLAN_TWT_CAPA_REQUIRED;
1780 
1781 	wlan_set_peer_twt_capabilities(mac_ctx->psoc, peer_mac, caps);
1782 }
1783 
1784 void lim_set_twt_ext_capabilities(struct mac_context *mac_ctx,
1785 				  struct qdf_mac_addr *peer_mac,
1786 				  struct s_ext_cap *ext_cap)
1787 {
1788 	uint8_t caps = 0;
1789 
1790 	if (ext_cap->twt_requestor_support)
1791 		caps |= WLAN_TWT_CAPA_REQUESTOR;
1792 
1793 	if (ext_cap->twt_responder_support)
1794 		caps |= WLAN_TWT_CAPA_RESPONDER;
1795 
1796 	wlan_set_peer_twt_capabilities(mac_ctx->psoc, peer_mac, caps);
1797 }
1798 #else
1799 void lim_set_twt_peer_capabilities(struct mac_context *mac_ctx,
1800 				   struct qdf_mac_addr *peer_mac,
1801 				   tDot11fIEhe_cap *he_cap,
1802 				   tDot11fIEhe_op *he_op)
1803 {
1804 	uint8_t caps = 0;
1805 
1806 	if (he_cap->twt_request)
1807 		caps |= WLAN_TWT_CAPA_REQUESTOR;
1808 
1809 	if (he_cap->twt_responder)
1810 		caps |= WLAN_TWT_CAPA_RESPONDER;
1811 
1812 	if (he_cap->broadcast_twt)
1813 		caps |= WLAN_TWT_CAPA_BROADCAST;
1814 
1815 	if (he_cap->flex_twt_sched)
1816 		caps |= WLAN_TWT_CAPA_FLEXIBLE;
1817 
1818 	if (he_op->twt_required)
1819 		caps |= WLAN_TWT_CAPA_REQUIRED;
1820 
1821 	mlme_set_twt_peer_capabilities(mac_ctx->psoc, peer_mac,
1822 				       caps);
1823 }
1824 
1825 void lim_set_twt_ext_capabilities(struct mac_context *mac_ctx,
1826 				  struct qdf_mac_addr *peer_mac,
1827 				  struct s_ext_cap *ext_cap)
1828 {
1829 	uint8_t caps = 0;
1830 
1831 	if (ext_cap->twt_requestor_support)
1832 		caps |= WLAN_TWT_CAPA_REQUESTOR;
1833 
1834 	if (ext_cap->twt_responder_support)
1835 		caps |= WLAN_TWT_CAPA_RESPONDER;
1836 
1837 	mlme_set_twt_peer_capabilities(mac_ctx->psoc, peer_mac, caps);
1838 }
1839 #endif /* WLAN_TWT_CONV_SUPPORTED */
1840 #endif /* WLAN_SUPPORT_TWT */
1841 
1842 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
1843 static void pe_update_crypto_params(struct mac_context *mac_ctx,
1844 				    struct pe_session *ft_session,
1845 				    struct roam_offload_synch_ind *roam_synch)
1846 {
1847 	uint8_t *assoc_ies;
1848 	uint32_t assoc_ies_len;
1849 	uint8_t ies_offset = WLAN_REASSOC_REQ_IES_OFFSET;
1850 	tpSirMacMgmtHdr hdr;
1851 	const uint8_t *wpa_ie, *rsn_ie;
1852 	uint32_t wpa_oui;
1853 	struct wlan_crypto_params *crypto_params;
1854 
1855 	hdr = (tpSirMacMgmtHdr)((uint8_t *)roam_synch +
1856 		roam_synch->reassoc_req_offset);
1857 	if (hdr->fc.type == SIR_MAC_MGMT_FRAME &&
1858 	    hdr->fc.subType == SIR_MAC_MGMT_ASSOC_REQ) {
1859 		ies_offset = WLAN_ASSOC_REQ_IES_OFFSET;
1860 		pe_debug("roam assoc req frm");
1861 	} else {
1862 		pe_debug("roam reassoc req frm");
1863 	}
1864 
1865 	if (roam_synch->reassoc_req_length <
1866 	    (sizeof(tSirMacMgmtHdr) + ies_offset)) {
1867 		pe_err("invalid reassoc req len %d",
1868 		       roam_synch->reassoc_req_length);
1869 		return;
1870 	}
1871 	qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
1872 			   (uint8_t *)roam_synch +
1873 				roam_synch->reassoc_req_offset,
1874 			   roam_synch->reassoc_req_length);
1875 
1876 	ft_session->limRmfEnabled = false;
1877 
1878 	assoc_ies = (uint8_t *)roam_synch + roam_synch->reassoc_req_offset +
1879 				sizeof(tSirMacMgmtHdr) + ies_offset;
1880 	assoc_ies_len = roam_synch->reassoc_req_length -
1881 				sizeof(tSirMacMgmtHdr) - ies_offset;
1882 
1883 	rsn_ie = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSN, assoc_ies,
1884 					  assoc_ies_len);
1885 	wpa_oui = WLAN_WPA_SEL(WLAN_WPA_OUI_TYPE);
1886 	wpa_ie = wlan_get_vendor_ie_ptr_from_oui((uint8_t *)&wpa_oui,
1887 						 WLAN_OUI_SIZE, assoc_ies,
1888 						 assoc_ies_len);
1889 	if (!wpa_ie && !rsn_ie) {
1890 		pe_nofl_debug("RSN and WPA IE not present");
1891 		return;
1892 	}
1893 
1894 	wlan_set_vdev_crypto_prarams_from_ie(ft_session->vdev, assoc_ies,
1895 					     assoc_ies_len);
1896 	ft_session->limRmfEnabled =
1897 		lim_get_vdev_rmf_capable(mac_ctx, ft_session);
1898 	crypto_params = wlan_crypto_vdev_get_crypto_params(ft_session->vdev);
1899 	if (!crypto_params) {
1900 		pe_err("crypto params is null");
1901 		return;
1902 	}
1903 
1904 	ft_session->connected_akm =
1905 		lim_get_connected_akm(ft_session, crypto_params->ucastcipherset,
1906 				      crypto_params->authmodeset,
1907 				      crypto_params->key_mgmt);
1908 	ft_session->encryptType =
1909 		lim_get_encrypt_ed_type(crypto_params->ucastcipherset);
1910 	pe_nofl_debug("vdev %d roam auth 0x%x akm 0x%0x rsn_caps 0x%x ucastcipher 0x%x akm %d enc: %d",
1911 		      ft_session->vdev_id,
1912 		      crypto_params->authmodeset,
1913 		      crypto_params->key_mgmt,
1914 		      crypto_params->rsn_caps,
1915 		      crypto_params->ucastcipherset,
1916 		      ft_session->connected_akm,
1917 		      ft_session->encryptType);
1918 }
1919 
1920 /**
1921  * sir_parse_bcn_fixed_fields() - Parse fixed fields in Beacon IE's
1922  *
1923  * @mac_ctx: MAC Context
1924  * @beacon_struct: Beacon/Probe Response structure
1925  * @buf: Fixed Fields buffer
1926  */
1927 static void sir_parse_bcn_fixed_fields(struct mac_context *mac_ctx,
1928 					tpSirProbeRespBeacon beacon_struct,
1929 					uint8_t *buf)
1930 {
1931 	tDot11fFfCapabilities dst;
1932 
1933 	beacon_struct->timeStamp[0] = lim_get_u32(buf);
1934 	beacon_struct->timeStamp[1] = lim_get_u32(buf + 4);
1935 	buf += 8;
1936 
1937 	beacon_struct->beaconInterval = lim_get_u16(buf);
1938 	buf += 2;
1939 
1940 	dot11f_unpack_ff_capabilities(mac_ctx, buf, &dst);
1941 
1942 	sir_copy_caps_info(mac_ctx, dst, beacon_struct);
1943 }
1944 
1945 static QDF_STATUS
1946 lim_roam_gen_mbssid_beacon(struct mac_context *mac,
1947 			   struct roam_offload_synch_ind *roam_ind,
1948 			   tpSirProbeRespBeacon parsed_frm,
1949 			   uint8_t **ie, uint32_t *ie_len)
1950 {
1951 	qdf_list_t *scan_list;
1952 	struct mgmt_rx_event_params rx_param = {0};
1953 	uint8_t list_count = 0, i;
1954 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
1955 	qdf_list_node_t *next_node = NULL, *cur_node = NULL;
1956 	struct scan_cache_node *scan_node;
1957 	struct scan_cache_entry *scan_entry;
1958 	uint8_t *bcn_prb_ptr;
1959 	uint32_t nontx_bcn_prbrsp_len = 0, offset, length;
1960 	uint8_t *nontx_bcn_prbrsp = NULL;
1961 	uint8_t ie_offset;
1962 
1963 	ie_offset = SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET;
1964 	bcn_prb_ptr = (uint8_t *)roam_ind +
1965 				roam_ind->beacon_probe_resp_offset;
1966 
1967 	rx_param.chan_freq = roam_ind->chan_freq;
1968 	rx_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(mac->pdev);
1969 	rx_param.rssi = roam_ind->rssi;
1970 
1971 	/* Set all per chain rssi as invalid */
1972 	for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++)
1973 		rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI;
1974 
1975 	scan_list = util_scan_unpack_beacon_frame(mac->pdev, bcn_prb_ptr,
1976 						  roam_ind->beacon_probe_resp_length,
1977 						  MGMT_SUBTYPE_BEACON, &rx_param);
1978 	if (!scan_list) {
1979 		pe_err("failed to parse");
1980 		return QDF_STATUS_E_FAILURE;
1981 	}
1982 
1983 	list_count = qdf_list_size(scan_list);
1984 	status = qdf_list_peek_front(scan_list, &cur_node);
1985 	if (QDF_IS_STATUS_ERROR(status) || !cur_node) {
1986 		pe_debug("list peek front failure. list size %d", list_count);
1987 		goto error;
1988 	}
1989 
1990 	for (i = 1; i < list_count; i++) {
1991 		scan_node = qdf_container_of(cur_node,
1992 					     struct scan_cache_node, node);
1993 		scan_entry = scan_node->entry;
1994 		if (qdf_is_macaddr_equal(&roam_ind->bssid,
1995 					 &scan_entry->bssid)) {
1996 			pe_debug("matched BSSID "QDF_MAC_ADDR_FMT" bcn len %d profiles %d",
1997 				 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes),
1998 				 scan_entry->raw_frame.len,
1999 				 list_count);
2000 			nontx_bcn_prbrsp = scan_entry->raw_frame.ptr;
2001 			nontx_bcn_prbrsp_len = scan_entry->raw_frame.len;
2002 			QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE,
2003 					   QDF_TRACE_LEVEL_DEBUG,
2004 					   scan_entry->raw_frame.ptr,
2005 					   nontx_bcn_prbrsp_len);
2006 			break;
2007 		}
2008 		status = qdf_list_peek_next(scan_list, cur_node, &next_node);
2009 		if (QDF_IS_STATUS_ERROR(status) || !next_node) {
2010 			pe_debug("list remove failure i:%d, lsize:%d",
2011 				 i, list_count);
2012 			goto error;
2013 		}
2014 		cur_node = next_node;
2015 	}
2016 
2017 	if (!nontx_bcn_prbrsp_len) {
2018 		pe_debug("failed to generate/find MBSSID beacon");
2019 		goto error;
2020 	}
2021 
2022 	if (roam_ind->is_beacon) {
2023 		offset = SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET;
2024 		length = nontx_bcn_prbrsp_len - SIR_MAC_HDR_LEN_3A;
2025 		if (sir_parse_beacon_ie(mac, parsed_frm,
2026 					&nontx_bcn_prbrsp[offset],
2027 					length) != QDF_STATUS_SUCCESS ||
2028 			!parsed_frm->ssidPresent) {
2029 			pe_err("Parse error Beacon, length: %d",
2030 			       roam_ind->beacon_probe_resp_length);
2031 			status =  QDF_STATUS_E_FAILURE;
2032 			goto error;
2033 		}
2034 	} else {
2035 		offset = SIR_MAC_HDR_LEN_3A;
2036 		length = nontx_bcn_prbrsp_len - SIR_MAC_HDR_LEN_3A;
2037 		if (sir_convert_probe_frame2_struct(mac,
2038 					    &nontx_bcn_prbrsp[offset],
2039 					    length,
2040 					    parsed_frm) != QDF_STATUS_SUCCESS ||
2041 			!parsed_frm->ssidPresent) {
2042 			pe_err("Parse error ProbeResponse, length: %d",
2043 			       roam_ind->beacon_probe_resp_length);
2044 			status = QDF_STATUS_E_FAILURE;
2045 			goto error;
2046 		}
2047 	}
2048 
2049 	*ie_len = nontx_bcn_prbrsp_len - ie_offset;
2050 	if (*ie_len) {
2051 		*ie = qdf_mem_malloc(*ie_len);
2052 		if (!*ie)
2053 			return QDF_STATUS_E_NOMEM;
2054 		qdf_mem_copy(*ie, nontx_bcn_prbrsp + ie_offset, *ie_len);
2055 		pe_debug("beacon/probe Ie length: %d", *ie_len);
2056 	}
2057 error:
2058 	for (i = 0; i < list_count; i++) {
2059 		status = qdf_list_remove_front(scan_list, &next_node);
2060 		if (QDF_IS_STATUS_ERROR(status) || !next_node) {
2061 			pe_debug("list remove failure i:%d, lsize:%d",
2062 				 i, list_count);
2063 			break;
2064 		}
2065 		scan_node = qdf_container_of(next_node,
2066 					     struct scan_cache_node, node);
2067 		util_scan_free_cache_entry(scan_node->entry);
2068 		qdf_mem_free(scan_node);
2069 	}
2070 	qdf_mem_free(scan_list);
2071 
2072 	return status;
2073 }
2074 
2075 static QDF_STATUS
2076 lim_roam_gen_beacon_descr(struct mac_context *mac,
2077 			  uint8_t *bcn_prb_ptr,
2078 			  uint16_t bcn_prb_len, bool is_mlo_link,
2079 			  struct roam_offload_synch_ind *roam_ind,
2080 			  tpSirProbeRespBeacon parsed_frm,
2081 			  uint8_t **ie, uint32_t *ie_len,
2082 			  struct qdf_mac_addr *bssid)
2083 {
2084 	QDF_STATUS status;
2085 	tpSirMacMgmtHdr mac_hdr;
2086 	uint8_t ie_offset;
2087 	bool is_beacon;
2088 
2089 	mac_hdr = (tpSirMacMgmtHdr)bcn_prb_ptr;
2090 	ie_offset = SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET;
2091 
2092 	if (qdf_is_macaddr_zero((struct qdf_mac_addr *)mac_hdr->bssId)) {
2093 		pe_debug("bssid is 0 in beacon/probe update it with bssId"
2094 			 QDF_MAC_ADDR_FMT "in sync ind",
2095 			 QDF_MAC_ADDR_REF(bssid->bytes));
2096 		qdf_mem_copy(mac_hdr->bssId, bssid->bytes,
2097 			     sizeof(tSirMacAddr));
2098 	}
2099 
2100 	is_beacon = is_mlo_link ? roam_ind->is_link_beacon : roam_ind->is_beacon;
2101 
2102 	if ((!is_multi_link_roam(roam_ind)) &&
2103 	    (qdf_mem_cmp(bssid->bytes,
2104 			 &mac_hdr->bssId, QDF_MAC_ADDR_SIZE) != 0)) {
2105 		pe_debug("LFR3:MBSSID Beacon/Prb Rsp: %d bssid "
2106 			 QDF_MAC_ADDR_FMT,
2107 			 roam_ind->is_beacon,
2108 			 QDF_MAC_ADDR_REF(mac_hdr->bssId));
2109 		/*
2110 		 * Its a MBSSID non-tx BSS roaming scenario.
2111 		 * Generate non tx BSS beacon/probe response
2112 		 */
2113 		status = lim_roam_gen_mbssid_beacon(mac,
2114 						    roam_ind,
2115 						    parsed_frm,
2116 						    ie, ie_len);
2117 		if (QDF_IS_STATUS_ERROR(status)) {
2118 			pe_err("failed to gen mbssid beacon");
2119 			return QDF_STATUS_E_FAILURE;
2120 		}
2121 	} else {
2122 		if (is_beacon) {
2123 			if (sir_parse_beacon_ie(mac, parsed_frm,
2124 				&bcn_prb_ptr[SIR_MAC_HDR_LEN_3A +
2125 				SIR_MAC_B_PR_SSID_OFFSET],
2126 				bcn_prb_len - SIR_MAC_HDR_LEN_3A) !=
2127 						QDF_STATUS_SUCCESS ||
2128 			    !parsed_frm->ssidPresent) {
2129 				pe_err("Parse error Beacon, length: %d",
2130 				       bcn_prb_len);
2131 				return QDF_STATUS_E_FAILURE;
2132 			}
2133 		} else {
2134 			if (sir_convert_probe_frame2_struct(mac,
2135 				&bcn_prb_ptr[SIR_MAC_HDR_LEN_3A],
2136 				bcn_prb_len -
2137 				SIR_MAC_HDR_LEN_3A, parsed_frm) !=
2138 				QDF_STATUS_SUCCESS ||
2139 				!parsed_frm->ssidPresent) {
2140 				pe_err("Parse error ProbeResponse, length: %d",
2141 				       bcn_prb_len);
2142 				return QDF_STATUS_E_FAILURE;
2143 			}
2144 		}
2145 		/* 24 byte MAC header and 12 byte to ssid IE */
2146 		if (bcn_prb_len > ie_offset) {
2147 			*ie_len = bcn_prb_len - ie_offset;
2148 			*ie = qdf_mem_malloc(*ie_len);
2149 			if (!*ie)
2150 				return QDF_STATUS_E_NOMEM;
2151 			qdf_mem_copy(*ie, bcn_prb_ptr + ie_offset, *ie_len);
2152 			pe_debug("beacon/probe Ie length: %d", *ie_len);
2153 		}
2154 	}
2155 	/*
2156 	 * For probe response, unpack core parses beacon interval, capabilities,
2157 	 * timestamp. For beacon IEs, these fields are not parsed.
2158 	 */
2159 	if (is_beacon)
2160 		sir_parse_bcn_fixed_fields(mac, parsed_frm,
2161 			&bcn_prb_ptr[SIR_MAC_HDR_LEN_3A]);
2162 
2163 	return QDF_STATUS_SUCCESS;
2164 }
2165 
2166 static QDF_STATUS
2167 lim_roam_fill_bss_descr(struct mac_context *mac,
2168 			struct roam_offload_synch_ind *roam_synch_ind,
2169 			struct bss_description *bss_desc_ptr,
2170 			struct pe_session *session)
2171 {
2172 	uint32_t ie_len = 0;
2173 	tpSirProbeRespBeacon parsed_frm_ptr = NULL;
2174 	tpSirMacMgmtHdr mac_hdr;
2175 	uint8_t *bcn_proberesp_ptr = NULL;
2176 	uint16_t bcn_proberesp_len = 0;
2177 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2178 	uint8_t *ie = NULL;
2179 	struct qdf_mac_addr bssid;
2180 	bool is_mlo_link = false;
2181 	uint8_t vdev_id = session->vdev_id;
2182 	struct element_info frame;
2183 	struct cm_roam_values_copy mdie_cfg = {0};
2184 
2185 	bcn_proberesp_ptr = (uint8_t *)roam_synch_ind +
2186 		roam_synch_ind->beacon_probe_resp_offset;
2187 	bcn_proberesp_len = roam_synch_ind->beacon_probe_resp_length;
2188 
2189 	frame.ptr = NULL;
2190 	frame.len = 0;
2191 	if (is_multi_link_roam(roam_synch_ind)) {
2192 		if (roam_synch_ind->link_beacon_probe_resp_length) {
2193 			if (wlan_vdev_mlme_get_is_mlo_link(mac->psoc,
2194 							   vdev_id)) {
2195 				bcn_proberesp_ptr = (uint8_t *)roam_synch_ind +
2196 				roam_synch_ind->link_beacon_probe_resp_offset;
2197 				bcn_proberesp_len =
2198 				roam_synch_ind->link_beacon_probe_resp_length;
2199 			}
2200 		} else {
2201 			mlo_get_sta_link_mac_addr(vdev_id, roam_synch_ind,
2202 						  &bssid);
2203 			status = wlan_scan_get_entry_by_mac_addr(mac->pdev,
2204 								 &bssid,
2205 								 &frame);
2206 			if (QDF_IS_STATUS_ERROR(status) && !frame.len) {
2207 				pe_err("Failed to get scan entry for " QDF_MAC_ADDR_FMT,
2208 				       QDF_MAC_ADDR_REF(bssid.bytes));
2209 				return status;
2210 			}
2211 			bcn_proberesp_ptr = frame.ptr;
2212 			bcn_proberesp_len = frame.len;
2213 		}
2214 		if (wlan_vdev_mlme_get_is_mlo_link(mac->psoc, vdev_id))
2215 			is_mlo_link = true;
2216 	}
2217 
2218 	mac_hdr = (tpSirMacMgmtHdr)bcn_proberesp_ptr;
2219 	parsed_frm_ptr = qdf_mem_malloc(sizeof(tSirProbeRespBeacon));
2220 	if (!parsed_frm_ptr) {
2221 		status = QDF_STATUS_E_NOMEM;
2222 		goto done;
2223 	}
2224 
2225 	if (bcn_proberesp_len <= SIR_MAC_HDR_LEN_3A) {
2226 		pe_err("very few bytes in synchInd %s beacon / probe resp frame! length: %d",
2227 		       is_mlo_link ? "link" : "", bcn_proberesp_len);
2228 		status = QDF_STATUS_E_FAILURE;
2229 		goto done;
2230 	}
2231 
2232 	if (is_multi_link_roam(roam_synch_ind))
2233 		mlo_get_sta_link_mac_addr(vdev_id, roam_synch_ind, &bssid);
2234 	else
2235 		bssid = roam_synch_ind->bssid;
2236 
2237 	pe_debug("LFR3:Beacon/Prb Rsp: %d bssid " QDF_MAC_ADDR_FMT
2238 		 " beacon " QDF_MAC_ADDR_FMT,
2239 		 is_mlo_link ? roam_synch_ind->is_link_beacon :
2240 			roam_synch_ind->is_beacon,
2241 		 QDF_MAC_ADDR_REF(bssid.bytes),
2242 		 QDF_MAC_ADDR_REF(mac_hdr->bssId));
2243 
2244 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
2245 			   bcn_proberesp_ptr,
2246 			   bcn_proberesp_len);
2247 
2248 	status = lim_roam_gen_beacon_descr(mac, bcn_proberesp_ptr,
2249 					   bcn_proberesp_len, is_mlo_link,
2250 					   roam_synch_ind, parsed_frm_ptr,
2251 					   &ie, &ie_len,
2252 					   &bssid);
2253 	if (QDF_IS_STATUS_ERROR(status)) {
2254 		pe_err("Failed to parse beacon");
2255 		status = QDF_STATUS_E_FAILURE;
2256 		goto done;
2257 	}
2258 
2259 	/*
2260 	 * Length of BSS description is without length of
2261 	 * length itself and length of pointer
2262 	 * that holds ieFields
2263 	 *
2264 	 * struct bss_description
2265 	 * +--------+---------------------------------+---------------+
2266 	 * | length | other fields                    | pointer to IEs|
2267 	 * +--------+---------------------------------+---------------+
2268 	 *                                            ^
2269 	 *                                            ieFields
2270 	 */
2271 	bss_desc_ptr->length = (uint16_t) (offsetof(struct bss_description,
2272 					   ieFields[0]) -
2273 				sizeof(bss_desc_ptr->length) + ie_len);
2274 
2275 	bss_desc_ptr->fProbeRsp = !(is_mlo_link ?
2276 					roam_synch_ind->is_link_beacon :
2277 					roam_synch_ind->is_beacon);
2278 	bss_desc_ptr->rssi = roam_synch_ind->rssi;
2279 	/* Copy Timestamp */
2280 	bss_desc_ptr->scansystimensec = qdf_get_monotonic_boottime_ns();
2281 
2282 	if (is_multi_link_roam(roam_synch_ind)) {
2283 		bss_desc_ptr->chan_freq =
2284 				mlo_roam_get_chan_freq(vdev_id, roam_synch_ind);
2285 	} else if (parsed_frm_ptr->he_op.oper_info_6g_present) {
2286 		bss_desc_ptr->chan_freq = wlan_reg_chan_band_to_freq(mac->pdev,
2287 			parsed_frm_ptr->he_op.oper_info_6g.info.primary_ch,
2288 			BIT(REG_BAND_6G));
2289 	} else if (parsed_frm_ptr->dsParamsPresent) {
2290 		bss_desc_ptr->chan_freq = parsed_frm_ptr->chan_freq;
2291 	} else if (parsed_frm_ptr->HTInfo.present) {
2292 		bss_desc_ptr->chan_freq =
2293 			wlan_reg_legacy_chan_to_freq(mac->pdev,
2294 						     parsed_frm_ptr->HTInfo.primaryChannel);
2295 	} else {
2296 		/*
2297 		 * If DS Params or HTIE is not present in the probe resp or
2298 		 * beacon, then use the channel frequency provided by firmware
2299 		 * to fill the channel in the BSS descriptor.*/
2300 		bss_desc_ptr->chan_freq = roam_synch_ind->chan_freq;
2301 	}
2302 
2303 	bss_desc_ptr->nwType = lim_get_nw_type(mac, bss_desc_ptr->chan_freq,
2304 					       SIR_MAC_MGMT_FRAME,
2305 					       parsed_frm_ptr);
2306 
2307 	bss_desc_ptr->sinr = 0;
2308 	bss_desc_ptr->beaconInterval = parsed_frm_ptr->beaconInterval;
2309 	bss_desc_ptr->timeStamp[0]   = parsed_frm_ptr->timeStamp[0];
2310 	bss_desc_ptr->timeStamp[1]   = parsed_frm_ptr->timeStamp[1];
2311 	qdf_mem_copy(&bss_desc_ptr->capabilityInfo,
2312 	&bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_CAPAB_OFFSET], 2);
2313 
2314 	qdf_mem_copy((uint8_t *) &bss_desc_ptr->bssId,
2315 		     (uint8_t *)&bssid.bytes,
2316 		     sizeof(tSirMacAddr));
2317 
2318 	qdf_mem_copy((uint8_t *)&bss_desc_ptr->seq_ctrl,
2319 		     (uint8_t *)&mac_hdr->seqControl,
2320 		     sizeof(tSirMacSeqCtl));
2321 
2322 	bss_desc_ptr->received_time =
2323 		      (uint64_t)qdf_mc_timer_get_system_time();
2324 	if (parsed_frm_ptr->mdiePresent) {
2325 		bss_desc_ptr->mdiePresent = parsed_frm_ptr->mdiePresent;
2326 		qdf_mem_copy((uint8_t *)bss_desc_ptr->mdie,
2327 				(uint8_t *)parsed_frm_ptr->mdie,
2328 				SIR_MDIE_SIZE);
2329 
2330 		mdie_cfg.bool_value = true;
2331 		mdie_cfg.uint_value =
2332 			(bss_desc_ptr->mdie[1] << 8) | (bss_desc_ptr->mdie[0]);
2333 
2334 		wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id,
2335 					   MOBILITY_DOMAIN, &mdie_cfg);
2336 	}
2337 	pe_debug("chan: %d rssi: %d ie_len %d mdie_present:%d mdie = %02x %02x %02x",
2338 		 bss_desc_ptr->chan_freq,
2339 		 bss_desc_ptr->rssi, ie_len, bss_desc_ptr->mdiePresent,
2340 		 bss_desc_ptr->mdie[0], bss_desc_ptr->mdie[1], bss_desc_ptr->mdie[2]);
2341 
2342 	if (ie_len) {
2343 		qdf_mem_copy(&bss_desc_ptr->ieFields,
2344 			     ie, ie_len);
2345 		qdf_mem_free(ie);
2346 	} else {
2347 		pe_err("Beacon/Probe rsp doesn't have any IEs");
2348 		status = QDF_STATUS_E_FAILURE;
2349 		goto done;
2350 	}
2351 done:
2352 	qdf_mem_free(frame.ptr);
2353 	qdf_mem_free(parsed_frm_ptr);
2354 	return status;
2355 }
2356 
2357 #if defined(WLAN_FEATURE_FILS_SK)
2358 /**
2359  * lim_copy_and_free_hlp_data_from_session - Copy HLP info
2360  * @session_ptr: PE session
2361  * @roam_sync_ind_ptr: Roam Synch Indication pointer
2362  *
2363  * This API is used to copy the parsed HLP info from PE session
2364  * to roam synch indication data. THe HLP info is expected to be
2365  * parsed/stored in PE session already from assoc IE's received
2366  * from fw as part of Roam Synch Indication.
2367  *
2368  * Return: None
2369  */
2370 static void
2371 lim_copy_and_free_hlp_data_from_session(struct pe_session *session_ptr,
2372 					struct roam_offload_synch_ind
2373 					*roam_sync_ind_ptr)
2374 {
2375 	if (session_ptr->fils_info->hlp_data &&
2376 	    session_ptr->fils_info->hlp_data_len) {
2377 		cds_copy_hlp_info(&session_ptr->fils_info->dst_mac,
2378 				  &session_ptr->fils_info->src_mac,
2379 				  session_ptr->fils_info->hlp_data_len,
2380 				  session_ptr->fils_info->hlp_data,
2381 				  &roam_sync_ind_ptr->dst_mac,
2382 				  &roam_sync_ind_ptr->src_mac,
2383 				  &roam_sync_ind_ptr->hlp_data_len,
2384 				  roam_sync_ind_ptr->hlp_data);
2385 
2386 		qdf_mem_free(session_ptr->fils_info->hlp_data);
2387 		session_ptr->fils_info->hlp_data = NULL;
2388 		session_ptr->fils_info->hlp_data_len = 0;
2389 	}
2390 }
2391 #else
2392 static inline void
2393 lim_copy_and_free_hlp_data_from_session(struct pe_session *session_ptr,
2394 					struct roam_offload_synch_ind
2395 					*roam_sync_ind_ptr)
2396 {}
2397 #endif
2398 
2399 static
2400 uint8_t *lim_process_rmf_disconnect_frame(struct mac_context *mac,
2401 					  struct pe_session *session,
2402 					  uint8_t *deauth_disassoc_frame,
2403 					  uint16_t deauth_disassoc_frame_len,
2404 					  uint16_t *extracted_length)
2405 {
2406 	struct wlan_frame_hdr *mac_hdr;
2407 	uint8_t mic_len, hdr_len, pdev_id;
2408 	uint8_t *orig_ptr, *efrm;
2409 	int32_t mgmtcipherset;
2410 	uint32_t mmie_len;
2411 	QDF_STATUS status;
2412 
2413 	mac_hdr = (struct wlan_frame_hdr *)deauth_disassoc_frame;
2414 	orig_ptr = (uint8_t *)mac_hdr;
2415 
2416 	if (mac_hdr->i_fc[1] & IEEE80211_FC1_WEP) {
2417 		if (QDF_IS_ADDR_BROADCAST(mac_hdr->i_addr1) ||
2418 		    IEEE80211_IS_MULTICAST(mac_hdr->i_addr1)) {
2419 			pe_err("Encrypted BC/MC frame dropping the frame");
2420 			*extracted_length = 0;
2421 			return NULL;
2422 		}
2423 
2424 		pdev_id = wlan_objmgr_pdev_get_pdev_id(mac->pdev);
2425 		status = mlme_get_peer_mic_len(mac->psoc, pdev_id,
2426 					       mac_hdr->i_addr2, &mic_len,
2427 					       &hdr_len);
2428 		if (QDF_IS_STATUS_ERROR(status)) {
2429 			pe_err("Failed to get mic hdr and length");
2430 			*extracted_length = 0;
2431 			return NULL;
2432 		}
2433 
2434 		if (deauth_disassoc_frame_len <
2435 		    (sizeof(*mac_hdr) + hdr_len + mic_len)) {
2436 			pe_err("Frame len less than expected %d",
2437 			       deauth_disassoc_frame_len);
2438 			*extracted_length = 0;
2439 			return NULL;
2440 		}
2441 
2442 		/*
2443 		 * Strip the privacy headers and trailer
2444 		 * for the received deauth/disassoc frame
2445 		 */
2446 		qdf_mem_move(orig_ptr + hdr_len, mac_hdr,
2447 			     sizeof(*mac_hdr));
2448 		*extracted_length = deauth_disassoc_frame_len -
2449 				    (hdr_len + mic_len);
2450 		return orig_ptr + hdr_len;
2451 	}
2452 
2453 	if (!(QDF_IS_ADDR_BROADCAST(mac_hdr->i_addr1) ||
2454 	      IEEE80211_IS_MULTICAST(mac_hdr->i_addr1))) {
2455 		pe_err("Rx unprotected unicast mgmt frame");
2456 		*extracted_length = 0;
2457 		return NULL;
2458 	}
2459 
2460 	mgmtcipherset = wlan_crypto_get_param(session->vdev,
2461 					      WLAN_CRYPTO_PARAM_MGMT_CIPHER);
2462 	if (mgmtcipherset < 0) {
2463 		pe_err("Invalid mgmt cipher");
2464 		*extracted_length = 0;
2465 		return NULL;
2466 	}
2467 
2468 	mmie_len = (mgmtcipherset & (1 << WLAN_CRYPTO_CIPHER_AES_CMAC) ?
2469 		    cds_get_mmie_size() : cds_get_gmac_mmie_size());
2470 
2471 	efrm = orig_ptr + deauth_disassoc_frame_len;
2472 	if (!mac->pmf_offload &&
2473 	    !wlan_crypto_is_mmie_valid(session->vdev, orig_ptr, efrm)) {
2474 		pe_err("Invalid MMIE");
2475 		*extracted_length = 0;
2476 		return NULL;
2477 	}
2478 
2479 	*extracted_length = deauth_disassoc_frame_len - mmie_len;
2480 
2481 	return deauth_disassoc_frame;
2482 }
2483 
2484 QDF_STATUS
2485 pe_disconnect_callback(struct mac_context *mac, uint8_t vdev_id,
2486 		       uint8_t *deauth_disassoc_frame,
2487 		       uint16_t deauth_disassoc_frame_len,
2488 		       uint16_t reason_code)
2489 {
2490 	struct pe_session *session;
2491 	uint8_t *extracted_frm = NULL;
2492 	uint16_t extracted_frm_len;
2493 	bool is_pmf_connection;
2494 
2495 	session = pe_find_session_by_vdev_id(mac, vdev_id);
2496 	if (!session) {
2497 		pe_err("LFR3: Vdev %d doesn't exist", vdev_id);
2498 		return QDF_STATUS_E_FAILURE;
2499 	}
2500 
2501 	if (!lim_is_sb_disconnect_allowed(session))
2502 		return QDF_STATUS_SUCCESS;
2503 
2504 	if (!deauth_disassoc_frame ||
2505 	    deauth_disassoc_frame_len <
2506 	    (sizeof(struct wlan_frame_hdr) + sizeof(reason_code))) {
2507 		pe_err_rl("Discard invalid disconnect evt. frame len:%d",
2508 			  deauth_disassoc_frame_len);
2509 		goto end;
2510 	}
2511 
2512 	/*
2513 	 * Use vdev pmf status instead of peer pmf capability as
2514 	 * the firmware might roam to new AP in powersave case and
2515 	 * roam synch can come before emergency deauth event.
2516 	 * In that case, get peer will fail and reason code received
2517 	 * from the WMI_ROAM_EVENTID  will be sent to upper layers.
2518 	 */
2519 	is_pmf_connection = lim_get_vdev_rmf_capable(mac, session);
2520 	if (is_pmf_connection) {
2521 		extracted_frm = lim_process_rmf_disconnect_frame(
2522 						mac, session,
2523 						deauth_disassoc_frame,
2524 						deauth_disassoc_frame_len,
2525 						&extracted_frm_len);
2526 		if (!extracted_frm) {
2527 			pe_err("PMF frame validation failed");
2528 			goto end;
2529 		}
2530 	} else {
2531 		extracted_frm = deauth_disassoc_frame;
2532 		extracted_frm_len = deauth_disassoc_frame_len;
2533 	}
2534 
2535 	lim_extract_ies_from_deauth_disassoc(session, extracted_frm,
2536 					     extracted_frm_len);
2537 
2538 	reason_code = sir_read_u16(extracted_frm +
2539 				   sizeof(struct wlan_frame_hdr));
2540 end:
2541 	lim_tear_down_link_with_ap(mac, session->peSessionId,
2542 				   reason_code,
2543 				   eLIM_PEER_ENTITY_DEAUTH);
2544 
2545 	return QDF_STATUS_SUCCESS;
2546 }
2547 
2548 #ifdef WLAN_FEATURE_FILS_SK
2549 static void
2550 lim_fill_fils_ft(struct pe_session *src_session,
2551 		 struct pe_session *dst_session)
2552 {
2553       if (src_session->fils_info &&
2554           src_session->fils_info->fils_ft_len) {
2555               dst_session->fils_info->fils_ft_len =
2556                       src_session->fils_info->fils_ft_len;
2557               qdf_mem_copy(dst_session->fils_info->fils_ft,
2558                            src_session->fils_info->fils_ft,
2559                            src_session->fils_info->fils_ft_len);
2560       }
2561 }
2562 #else
2563 static inline void
2564 lim_fill_fils_ft(struct pe_session *src_session,
2565 		 struct pe_session *dst_session)
2566 {}
2567 #endif
2568 
2569 #ifdef WLAN_SUPPORT_TWT
2570 void
2571 lim_fill_roamed_peer_twt_caps(struct mac_context *mac_ctx,
2572 			      uint8_t vdev_id,
2573 			      struct roam_offload_synch_ind *roam_synch)
2574 {
2575 	uint8_t *reassoc_body;
2576 	uint16_t len;
2577 	uint32_t status;
2578 	tDot11fReAssocResponse *reassoc_rsp;
2579 	struct pe_session *pe_session;
2580 	struct qdf_mac_addr mac_addr;
2581 
2582 	pe_session = pe_find_session_by_vdev_id(mac_ctx, vdev_id);
2583 	if (!pe_session) {
2584 		pe_err("session not found for given vdev_id %d", vdev_id);
2585 		return;
2586 	}
2587 
2588 	reassoc_rsp = qdf_mem_malloc(sizeof(*reassoc_rsp));
2589 	if (!reassoc_rsp)
2590 		return;
2591 
2592 	len = roam_synch->reassoc_resp_length - sizeof(tSirMacMgmtHdr);
2593 	reassoc_body = (uint8_t *)roam_synch + sizeof(tSirMacMgmtHdr) +
2594 			roam_synch->reassoc_resp_offset;
2595 
2596 	status = dot11f_unpack_re_assoc_response(mac_ctx, reassoc_body, len,
2597 						 reassoc_rsp, false);
2598 	if (DOT11F_FAILED(status)) {
2599 		pe_err("Failed to parse a Re-association Rsp (0x%08x, %d bytes):",
2600 		       status, len);
2601 		QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO,
2602 				   reassoc_body, len);
2603 		qdf_mem_free(reassoc_rsp);
2604 		return;
2605 	} else if (DOT11F_WARNED(status)) {
2606 		pe_debug("Warnings while unpacking a Re-association Rsp (0x%08x, %d bytes):",
2607 			 status, len);
2608 	}
2609 
2610 	if (lim_is_session_he_capable(pe_session)) {
2611 		if (is_multi_link_roam(roam_synch))
2612 			mlo_get_sta_link_mac_addr(vdev_id, roam_synch,
2613 						  &mac_addr);
2614 		else
2615 			qdf_copy_macaddr(&mac_addr, &roam_synch->bssid);
2616 		lim_set_twt_peer_capabilities(mac_ctx,
2617 					      &mac_addr,
2618 					      &reassoc_rsp->he_cap,
2619 					      &reassoc_rsp->he_op);
2620 	}
2621 	qdf_mem_free(reassoc_rsp);
2622 }
2623 #endif
2624 
2625 /**
2626  * lim_check_ft_initial_im_association() - To check FT initial mobility(im)
2627  * association
2628  * @roam_synch: A pointer to roam sync ind structure
2629  * @session_entry: pe session
2630  *
2631  * This function is to check ft_initial_im_association.
2632  *
2633  * Return: None
2634  */
2635 void
2636 lim_check_ft_initial_im_association(struct roam_offload_synch_ind *roam_synch,
2637 				    struct pe_session *session_entry)
2638 {
2639 	tpSirMacMgmtHdr hdr;
2640 	uint8_t *assoc_req_ptr;
2641 
2642 	assoc_req_ptr = (uint8_t *) roam_synch + roam_synch->reassoc_req_offset;
2643 	hdr = (tpSirMacMgmtHdr) assoc_req_ptr;
2644 
2645 	if (hdr->fc.type == SIR_MAC_MGMT_FRAME &&
2646 	    hdr->fc.subType == SIR_MAC_MGMT_ASSOC_REQ) {
2647 		roam_synch->is_assoc = true;
2648 		if (session_entry->is11Rconnection) {
2649 			pe_debug("Frame subtype: %d and connection is %d",
2650 				 hdr->fc.subType,
2651 				 session_entry->is11Rconnection);
2652 			roam_synch->is_ft_im_roam = true;
2653 		}
2654 	}
2655 }
2656 
2657 #ifdef WLAN_FEATURE_11BE_MLO
2658 static void
2659 lim_mlo_roam_copy_partner_info_to_session(struct pe_session *session,
2660 					  struct roam_offload_synch_ind *sync_ind)
2661 {
2662 	mlo_roam_copy_partner_info(&session->ml_partner_info,
2663 				   sync_ind, sync_ind->roamed_vdev_id, false);
2664 }
2665 
2666 static QDF_STATUS
2667 lim_gen_link_specific_assoc_rsp(struct mac_context *mac_ctx,
2668 				struct pe_session *session_entry,
2669 				uint8_t *reassoc_rsp,
2670 				uint32_t reassoc_rsp_len)
2671 {
2672 	struct element_info link_reassoc_rsp;
2673 	struct qdf_mac_addr sta_link_addr;
2674 	struct mlo_partner_info *ml_partner_info;
2675 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2676 	uint8_t idx = 0, num_partner_links, link_id, link_vdev_id;
2677 
2678 	link_reassoc_rsp.ptr = qdf_mem_malloc(reassoc_rsp_len);
2679 	if (!link_reassoc_rsp.ptr)
2680 		return QDF_STATUS_E_NOMEM;
2681 
2682 	qdf_mem_copy(&sta_link_addr, session_entry->self_mac_addr,
2683 		     QDF_MAC_ADDR_SIZE);
2684 
2685 	link_reassoc_rsp.len = reassoc_rsp_len;
2686 
2687 	ml_partner_info = &session_entry->ml_partner_info;
2688 	num_partner_links = ml_partner_info->num_partner_links;
2689 	for (idx = 0; idx < num_partner_links; idx++) {
2690 		link_vdev_id = ml_partner_info->partner_link_info[idx].vdev_id;
2691 		if (link_vdev_id == WLAN_INVALID_VDEV_ID)
2692 			continue;
2693 
2694 		if (link_vdev_id != session_entry->vdev_id)
2695 			continue;
2696 
2697 		link_id = ml_partner_info->partner_link_info[idx].link_id;
2698 		status = util_gen_link_assoc_rsp(
2699 					reassoc_rsp + WLAN_MAC_HDR_LEN_3A,
2700 					reassoc_rsp_len - WLAN_MAC_HDR_LEN_3A,
2701 					true, link_id, sta_link_addr,
2702 					link_reassoc_rsp.ptr, reassoc_rsp_len,
2703 					(qdf_size_t *)&link_reassoc_rsp.len);
2704 		if (QDF_IS_STATUS_ERROR(status)) {
2705 			pe_err("MLO ROAM: link_id:%d vdev:%d Reassoc generation failed %d",
2706 			       link_id, link_vdev_id, status);
2707 			goto end;
2708 		}
2709 
2710 		lim_process_assoc_rsp_frame(mac_ctx, link_reassoc_rsp.ptr,
2711 					    link_reassoc_rsp.len - WLAN_MAC_HDR_LEN_3A,
2712 					    LIM_REASSOC, session_entry);
2713 	}
2714 end:
2715 	qdf_mem_free(link_reassoc_rsp.ptr);
2716 	link_reassoc_rsp.len = 0;
2717 	return status;
2718 }
2719 
2720 #else
2721 static inline void
2722 lim_mlo_roam_copy_partner_info_to_session(struct pe_session *session,
2723 					struct roam_offload_synch_ind *sync_ind)
2724 {}
2725 
2726 static QDF_STATUS
2727 lim_gen_link_specific_assoc_rsp(struct mac_context *mac_ctx,
2728 				struct pe_session *session_entry,
2729 				uint8_t *reassoc_rsp,
2730 				uint32_t reassoc_rsp_len)
2731 {
2732 	return QDF_STATUS_E_NOSUPPORT;
2733 }
2734 #endif
2735 
2736 #ifdef WLAN_FEATURE_11AX
2737 static void pe_roam_fill_obss_scan_param(struct pe_session *src_session,
2738 					 struct pe_session *dst_session)
2739 {
2740 	dst_session->obss_color_collision_dec_evt =
2741 				src_session->obss_color_collision_dec_evt;
2742 	dst_session->he_op.bss_color = src_session->he_op.bss_color;
2743 }
2744 #else
2745 static inline void pe_roam_fill_obss_scan_param(struct pe_session *src_session,
2746 						struct pe_session *dst_session)
2747 {
2748 }
2749 #endif
2750 
2751 #ifdef WLAN_FEATURE_SR
2752 void lim_handle_sr_cap(struct wlan_objmgr_vdev *vdev,
2753 		       enum sr_osif_reason_code reason)
2754 {
2755 	int32_t non_srg_pd_threshold = 0;
2756 	int32_t srg_pd_threshold = 0;
2757 	uint8_t non_srg_pd_offset = 0;
2758 	uint8_t srg_max_pd_offset = 0;
2759 	uint8_t srg_min_pd_offset = 0;
2760 	uint8_t sr_ctrl, sr_enable_modes;
2761 	bool is_pd_threshold_present = false;
2762 	struct wlan_objmgr_pdev *pdev;
2763 	enum sr_status_of_roamed_ap sr_status;
2764 	enum sr_osif_operation sr_op;
2765 	enum QDF_OPMODE opmode;
2766 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
2767 
2768 	if (!mac) {
2769 		pe_err("mac ctx is null");
2770 		return;
2771 	}
2772 	pdev = wlan_vdev_get_pdev(vdev);
2773 	if (!pdev) {
2774 		pe_err("invalid pdev");
2775 		return;
2776 	}
2777 
2778 	opmode = wlan_vdev_mlme_get_opmode(vdev);
2779 	/* If SR is disabled in INI for the session-operating mode
2780 	 * Then return.
2781 	 */
2782 	wlan_mlme_get_sr_enable_modes(mac->psoc, &sr_enable_modes);
2783 	if (!(sr_enable_modes & (1 << opmode))) {
2784 		pe_debug("SR is disabled in INI for mode: %d", opmode);
2785 		return;
2786 	}
2787 	if (!wlan_vdev_mlme_get_he_spr_enabled(vdev)) {
2788 		pe_debug("SR is not enabled");
2789 		return;
2790 	}
2791 	non_srg_pd_offset = wlan_vdev_mlme_get_non_srg_pd_offset(vdev);
2792 	wlan_vdev_mlme_get_srg_pd_offset(vdev, &srg_max_pd_offset,
2793 					 &srg_min_pd_offset);
2794 	wlan_vdev_mlme_get_current_non_srg_pd_threshold(vdev,
2795 							&non_srg_pd_threshold);
2796 	wlan_vdev_mlme_get_current_srg_pd_threshold(vdev,
2797 						    &srg_pd_threshold);
2798 
2799 	sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(vdev);
2800 	if ((sr_ctrl & NON_SRG_PD_SR_DISALLOWED) &&
2801 	    (!(sr_ctrl & SRG_INFO_PRESENT))) {
2802 		sr_status = SR_DISALLOW;
2803 	} else {
2804 		if ((!(sr_ctrl & NON_SRG_PD_SR_DISALLOWED) &&
2805 		     (non_srg_pd_threshold > non_srg_pd_offset +
2806 		      SR_PD_THRESHOLD_MIN)) ||
2807 		     ((sr_ctrl & SRG_INFO_PRESENT) &&
2808 		      ((srg_pd_threshold > srg_max_pd_offset +
2809 		     SR_PD_THRESHOLD_MIN) ||
2810 		      (srg_pd_threshold < srg_min_pd_offset +
2811 		       SR_PD_THRESHOLD_MIN))))
2812 			sr_status = SR_THRESHOLD_NOT_IN_RANGE;
2813 		else
2814 			sr_status = SR_THRESHOLD_IN_RANGE;
2815 	}
2816 	pe_debug("sr status %d reason %d existing thresholds srg: %d non-srg: %d New: sr offset srg: max %d min %d non-srg: %d",
2817 		 sr_status, reason, srg_pd_threshold, non_srg_pd_threshold,
2818 		 srg_max_pd_offset, srg_min_pd_offset, non_srg_pd_offset);
2819 	switch (sr_status) {
2820 	case SR_DISALLOW:
2821 		/** clear thresholds set by previous AP **/
2822 		wlan_vdev_mlme_set_current_non_srg_pd_threshold(vdev, 0);
2823 		wlan_vdev_mlme_set_current_srg_pd_threshold(vdev, 0);
2824 		wlan_spatial_reuse_osif_event(vdev,
2825 					      SR_OPERATION_SUSPEND,
2826 					      reason);
2827 		/*
2828 		 * If SR is disabled due to beacon update,
2829 		 * notify the firmware to disable SR
2830 		 */
2831 		if (reason == SR_REASON_CODE_BCN_IE_CHANGE)
2832 			wlan_sr_setup_req(vdev, pdev, false, 0, 0);
2833 	break;
2834 	case SR_THRESHOLD_NOT_IN_RANGE:
2835 		wlan_vdev_mlme_get_pd_threshold_present(
2836 						vdev, &is_pd_threshold_present);
2837 		/*
2838 		 * if userspace gives pd threshold then check if its within
2839 		 * range of roamed AP's min and max thresholds, if not in
2840 		 * range disable and let userspace decide to re-enable.
2841 		 * if userspace dosesnt give PD threshold then always enable
2842 		 * SRG based on AP's recommendation of thresholds.
2843 		 */
2844 		if (is_pd_threshold_present) {
2845 			wlan_vdev_mlme_set_current_non_srg_pd_threshold(vdev,
2846 									0);
2847 			wlan_vdev_mlme_set_current_srg_pd_threshold(vdev, 0);
2848 			wlan_spatial_reuse_osif_event(vdev,
2849 						      SR_OPERATION_SUSPEND,
2850 						      reason);
2851 		} else {
2852 			sr_op = (reason == SR_REASON_CODE_ROAMING) ?
2853 				SR_OPERATION_RESUME :
2854 				SR_OPERATION_UPDATE_PARAMS;
2855 			wlan_sr_setup_req(
2856 				vdev, pdev, true,
2857 				srg_max_pd_offset + SR_PD_THRESHOLD_MIN,
2858 				non_srg_pd_threshold + SR_PD_THRESHOLD_MIN);
2859 			wlan_spatial_reuse_osif_event(vdev, sr_op, reason);
2860 		}
2861 	break;
2862 	case SR_THRESHOLD_IN_RANGE:
2863 		/* Send enable command to fw, as fw disables SR on roaming */
2864 		wlan_sr_setup_req(vdev, pdev, true, srg_pd_threshold,
2865 				  non_srg_pd_threshold);
2866 	break;
2867 	}
2868 }
2869 #endif
2870 
2871 QDF_STATUS
2872 pe_roam_synch_callback(struct mac_context *mac_ctx,
2873 		       uint8_t vdev_id,
2874 		       struct roam_offload_synch_ind *roam_sync_ind_ptr,
2875 		       uint16_t ie_len,
2876 		       enum sir_roam_op_code reason)
2877 {
2878 	struct pe_session *session_ptr;
2879 	struct pe_session *ft_session_ptr;
2880 	uint8_t session_id;
2881 	uint8_t *reassoc_resp;
2882 	tpDphHashNode curr_sta_ds = NULL, sta_ds = NULL;
2883 	uint16_t aid;
2884 	struct bss_params *add_bss_params;
2885 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
2886 	struct bss_description *bss_desc = NULL;
2887 	uint16_t ric_tspec_len;
2888 	struct qdf_mac_addr bssid;
2889 	uint8_t *oui_ie_ptr;
2890 	uint16_t oui_ie_len;
2891 
2892 	if (!roam_sync_ind_ptr) {
2893 		pe_err("LFR3:roam_sync_ind_ptr is NULL");
2894 		return status;
2895 	}
2896 	session_ptr = pe_find_session_by_vdev_id(mac_ctx,
2897 				vdev_id);
2898 
2899 	if (!session_ptr) {
2900 		pe_err("LFR3:Unable to find session");
2901 		return status;
2902 	}
2903 
2904 	if (!LIM_IS_STA_ROLE(session_ptr)) {
2905 		pe_err("LFR3:session is not in STA mode");
2906 		return status;
2907 	}
2908 
2909 	if (is_multi_link_roam(roam_sync_ind_ptr))
2910 		mlo_get_sta_link_mac_addr(vdev_id, roam_sync_ind_ptr, &bssid);
2911 	else
2912 		bssid = roam_sync_ind_ptr->bssid;
2913 
2914 	pe_debug("LFR3: PE callback reason: %d", reason);
2915 	switch (reason) {
2916 	case SIR_ROAMING_ABORT:
2917 		/*
2918 		 * If there was a disassoc or deauth that was received
2919 		 * during roaming and it was not honored, then we have
2920 		 * to internally initiate a disconnect because with
2921 		 * ROAM_ABORT we come back to original AP.
2922 		 */
2923 		if (session_ptr->recvd_deauth_while_roaming)
2924 			lim_perform_deauth(mac_ctx, session_ptr,
2925 					   session_ptr->deauth_disassoc_rc,
2926 					   session_ptr->bssId, 0);
2927 		if (session_ptr->recvd_disassoc_while_roaming) {
2928 			lim_disassoc_tdls_peers(mac_ctx, session_ptr,
2929 						session_ptr->bssId);
2930 			lim_perform_disassoc(mac_ctx, 0,
2931 					     session_ptr->deauth_disassoc_rc,
2932 					     session_ptr, session_ptr->bssId);
2933 		}
2934 		return QDF_STATUS_SUCCESS;
2935 	case SIR_ROAM_SYNCH_PROPAGATION:
2936 		break;
2937 	default:
2938 		return status;
2939 	}
2940 
2941 	pe_debug("LFR3:Received ROAM SYNCH IND bssid "QDF_MAC_ADDR_FMT" auth: %d vdevId: %d",
2942 		 QDF_MAC_ADDR_REF(roam_sync_ind_ptr->bssid.bytes),
2943 		 roam_sync_ind_ptr->auth_status,
2944 		 vdev_id);
2945 
2946 	/*
2947 	 * If deauth from AP already in progress, ignore Roam Synch Indication
2948 	 * from firmware.
2949 	 */
2950 	if (session_ptr->limSmeState != eLIM_SME_LINK_EST_STATE) {
2951 		pe_err("LFR3: Not in Link est state");
2952 		return status;
2953 	}
2954 
2955 	bss_desc = qdf_mem_malloc(sizeof(struct bss_description) + ie_len);
2956 	if (!bss_desc) {
2957 		QDF_ASSERT(bss_desc);
2958 		status = -QDF_STATUS_E_NOMEM;
2959 		return status;
2960 	}
2961 
2962 	status = lim_roam_fill_bss_descr(mac_ctx, roam_sync_ind_ptr,
2963 					 bss_desc, session_ptr);
2964 	if (!QDF_IS_STATUS_SUCCESS(status)) {
2965 		pe_err("LFR3:Failed to fill Bss Descr");
2966 		qdf_mem_free(bss_desc);
2967 		return status;
2968 	}
2969 	status = QDF_STATUS_E_FAILURE;
2970 	ft_session_ptr = pe_create_session(mac_ctx, bss_desc->bssId,
2971 					   &session_id,
2972 					   mac_ctx->lim.max_sta_of_pe_session,
2973 					   session_ptr->bssType,
2974 					   session_ptr->vdev_id);
2975 	if (!ft_session_ptr) {
2976 		pe_err("LFR3:Cannot create PE Session bssid: "QDF_MAC_ADDR_FMT,
2977 		       QDF_MAC_ADDR_REF(bss_desc->bssId));
2978 		qdf_mem_free(bss_desc);
2979 		return status;
2980 	}
2981 	/* Update the beacon/probe filter in mac_ctx */
2982 	lim_set_bcn_probe_filter(mac_ctx, ft_session_ptr, 0);
2983 	sir_copy_mac_addr(ft_session_ptr->limReAssocbssId, bss_desc->bssId);
2984 	session_ptr->bRoamSynchInProgress = true;
2985 	ft_session_ptr->bRoamSynchInProgress = true;
2986 	ft_session_ptr->limSystemRole = eLIM_STA_ROLE;
2987 	sir_copy_mac_addr(session_ptr->limReAssocbssId, bss_desc->bssId);
2988 	ft_session_ptr->csaOffloadEnable = session_ptr->csaOffloadEnable;
2989 
2990 	/* Next routine will update nss and vdev_nss with AP's capabilities */
2991 	status = lim_fill_ft_session(mac_ctx, bss_desc, ft_session_ptr,
2992 				     session_ptr, roam_sync_ind_ptr->phy_mode);
2993 	if (QDF_IS_STATUS_ERROR(status)) {
2994 		pe_err("Failed to fill ft session for vdev id %d",
2995 		       ft_session_ptr->vdev_id);
2996 		qdf_mem_free(bss_desc);
2997 		goto roam_sync_fail;
2998 	}
2999 
3000 	roam_sync_ind_ptr->ssid.length =
3001 		qdf_min((qdf_size_t)ft_session_ptr->ssId.length,
3002 			sizeof(roam_sync_ind_ptr->ssid.ssid));
3003 	qdf_mem_copy(roam_sync_ind_ptr->ssid.ssid, ft_session_ptr->ssId.ssId,
3004 		     roam_sync_ind_ptr->ssid.length);
3005 	pe_update_crypto_params(mac_ctx, ft_session_ptr, roam_sync_ind_ptr);
3006 
3007 	/* Reset the SPMK global cache */
3008 	wlan_mlme_set_sae_single_pmk_bss_cap(mac_ctx->psoc, vdev_id, false);
3009 
3010 	/* Next routine may update nss based on dot11Mode */
3011 
3012 	lim_ft_prepare_add_bss_req(mac_ctx, ft_session_ptr, bss_desc);
3013 	lim_set_tpc_power(mac_ctx, ft_session_ptr, bss_desc);
3014 
3015 	if (session_ptr->is11Rconnection)
3016 		lim_fill_fils_ft(session_ptr, ft_session_ptr);
3017 
3018 	roam_sync_ind_ptr->add_bss_params =
3019 		(struct bss_params *) ft_session_ptr->ftPEContext.pAddBssReq;
3020 	add_bss_params = ft_session_ptr->ftPEContext.pAddBssReq;
3021 	lim_delete_tdls_peers(mac_ctx, session_ptr);
3022 	/*
3023 	 * After deleting the TDLS peers notify the Firmware about TDLS STA
3024 	 * disconnection due to roaming
3025 	 */
3026 	wlan_tdls_notify_sta_disconnect(vdev_id, true,
3027 					false, session_ptr->vdev);
3028 
3029 	sta_ds = dph_lookup_hash_entry(mac_ctx, session_ptr->bssId, &aid,
3030 				       &session_ptr->dph.dphHashTable);
3031 	if (!sta_ds && !is_multi_link_roam(roam_sync_ind_ptr)) {
3032 		pe_err("LFR3:failed to lookup hash entry");
3033 		ft_session_ptr->bRoamSynchInProgress = false;
3034 		qdf_mem_free(bss_desc);
3035 		goto roam_sync_fail;
3036 	}
3037 
3038 	/* update OBSS scan param */
3039 	pe_roam_fill_obss_scan_param(session_ptr, ft_session_ptr);
3040 
3041 	curr_sta_ds = dph_add_hash_entry(mac_ctx,
3042 					 bssid.bytes,
3043 					 DPH_STA_HASH_INDEX_PEER,
3044 					 &ft_session_ptr->dph.dphHashTable);
3045 	if (!curr_sta_ds) {
3046 		pe_err("LFR3:failed to add hash entry for "QDF_MAC_ADDR_FMT,
3047 		       QDF_MAC_ADDR_REF(add_bss_params->staContext.staMac));
3048 		ft_session_ptr->bRoamSynchInProgress = false;
3049 		qdf_mem_free(bss_desc);
3050 		goto roam_sync_fail;
3051 	}
3052 
3053 	if (roam_sync_ind_ptr->auth_status == ROAM_AUTH_STATUS_AUTHENTICATED)
3054 		curr_sta_ds->is_key_installed = true;
3055 
3056 	lim_mlo_roam_copy_partner_info_to_session(ft_session_ptr,
3057 						  roam_sync_ind_ptr);
3058 
3059 	reassoc_resp = (uint8_t *)roam_sync_ind_ptr +
3060 			roam_sync_ind_ptr->reassoc_resp_offset;
3061 
3062 	if (wlan_vdev_mlme_get_is_mlo_link(mac_ctx->psoc, vdev_id)) {
3063 		status = lim_gen_link_specific_assoc_rsp(mac_ctx,
3064 						ft_session_ptr,
3065 						reassoc_resp,
3066 						roam_sync_ind_ptr->reassoc_resp_length);
3067 		if (ft_session_ptr->is_unexpected_peer_error)
3068 			status = QDF_STATUS_E_FAILURE;
3069 
3070 		if (QDF_IS_STATUS_ERROR(status)) {
3071 			qdf_mem_free(bss_desc);
3072 			goto roam_sync_fail;
3073 		}
3074 	} else {
3075 		lim_process_assoc_rsp_frame(mac_ctx, reassoc_resp,
3076 					    roam_sync_ind_ptr->reassoc_resp_length - SIR_MAC_HDR_LEN_3A,
3077 					    LIM_REASSOC, ft_session_ptr);
3078 		if (ft_session_ptr->is_unexpected_peer_error) {
3079 			status = QDF_STATUS_E_FAILURE;
3080 			qdf_mem_free(bss_desc);
3081 			goto roam_sync_fail;
3082 		}
3083 	}
3084 
3085 	oui_ie_ptr = (uint8_t *)&bss_desc->ieFields[0];
3086 	oui_ie_len = wlan_get_ielen_from_bss_description(bss_desc);
3087 	lim_enable_cts_to_self_for_exempted_iot_ap(mac_ctx,
3088 						   ft_session_ptr,
3089 						   oui_ie_ptr, oui_ie_len);
3090 	qdf_mem_free(bss_desc);
3091 	oui_ie_len = 0;
3092 	oui_ie_ptr = NULL;
3093 
3094 	lim_check_ft_initial_im_association(roam_sync_ind_ptr, ft_session_ptr);
3095 
3096 	lim_copy_and_free_hlp_data_from_session(ft_session_ptr,
3097 						roam_sync_ind_ptr);
3098 	roam_sync_ind_ptr->aid = ft_session_ptr->limAID;
3099 	curr_sta_ds->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE;
3100 	curr_sta_ds->nss = ft_session_ptr->nss;
3101 	roam_sync_ind_ptr->nss = ft_session_ptr->nss;
3102 	ft_session_ptr->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE;
3103 	ft_session_ptr->limPrevMlmState = ft_session_ptr->limMlmState;
3104 	lim_init_tdls_data(mac_ctx, ft_session_ptr);
3105 	ric_tspec_len = ft_session_ptr->RICDataLen;
3106 	pe_debug("LFR3: Session RicLength: %d", ft_session_ptr->RICDataLen);
3107 	lim_handle_sr_cap(ft_session_ptr->vdev, SR_REASON_CODE_ROAMING);
3108 #ifdef FEATURE_WLAN_ESE
3109 	ric_tspec_len += ft_session_ptr->tspecLen;
3110 	pe_debug("LFR3: tspecLen: %d", ft_session_ptr->tspecLen);
3111 #endif
3112 	if (ric_tspec_len) {
3113 		roam_sync_ind_ptr->ric_tspec_data =
3114 				qdf_mem_malloc(ric_tspec_len);
3115 		if (!roam_sync_ind_ptr->ric_tspec_data) {
3116 			ft_session_ptr->bRoamSynchInProgress = false;
3117 			status = QDF_STATUS_E_NOMEM;
3118 			goto roam_sync_fail;
3119 		}
3120 
3121 		if (ft_session_ptr->ricData) {
3122 			roam_sync_ind_ptr->ric_data_len =
3123 					ft_session_ptr->RICDataLen;
3124 			qdf_mem_copy(roam_sync_ind_ptr->ric_tspec_data,
3125 				     ft_session_ptr->ricData,
3126 				     roam_sync_ind_ptr->ric_data_len);
3127 			qdf_mem_free(ft_session_ptr->ricData);
3128 			ft_session_ptr->ricData = NULL;
3129 			ft_session_ptr->RICDataLen = 0;
3130 		}
3131 #ifdef FEATURE_WLAN_ESE
3132 		if (ft_session_ptr->tspecIes) {
3133 			roam_sync_ind_ptr->tspec_len = ft_session_ptr->tspecLen;
3134 			qdf_mem_copy(roam_sync_ind_ptr->ric_tspec_data +
3135 				     roam_sync_ind_ptr->ric_data_len,
3136 				     ft_session_ptr->tspecIes,
3137 				     roam_sync_ind_ptr->tspec_len);
3138 			qdf_mem_free(ft_session_ptr->tspecIes);
3139 			ft_session_ptr->tspecIes = NULL;
3140 			ft_session_ptr->tspecLen = 0;
3141 		}
3142 #endif
3143 	}
3144 	roam_sync_ind_ptr->chan_width = ft_session_ptr->ch_width;
3145 	roam_sync_ind_ptr->max_rate_flags =
3146 			lim_get_max_rate_flags(mac_ctx, curr_sta_ds);
3147 	ft_session_ptr->limSmeState = eLIM_SME_LINK_EST_STATE;
3148 	ft_session_ptr->limPrevSmeState = ft_session_ptr->limSmeState;
3149 	ft_session_ptr->bRoamSynchInProgress = false;
3150 
3151 	/* Cleanup the old session */
3152 	session_ptr->limSmeState = eLIM_SME_IDLE_STATE;
3153 
3154 	/*
3155 	 * Delete the ml_peer only if DUT is roamed to a non-11BE candidate.
3156 	 * ml_peer is already cleaned up in wma_delete_all_peers() at the
3157 	 * beginning of roam_sync handling for 11BE candidates.
3158 	 */
3159 	if (sta_ds) {
3160 		if (!wlan_vdev_mlme_is_mlo_vdev(session_ptr->vdev)) {
3161 			lim_mlo_notify_peer_disconn(session_ptr, sta_ds);
3162 			lim_mlo_roam_delete_link_peer(session_ptr, sta_ds);
3163 		}
3164 		lim_cleanup_rx_path(mac_ctx, sta_ds, session_ptr, false);
3165 		lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, aid,
3166 					  session_ptr);
3167 	}
3168 
3169 	pe_delete_session(mac_ctx, session_ptr);
3170 	return QDF_STATUS_SUCCESS;
3171 
3172 roam_sync_fail:
3173 	pe_err("Roam sync failure status %d session vdev %d", status,
3174 	       session_ptr->vdev_id);
3175 	/*
3176 	 * Cleanup the new session upon roam sync failure.
3177 	 * Retain the old session for graceful HO failure handling.
3178 	 */
3179 	if (curr_sta_ds) {
3180 		lim_cleanup_rx_path(mac_ctx, curr_sta_ds, ft_session_ptr,
3181 				    false);
3182 		lim_delete_dph_hash_entry(mac_ctx, curr_sta_ds->staAddr,
3183 					  curr_sta_ds->assocId, ft_session_ptr);
3184 	}
3185 	pe_delete_session(mac_ctx, ft_session_ptr);
3186 	return status;
3187 }
3188 
3189 QDF_STATUS
3190 pe_set_ie_for_roam_invoke(struct mac_context *mac_ctx, uint8_t vdev_id,
3191 			  uint16_t dot11_mode, enum QDF_OPMODE opmode)
3192 {
3193 	QDF_STATUS status;
3194 
3195 	if (!mac_ctx)
3196 		return QDF_STATUS_E_FAILURE;
3197 
3198 	status = lim_send_ies_per_band(mac_ctx, vdev_id, dot11_mode, opmode);
3199 	return status;
3200 }
3201 
3202 #endif
3203 
3204 static bool lim_is_beacon_miss_scenario(struct mac_context *mac,
3205 					uint8_t *pRxPacketInfo)
3206 {
3207 	tpSirMacMgmtHdr pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
3208 	uint8_t sessionId;
3209 	struct pe_session *pe_session =
3210 		pe_find_session_by_bssid(mac, pHdr->bssId, &sessionId);
3211 
3212 	if (pe_session && pe_session->pmmOffloadInfo.bcnmiss)
3213 		return true;
3214 	return false;
3215 }
3216 
3217 /** -----------------------------------------------------------------
3218    \brief lim_is_pkt_candidate_for_drop() - decides whether to drop the frame or not
3219 
3220    This function is called before enqueuing the frame to PE queue for further processing.
3221    This prevents unnecessary frames getting into PE Queue and drops them right away.
3222    Frames will be dropped in the following scenarios:
3223 
3224    - In Scan State, drop the frames which are not marked as scan frames
3225    - In non-Scan state, drop the frames which are marked as scan frames.
3226 
3227    \param mac - global mac structure
3228    \return - none
3229    \sa
3230    ----------------------------------------------------------------- */
3231 
3232 tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac,
3233 						 uint8_t *pRxPacketInfo,
3234 						 uint32_t subType)
3235 {
3236 	uint32_t framelen;
3237 	uint8_t *pBody;
3238 	tSirMacCapabilityInfo capabilityInfo;
3239 	tpSirMacMgmtHdr pHdr = NULL;
3240 	struct wlan_objmgr_vdev *vdev;
3241 
3242 	/*
3243 	 *
3244 	 * In scan mode, drop only Beacon/Probe Response which are NOT marked as scan-frames.
3245 	 * In non-scan mode, drop only Beacon/Probe Response which are marked as scan frames.
3246 	 * Allow other mgmt frames, they must be from our own AP, as we don't allow
3247 	 * other than beacons or probe responses in scan state.
3248 	 */
3249 	if ((subType == SIR_MAC_MGMT_BEACON) ||
3250 	    (subType == SIR_MAC_MGMT_PROBE_RSP)) {
3251 		if (lim_is_beacon_miss_scenario(mac, pRxPacketInfo)) {
3252 			MTRACE(mac_trace(mac, TRACE_CODE_INFO_LOG, 0,
3253 					 eLOG_NODROP_MISSED_BEACON_SCENARIO));
3254 			return eMGMT_DROP_NO_DROP;
3255 		}
3256 
3257 		framelen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
3258 		pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo);
3259 		/* drop the frame if length is less than 12 */
3260 		if (framelen < LIM_MIN_BCN_PR_LENGTH)
3261 			return eMGMT_DROP_INVALID_SIZE;
3262 
3263 		*((uint16_t *) &capabilityInfo) =
3264 			sir_read_u16(pBody + LIM_BCN_PR_CAPABILITY_OFFSET);
3265 
3266 		/* Note sure if this is sufficient, basically this condition allows all probe responses and
3267 		 *   beacons from an infrastructure network
3268 		 */
3269 		if (!capabilityInfo.ibss)
3270 			return eMGMT_DROP_NO_DROP;
3271 
3272 		/* Drop INFRA Beacons and Probe Responses in IBSS Mode */
3273 		/* This can be enhanced to even check the SSID before deciding to enqueue the frame. */
3274 		if (capabilityInfo.ess)
3275 			return eMGMT_DROP_INFRA_BCN_IN_IBSS;
3276 
3277 	} else if (subType == SIR_MAC_MGMT_AUTH) {
3278 		uint16_t curr_seq_num = 0;
3279 		struct tLimPreAuthNode *auth_node;
3280 
3281 		pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
3282 		vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(mac->pdev,
3283 								 pHdr->da,
3284 								 WLAN_LEGACY_MAC_ID);
3285 		if (!vdev)
3286 			return eMGMT_DROP_NO_DROP;
3287 		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
3288 
3289 		curr_seq_num = ((pHdr->seqControl.seqNumHi << 4) |
3290 				(pHdr->seqControl.seqNumLo));
3291 		auth_node = lim_search_pre_auth_list(mac, pHdr->sa);
3292 		if (auth_node && pHdr->fc.retry &&
3293 		    (auth_node->seq_num == curr_seq_num)) {
3294 			pe_err_rl("auth frame, seq num: %d is already processed, drop it",
3295 				  curr_seq_num);
3296 			return eMGMT_DROP_DUPLICATE_AUTH_FRAME;
3297 		}
3298 	} else if ((subType == SIR_MAC_MGMT_ASSOC_REQ) ||
3299 		   (subType == SIR_MAC_MGMT_DISASSOC) ||
3300 		   (subType == SIR_MAC_MGMT_DEAUTH)) {
3301 		struct peer_mlme_priv_obj *peer_priv;
3302 		struct wlan_objmgr_peer *peer;
3303 		qdf_time_t *timestamp;
3304 
3305 		pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
3306 		vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(mac->pdev,
3307 								 pHdr->da,
3308 								 WLAN_LEGACY_MAC_ID);
3309 		if (!vdev)
3310 			return eMGMT_DROP_SPURIOUS_FRAME;
3311 
3312 		peer = wlan_objmgr_get_peer_by_mac(mac->psoc,
3313 						   pHdr->sa,
3314 						   WLAN_LEGACY_MAC_ID);
3315 		if (!peer) {
3316 			if (subType == SIR_MAC_MGMT_ASSOC_REQ) {
3317 				wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
3318 				return eMGMT_DROP_NO_DROP;
3319 			}
3320 			wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
3321 			return eMGMT_DROP_SPURIOUS_FRAME;
3322 		}
3323 
3324 		peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
3325 							WLAN_UMAC_COMP_MLME);
3326 		if (!peer_priv) {
3327 			wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
3328 			if (subType == SIR_MAC_MGMT_ASSOC_REQ) {
3329 				wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
3330 				return eMGMT_DROP_NO_DROP;
3331 			}
3332 			wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
3333 			return eMGMT_DROP_SPURIOUS_FRAME;
3334 		}
3335 
3336 		if (QDF_STA_MODE == wlan_vdev_mlme_get_opmode(vdev) &&
3337 		    wlan_cm_is_vdev_roam_started(vdev) &&
3338 		    (subType == SIR_MAC_MGMT_DISASSOC ||
3339 		     subType == SIR_MAC_MGMT_DEAUTH)) {
3340 			wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
3341 			return eMGMT_DROP_DEAUTH_DURING_ROAM_STARTED;
3342 		}
3343 		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
3344 
3345 		if (subType == SIR_MAC_MGMT_ASSOC_REQ)
3346 			timestamp =
3347 			   &peer_priv->last_assoc_received_time;
3348 		else
3349 			timestamp =
3350 			   &peer_priv->last_disassoc_deauth_received_time;
3351 
3352 		if (*timestamp > 0 &&
3353 		    qdf_system_time_before(qdf_get_system_timestamp(),
3354 					   *timestamp +
3355 					   LIM_DOS_PROTECTION_TIME)) {
3356 			pe_debug_rl(FL("Dropping subtype 0x%x frame. %s %d ms %s %d ms"),
3357 				    subType, "It is received after",
3358 				    (int)(qdf_get_system_timestamp() - *timestamp),
3359 				    "of last frame. Allow it only after",
3360 				    LIM_DOS_PROTECTION_TIME);
3361 			wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
3362 			return eMGMT_DROP_EXCESSIVE_MGMT_FRAME;
3363 		}
3364 
3365 		*timestamp = qdf_get_system_timestamp();
3366 		wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
3367 
3368 	}
3369 
3370 	return eMGMT_DROP_NO_DROP;
3371 }
3372 
3373 void lim_update_lost_link_info(struct mac_context *mac, struct pe_session *session,
3374 				int32_t rssi)
3375 {
3376 	struct sir_lost_link_info *lost_link_info;
3377 	struct scheduler_msg mmh_msg = {0};
3378 
3379 	if ((!mac) || (!session)) {
3380 		pe_err("parameter NULL");
3381 		return;
3382 	}
3383 	if (!LIM_IS_STA_ROLE(session))
3384 		return;
3385 
3386 	lost_link_info = qdf_mem_malloc(sizeof(*lost_link_info));
3387 	if (!lost_link_info)
3388 		return;
3389 
3390 	lost_link_info->vdev_id = session->smeSessionId;
3391 	lost_link_info->rssi = rssi;
3392 	mmh_msg.type = eWNI_SME_LOST_LINK_INFO_IND;
3393 	mmh_msg.bodyptr = lost_link_info;
3394 	mmh_msg.bodyval = 0;
3395 	pe_debug("post eWNI_SME_LOST_LINK_INFO_IND, bss_idx: %d rssi: %d",
3396 		lost_link_info->vdev_id, lost_link_info->rssi);
3397 
3398 	lim_sys_process_mmh_msg_api(mac, &mmh_msg);
3399 }
3400 
3401 /**
3402  * lim_mon_init_session() - create PE session for monitor mode operation
3403  * @mac_ptr: mac pointer
3404  * @msg: Pointer to struct sir_create_session type.
3405  *
3406  * Return: NONE
3407  */
3408 void lim_mon_init_session(struct mac_context *mac_ptr,
3409 			  struct sir_create_session *msg)
3410 {
3411 	struct pe_session *psession_entry;
3412 	uint8_t session_id;
3413 
3414 	psession_entry = pe_create_session(mac_ptr, msg->bss_id.bytes,
3415 					   &session_id,
3416 					   mac_ptr->lim.max_sta_of_pe_session,
3417 					   eSIR_MONITOR_MODE,
3418 					   msg->vdev_id);
3419 	if (!psession_entry) {
3420 		pe_err("Monitor mode: Session Can not be created bssid: "
3421 			QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(msg->bss_id.bytes));
3422 		return;
3423 	}
3424 	psession_entry->vhtCapability = 1;
3425 }
3426 
3427 void lim_mon_deinit_session(struct mac_context *mac_ptr,
3428 			    struct sir_delete_session *msg)
3429 {
3430 	struct pe_session *session;
3431 
3432 	session = pe_find_session_by_vdev_id(mac_ptr, msg->vdev_id);
3433 
3434 	if (session && session->bssType == eSIR_MONITOR_MODE)
3435 		pe_delete_session(mac_ptr, session);
3436 }
3437 
3438 /**
3439  * lim_update_ext_cap_ie() - Update Extended capabilities IE(if present)
3440  *          with capabilities of Fine Time measurements(FTM) if set in driver
3441  *
3442  * @mac_ctx: Pointer to Global MAC structure
3443  * @ie_data: Default Scan IE data
3444  * @local_ie_buf: Local Scan IE data
3445  * @local_ie_len: Pointer to length of @ie_data
3446  * @session: Pointer to pe session
3447  *
3448  * Return: QDF_STATUS
3449  */
3450 QDF_STATUS lim_update_ext_cap_ie(struct mac_context *mac_ctx, uint8_t *ie_data,
3451 				 uint8_t *local_ie_buf, uint16_t *local_ie_len,
3452 				 struct pe_session *session)
3453 {
3454 	uint32_t dot11mode;
3455 	bool vht_enabled = false;
3456 	tDot11fIEExtCap default_scan_ext_cap = {0}, driver_ext_cap = {0};
3457 	QDF_STATUS status;
3458 
3459 	status = lim_strip_extcap_update_struct(mac_ctx, ie_data,
3460 				   local_ie_len, &default_scan_ext_cap);
3461 	if (QDF_STATUS_SUCCESS != status) {
3462 		pe_err("Strip ext cap fails %d", status);
3463 		return QDF_STATUS_E_FAILURE;
3464 	}
3465 
3466 	if ((*local_ie_len) > (MAX_DEFAULT_SCAN_IE_LEN - EXT_CAP_IE_HDR_LEN)) {
3467 		pe_err("Invalid Scan IE length");
3468 		return QDF_STATUS_E_FAILURE;
3469 	}
3470 	/* copy ie prior to ext cap to local buffer */
3471 	qdf_mem_copy(local_ie_buf, ie_data, (*local_ie_len));
3472 
3473 	/* from here ext cap ie starts, set EID */
3474 	local_ie_buf[*local_ie_len] = DOT11F_EID_EXTCAP;
3475 
3476 	dot11mode = mac_ctx->mlme_cfg->dot11_mode.dot11_mode;
3477 	if (IS_DOT11_MODE_VHT(dot11mode))
3478 		vht_enabled = true;
3479 
3480 	status = populate_dot11f_ext_cap(mac_ctx, vht_enabled,
3481 					&driver_ext_cap, NULL);
3482 	if (QDF_STATUS_SUCCESS != status) {
3483 		pe_err("Failed %d to create ext cap IE. Use default value instead",
3484 				status);
3485 		local_ie_buf[*local_ie_len + 1] = DOT11F_IE_EXTCAP_MAX_LEN;
3486 
3487 		if ((*local_ie_len) > (MAX_DEFAULT_SCAN_IE_LEN -
3488 		    (DOT11F_IE_EXTCAP_MAX_LEN + EXT_CAP_IE_HDR_LEN))) {
3489 			pe_err("Invalid Scan IE length");
3490 			return QDF_STATUS_E_FAILURE;
3491 		}
3492 		(*local_ie_len) += EXT_CAP_IE_HDR_LEN;
3493 		qdf_mem_copy(local_ie_buf + (*local_ie_len),
3494 				default_scan_ext_cap.bytes,
3495 				DOT11F_IE_EXTCAP_MAX_LEN);
3496 		(*local_ie_len) += DOT11F_IE_EXTCAP_MAX_LEN;
3497 		return QDF_STATUS_SUCCESS;
3498 	}
3499 	lim_merge_extcap_struct(&driver_ext_cap, &default_scan_ext_cap, true);
3500 
3501 	if (session)
3502 		populate_dot11f_twt_extended_caps(mac_ctx, session,
3503 						  &driver_ext_cap);
3504 	else
3505 		pe_debug("Session NULL, cannot set TWT caps");
3506 
3507 	local_ie_buf[*local_ie_len + 1] = driver_ext_cap.num_bytes;
3508 
3509 	if ((*local_ie_len) > (MAX_DEFAULT_SCAN_IE_LEN -
3510 	    (EXT_CAP_IE_HDR_LEN + driver_ext_cap.num_bytes))) {
3511 		pe_err("Invalid Scan IE length");
3512 		return QDF_STATUS_E_FAILURE;
3513 	}
3514 	(*local_ie_len) += EXT_CAP_IE_HDR_LEN;
3515 	qdf_mem_copy(local_ie_buf + (*local_ie_len),
3516 			driver_ext_cap.bytes, driver_ext_cap.num_bytes);
3517 	(*local_ie_len) += driver_ext_cap.num_bytes;
3518 	return QDF_STATUS_SUCCESS;
3519 }
3520 
3521 #define LIM_RSN_OUI_SIZE 4
3522 
3523 struct rsn_oui_akm_type_map {
3524 	enum ani_akm_type akm_type;
3525 	uint8_t rsn_oui[LIM_RSN_OUI_SIZE];
3526 };
3527 
3528 static const struct rsn_oui_akm_type_map rsn_oui_akm_type_mapping_table[] = {
3529 	{ANI_AKM_TYPE_RSN,                  {0x00, 0x0F, 0xAC, 0x01} },
3530 	{ANI_AKM_TYPE_RSN_PSK,              {0x00, 0x0F, 0xAC, 0x02} },
3531 	{ANI_AKM_TYPE_FT_RSN,               {0x00, 0x0F, 0xAC, 0x03} },
3532 	{ANI_AKM_TYPE_FT_RSN_PSK,           {0x00, 0x0F, 0xAC, 0x04} },
3533 	{ANI_AKM_TYPE_RSN_8021X_SHA256,     {0x00, 0x0F, 0xAC, 0x05} },
3534 	{ANI_AKM_TYPE_RSN_PSK_SHA256,       {0x00, 0x0F, 0xAC, 0x06} },
3535 #ifdef WLAN_FEATURE_SAE
3536 	{ANI_AKM_TYPE_SAE,                  {0x00, 0x0F, 0xAC, 0x08} },
3537 	{ANI_AKM_TYPE_FT_SAE,               {0x00, 0x0F, 0xAC, 0x09} },
3538 #endif
3539 	{ANI_AKM_TYPE_SUITEB_EAP_SHA256,    {0x00, 0x0F, 0xAC, 0x0B} },
3540 	{ANI_AKM_TYPE_SUITEB_EAP_SHA384,    {0x00, 0x0F, 0xAC, 0x0C} },
3541 	{ANI_AKM_TYPE_FT_SUITEB_EAP_SHA384, {0x00, 0x0F, 0xAC, 0x0D} },
3542 	{ANI_AKM_TYPE_FILS_SHA256,          {0x00, 0x0F, 0xAC, 0x0E} },
3543 	{ANI_AKM_TYPE_FILS_SHA384,          {0x00, 0x0F, 0xAC, 0x0F} },
3544 	{ANI_AKM_TYPE_FT_FILS_SHA256,       {0x00, 0x0F, 0xAC, 0x10} },
3545 	{ANI_AKM_TYPE_FT_FILS_SHA384,       {0x00, 0x0F, 0xAC, 0x11} },
3546 	{ANI_AKM_TYPE_OWE,                  {0x00, 0x0F, 0xAC, 0x12} },
3547 #ifdef FEATURE_WLAN_ESE
3548 	{ANI_AKM_TYPE_CCKM,                 {0x00, 0x40, 0x96, 0x00} },
3549 #endif
3550 	{ANI_AKM_TYPE_OSEN,                 {0x50, 0x6F, 0x9A, 0x01} },
3551 	{ANI_AKM_TYPE_DPP_RSN,              {0x50, 0x6F, 0x9A, 0x02} },
3552 	{ANI_AKM_TYPE_WPA,                  {0x00, 0x50, 0xF2, 0x01} },
3553 	{ANI_AKM_TYPE_WPA_PSK,              {0x00, 0x50, 0xF2, 0x02} },
3554 	{ANI_AKM_TYPE_SAE_EXT_KEY,          {0x00, 0x0F, 0xAC, 0x18} },
3555 	{ANI_AKM_TYPE_FT_SAE_EXT_KEY,       {0x00, 0x0F, 0xAC, 0x19} },
3556 	/* Add akm type above here */
3557 	{ANI_AKM_TYPE_UNKNOWN, {0} },
3558 };
3559 
3560 enum ani_akm_type lim_translate_rsn_oui_to_akm_type(uint8_t auth_suite[4])
3561 {
3562 	const struct rsn_oui_akm_type_map *map;
3563 	enum ani_akm_type akm_type;
3564 
3565 	map = rsn_oui_akm_type_mapping_table;
3566 	while (true) {
3567 		akm_type = map->akm_type;
3568 		if ((akm_type == ANI_AKM_TYPE_UNKNOWN) ||
3569 		    (qdf_mem_cmp(auth_suite, map->rsn_oui, 4) == 0))
3570 			break;
3571 		map++;
3572 	}
3573 
3574 	pe_debug("akm_type: %d", akm_type);
3575 
3576 	return akm_type;
3577 }
3578 
3579 #if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO)
3580 QDF_STATUS
3581 lim_cm_fill_link_session(struct mac_context *mac_ctx,
3582 			 uint8_t vdev_id,
3583 			 struct pe_session *pe_session,
3584 			 struct roam_offload_synch_ind *sync_ind,
3585 			 uint16_t ie_len)
3586 {
3587 	struct wlan_objmgr_vdev *vdev;
3588 	struct wlan_objmgr_vdev *assoc_vdev;
3589 	QDF_STATUS status = QDF_STATUS_SUCCESS;
3590 	struct bss_description *bss_desc = NULL;
3591 	uint32_t bss_len;
3592 	struct join_req *pe_join_req;
3593 
3594 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc,
3595 						    vdev_id,
3596 						    WLAN_LEGACY_MAC_ID);
3597 	if (!vdev) {
3598 		pe_err("Vdev is NULL");
3599 		return QDF_STATUS_E_NULL_VALUE;
3600 	}
3601 
3602 	bss_len = (uint16_t)(offsetof(struct bss_description,
3603 			   ieFields[0]) + ie_len);
3604 
3605 	assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
3606 
3607 	if (!assoc_vdev) {
3608 		pe_err("Assoc vdev is NULL");
3609 		status = QDF_STATUS_E_FAILURE;
3610 		goto end;
3611 	}
3612 
3613 	status = wlan_vdev_mlme_get_ssid(assoc_vdev,
3614 					 pe_session->ssId.ssId,
3615 					 &pe_session->ssId.length);
3616 
3617 	if (QDF_IS_STATUS_ERROR(status)) {
3618 		pe_err("Failed to get ssid vdev id %d",
3619 		       vdev_id);
3620 		status = QDF_STATUS_E_FAILURE;
3621 		goto end;
3622 	}
3623 
3624 	pe_session->lim_join_req =
3625 		qdf_mem_malloc(sizeof(*pe_session->lim_join_req) + bss_len);
3626 	if (!pe_session->lim_join_req) {
3627 		status = QDF_STATUS_E_NOMEM;
3628 		goto end;
3629 	}
3630 
3631 	pe_join_req = pe_session->lim_join_req;
3632 
3633 	mlo_roam_copy_partner_info(&pe_join_req->partner_info,
3634 				   sync_ind, vdev_id, false);
3635 
3636 	bss_desc = &pe_session->lim_join_req->bssDescription;
3637 
3638 	status = lim_roam_fill_bss_descr(mac_ctx, sync_ind, bss_desc,
3639 					 pe_session);
3640 	if (!QDF_IS_STATUS_SUCCESS(status)) {
3641 		pe_err("LFR3:Failed to fill Bss Descr");
3642 		goto end;
3643 	}
3644 
3645 	status = lim_fill_pe_session(mac_ctx, pe_session, bss_desc);
3646 	if (QDF_IS_STATUS_ERROR(status)) {
3647 		pe_err("Failed to fill pe session vdev id %d",
3648 		       pe_session->vdev_id);
3649 		goto end;
3650 	}
3651 
3652 	if (pe_session->limSmeState == eLIM_SME_WT_JOIN_STATE) {
3653 		pe_session->limSmeState = eLIM_SME_LINK_EST_STATE;
3654 		pe_session->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE;
3655 	}
3656 end:
3657 	if (QDF_IS_STATUS_ERROR(status)) {
3658 		qdf_mem_free(pe_session->lim_join_req);
3659 		pe_session->lim_join_req = NULL;
3660 	}
3661 	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
3662 
3663 	return status;
3664 }
3665 
3666 struct pe_session *
3667 lim_cm_roam_create_session(struct mac_context *mac_ctx,
3668 			   uint8_t vdev_id,
3669 			   struct roam_offload_synch_ind *sync_ind)
3670 {
3671 	struct pe_session *pe_session = NULL;
3672 	struct qdf_mac_addr link_mac_addr;
3673 	bool is_link_vdev = false;
3674 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
3675 	uint8_t session_id;
3676 
3677 	is_link_vdev = wlan_vdev_mlme_get_is_mlo_link(mac_ctx->psoc, vdev_id);
3678 	status = mlo_get_sta_link_mac_addr(vdev_id, sync_ind,
3679 					   &link_mac_addr);
3680 
3681 	if (QDF_IS_STATUS_ERROR(status))
3682 		return NULL;
3683 
3684 	/* In case of legacy to mlo roaming, create pe session */
3685 	if (!pe_session && is_link_vdev) {
3686 		pe_session = pe_create_session(mac_ctx, &link_mac_addr.bytes[0],
3687 					       &session_id,
3688 					       mac_ctx->lim.max_sta_of_pe_session,
3689 					       eSIR_INFRASTRUCTURE_MODE,
3690 					       vdev_id);
3691 		if (!pe_session) {
3692 			pe_err("vdev_id %d : pe session create failed BSSID"
3693 			       QDF_MAC_ADDR_FMT, vdev_id,
3694 			       QDF_MAC_ADDR_REF(link_mac_addr.bytes));
3695 			return NULL;
3696 		}
3697 	}
3698 
3699 	return pe_session;
3700 }
3701 
3702 QDF_STATUS
3703 lim_create_and_fill_link_session(struct mac_context *mac_ctx,
3704 				 uint8_t vdev_id,
3705 				 struct roam_offload_synch_ind *sync_ind,
3706 				 uint16_t ie_len)
3707 {
3708 	struct pe_session *pe_session;
3709 	QDF_STATUS status;
3710 
3711 	if (!mac_ctx)
3712 		return QDF_STATUS_E_INVAL;
3713 
3714 	pe_session = lim_cm_roam_create_session(mac_ctx, vdev_id, sync_ind);
3715 	if (!pe_session)
3716 		goto fail;
3717 
3718 	status = lim_cm_fill_link_session(mac_ctx, vdev_id,
3719 					  pe_session, sync_ind, ie_len);
3720 	if (QDF_IS_STATUS_ERROR(status))
3721 		goto fail;
3722 
3723 	return QDF_STATUS_SUCCESS;
3724 
3725 fail:
3726 	if (pe_session)
3727 		pe_delete_session(mac_ctx, pe_session);
3728 
3729 	pe_err("MLO ROAM: Link session creation failed");
3730 	return QDF_STATUS_E_FAILURE;
3731 }
3732 
3733 void lim_roam_mlo_create_peer(struct mac_context *mac,
3734 			      struct roam_offload_synch_ind *sync_ind,
3735 			      uint8_t vdev_id,
3736 			      uint8_t *peer_mac)
3737 {
3738 	struct wlan_objmgr_vdev *vdev;
3739 	struct wlan_objmgr_peer *link_peer = NULL;
3740 	uint8_t link_id;
3741 	struct mlo_partner_info partner_info;
3742 	struct qdf_mac_addr link_addr;
3743 	QDF_STATUS status;
3744 
3745 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc,
3746 						    vdev_id,
3747 						    WLAN_LEGACY_MAC_ID);
3748 	if (!vdev)
3749 		return;
3750 
3751 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
3752 		goto end;
3753 
3754 	link_id = mlo_roam_get_link_id(vdev_id, sync_ind);
3755 	/* currently only 2 link MLO supported */
3756 	partner_info.num_partner_links = 1;
3757 	status = mlo_get_sta_link_mac_addr(vdev_id, sync_ind, &link_addr);
3758 	if (QDF_IS_STATUS_ERROR(status)) {
3759 		pe_err("Link mac address not found");
3760 		goto end;
3761 	}
3762 
3763 	qdf_mem_copy(partner_info.partner_link_info[0].link_addr.bytes,
3764 		     link_addr.bytes, QDF_MAC_ADDR_SIZE);
3765 	partner_info.partner_link_info[0].link_id = link_id;
3766 	pe_debug("link_addr " QDF_MAC_ADDR_FMT,
3767 		 QDF_MAC_ADDR_REF(
3768 			partner_info.partner_link_info[0].link_addr.bytes));
3769 
3770 	/* Get the bss peer obj */
3771 	link_peer = wlan_objmgr_get_peer_by_mac(mac->psoc, peer_mac,
3772 						WLAN_LEGACY_MAC_ID);
3773 	if (!link_peer)
3774 		goto end;
3775 
3776 	status = wlan_mlo_peer_create(vdev, link_peer,
3777 				      &partner_info, NULL, 0);
3778 
3779 	if (QDF_IS_STATUS_ERROR(status))
3780 		pe_err("Peer creation failed");
3781 
3782 	wlan_objmgr_peer_release_ref(link_peer, WLAN_LEGACY_MAC_ID);
3783 
3784 end:
3785 	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
3786 }
3787 
3788 void
3789 lim_mlo_roam_delete_link_peer(struct pe_session *pe_session,
3790 			      tpDphHashNode sta_ds)
3791 {
3792 	struct wlan_objmgr_peer *peer = NULL;
3793 	struct mac_context *mac;
3794 
3795 	mac = cds_get_context(QDF_MODULE_ID_PE);
3796 	if (!mac) {
3797 		pe_err("mac ctx is null");
3798 		return;
3799 	}
3800 	if (!pe_session) {
3801 		pe_err("pe session is null");
3802 		return;
3803 	}
3804 	if (!sta_ds) {
3805 		pe_err("sta ds is null");
3806 		return;
3807 	}
3808 
3809 	peer = wlan_objmgr_get_peer_by_mac(mac->psoc,
3810 					   sta_ds->staAddr,
3811 					   WLAN_LEGACY_MAC_ID);
3812 	if (!peer) {
3813 		mlo_err("Peer is null");
3814 		return;
3815 	}
3816 
3817 	wlan_mlo_link_peer_delete(peer);
3818 
3819 	wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
3820 }
3821 #endif
3822 
3823 #ifdef WLAN_FEATURE_11BE_MLO
3824 static bool
3825 lim_match_link_info(uint8_t req_link_id,
3826 		    struct qdf_mac_addr *link_addr,
3827 		    struct mlo_partner_info *partner_info)
3828 {
3829 	uint8_t i;
3830 
3831 	for (i = 0; i < partner_info->num_partner_links; i++) {
3832 		if (partner_info->partner_link_info[i].link_id == req_link_id &&
3833 		    (qdf_is_macaddr_equal(link_addr,
3834 					  &partner_info->partner_link_info[i].link_addr)))
3835 			return true;
3836 	}
3837 
3838 	return false;
3839 }
3840 
3841 static QDF_STATUS
3842 lim_add_bcn_probe(struct wlan_objmgr_vdev *vdev, uint8_t *bcn_probe,
3843 		  uint32_t len, qdf_freq_t freq, int32_t rssi)
3844 {
3845 	qdf_nbuf_t buf;
3846 	struct wlan_objmgr_pdev *pdev;
3847 	uint8_t *data, i, vdev_id;
3848 	struct mgmt_rx_event_params rx_param = {0};
3849 	struct wlan_frame_hdr *hdr;
3850 	enum mgmt_frame_type frm_type = MGMT_BEACON;
3851 	QDF_STATUS status = QDF_STATUS_SUCCESS;
3852 
3853 	vdev_id = wlan_vdev_get_id(vdev);
3854 	if (!bcn_probe || !len || (len < sizeof(*hdr)) ||
3855 	    len > MAX_MGMT_MPDU_LEN) {
3856 		pe_err("bcn_probe is null or invalid len %d",
3857 		       len);
3858 		return QDF_STATUS_E_FAILURE;
3859 	}
3860 
3861 	pdev = wlan_vdev_get_pdev(vdev);
3862 	if (!pdev) {
3863 		pe_err("Failed to find pdev");
3864 		return QDF_STATUS_E_FAILURE;
3865 	}
3866 
3867 	hdr = (struct wlan_frame_hdr *)bcn_probe;
3868 	if ((hdr->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_MASK) ==
3869 	    MGMT_SUBTYPE_PROBE_RESP)
3870 		frm_type = MGMT_PROBE_RESP;
3871 
3872 	rx_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
3873 	rx_param.chan_freq = freq;
3874 	rx_param.rssi = rssi;
3875 
3876 	/* Set all per chain rssi as invalid */
3877 	for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++)
3878 		rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI;
3879 
3880 	buf = qdf_nbuf_alloc(NULL, qdf_roundup(len, 4), 0, 4, false);
3881 	if (!buf)
3882 		return QDF_STATUS_E_FAILURE;
3883 
3884 	qdf_nbuf_put_tail(buf, len);
3885 	qdf_nbuf_set_protocol(buf, ETH_P_CONTROL);
3886 
3887 	data = qdf_nbuf_data(buf);
3888 	qdf_mem_copy(data, bcn_probe, len);
3889 
3890 	pe_debug("MLO: add prb rsp to scan db");
3891 	/* buf will be freed by scan module in error or success case */
3892 	status = wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(pdev), buf,
3893 			&rx_param, frm_type);
3894 
3895 	return status;
3896 }
3897 
3898 #ifdef WLAN_FEATURE_11BE_MLO
3899 static QDF_STATUS
3900 lim_validate_probe_rsp_link_info(struct pe_session *session_entry,
3901 				 uint8_t *probe_rsp,
3902 				 uint32_t probe_rsp_len)
3903 {
3904 	QDF_STATUS status = QDF_STATUS_SUCCESS;
3905 	uint8_t *ml_ie = NULL;
3906 	qdf_size_t ml_ie_total_len;
3907 	struct mlo_partner_info partner_info;
3908 	uint8_t i;
3909 	struct mlo_partner_info ml_partner_info;
3910 
3911 	status = util_find_mlie(probe_rsp + WLAN_PROBE_RESP_IES_OFFSET,
3912 				probe_rsp_len - WLAN_PROBE_RESP_IES_OFFSET,
3913 				&ml_ie, &ml_ie_total_len);
3914 	if (QDF_IS_STATUS_ERROR(status)) {
3915 		pe_err("Mlo ie not found in Probe response");
3916 		return status;
3917 	}
3918 	status = util_get_bvmlie_persta_partner_info(ml_ie,
3919 						     ml_ie_total_len,
3920 						     &partner_info);
3921 
3922 	if (QDF_IS_STATUS_ERROR(status)) {
3923 		pe_err("Per STA profile parsing failed");
3924 		return status;
3925 	}
3926 
3927 	ml_partner_info = session_entry->lim_join_req->partner_info;
3928 	for (i = 0; i < ml_partner_info.num_partner_links; i++) {
3929 		if (!lim_match_link_info(ml_partner_info.partner_link_info[i].link_id,
3930 					 &ml_partner_info.partner_link_info[i].link_addr,
3931 					 &partner_info)) {
3932 			pe_err("Prb req link info does not match prb resp link info");
3933 			return QDF_STATUS_E_PROTO;
3934 		}
3935 	}
3936 
3937 	return status;
3938 }
3939 
3940 static void
3941 lim_clear_ml_partner_info(struct pe_session *session_entry)
3942 {
3943 	uint8_t idx;
3944 	struct mlo_partner_info *partner_info = NULL;
3945 
3946 	if (!session_entry || !session_entry->lim_join_req)
3947 		return;
3948 
3949 	partner_info = &session_entry->lim_join_req->partner_info;
3950 	if (!partner_info) {
3951 		pe_err("Partner link info not present");
3952 		return;
3953 	}
3954 	pe_debug_rl("Clear Partner Link/s information");
3955 	for (idx = 0; idx < partner_info->num_partner_links; idx++) {
3956 		mlo_mgr_clear_ap_link_info(session_entry->vdev,
3957 			partner_info->partner_link_info[idx].link_addr.bytes);
3958 
3959 		partner_info->partner_link_info[idx].link_id = 0;
3960 		qdf_zero_macaddr(
3961 			&partner_info->partner_link_info[idx].link_addr);
3962 	}
3963 	partner_info->num_partner_links = 0;
3964 }
3965 
3966 static QDF_STATUS
3967 lim_compare_scan_entry_partner_info_with_join_req(struct mlo_partner_info
3968 						  *partner_info,
3969 						  struct partner_link_info
3970 						  *partner_link)
3971 {
3972 	int i;
3973 	int j;
3974 	struct mlo_link_info *partner_link_info;
3975 	struct partner_link_info *scan_info;
3976 	int num_matching_links = 0;
3977 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
3978 
3979 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
3980 		partner_link_info = &partner_info->partner_link_info[i];
3981 		for (j = 0; j < MLD_MAX_LINKS - 1; j++) {
3982 			scan_info = &partner_link[j];
3983 			if (!scan_info)
3984 				continue;
3985 			/*
3986 			 * do not compare if both have freq as zero
3987 			 */
3988 			if (scan_info->freq == 0)
3989 				continue;
3990 
3991 			if (scan_info->freq == partner_link_info->chan_freq) {
3992 				qdf_mem_cmp(partner_link_info->link_addr.bytes,
3993 					    scan_info->link_addr.bytes,
3994 					    QDF_MAC_ADDR_SIZE);
3995 				num_matching_links += 1;
3996 			}
3997 		}
3998 	}
3999 
4000 	if (partner_info->num_partner_links == num_matching_links) {
4001 		pe_debug("num of matching partner links %d",
4002 			 num_matching_links);
4003 		status = QDF_STATUS_SUCCESS;
4004 	}
4005 
4006 	return status;
4007 }
4008 
4009 static QDF_STATUS
4010 lim_check_scan_db_for_join_req_partner_info(struct pe_session *session_entry,
4011 					    struct mac_context *mac_ctx)
4012 {
4013 	struct join_req *lim_join_req;
4014 	struct wlan_objmgr_pdev *pdev;
4015 	struct partner_link_info *partner_link = NULL;
4016 	struct qdf_mac_addr qdf_bssid;
4017 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
4018 	struct mlo_partner_info *partner_info;
4019 	uint16_t join_req_freq = 0;
4020 	struct scan_cache_entry *cache_entry;
4021 
4022 	if (!session_entry) {
4023 		pe_err("session entry is NULL");
4024 		return QDF_STATUS_E_NULL_VALUE;
4025 	}
4026 
4027 	if (!mac_ctx) {
4028 		pe_err("mac context is NULL");
4029 		return QDF_STATUS_E_NULL_VALUE;
4030 	}
4031 
4032 	lim_join_req = session_entry->lim_join_req;
4033 	if (!lim_join_req) {
4034 		pe_err("join req is NULL");
4035 		return QDF_STATUS_E_NULL_VALUE;
4036 	}
4037 
4038 	pdev = mac_ctx->pdev;
4039 	if (!pdev) {
4040 		pe_err("pdev is NULL");
4041 		return QDF_STATUS_E_NULL_VALUE;
4042 	}
4043 
4044 	partner_link = qdf_mem_malloc(sizeof(struct partner_link_info) *
4045 			(MLD_MAX_LINKS - 1));
4046 
4047 	if (!partner_link)
4048 		return QDF_STATUS_E_FAILURE;
4049 
4050 	qdf_mem_copy(&qdf_bssid,
4051 		     &(lim_join_req->bssDescription.bssId),
4052 		     QDF_MAC_ADDR_SIZE);
4053 
4054 	join_req_freq = lim_join_req->bssDescription.chan_freq;
4055 
4056 	cache_entry = wlan_scan_get_scan_entry_by_mac_freq(pdev,
4057 							   &qdf_bssid,
4058 							   join_req_freq);
4059 
4060 	if (!cache_entry) {
4061 		pe_err("failed to get partner link info by mac addr");
4062 		status = QDF_STATUS_E_FAILURE;
4063 		goto free_mem;
4064 	}
4065 
4066 	qdf_mem_copy(partner_link, cache_entry->ml_info.link_info,
4067 		     sizeof(struct partner_link_info) * (MLD_MAX_LINKS - 1));
4068 
4069 	util_scan_free_cache_entry(cache_entry);
4070 
4071 	partner_info = &lim_join_req->partner_info;
4072 
4073 	status = lim_compare_scan_entry_partner_info_with_join_req(
4074 			partner_info, partner_link);
4075 
4076 	if (!QDF_IS_STATUS_SUCCESS(status)) {
4077 		pe_err("failed to match num of partner links in scan entry");
4078 		status = QDF_STATUS_E_FAILURE;
4079 		goto free_mem;
4080 	}
4081 
4082 free_mem:
4083 	qdf_mem_free(partner_link);
4084 	return status;
4085 }
4086 
4087 QDF_STATUS lim_update_mlo_mgr_info(struct mac_context *mac_ctx,
4088 				   struct wlan_objmgr_vdev *vdev,
4089 				   struct qdf_mac_addr *link_addr,
4090 				   uint8_t link_id, uint16_t freq)
4091 {
4092 	struct wlan_objmgr_pdev *pdev;
4093 	struct scan_cache_entry *cache_entry;
4094 	struct wlan_channel channel;
4095 	bool is_security_allowed;
4096 
4097 	pdev = mac_ctx->pdev;
4098 	if (!pdev) {
4099 		pe_err("pdev is NULL");
4100 		return QDF_STATUS_E_NULL_VALUE;
4101 	}
4102 
4103 	cache_entry = wlan_scan_get_scan_entry_by_mac_freq(pdev, link_addr,
4104 							   freq);
4105 	if (!cache_entry)
4106 		return QDF_STATUS_E_FAILURE;
4107 
4108 	/**
4109 	 * Reject all the partner link if any partner link  doesn’t pass the
4110 	 * security check and proceed connection with single link.
4111 	 */
4112 	is_security_allowed =
4113 		wlan_cm_is_eht_allowed_for_current_security(
4114 					wlan_pdev_get_psoc(mac_ctx->pdev),
4115 					cache_entry);
4116 
4117 	if (!is_security_allowed) {
4118 		mlme_debug("current security is not valid for partner link link_addr:" QDF_MAC_ADDR_FMT,
4119 			   QDF_MAC_ADDR_REF(link_addr->bytes));
4120 		util_scan_free_cache_entry(cache_entry);
4121 		return QDF_STATUS_E_FAILURE;
4122 	}
4123 
4124 	channel.ch_freq = cache_entry->channel.chan_freq;
4125 	channel.ch_ieee = wlan_reg_freq_to_chan(pdev, channel.ch_freq);
4126 	channel.ch_phymode = cache_entry->phy_mode;
4127 	channel.ch_cfreq1 = cache_entry->channel.cfreq0;
4128 	channel.ch_cfreq2 = cache_entry->channel.cfreq1;
4129 
4130 	util_scan_free_cache_entry(cache_entry);
4131 
4132 	mlo_mgr_update_ap_channel_info(vdev, link_id, (uint8_t *)link_addr,
4133 				       channel);
4134 
4135 	return QDF_STATUS_SUCCESS;
4136 }
4137 #else
4138 static inline void
4139 lim_clear_ml_partner_info(struct pe_session *session_entry)
4140 {
4141 }
4142 
4143 static QDF_STATUS
4144 lim_check_db_for_join_req_partner_info(struct pe_session *session_entry,
4145 				       struct mac_context *mac_ctx)
4146 {
4147 
4148 	return QDF_STATUS_E_FAILURE;
4149 }
4150 #endif
4151 
4152 QDF_STATUS lim_check_for_ml_probe_req(struct pe_session *session)
4153 {
4154 	if (!session || !session->lim_join_req)
4155 		return QDF_STATUS_E_NULL_VALUE;
4156 
4157 	if (session->lim_join_req->is_ml_probe_req_sent)
4158 		return QDF_STATUS_SUCCESS;
4159 
4160 	return QDF_STATUS_E_FAILURE;
4161 }
4162 
4163 QDF_STATUS
4164 lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx,
4165 				struct pe_session *session_entry,
4166 				tpSirProbeRespBeacon rcvd_probe_resp,
4167 				uint8_t *probe_rsp,
4168 				uint32_t probe_rsp_len,
4169 				int32_t rssi)
4170 {
4171 	struct element_info link_probe_rsp = {0};
4172 	struct qdf_mac_addr sta_link_addr;
4173 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
4174 	struct mlo_link_info *link_info = NULL;
4175 	struct mlo_partner_info *partner_info;
4176 	uint8_t chan;
4177 	uint8_t op_class;
4178 	uint16_t chan_freq, gen_frame_len;
4179 	uint8_t idx;
4180 	uint8_t req_link_id;
4181 
4182 	if (!session_entry)
4183 		return QDF_STATUS_E_NULL_VALUE;
4184 
4185 	if (!session_entry->lim_join_req)
4186 		return status;
4187 
4188 	partner_info = &session_entry->lim_join_req->partner_info;
4189 	if (!partner_info->num_partner_links) {
4190 		pe_debug("No partner link info since supports 1 link only");
4191 		return status;
4192 	}
4193 
4194 	if (session_entry->lim_join_req->is_ml_probe_req_sent &&
4195 	    rcvd_probe_resp->mlo_ie.mlo_ie_present) {
4196 		session_entry->lim_join_req->is_ml_probe_req_sent = false;
4197 
4198 		partner_info = &session_entry->lim_join_req->partner_info;
4199 		if (!partner_info->num_partner_links) {
4200 			pe_err("STA doesn't have any partner link information");
4201 			return QDF_STATUS_E_FAILURE;
4202 		}
4203 
4204 		status = lim_validate_probe_rsp_link_info(session_entry,
4205 							  probe_rsp,
4206 							  probe_rsp_len);
4207 		if (QDF_IS_STATUS_ERROR(status)) {
4208 			if(QDF_IS_STATUS_ERROR(
4209 				lim_check_scan_db_for_join_req_partner_info(
4210 						session_entry,
4211 						mac_ctx)))
4212 				lim_clear_ml_partner_info(session_entry);
4213 			return status;
4214 		}
4215 
4216 		/*
4217 		 * When an MLO probe response is received from a link,
4218 		 * the other link might be superior in features compared to the
4219 		 * link that sent ML probe rsp and the per-STA profile
4220 		 * info may carry corresponding IEs. These IEs are extracted
4221 		 * and added to IE list of link probe response while generating
4222 		 * it. So, the new link probe response generated might be of
4223 		 * more size than the original link probe rsp. Allocate buffer
4224 		 * for the scan entry to accommodate all of the IEs got
4225 		 * generated as part of link probe rsp generation. Allocate
4226 		 * MAX_MGMT_MPDU_LEN bytes for IEs as the max frame size that
4227 		 * can be received from AP is MAX_MGMT_MPDU_LEN bytes.
4228 		 */
4229 		gen_frame_len = MAX_MGMT_MPDU_LEN;
4230 
4231 		link_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len);
4232 		if (!link_probe_rsp.ptr) {
4233 			if(QDF_IS_STATUS_ERROR(
4234 				lim_check_scan_db_for_join_req_partner_info(
4235 					session_entry,
4236 					mac_ctx)))
4237 				lim_clear_ml_partner_info(session_entry);
4238 			return QDF_STATUS_E_NOMEM;
4239 		}
4240 
4241 		link_probe_rsp.len = gen_frame_len;
4242 		qdf_mem_copy(&sta_link_addr, session_entry->self_mac_addr,
4243 			     QDF_MAC_ADDR_SIZE);
4244 
4245 		for (idx = 0; idx < partner_info->num_partner_links; idx++) {
4246 			req_link_id =
4247 				partner_info->partner_link_info[idx].link_id;
4248 			status = util_gen_link_probe_rsp(probe_rsp,
4249 					probe_rsp_len, req_link_id,
4250 					sta_link_addr, link_probe_rsp.ptr,
4251 					gen_frame_len,
4252 					(qdf_size_t *)&link_probe_rsp.len);
4253 
4254 			if (QDF_IS_STATUS_ERROR(status)) {
4255 				pe_err("MLO: Link %d probe resp gen failed %d",
4256 				       req_link_id, status);
4257 				status =
4258 				   lim_check_scan_db_for_join_req_partner_info(
4259 							session_entry, mac_ctx);
4260 				if (QDF_IS_STATUS_ERROR(status))
4261 				       lim_clear_ml_partner_info(session_entry);
4262 
4263 				goto end;
4264 			}
4265 
4266 			pe_debug("MLO:link probe rsp size:%u orig probe rsp:%u",
4267 				 link_probe_rsp.len, probe_rsp_len);
4268 
4269 			link_info = &partner_info->partner_link_info[idx];
4270 			wlan_get_chan_by_bssid_from_rnr(session_entry->vdev,
4271 							session_entry->cm_id,
4272 							&link_info->link_addr,
4273 							&chan, &op_class);
4274 			if (!chan)
4275 				wlan_get_chan_by_link_id_from_rnr(
4276 							session_entry->vdev,
4277 							session_entry->cm_id,
4278 							link_info->link_id,
4279 							&chan, &op_class);
4280 			if (!chan) {
4281 				pe_err("Invalid link id %d link mac: " QDF_MAC_ADDR_FMT,
4282 				  link_info->link_id,
4283 				  QDF_MAC_ADDR_REF(link_info->link_addr.bytes));
4284 				status =
4285 				   lim_check_scan_db_for_join_req_partner_info(
4286 					session_entry, mac_ctx);
4287 				if (QDF_IS_STATUS_ERROR(status))
4288 				       lim_clear_ml_partner_info(session_entry);
4289 
4290 				status = QDF_STATUS_E_FAILURE;
4291 				goto end;
4292 			}
4293 			chan_freq =
4294 				wlan_reg_chan_opclass_to_freq(chan, op_class,
4295 							      true);
4296 
4297 			status = lim_add_bcn_probe(session_entry->vdev,
4298 						   link_probe_rsp.ptr,
4299 						   link_probe_rsp.len,
4300 						   chan_freq, rssi);
4301 			if (QDF_IS_STATUS_ERROR(status)) {
4302 				pe_err("failed to add bcn probe %d", status);
4303 				status =
4304 				   lim_check_scan_db_for_join_req_partner_info(
4305 					session_entry, mac_ctx);
4306 				if (QDF_IS_STATUS_ERROR(status))
4307 				       lim_clear_ml_partner_info(session_entry);
4308 
4309 				goto end;
4310 			}
4311 
4312 			status = lim_update_mlo_mgr_info(mac_ctx,
4313 							 session_entry->vdev,
4314 							 &link_info->link_addr,
4315 							 link_info->link_id,
4316 							 link_info->chan_freq);
4317 			if (QDF_IS_STATUS_ERROR(status)) {
4318 				pe_err("failed to update mlo_mgr %d", status);
4319 				lim_clear_ml_partner_info(session_entry);
4320 
4321 				goto end;
4322 			}
4323 		}
4324 	} else if (session_entry->lim_join_req->is_ml_probe_req_sent &&
4325 		   !rcvd_probe_resp->mlo_ie.mlo_ie_present) {
4326 		status =
4327 			lim_check_scan_db_for_join_req_partner_info(
4328 						session_entry, mac_ctx);
4329 		if (QDF_IS_STATUS_ERROR(status))
4330 			lim_clear_ml_partner_info(session_entry);
4331 
4332 		status = QDF_STATUS_E_FAILURE;
4333 		return status;
4334 	} else {
4335 		return status;
4336 	}
4337 end:
4338 	if (link_probe_rsp.ptr)
4339 		qdf_mem_free(link_probe_rsp.ptr);
4340 	link_probe_rsp.ptr = NULL;
4341 	link_probe_rsp.len = 0;
4342 	return status;
4343 }
4344 
4345 QDF_STATUS
4346 lim_process_cu_for_probe_rsp(struct mac_context *mac_ctx,
4347 			     struct pe_session *session,
4348 			     uint8_t *probe_rsp,
4349 			     uint32_t probe_rsp_len)
4350 {
4351 	struct element_info link_probe_rsp;
4352 	struct qdf_mac_addr sta_link_addr;
4353 	struct wlan_objmgr_vdev *vdev;
4354 	struct wlan_objmgr_vdev *partner_vdev;
4355 	uint8_t *ml_ie = NULL;
4356 	qdf_size_t ml_ie_total_len = 0;
4357 	struct mlo_partner_info partner_info;
4358 	uint8_t i, link_id, vdev_id;
4359 	uint8_t bpcc, aui;
4360 	bool cu_flag = false;
4361 	const uint8_t *rnr;
4362 	bool msd_cap_found = false;
4363 	QDF_STATUS status = QDF_STATUS_E_INVAL;
4364 
4365 	vdev = session->vdev;
4366 	if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev))
4367 		return status;
4368 
4369 	rnr = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_REDUCED_NEIGHBOR_REPORT,
4370 				   probe_rsp + WLAN_PROBE_RESP_IES_OFFSET,
4371 				   probe_rsp_len - WLAN_PROBE_RESP_IES_OFFSET);
4372 	if (!rnr)
4373 		return status;
4374 
4375 	status = util_find_mlie(probe_rsp + WLAN_PROBE_RESP_IES_OFFSET,
4376 				probe_rsp_len - WLAN_PROBE_RESP_IES_OFFSET,
4377 				&ml_ie, &ml_ie_total_len);
4378 	if (QDF_IS_STATUS_ERROR(status)) {
4379 		pe_err("Mlo ie not found in Probe response");
4380 		return status;
4381 	}
4382 
4383 	util_get_bvmlie_msd_cap(ml_ie, ml_ie_total_len, &msd_cap_found,
4384 				NULL);
4385 	if (msd_cap_found) {
4386 		wlan_vdev_mlme_cap_clear(vdev, WLAN_VDEV_C_EMLSR_CAP);
4387 		pe_debug("EMLSR not supported with D2.0 AP");
4388 	}
4389 
4390 	status = util_get_bvmlie_persta_partner_info(ml_ie,
4391 						     ml_ie_total_len,
4392 						     &partner_info);
4393 	if (QDF_IS_STATUS_ERROR(status)) {
4394 		pe_err("Per STA profile parsing failed");
4395 		return status;
4396 	}
4397 
4398 	link_probe_rsp.ptr = qdf_mem_malloc(probe_rsp_len);
4399 	if (!link_probe_rsp.ptr)
4400 		return QDF_STATUS_E_NOMEM;
4401 
4402 	for (i = 0; i < partner_info.num_partner_links; i++) {
4403 		link_id = partner_info.partner_link_info[i].link_id;
4404 		partner_vdev = mlo_get_vdev_by_link_id(vdev, link_id,
4405 						       WLAN_LEGACY_MAC_ID);
4406 		if (!partner_vdev) {
4407 			pe_debug("No partner vdev for link id %d", link_id);
4408 			continue;
4409 		}
4410 
4411 		status = lim_cu_info_from_rnr_per_link_id(rnr, link_id,
4412 							  &bpcc, &aui);
4413 		if (QDF_IS_STATUS_ERROR(status)) {
4414 			pe_debug("no cu info in rnr for link id %d", link_id);
4415 			goto ref_rel;
4416 		}
4417 
4418 		cu_flag = lim_check_cu_happens(partner_vdev, bpcc);
4419 		if (!cu_flag)
4420 			goto ref_rel;
4421 
4422 		vdev_id = wlan_vdev_get_id(partner_vdev);
4423 		session = pe_find_session_by_vdev_id(mac_ctx, vdev_id);
4424 		if (!session) {
4425 			pe_debug("session is null for vdev id %d", vdev_id);
4426 			goto ref_rel;
4427 		}
4428 
4429 		qdf_mem_copy(&sta_link_addr, session->self_mac_addr,
4430 			     QDF_MAC_ADDR_SIZE);
4431 
4432 		link_probe_rsp.len = probe_rsp_len;
4433 		/* Todo:
4434 		 * it needs to use link_id as parameter to generate
4435 		 * specific probe rsp frame when api util_gen_link_probe_rsp
4436 		 * updated.
4437 		 */
4438 		status =
4439 		     util_gen_link_probe_rsp(probe_rsp, probe_rsp_len, link_id,
4440 					     sta_link_addr, link_probe_rsp.ptr,
4441 					     probe_rsp_len,
4442 					     (qdf_size_t *)&link_probe_rsp.len);
4443 		if (QDF_IS_STATUS_ERROR(status)) {
4444 			pe_err("MLO: Link probe response generation failed %d",
4445 			       status);
4446 			goto ref_rel;
4447 		}
4448 
4449 		lim_process_gen_probe_rsp_frame(mac_ctx, session,
4450 						link_probe_rsp.ptr,
4451 						link_probe_rsp.len);
4452 
4453 ref_rel:
4454 		wlan_objmgr_vdev_release_ref(partner_vdev, WLAN_LEGACY_MAC_ID);
4455 	}
4456 
4457 	qdf_mem_free(link_probe_rsp.ptr);
4458 	link_probe_rsp.ptr = NULL;
4459 	link_probe_rsp.len = 0;
4460 	return status;
4461 }
4462 #endif
4463 
4464 #ifdef WLAN_FEATURE_SR
4465 static
4466 void lim_store_array_to_bit_map(uint64_t *val, uint8_t array[8])
4467 {
4468 	uint32_t bit_map_0 = 0;
4469 	uint32_t bit_map_1 = 0;
4470 
4471 	QDF_SET_BITS(bit_map_0, 0, SR_PADDING_BYTE, array[0]);
4472 	QDF_SET_BITS(bit_map_0, 8, SR_PADDING_BYTE, array[1]);
4473 	QDF_SET_BITS(bit_map_0, 16, SR_PADDING_BYTE, array[2]);
4474 	QDF_SET_BITS(bit_map_0, 24, SR_PADDING_BYTE, array[3]);
4475 	QDF_SET_BITS(bit_map_1, 0, SR_PADDING_BYTE, array[4]);
4476 	QDF_SET_BITS(bit_map_1, 8, SR_PADDING_BYTE, array[5]);
4477 	QDF_SET_BITS(bit_map_1, 16, SR_PADDING_BYTE, array[6]);
4478 	QDF_SET_BITS(bit_map_1, 24, SR_PADDING_BYTE, array[7]);
4479 	*val = (uint64_t) bit_map_0 |
4480 	       (((uint64_t)bit_map_1) << 32);
4481 }
4482 
4483 void lim_update_vdev_sr_elements(struct pe_session *session_entry,
4484 				 tpDphHashNode sta_ds)
4485 {
4486 	uint8_t sr_ctrl;
4487 	uint8_t non_srg_max_pd_offset, srg_min_pd_offset, srg_max_pd_offset;
4488 	uint64_t srg_color_bit_map = 0;
4489 	uint64_t srg_partial_bssid_bit_map = 0;
4490 	tDot11fIEspatial_reuse *srp_ie = &sta_ds->parsed_ies.srp_ie;
4491 
4492 	sr_ctrl = srp_ie->sr_value15_allow << 4 |
4493 		  srp_ie->srg_info_present << 3 |
4494 		  srp_ie->non_srg_offset_present << 2 |
4495 		  srp_ie->non_srg_pd_sr_disallow << 1 |
4496 		  srp_ie->psr_disallow;
4497 	non_srg_max_pd_offset =
4498 		srp_ie->non_srg_offset.info.non_srg_pd_max_offset;
4499 	srg_min_pd_offset = srp_ie->srg_info.info.srg_pd_min_offset;
4500 	srg_max_pd_offset = srp_ie->srg_info.info.srg_pd_max_offset;
4501 	lim_store_array_to_bit_map(&srg_color_bit_map,
4502 				   srp_ie->srg_info.info.srg_color);
4503 	lim_store_array_to_bit_map(&srg_partial_bssid_bit_map,
4504 				   srp_ie->srg_info.info.srg_partial_bssid);
4505 	pe_debug("Spatial Reuse Control field: %x Non-SRG Max PD Offset: %x SRG range %d - %d srg_color_bit_map:%llu srg_partial_bssid_bit_map: %llu",
4506 		 sr_ctrl, non_srg_max_pd_offset, srg_min_pd_offset,
4507 		 srg_max_pd_offset, srg_color_bit_map,
4508 		 srg_partial_bssid_bit_map);
4509 	wlan_vdev_mlme_set_srg_partial_bssid_bit_map(session_entry->vdev,
4510 						     srg_partial_bssid_bit_map);
4511 	wlan_vdev_mlme_set_srg_bss_color_bit_map(session_entry->vdev,
4512 						 srg_color_bit_map);
4513 	wlan_vdev_mlme_set_sr_ctrl(session_entry->vdev, sr_ctrl);
4514 	wlan_vdev_mlme_set_non_srg_pd_offset(session_entry->vdev,
4515 					     non_srg_max_pd_offset);
4516 	wlan_vdev_mlme_set_srg_pd_offset(session_entry->vdev, srg_max_pd_offset,
4517 					 srg_min_pd_offset);
4518 
4519 }
4520 #endif
4521