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