xref: /wlan-driver/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2012-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 sch_beacon_process.cc contains beacon processing related
22  * functions
23  *
24  * Author:      Sandesh Goel
25  * Date:        02/25/02
26  * History:-
27  * Date            Modified by    Modification Information
28  * --------------------------------------------------------------------
29  *
30  */
31 
32 #include "cds_api.h"
33 #include "wni_cfg.h"
34 
35 #include "cfg_ucfg_api.h"
36 #include "lim_api.h"
37 #include "utils_api.h"
38 #include "sch_api.h"
39 
40 #include "lim_utils.h"
41 #include "lim_send_messages.h"
42 #include "rrm_api.h"
43 #include "lim_mlo.h"
44 
45 #ifdef FEATURE_WLAN_DIAG_SUPPORT
46 #include "host_diag_core_log.h"
47 #endif /* FEATURE_WLAN_DIAG_SUPPORT */
48 
49 #include "wma.h"
50 
51 #include "wlan_lmac_if_def.h"
52 #include "wlan_reg_services_api.h"
53 #include "wlan_mlo_mgr_sta.h"
54 #include "wlan_mlme_main.h"
55 #include <wlan_mlo_mgr_link_switch.h>
56 
57 static void
ap_beacon_process_5_ghz(struct mac_context * mac_ctx,uint8_t * rx_pkt_info,tpSchBeaconStruct bcn_struct,tpUpdateBeaconParams bcn_prm,struct pe_session * session,uint32_t phy_mode)58 ap_beacon_process_5_ghz(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
59 			tpSchBeaconStruct bcn_struct,
60 			tpUpdateBeaconParams bcn_prm, struct pe_session *session,
61 			uint32_t phy_mode)
62 {
63 	tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info);
64 
65 	if (!session->htCapability)
66 		return;
67 
68 	if (bcn_struct->chan_freq != session->curr_op_freq)
69 		return;
70 
71 	/* 11a (non HT) AP  overlaps or */
72 	/* HT AP with HT op mode as mixed overlaps. */
73 	/* HT AP with HT op mode as overlap legacy overlaps. */
74 	if (!bcn_struct->HTInfo.present
75 	    || (eSIR_HT_OP_MODE_MIXED == bcn_struct->HTInfo.opMode)
76 	    || (eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode)) {
77 		lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId,
78 					&(session->gLimOverlap11aParams));
79 
80 		if (session->gLimOverlap11aParams.numSta
81 		    && !session->gLimOverlap11aParams.protectionEnabled) {
82 			lim_update_11a_protection(mac_ctx, true, true,
83 						 bcn_prm, session);
84 		}
85 		return;
86 	}
87 	/* HT AP with HT20 op mode overlaps. */
88 	if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT != bcn_struct->HTInfo.opMode)
89 		return;
90 
91 	lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId,
92 				     &(session->gLimOverlapHt20Params));
93 
94 	if (session->gLimOverlapHt20Params.numSta
95 	    && !session->gLimOverlapHt20Params.protectionEnabled)
96 		lim_enable_ht20_protection(mac_ctx, true, true,
97 					   bcn_prm, session);
98 }
99 
100 static void
ap_beacon_process_24_ghz(struct mac_context * mac_ctx,uint8_t * rx_pkt_info,tpSchBeaconStruct bcn_struct,tpUpdateBeaconParams bcn_prm,struct pe_session * session,uint32_t phy_mode)101 ap_beacon_process_24_ghz(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
102 			 tpSchBeaconStruct bcn_struct,
103 			 tpUpdateBeaconParams bcn_prm, struct pe_session *session,
104 			 uint32_t phy_mode)
105 {
106 	tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info);
107 	bool tmp_exp = false;
108 	/* We are 11G AP. */
109 	if ((phy_mode == WNI_CFG_PHY_MODE_11G) &&
110 	    (false == session->htCapability)) {
111 		if (bcn_struct->chan_freq != session->curr_op_freq)
112 			return;
113 
114 		tmp_exp = (!bcn_struct->erpPresent &&
115 			   !bcn_struct->HTInfo.present) ||
116 			    /* if erp not present then  11B AP overlapping */
117 			  (!mac_ctx->mlme_cfg->sta.ignore_peer_erp_info &&
118 			   bcn_struct->erpPresent &&
119 			   (bcn_struct->erpIEInfo.useProtection ||
120 			    bcn_struct->erpIEInfo.nonErpPresent));
121 		if (!tmp_exp)
122 			return;
123 #ifdef FEATURE_WLAN_ESE
124 		if (wlan_cm_get_ese_assoc(mac_ctx->pdev, session->vdev_id))
125 			pe_info("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d",
126 				bcn_struct->erpPresent,
127 				bcn_struct->erpIEInfo.useProtection,
128 				bcn_struct->erpIEInfo.nonErpPresent);
129 #endif
130 		lim_enable_overlap11g_protection(mac_ctx, bcn_prm,
131 						 mac_hdr, session);
132 		return;
133 	}
134 	/* handling the case when HT AP has overlapping legacy BSS. */
135 	if (!session->htCapability)
136 		return;
137 
138 	if (bcn_struct->chan_freq != session->curr_op_freq)
139 		return;
140 
141 	tmp_exp = (!bcn_struct->erpPresent && !bcn_struct->HTInfo.present) ||
142 		    /* if erp not present then  11B AP overlapping */
143 		   (!mac_ctx->mlme_cfg->sta.ignore_peer_erp_info &&
144 		    bcn_struct->erpPresent &&
145 		    (bcn_struct->erpIEInfo.useProtection ||
146 		     bcn_struct->erpIEInfo.nonErpPresent));
147 	if (tmp_exp) {
148 #ifdef FEATURE_WLAN_ESE
149 		if (wlan_cm_get_ese_assoc(mac_ctx->pdev, session->vdev_id)) {
150 			pe_info("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d",
151 				bcn_struct->erpPresent,
152 				bcn_struct->erpIEInfo.useProtection,
153 				bcn_struct->erpIEInfo.nonErpPresent);
154 		}
155 #endif
156 		lim_enable_overlap11g_protection(mac_ctx, bcn_prm,
157 						 mac_hdr, session);
158 	}
159 	/* 11g device overlaps */
160 	tmp_exp = bcn_struct->erpPresent
161 		&& !(bcn_struct->erpIEInfo.useProtection
162 		     || bcn_struct->erpIEInfo.nonErpPresent)
163 		&& !(bcn_struct->HTInfo.present);
164 	if (tmp_exp) {
165 		lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId,
166 					     &(session->gLimOverlap11gParams));
167 
168 		if (session->gLimOverlap11gParams.numSta
169 		    && !session->gLimOverlap11gParams.protectionEnabled)
170 			lim_enable_ht_protection_from11g(mac_ctx, true, true,
171 							 bcn_prm, session);
172 	}
173 	/* ht device overlaps.
174 	 * here we will check for HT related devices only which might need
175 	 * protection. check for 11b and 11g is already done in the previous
176 	 * blocks. so we will not check for HT operating mode as MIXED.
177 	 */
178 	if (!bcn_struct->HTInfo.present)
179 		return;
180 
181 	/*
182 	 * if we are not already in mixed mode or legacy mode as HT operating
183 	 * mode and received beacon has HT operating mode as legacy then we need
184 	 * to enable protection from 11g station. we don't need protection from
185 	 * 11b because if that's needed then our operating mode would have
186 	 * already been set to legacy in the previous blocks.
187 	 */
188 	if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode) &&
189 		!mac_ctx->mlme_cfg->sap_protection_cfg.ignore_peer_ht_opmode) {
190 		if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == mac_ctx->lim.gHTOperMode
191 		    || eSIR_HT_OP_MODE_MIXED == mac_ctx->lim.gHTOperMode)
192 			return;
193 		lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId,
194 					     &(session->gLimOverlap11gParams));
195 		if (session->gLimOverlap11gParams.numSta
196 		    && !session->gLimOverlap11gParams.protectionEnabled)
197 			lim_enable_ht_protection_from11g(mac_ctx, true, true,
198 							 bcn_prm, session);
199 		return;
200 	}
201 
202 	if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == bcn_struct->HTInfo.opMode) {
203 		lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId,
204 					     &(session->gLimOverlapHt20Params));
205 		if (session->gLimOverlapHt20Params.numSta
206 		    && !session->gLimOverlapHt20Params.protectionEnabled)
207 			lim_enable_ht20_protection(mac_ctx, true, true,
208 						   bcn_prm, session);
209 	}
210 }
211 
212 /**
213  * ap_beacon_process() - processes incoming beacons
214  *
215  * @mac_ctx:         mac global context
216  * @rx_pkt_info:     incoming beacon packet
217  * @bcn_struct:      beacon struct
218  * @bcn_prm:         beacon params
219  * @session:         pe session entry
220  *
221  * Return: void
222  */
223 static void
ap_beacon_process(struct mac_context * mac_ctx,uint8_t * rx_pkt_info,tpSchBeaconStruct bcn_struct,tpUpdateBeaconParams bcn_prm,struct pe_session * session)224 ap_beacon_process(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
225 		  tpSchBeaconStruct bcn_struct,
226 		  tpUpdateBeaconParams bcn_prm, struct pe_session *session)
227 {
228 	uint32_t phy_mode;
229 	enum reg_wifi_band rf_band = REG_BAND_UNKNOWN;
230 	/* Get RF band from session */
231 	rf_band = session->limRFBand;
232 
233 	lim_get_phy_mode(mac_ctx, &phy_mode, session);
234 
235 	if (REG_BAND_5G == rf_band)
236 		ap_beacon_process_5_ghz(mac_ctx, rx_pkt_info, bcn_struct,
237 					bcn_prm, session, phy_mode);
238 	else if (REG_BAND_2G == rf_band)
239 		ap_beacon_process_24_ghz(mac_ctx, rx_pkt_info, bcn_struct,
240 					 bcn_prm, session, phy_mode);
241 }
242 
243 /* -------------------------------------------------------------------- */
244 
245 /*
246  * sch_bcn_process_sta() - Process the received beacon frame for sta
247  * @mac_ctx:        mac_ctx
248  * @bcn:            beacon struct
249  * @rx_pkt_info:    received packet info
250  * @session:        pe session pointer
251  * @beaconParams:   update beacon params
252  * @sendProbeReq:   out flag to indicate if probe rsp is to be sent
253  * @pMh:            mac header
254  *
255  * Process the received beacon frame for sta
256  *
257  * Return: success of failure of operation
258  */
259 static bool
sch_bcn_process_sta(struct mac_context * mac_ctx,tpSchBeaconStruct bcn,uint8_t * rx_pkt_info,struct pe_session * session,tUpdateBeaconParams * beaconParams,uint8_t * sendProbeReq,tpSirMacMgmtHdr pMh)260 sch_bcn_process_sta(struct mac_context *mac_ctx,
261 			       tpSchBeaconStruct bcn,
262 			       uint8_t *rx_pkt_info,
263 			       struct pe_session *session,
264 			       tUpdateBeaconParams *beaconParams,
265 			       uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh)
266 {
267 	uint32_t bi;
268 	tpDphHashNode sta = NULL;
269 	QDF_STATUS status;
270 
271 	/*
272 	 *  This handles two cases:
273 	 *  -- Infra STA receiving beacons from AP
274 	 */
275 
276 	/**
277 	 * This is the Beacon received from the AP  we're currently associated
278 	 * with. Check if there are any changes in AP's capabilities
279 	 */
280 	if (bcn->chan_freq != session->curr_op_freq) {
281 		pe_err("Channel Change freq from %d --> %d - Ignoring beacon!",
282 		       session->curr_op_freq, bcn->chan_freq);
283 		return false;
284 	}
285 
286 	/*
287 	 * Ignore bcn as channel switch IE present and csa offload is enabled,
288 	 * as in CSA offload enabled case FW will send Event to switch channel
289 	 */
290 	if (bcn->channelSwitchPresent && wma_is_csa_offload_enabled()) {
291 		pe_err_rl("Ignore bcn as channel switch IE present and csa offload is enabled");
292 		return false;
293 	}
294 
295 	lim_detect_change_in_ap_capabilities(mac_ctx, bcn, session, true);
296 	beaconParams->bss_idx = session->vdev_id;
297 	qdf_mem_copy((uint8_t *) &session->lastBeaconTimeStamp,
298 			(uint8_t *) bcn->timeStamp, sizeof(uint64_t));
299 	session->currentBssBeaconCnt++;
300 	if (session->bcon_dtim_period != bcn->tim.dtimPeriod) {
301 		session->bcon_dtim_period = bcn->tim.dtimPeriod;
302 		lim_send_set_dtim_period(mac_ctx, bcn->tim.dtimPeriod,
303 				session);
304 	}
305 	MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF,
306 	       session->peSessionId, bcn->timeStamp[0]));
307 	MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF,
308 	       session->peSessionId, bcn->timeStamp[1]));
309 
310 	/* Read beacon interval session Entry */
311 	bi = session->beaconParams.beaconInterval;
312 	if (bi != bcn->beaconInterval) {
313 		pe_debug("Beacon interval changed from %d to %d",
314 		       bcn->beaconInterval, bi);
315 
316 		bi = bcn->beaconInterval;
317 		session->beaconParams.beaconInterval = (uint16_t) bi;
318 		beaconParams->paramChangeBitmap |= PARAM_BCN_INTERVAL_CHANGED;
319 		beaconParams->beaconInterval = (uint16_t) bi;
320 	}
321 
322 	if (bcn->cfPresent) {
323 		if (!cfg_in_range(CFG_CFP_PERIOD, bcn->cfParamSet.cfpPeriod)) {
324 			pe_err("Error in setting CFG item CFP Period");
325 			return false;
326 		}
327 		mac_ctx->mlme_cfg->rates.cfp_period = bcn->cfParamSet.cfpPeriod;
328 	}
329 
330 	/* No need to send DTIM Period and Count to HAL/SMAC */
331 	/* SMAC already parses TIM bit. */
332 	if (bcn->timPresent) {
333 		if (cfg_in_range(CFG_DTIM_PERIOD, bcn->tim.dtimPeriod))
334 			mac_ctx->mlme_cfg->sap_cfg.dtim_interval =
335 						bcn->tim.dtimPeriod;
336 	}
337 
338 	if (mac_ctx->lim.gLimProtectionControl !=
339 	    MLME_FORCE_POLICY_PROTECTION_DISABLE)
340 		lim_decide_sta_protection(mac_ctx, bcn, beaconParams, session);
341 
342 	if (bcn->erpPresent) {
343 		if (bcn->erpIEInfo.barkerPreambleMode)
344 			lim_enable_short_preamble(mac_ctx, false,
345 						  beaconParams, session);
346 		else
347 			lim_enable_short_preamble(mac_ctx, true,
348 						  beaconParams, session);
349 	}
350 	lim_update_short_slot(mac_ctx, bcn, beaconParams, session);
351 
352 	sta = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER,
353 				    &session->dph.dphHashTable);
354 	if ((bcn->wmeEdcaPresent && session->limWmeEnabled) ||
355 	    (bcn->edcaPresent && session->limQosEnabled)) {
356 		if (bcn->edcaParams.qosInfo.count !=
357 		    session->gLimEdcaParamSetCount) {
358 			qdf_mem_copy(&sta->qos.peer_edca_params,
359 				     &bcn->edcaParams,
360 				     sizeof(bcn->edcaParams));
361 			status = sch_beacon_edca_process(mac_ctx,
362 							 &bcn->edcaParams,
363 							 session);
364 			if (QDF_IS_STATUS_ERROR(status)) {
365 				pe_err("EDCA parameter processing error");
366 			} else if (sta) {
367 				/* If needed, downgrade the EDCA parameters */
368 				lim_set_active_edca_params(mac_ctx,
369 					session->gLimEdcaParams, session);
370 				lim_send_edca_params(mac_ctx,
371 					session->gLimEdcaParamsActive,
372 					session->vdev_id, false);
373 				sch_qos_concurrency_update();
374 			} else {
375 				pe_err("Self Entry missing in Hash Table");
376 			}
377 		}
378 		return true;
379 	}
380 
381 	if ((bcn->qosCapabilityPresent && session->limQosEnabled)
382 	    && (bcn->qosCapability.qosInfo.count !=
383 		session->gLimEdcaParamSetCount))
384 		*sendProbeReq = true;
385 
386 	return true;
387 }
388 
389 #ifdef WLAN_FEATURE_11AX_BSS_COLOR
390 static void
sch_bcn_update_he_ies(struct mac_context * mac_ctx,tpDphHashNode sta_ds,struct pe_session * session,tpSchBeaconStruct bcn,tpSirMacMgmtHdr mac_hdr)391 sch_bcn_update_he_ies(struct mac_context *mac_ctx, tpDphHashNode sta_ds,
392 				struct pe_session *session, tpSchBeaconStruct bcn,
393 				tpSirMacMgmtHdr mac_hdr)
394 {
395 	uint8_t session_bss_col_disabled_flag;
396 	bool anything_changed = false;
397 
398 	if (session->is_session_obss_color_collision_det_enabled)
399 		return;
400 
401 	if (session->he_op.present && bcn->he_op.present) {
402 		if (bcn->vendor_he_bss_color_change.present &&
403 				(session->he_op.bss_color !=
404 				 bcn->vendor_he_bss_color_change.new_color)) {
405 			pe_debug("bss color changed from [%d] to [%d]",
406 				session->he_op.bss_color,
407 				bcn->vendor_he_bss_color_change.new_color);
408 			session->he_op.bss_color =
409 				bcn->vendor_he_bss_color_change.new_color;
410 			anything_changed = true;
411 		}
412 		session_bss_col_disabled_flag = session->he_op.bss_col_disabled;
413 		if (session_bss_col_disabled_flag !=
414 				bcn->he_op.bss_col_disabled) {
415 			pe_debug("color disable flag changed from [%d] to [%d]",
416 				session->he_op.bss_col_disabled,
417 				bcn->he_op.bss_col_disabled);
418 			session->he_op.bss_col_disabled =
419 				bcn->he_op.bss_col_disabled;
420 			anything_changed = true;
421 		}
422 	}
423 	if (anything_changed)
424 		lim_send_he_ie_update(mac_ctx, session);
425 }
426 #else
427 static void
sch_bcn_update_he_ies(struct mac_context * mac_ctx,tpDphHashNode sta_ds,struct pe_session * session,tpSchBeaconStruct bcn,tpSirMacMgmtHdr mac_hdr)428 sch_bcn_update_he_ies(struct mac_context *mac_ctx, tpDphHashNode sta_ds,
429 				struct pe_session *session, tpSchBeaconStruct bcn,
430 				tpSirMacMgmtHdr mac_hdr)
431 {
432 	return;
433 }
434 #endif
435 
436 static void
sch_bcn_update_opmode_change(struct mac_context * mac_ctx,tpDphHashNode sta_ds,struct pe_session * session,tpSchBeaconStruct bcn,tpSirMacMgmtHdr mac_hdr)437 sch_bcn_update_opmode_change(struct mac_context *mac_ctx, tpDphHashNode sta_ds,
438 			     struct pe_session *session, tpSchBeaconStruct bcn,
439 			     tpSirMacMgmtHdr mac_hdr)
440 {
441 	enum phy_ch_width ch_bw;
442 	enum phy_ch_width ch_width = CH_WIDTH_20MHZ;
443 	tDot11fIEVHTCaps *vht_caps = NULL;
444 	tDot11fIEVHTOperation *vht_op = NULL;
445 	uint8_t bcn_vht_chwidth = 0;
446 	bool is_40 = false;
447 
448 	/*
449 	 * Ignore opmode change during channel change The opmode will be updated
450 	 * with the beacons on new channel once the AP move to new channel.
451 	 */
452 	if (session->ch_switch_in_progress) {
453 		pe_debug("Ignore opmode change as channel switch is in progress");
454 		return;
455 	}
456 	if (bcn->eht_op.eht_op_information_present) {
457 		pe_debug("Ignore opmode change as there is EHT operation information");
458 		return;
459 	}
460 
461 	if (bcn->VHTCaps.present) {
462 		vht_caps = &bcn->VHTCaps;
463 		vht_op = &bcn->VHTOperation;
464 	} else if (bcn->vendor_vht_ie.VHTCaps.present) {
465 		vht_caps = &bcn->vendor_vht_ie.VHTCaps;
466 		vht_op = &bcn->vendor_vht_ie.VHTOperation;
467 	}
468 	if (!session->vhtCapability ||
469 	    !(bcn->OperatingMode.present ||
470 	      (vht_op && vht_op->present && vht_caps)))
471 		return;
472 
473 	is_40 = bcn->HTInfo.present ?
474 			bcn->HTInfo.recommendedTxWidthSet : false;
475 
476 	if (bcn->OperatingMode.present) {
477 		lim_update_nss(mac_ctx, sta_ds, bcn->OperatingMode.rxNSS,
478 			       session);
479 		ch_width = bcn->OperatingMode.chanWidth;
480 		pe_debug("OMN IE present in bcn/probe rsp, omn_ie_ch_width: %d",
481 			 ch_width);
482 		lim_update_omn_ie_ch_width(session->vdev, ch_width);
483 
484 	} else {
485 		bcn_vht_chwidth = lim_get_vht_ch_width(vht_caps, vht_op,
486 						       &bcn->HTInfo);
487 		ch_width =
488 			lim_convert_vht_chwidth_to_phy_chwidth(bcn_vht_chwidth,
489 							       is_40);
490 	}
491 
492 	lim_update_channel_width(mac_ctx, sta_ds, session, ch_width, &ch_bw);
493 }
494 
495 #ifdef WLAN_FEATURE_SR
496 /**
497  * lim_detect_change_in_srp() - Detect change in SRP IE
498  * of the beacon
499  *
500  * @mac_ctx: global mac context
501  * @sta: pointer to sta node
502  * @session: pointer to LIM session
503  * @bcn: beacon from associated AP
504  *
505  * Detect change in SRP IE of the beacon and update the params
506  * accordingly.
507  *
508  * Return: None
509  */
lim_detect_change_in_srp(struct mac_context * mac_ctx,tpDphHashNode sta,struct pe_session * session,tpSchBeaconStruct bcn)510 static void lim_detect_change_in_srp(struct mac_context *mac_ctx,
511 				     tpDphHashNode sta,
512 				     struct pe_session *session,
513 				     tpSchBeaconStruct bcn)
514 {
515 	tDot11fIEspatial_reuse sr_ie;
516 	int32_t ret = 0;
517 
518 	sr_ie = sta->parsed_ies.srp_ie;
519 	if (sr_ie.present || bcn->srp_ie.present) {
520 		ret = qdf_mem_cmp(&sr_ie, &bcn->srp_ie,
521 				  sizeof(tDot11fIEspatial_reuse));
522 
523 		if (ret) {
524 			/*
525 			 * If SRP IE has changes, update the new params.
526 			 */
527 			sta->parsed_ies.srp_ie = bcn->srp_ie;
528 			lim_update_vdev_sr_elements(session, sta);
529 
530 			lim_handle_sr_cap(session->vdev,
531 					  SR_REASON_CODE_BCN_IE_CHANGE);
532 		}
533 	}
534 }
535 #else
lim_detect_change_in_srp(struct mac_context * mac_ctx,tpDphHashNode sta,struct pe_session * session,tpSchBeaconStruct bcn)536 static void lim_detect_change_in_srp(struct mac_context *mac_ctx,
537 				     tpDphHashNode sta,
538 				     struct pe_session *session,
539 				     tpSchBeaconStruct bcn)
540 {
541 }
542 #endif
543 
544 static void
sch_bcn_process_sta_opmode(struct mac_context * mac_ctx,tpSchBeaconStruct bcn,uint8_t * rx_pkt_info,struct pe_session * session,tUpdateBeaconParams * beaconParams,uint8_t * sendProbeReq,tpSirMacMgmtHdr pMh)545 sch_bcn_process_sta_opmode(struct mac_context *mac_ctx,
546 			    tpSchBeaconStruct bcn,
547 			    uint8_t *rx_pkt_info,
548 			    struct pe_session *session,
549 			    tUpdateBeaconParams *beaconParams,
550 			    uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh)
551 {
552 	tpDphHashNode sta = NULL;
553 	uint16_t aid;
554 
555 	/* check for VHT capability */
556 	sta = dph_lookup_hash_entry(mac_ctx, pMh->sa, &aid,
557 			&session->dph.dphHashTable);
558 	if (!sta)
559 		return;
560 	sch_bcn_update_opmode_change(mac_ctx, sta, session, bcn, pMh);
561 	sch_bcn_update_he_ies(mac_ctx, sta, session, bcn, pMh);
562 	lim_detect_change_in_srp(mac_ctx, sta, session, bcn);
563 	return;
564 }
565 
566 /**
567  * get_local_power_constraint_beacon() - extracts local constraint
568  * from beacon
569  * @bcn: beacon structure
570  * @local_constraint: local constraint pointer
571  * @is_power_constraint_abs: is power constraint absolute
572  *
573  * Return: None
574  */
575 #ifdef FEATURE_WLAN_ESE
get_local_power_constraint_beacon(tpSchBeaconStruct bcn,int8_t * local_constraint,bool * is_power_constraint_abs)576 static void get_local_power_constraint_beacon(
577 		tpSchBeaconStruct bcn,
578 		int8_t *local_constraint,
579 		bool *is_power_constraint_abs)
580 {
581 	if (bcn->eseTxPwr.present) {
582 		*local_constraint = bcn->eseTxPwr.power_limit;
583 		*is_power_constraint_abs = true;
584 	}
585 }
586 #else
get_local_power_constraint_beacon(tpSchBeaconStruct bcn,int8_t * local_constraint,bool * is_power_constraint_abs)587 static void get_local_power_constraint_beacon(
588 		tpSchBeaconStruct bcn,
589 		int8_t *local_constraint,
590 		bool *is_power_constraint_abs)
591 {
592 
593 }
594 #endif
595 
__sch_beacon_process_for_session(struct mac_context * mac_ctx,tpSchBeaconStruct bcn,uint8_t * rx_pkt_info,struct pe_session * session)596 static void __sch_beacon_process_for_session(struct mac_context *mac_ctx,
597 					     tpSchBeaconStruct bcn,
598 					     uint8_t *rx_pkt_info,
599 					     struct pe_session *session)
600 {
601 	tUpdateBeaconParams beaconParams;
602 	uint8_t sendProbeReq = false;
603 	tpSirMacMgmtHdr pMh = WMA_GET_RX_MAC_HEADER(rx_pkt_info);
604 	int8_t local_constraint = 0;
605 	uint32_t chan_freq = 0;
606 	struct vdev_mlme_obj *mlme_obj;
607 	struct wlan_lmac_if_reg_tx_ops *tx_ops;
608 	bool ap_constraint_change = false, tpe_change = false;
609 	bool allow_tpc = false;
610 	int8_t regMax = 0, maxTxPower = 0;
611 	QDF_STATUS status;
612 	bool skip_tpe = false, is_sap_go_switched_ch;
613 	enum reg_6g_ap_type pwr_type_6g;
614 	uint8_t bpcc;
615 	bool cu_flag = true;
616 	bool is_power_constraint_abs = false;
617 
618 	if (mlo_is_mld_sta(session->vdev)) {
619 		cu_flag = false;
620 		status = lim_get_bpcc_from_mlo_ie(bcn, &bpcc);
621 		if (QDF_IS_STATUS_SUCCESS(status))
622 			cu_flag = lim_check_cu_happens(session->vdev, bpcc);
623 		lim_process_ml_reconfig(mac_ctx, session, rx_pkt_info);
624 	}
625 
626 	if (!cu_flag)
627 		return;
628 
629 	qdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams));
630 	beaconParams.paramChangeBitmap = 0;
631 
632 	if (LIM_IS_STA_ROLE(session)) {
633 		is_sap_go_switched_ch =
634 			wlan_vdev_mlme_is_sap_go_move_before_sta(session->vdev);
635 		if (is_sap_go_switched_ch)
636 			policy_mgr_sta_sap_dfs_enforce_scc(mac_ctx->psoc,
637 							   session->vdev_id);
638 		if (false == sch_bcn_process_sta(mac_ctx, bcn, rx_pkt_info,
639 						 session, &beaconParams,
640 						 &sendProbeReq, pMh))
641 			return;
642 	}
643 
644 	/*
645 	 * For vht session, if opermode ie or vht oper IE is present
646 	 * bandwidth change will be taken care using these vht IEs.
647 	 */
648 	if (!(session->vhtCapability && (bcn->OperatingMode.present ||
649 	   bcn->VHTOperation.present)) && session->htCapability &&
650 	   bcn->HTInfo.present)
651 		lim_update_sta_run_time_ht_switch_chnl_params(mac_ctx,
652 						&bcn->HTInfo, session);
653 
654 	if (LIM_IS_STA_ROLE(session))
655 		sch_bcn_process_sta_opmode(mac_ctx, bcn, rx_pkt_info, session,
656 					    &beaconParams, &sendProbeReq, pMh);
657 
658 	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(session->vdev);
659 	if (!mlme_obj) {
660 		pe_err("vdev component object is NULL");
661 		return;
662 	}
663 
664 	if (!wlan_reg_is_6ghz_chan_freq(bcn->chan_freq)) {
665 		skip_tpe = wlan_mlme_skip_tpe(mac_ctx->psoc);
666 	} else {
667 		if (!bcn->countryInfoParam.countryString[0]) {
668 			pe_err("Channel is 6G but country IE not present");
669 			return;
670 		}
671 		if (bcn->he_op.oper_info_6g_present) {
672 			session->ap_defined_power_type_6g =
673 					bcn->he_op.oper_info_6g.info.reg_info;
674 			if (session->ap_defined_power_type_6g < REG_INDOOR_AP ||
675 			    session->ap_defined_power_type_6g >
676 			    REG_MAX_SUPP_AP_TYPE) {
677 				session->ap_defined_power_type_6g =
678 						REG_CURRENT_MAX_AP_TYPE;
679 				pe_debug("AP power type is invalid, defaulting to MAX_AP_TYPE");
680 			}
681 		} else {
682 			pe_debug("AP power type is null, defaulting to MAX_AP_TYPE");
683 			session->ap_defined_power_type_6g =
684 						REG_CURRENT_MAX_AP_TYPE;
685 		}
686 
687 		status = wlan_reg_get_best_6g_power_type(
688 				mac_ctx->psoc, mac_ctx->pdev, &pwr_type_6g,
689 				session->ap_defined_power_type_6g,
690 				bcn->chan_freq);
691 		if (QDF_IS_STATUS_ERROR(status))
692 			return;
693 
694 		session->best_6g_power_type = pwr_type_6g;
695 		mlme_set_best_6g_power_type(session->vdev, pwr_type_6g);
696 	}
697 
698 	/*
699 	 * STA LPI + SAP VLP is supported. For this STA should operate in VLP
700 	 * power level of the SAP.
701 	 * If STA is operating in VLP power of SAP, do not update STA power.
702 	 */
703 	if (wlan_reg_is_ext_tpc_supported(mac_ctx->psoc) &&
704 	    !session->sta_follows_sap_power) {
705 		tx_ops = wlan_reg_get_tx_ops(mac_ctx->psoc);
706 
707 		lim_parse_tpe_ie(mac_ctx, session, bcn->transmit_power_env,
708 				 bcn->num_transmit_power_env, &bcn->he_op,
709 				 &tpe_change);
710 
711 		if (mac_ctx->mlme_cfg->sta.allow_tpc_from_ap) {
712 			get_local_power_constraint_beacon(
713 						bcn, &local_constraint,
714 						&is_power_constraint_abs);
715 
716 			if (mac_ctx->rrm.rrmPEContext.rrmEnable &&
717 			    bcn->powerConstraintPresent) {
718 				local_constraint =
719 				bcn->localPowerConstraint.localPowerConstraints;
720 				is_power_constraint_abs = false;
721 			}
722 			allow_tpc = true;
723 		}
724 
725 		if (allow_tpc && local_constraint !=
726 		    mlme_obj->reg_tpc_obj.ap_constraint_power) {
727 			mlme_obj->reg_tpc_obj.ap_constraint_power =
728 							local_constraint;
729 			mlme_obj->reg_tpc_obj.is_power_constraint_abs =
730 							is_power_constraint_abs;
731 			ap_constraint_change = true;
732 		}
733 
734 		if (ap_constraint_change || (tpe_change && !skip_tpe)) {
735 			lim_calculate_tpc(mac_ctx, session);
736 
737 			if (tx_ops->set_tpc_power)
738 				tx_ops->set_tpc_power(mac_ctx->psoc,
739 						      session->vdev_id,
740 						      &mlme_obj->reg_tpc_obj);
741 		}
742 	} else if (!session->sta_follows_sap_power) {
743 		/* Obtain the Max Tx power for the current regulatory  */
744 		regMax = wlan_reg_get_channel_reg_power_for_freq(
745 					mac_ctx->pdev, session->curr_op_freq);
746 		local_constraint = regMax;
747 
748 		if (mac_ctx->mlme_cfg->sta.allow_tpc_from_ap) {
749 			get_local_power_constraint_beacon(
750 						bcn, &local_constraint,
751 						&is_power_constraint_abs);
752 
753 			if (mac_ctx->rrm.rrmPEContext.rrmEnable &&
754 			    bcn->powerConstraintPresent) {
755 				local_constraint = regMax;
756 				local_constraint -=
757 				bcn->localPowerConstraint.localPowerConstraints;
758 				is_power_constraint_abs = false;
759 
760 			}
761 		}
762 		mlme_obj->reg_tpc_obj.is_power_constraint_abs =
763 						is_power_constraint_abs;
764 		mlme_obj->reg_tpc_obj.reg_max[0] = regMax;
765 		mlme_obj->reg_tpc_obj.ap_constraint_power = local_constraint;
766 		mlme_obj->reg_tpc_obj.frequency[0] = session->curr_op_freq;
767 
768 		maxTxPower = lim_get_max_tx_power(mac_ctx, mlme_obj);
769 
770 		/* If maxTxPower is increased or decreased */
771 		if (maxTxPower != session->maxTxPower) {
772 			pe_debug("New maxTx power %d, old pwr %d",
773 				 maxTxPower, session->maxTxPower);
774 			pe_debug("regMax %d, local %d", regMax,
775 				 local_constraint);
776 			status = lim_send_set_max_tx_power_req(mac_ctx,
777 							       maxTxPower,
778 							       session);
779 			if (status == QDF_STATUS_SUCCESS)
780 				session->maxTxPower = maxTxPower;
781 		}
782 	}
783 	/* Indicate to LIM that Beacon is received */
784 	if (bcn->HTInfo.present) {
785 		chan_freq = wlan_reg_legacy_chan_to_freq(mac_ctx->pdev,
786 							 bcn->HTInfo.primaryChannel);
787 		lim_received_hb_handler(mac_ctx, chan_freq, session);
788 	} else
789 		lim_received_hb_handler(mac_ctx, bcn->chan_freq, session);
790 
791 	/*
792 	 * I don't know if any additional IE is required here. Currently, not
793 	 * include addIE.
794 	 */
795 	if (sendProbeReq)
796 		lim_send_probe_req_mgmt_frame(mac_ctx, &session->ssId,
797 			session->bssId, session->curr_op_freq,
798 			session->self_mac_addr, session->dot11mode, NULL, NULL);
799 
800 	if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)
801 	    && beaconParams.paramChangeBitmap) {
802 		pe_debug("Beacon for session[%d] got changed param change bitmap: 0x%x",
803 			 session->peSessionId, beaconParams.paramChangeBitmap);
804 		lim_send_beacon_params(mac_ctx, &beaconParams, session);
805 	}
806 
807 	if ((session->opmode == QDF_P2P_CLIENT_MODE) &&
808 	    session->send_p2p_conf_frame) {
809 		lim_p2p_oper_chan_change_confirm_action_frame(mac_ctx,
810 							      session->bssId,
811 							      session);
812 		session->send_p2p_conf_frame = false;
813 	}
814 
815 	lim_process_beacon_eht(mac_ctx, session, bcn);
816 	lim_process_bcn_prb_rsp_t2lm(mac_ctx, session, bcn);
817 }
818 
819 #ifdef WLAN_FEATURE_11AX_BSS_COLOR
ap_update_bss_color_info(struct mac_context * mac_ctx,struct pe_session * session,uint8_t bss_color)820 static void ap_update_bss_color_info(struct mac_context *mac_ctx,
821 						struct pe_session *session,
822 						uint8_t bss_color)
823 {
824 	if (!session)
825 		return;
826 
827 	if (bss_color < 1 || bss_color > 63) {
828 		pe_warn("Invalid BSS color");
829 		return;
830 	}
831 
832 	session->bss_color_info[bss_color - 1].seen_count++;
833 	session->bss_color_info[bss_color - 1].timestamp =
834 					qdf_get_system_timestamp();
835 }
836 
ap_get_new_bss_color(struct mac_context * mac_ctx,struct pe_session * session)837 static uint8_t ap_get_new_bss_color(struct mac_context *mac_ctx, struct pe_session *session)
838 {
839 	int i;
840 	uint8_t new_bss_color;
841 	struct bss_color_info color_info;
842 	qdf_time_t cur_timestamp;
843 
844 	if (!session)
845 		return 0;
846 
847 	color_info = session->bss_color_info[0];
848 	new_bss_color = 0;
849 	cur_timestamp = qdf_get_system_timestamp();
850 	for (i = 1; i < MAX_BSS_COLOR_VALUE; i++) {
851 		if (session->bss_color_info[i].seen_count == 0) {
852 			new_bss_color = i + 1;
853 			return new_bss_color;
854 		}
855 
856 		if (color_info.seen_count >
857 				session->bss_color_info[i].seen_count &&
858 				(cur_timestamp - session->bss_color_info[i].
859 					timestamp) > TIME_BEACON_NOT_UPDATED) {
860 			color_info = session->bss_color_info[i];
861 			new_bss_color = i + 1;
862 		}
863 	}
864 	pe_debug("new bss color: %d", new_bss_color);
865 	return new_bss_color;
866 }
867 
sch_check_bss_color_ie(struct mac_context * mac_ctx,struct pe_session * ap_session,tSchBeaconStruct * bcn,tUpdateBeaconParams * bcn_prm)868 static void sch_check_bss_color_ie(struct mac_context *mac_ctx,
869 					struct pe_session *ap_session,
870 					tSchBeaconStruct *bcn,
871 					tUpdateBeaconParams *bcn_prm)
872 {
873 	/* check bss color in the beacon */
874 	if (ap_session->he_op.present && !ap_session->he_op.bss_color) {
875 		if (bcn->he_op.present &&
876 			(bcn->he_op.bss_color ==
877 					ap_session->he_op.bss_color)) {
878 			ap_session->he_op.bss_col_disabled = 1;
879 			bcn_prm->paramChangeBitmap |=
880 						PARAM_BSS_COLOR_CHANGED;
881 			ap_session->he_bss_color_change.countdown =
882 						BSS_COLOR_SWITCH_COUNTDOWN;
883 			ap_session->he_bss_color_change.new_color =
884 					ap_get_new_bss_color(mac_ctx,
885 								ap_session);
886 			ap_session->he_op.bss_color = ap_session->
887 						he_bss_color_change.new_color;
888 			bcn_prm->bss_color = ap_session->he_op.bss_color;
889 			bcn_prm->bss_color_disabled =
890 					ap_session->he_op.bss_col_disabled;
891 			ap_session->bss_color_changing = 1;
892 		} else {
893 			/* update info for the bss color */
894 			if (bcn->he_op.present)
895 				ap_update_bss_color_info(mac_ctx,
896 						ap_session,
897 						bcn->he_op.bss_color);
898 		}
899 	}
900 }
901 
902 #else
sch_check_bss_color_ie(struct mac_context * mac_ctx,struct pe_session * ap_session,tSchBeaconStruct * bcn,tUpdateBeaconParams * bcn_prm)903 static void  sch_check_bss_color_ie(struct mac_context *mac_ctx,
904 					struct pe_session *ap_session,
905 					tSchBeaconStruct *bcn,
906 					tUpdateBeaconParams *bcn_prm)
907 {
908 }
909 #endif
910 
sch_beacon_process_for_ap(struct mac_context * mac_ctx,uint8_t session_id,uint8_t * rx_pkt_info,tSchBeaconStruct * bcn)911 void sch_beacon_process_for_ap(struct mac_context *mac_ctx,
912 				uint8_t session_id,
913 				uint8_t *rx_pkt_info,
914 				tSchBeaconStruct *bcn)
915 {
916 	struct pe_session *ap_session;
917 	tUpdateBeaconParams bcn_prm;
918 
919 	if (!bcn || !rx_pkt_info) {
920 		pe_debug("bcn %pK or rx_pkt_info %pKis NULL",
921 			 bcn, rx_pkt_info);
922 		return;
923 	}
924 
925 	ap_session = pe_find_session_by_session_id(mac_ctx, session_id);
926 	if (!ap_session)
927 		return;
928 
929 	if (!LIM_IS_AP_ROLE(ap_session))
930 		return;
931 
932 	qdf_mem_zero(&bcn_prm, sizeof(tUpdateBeaconParams));
933 	bcn_prm.paramChangeBitmap = 0;
934 
935 	bcn_prm.bss_idx = ap_session->vdev_id;
936 
937 	if (!ap_session->is_session_obss_color_collision_det_enabled)
938 		sch_check_bss_color_ie(mac_ctx, ap_session,
939 					bcn, &bcn_prm);
940 
941 	if ((ap_session->gLimProtectionControl !=
942 	     MLME_FORCE_POLICY_PROTECTION_DISABLE) &&
943 	    !ap_session->is_session_obss_offload_enabled)
944 		ap_beacon_process(mac_ctx, rx_pkt_info,
945 					bcn, &bcn_prm, ap_session);
946 
947 	if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)
948 	    && bcn_prm.paramChangeBitmap) {
949 		/* Update the bcn and apply the new settings to HAL */
950 		sch_set_fixed_beacon_fields(mac_ctx, ap_session);
951 		pe_debug("Beacon for PE session[%d] got changed",
952 		       ap_session->peSessionId);
953 		pe_debug("sending beacon param change bitmap: 0x%x",
954 		       bcn_prm.paramChangeBitmap);
955 		lim_send_beacon_params(mac_ctx, &bcn_prm, ap_session);
956 	}
957 }
958 
959 #ifdef WLAN_BCN_RECV_FEATURE
960 /*
961  * sch_send_beacon_report() - To Fill beacon report for
962  * each beacon coming from connected peer and sends it
963  * to upper layer
964  * @mac_ctx: Mac context
965  * @beacon_struct: Pointing to beacon structure
966  * @session: pointer to the PE session
967  *
968  * Return: None
969  */
970 static
sch_send_beacon_report(struct mac_context * mac_ctx,struct sSirProbeRespBeacon * beacon_struct,struct pe_session * session)971 void sch_send_beacon_report(struct mac_context *mac_ctx,
972 			    struct sSirProbeRespBeacon *beacon_struct,
973 			    struct pe_session *session)
974 {
975 	struct wlan_beacon_report beacon_report;
976 	beacon_report_cb sme_bcn_cb;
977 
978 	sme_bcn_cb = mac_ctx->lim.sme_bcn_rcv_callback;
979 	if (!sme_bcn_cb)
980 		return;
981 
982 	if (!LIM_IS_STA_ROLE(session))
983 		return;
984 
985 	if (sir_compare_mac_addr(session->bssId, beacon_struct->bssid)) {
986 		/* Prepare beacon report from incoming beacon */
987 		qdf_mem_copy(beacon_report.bssid.bytes, beacon_struct->bssid,
988 			     sizeof(tSirMacAddr));
989 
990 		qdf_mem_copy(&beacon_report.time_stamp,
991 			     &beacon_struct->timeStamp, sizeof(qdf_time_t));
992 		beacon_report.beacon_interval = beacon_struct->beaconInterval;
993 		beacon_report.frequency = beacon_struct->chan_freq;
994 
995 		beacon_report.ssid.length = beacon_struct->ssId.length;
996 		qdf_mem_copy(&beacon_report.ssid.ssid,
997 			     &beacon_struct->ssId.ssId,
998 			     beacon_report.ssid.length);
999 
1000 		beacon_report.boot_time =
1001 				qdf_do_div(qdf_get_monotonic_boottime(),
1002 					   QDF_MC_TIMER_TO_MS_UNIT);
1003 
1004 		beacon_report.vdev_id = session->vdev_id;
1005 
1006 		/* Send report to upper layer */
1007 		sme_bcn_cb(mac_ctx->hdd_handle, &beacon_report);
1008 	}
1009 }
1010 
1011 #else
1012 static inline
sch_send_beacon_report(struct mac_context * mac_ctx,struct sSirProbeRespBeacon * beacon_struct,struct pe_session * session)1013 void sch_send_beacon_report(struct mac_context *mac_ctx,
1014 			    struct sSirProbeRespBeacon *beacon_struct,
1015 			    struct pe_session *session)
1016 {
1017 }
1018 #endif
1019 
1020 /**
1021  * sch_beacon_process() - process the beacon frame
1022  * @mac_ctx: mac global context
1023  * @rx_pkt_info: pointer to buffer descriptor
1024  * @session: pointer to the PE session
1025  *
1026  * Return: None
1027  */
1028 void
sch_beacon_process(struct mac_context * mac_ctx,uint8_t * rx_pkt_info,struct pe_session * session)1029 sch_beacon_process(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
1030 		   struct pe_session *session)
1031 {
1032 	static tSchBeaconStruct bcn;
1033 
1034 	if (!session)
1035 		return;
1036 
1037 	/*
1038 	 * Drop the beacon/probe response from current connected AP in
1039 	 * below cases to avoid responding to the changes in beacon(e.g. doing
1040 	 * VDEV_RESTART to update to the latest capabilities),
1041 	 * 1. vdev is not in connected state: vdev might be transitioning
1042 	 * 2. Link switch is in progress: Current link or one of the partner
1043 	 *                                links are getting replaced.
1044 	 *
1045 	 * New beacons/probe rsps can be considered once post these operations.
1046 	 */
1047 	if (LIM_IS_STA_ROLE(session) &&
1048 	    (!wlan_cm_is_vdev_connected(session->vdev) ||
1049 	     mlo_mgr_is_link_switch_in_progress(session->vdev))) {
1050 		pe_debug_rl("vdev %d, drop beacon", session->vdev_id);
1051 		return;
1052 	}
1053 
1054 	/* Convert the beacon frame into a structure */
1055 	if (sir_convert_beacon_frame2_struct(mac_ctx, (uint8_t *) rx_pkt_info,
1056 		&bcn) != QDF_STATUS_SUCCESS) {
1057 		pe_err_rl("beacon parsing failed");
1058 		return;
1059 	}
1060 
1061 	session->dtimPeriod = bcn.tim.dtimPeriod;
1062 
1063 	sch_send_beacon_report(mac_ctx, &bcn, session);
1064 	__sch_beacon_process_for_session(mac_ctx, &bcn, rx_pkt_info, session);
1065 }
1066 
1067 /**
1068  * sch_beacon_edca_process(): Process the EDCA parameter set in the received
1069  * beacon frame
1070  *
1071  * @mac_ctx:    mac global context
1072  * @edca:       reference to edca parameters in beacon struct
1073  * @session :   pesession entry
1074  *
1075  * @return status of operation
1076  */
1077 QDF_STATUS
sch_beacon_edca_process(struct mac_context * mac,tSirMacEdcaParamSetIE * edca,struct pe_session * session)1078 sch_beacon_edca_process(struct mac_context *mac, tSirMacEdcaParamSetIE *edca,
1079 			struct pe_session *session)
1080 {
1081 	bool follow_ap_edca;
1082 #ifdef FEATURE_WLAN_DIAG_SUPPORT
1083 	host_log_qos_edca_pkt_type *log_ptr = NULL;
1084 #endif /* FEATURE_WLAN_DIAG_SUPPORT */
1085 
1086 	if (!(mac->mlme_cfg)) {
1087 		pe_err("invalid mlme cfg");
1088 		return QDF_STATUS_E_FAILURE;
1089 	}
1090 
1091 	follow_ap_edca = mlme_get_follow_ap_edca_flag(session->vdev);
1092 
1093 	session->gLimEdcaParamSetCount = edca->qosInfo.count;
1094 	session->gLimEdcaParams[QCA_WLAN_AC_BE] = edca->acbe;
1095 	session->gLimEdcaParams[QCA_WLAN_AC_BK] = edca->acbk;
1096 	session->gLimEdcaParams[QCA_WLAN_AC_VI] = edca->acvi;
1097 	session->gLimEdcaParams[QCA_WLAN_AC_VO] = edca->acvo;
1098 
1099 	if (mac->mlme_cfg->edca_params.enable_edca_params && !follow_ap_edca) {
1100 		session->gLimEdcaParams[QCA_WLAN_AC_VO].aci.aifsn =
1101 			mac->mlme_cfg->edca_params.edca_ac_vo.vo_aifs;
1102 		session->gLimEdcaParams[QCA_WLAN_AC_VI].aci.aifsn =
1103 			mac->mlme_cfg->edca_params.edca_ac_vi.vi_aifs;
1104 		session->gLimEdcaParams[QCA_WLAN_AC_BK].aci.aifsn =
1105 			mac->mlme_cfg->edca_params.edca_ac_bk.bk_aifs;
1106 		session->gLimEdcaParams[QCA_WLAN_AC_BE].aci.aifsn =
1107 			mac->mlme_cfg->edca_params.edca_ac_be.be_aifs;
1108 
1109 		session->gLimEdcaParams[QCA_WLAN_AC_VO].cw.min =
1110 			mac->mlme_cfg->edca_params.edca_ac_vo.vo_cwmin;
1111 		session->gLimEdcaParams[QCA_WLAN_AC_VI].cw.min =
1112 			mac->mlme_cfg->edca_params.edca_ac_vi.vi_cwmin;
1113 		session->gLimEdcaParams[QCA_WLAN_AC_BK].cw.min =
1114 			mac->mlme_cfg->edca_params.edca_ac_bk.bk_cwmin;
1115 		session->gLimEdcaParams[QCA_WLAN_AC_BE].cw.min =
1116 			mac->mlme_cfg->edca_params.edca_ac_be.be_cwmin;
1117 
1118 		session->gLimEdcaParams[QCA_WLAN_AC_VO].cw.max =
1119 			mac->mlme_cfg->edca_params.edca_ac_vo.vo_cwmax;
1120 		session->gLimEdcaParams[QCA_WLAN_AC_VI].cw.max =
1121 			mac->mlme_cfg->edca_params.edca_ac_vi.vi_cwmax;
1122 		session->gLimEdcaParams[QCA_WLAN_AC_BK].cw.max =
1123 			mac->mlme_cfg->edca_params.edca_ac_bk.bk_cwmax;
1124 		session->gLimEdcaParams[QCA_WLAN_AC_BE].cw.max =
1125 			mac->mlme_cfg->edca_params.edca_ac_be.be_cwmax;
1126 	}
1127 #ifdef FEATURE_WLAN_DIAG_SUPPORT
1128 	WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_edca_pkt_type,
1129 				 LOG_WLAN_QOS_EDCA_C);
1130 	if (log_ptr) {
1131 		log_ptr->aci_be = session->gLimEdcaParams[QCA_WLAN_AC_BE].aci.aci;
1132 		log_ptr->cw_be =
1133 			session->gLimEdcaParams[QCA_WLAN_AC_BE].cw.max << 4
1134 				| session->gLimEdcaParams[QCA_WLAN_AC_BE].cw.min;
1135 		log_ptr->txoplimit_be =
1136 			session->gLimEdcaParams[QCA_WLAN_AC_BE].txoplimit;
1137 		log_ptr->aci_bk =
1138 			session->gLimEdcaParams[QCA_WLAN_AC_BK].aci.aci;
1139 		log_ptr->cw_bk =
1140 			session->gLimEdcaParams[QCA_WLAN_AC_BK].cw.max << 4
1141 				| session->gLimEdcaParams[QCA_WLAN_AC_BK].cw.min;
1142 		log_ptr->txoplimit_bk =
1143 			session->gLimEdcaParams[QCA_WLAN_AC_BK].txoplimit;
1144 		log_ptr->aci_vi =
1145 			session->gLimEdcaParams[QCA_WLAN_AC_VI].aci.aci;
1146 		log_ptr->cw_vi =
1147 			session->gLimEdcaParams[QCA_WLAN_AC_VI].cw.max << 4
1148 				| session->gLimEdcaParams[QCA_WLAN_AC_VI].cw.min;
1149 		log_ptr->txoplimit_vi =
1150 			session->gLimEdcaParams[QCA_WLAN_AC_VI].txoplimit;
1151 		log_ptr->aci_vo =
1152 			session->gLimEdcaParams[QCA_WLAN_AC_VO].aci.aci;
1153 		log_ptr->cw_vo =
1154 			session->gLimEdcaParams[QCA_WLAN_AC_VO].cw.max << 4
1155 				| session->gLimEdcaParams[QCA_WLAN_AC_VO].cw.min;
1156 		log_ptr->txoplimit_vo =
1157 			session->gLimEdcaParams[QCA_WLAN_AC_VO].txoplimit;
1158 	}
1159 	WLAN_HOST_DIAG_LOG_REPORT(log_ptr);
1160 #endif /* FEATURE_WLAN_DIAG_SUPPORT */
1161 	pe_debug("Edca param enabled %d. Updating Local Params to: AC_BE: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d  AC_BK: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d  AC_VI: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d  AC_VO: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d",
1162 		 mac->mlme_cfg->edca_params.enable_edca_params,
1163 		 session->gLimEdcaParams[0].aci.aifsn,
1164 		 session->gLimEdcaParams[0].aci.acm,
1165 		 session->gLimEdcaParams[0].cw.min,
1166 		 session->gLimEdcaParams[0].cw.max,
1167 		 session->gLimEdcaParams[0].txoplimit,
1168 		 session->gLimEdcaParams[1].aci.aifsn,
1169 		 session->gLimEdcaParams[1].aci.acm,
1170 		 session->gLimEdcaParams[1].cw.min,
1171 		 session->gLimEdcaParams[1].cw.max,
1172 		 session->gLimEdcaParams[1].txoplimit,
1173 		 session->gLimEdcaParams[2].aci.aifsn,
1174 		 session->gLimEdcaParams[2].aci.acm,
1175 		 session->gLimEdcaParams[2].cw.min,
1176 		 session->gLimEdcaParams[2].cw.max,
1177 		 session->gLimEdcaParams[2].txoplimit,
1178 		 session->gLimEdcaParams[3].aci.aifsn,
1179 		 session->gLimEdcaParams[3].aci.acm,
1180 		 session->gLimEdcaParams[3].cw.min,
1181 		 session->gLimEdcaParams[3].cw.max,
1182 		 session->gLimEdcaParams[3].txoplimit);
1183 
1184 	return QDF_STATUS_SUCCESS;
1185 }
1186 
lim_enable_obss_detection_config(struct mac_context * mac_ctx,struct pe_session * session)1187 void lim_enable_obss_detection_config(struct mac_context *mac_ctx,
1188 				      struct pe_session *session)
1189 {
1190 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1191 
1192 	if (!session) {
1193 		pe_err("Invalid session, protection not enabled");
1194 		return;
1195 	}
1196 
1197 	if (session->gLimProtectionControl ==
1198 	    MLME_FORCE_POLICY_PROTECTION_DISABLE) {
1199 		pe_err("protectiond disabled, force policy, session %d",
1200 		       session->smeSessionId);
1201 		return;
1202 	}
1203 
1204 	if (mac_ctx->mlme_cfg->obss_ht40.obss_detection_offload_enabled) {
1205 		status = lim_obss_send_detection_cfg(mac_ctx, session, true);
1206 		if (QDF_IS_STATUS_ERROR(status)) {
1207 			pe_err("vdev %d: offload enable failed, trying legacy",
1208 			       session->smeSessionId);
1209 			session->is_session_obss_offload_enabled = false;
1210 		} else {
1211 			pe_debug("vdev %d: offload detection enabled",
1212 				 session->smeSessionId);
1213 			session->is_session_obss_offload_enabled = true;
1214 			lim_obss_send_detection_cfg(mac_ctx, session, true);
1215 		}
1216 	}
1217 
1218 	if (!mac_ctx->mlme_cfg->obss_ht40.obss_detection_offload_enabled ||
1219 	    QDF_IS_STATUS_ERROR(status)) {
1220 		status = qdf_mc_timer_start(&session->
1221 					    protection_fields_reset_timer,
1222 					    SCH_PROTECTION_RESET_TIME);
1223 		if (QDF_IS_STATUS_ERROR(status))
1224 			pe_err("vdev %d: start timer failed",
1225 			       session->smeSessionId);
1226 		else
1227 			pe_debug("vdev %d: legacy detection enabled",
1228 				 session->smeSessionId);
1229 	}
1230 }
1231 
lim_obss_generate_detection_config(struct mac_context * mac_ctx,struct pe_session * session,struct obss_detection_cfg * cfg)1232 QDF_STATUS lim_obss_generate_detection_config(struct mac_context *mac_ctx,
1233 					      struct pe_session *session,
1234 					      struct obss_detection_cfg *cfg)
1235 {
1236 	uint32_t phy_mode;
1237 	enum reg_wifi_band rf_band = REG_BAND_UNKNOWN;
1238 	struct obss_detection_cfg *cur_detect;
1239 
1240 	if (!mac_ctx || !session || !cfg) {
1241 		pe_err("Invalid params mac_ctx %pK, session %pK, cfg %pK",
1242 			mac_ctx, session, cfg);
1243 		return QDF_STATUS_E_INVAL;
1244 	}
1245 
1246 	lim_get_phy_mode(mac_ctx, &phy_mode, session);
1247 	rf_band = session->limRFBand;
1248 	qdf_mem_zero(cfg, sizeof(*cfg));
1249 	cur_detect = &session->current_obss_detection;
1250 
1251 	pe_debug("band:%d, phy_mode:%d, ht_cap:%d, ht_oper_mode:%d",
1252 		 rf_band, phy_mode, session->htCapability,
1253 		 mac_ctx->lim.gHTOperMode);
1254 	pe_debug("assoc_sta: 11b:%d, 11g:%d, 11a:%d, ht20:%d",
1255 		 session->gLim11bParams.protectionEnabled,
1256 		 session->gLim11gParams.protectionEnabled,
1257 		 session->gLim11aParams.protectionEnabled,
1258 		 session->gLimHt20Params.protectionEnabled);
1259 	pe_debug("obss: 11b:%d, 11g:%d, 11a:%d, ht20:%d",
1260 		 session->gLimOlbcParams.protectionEnabled,
1261 		 session->gLimOverlap11gParams.protectionEnabled,
1262 		 session->gLimOverlap11aParams.protectionEnabled,
1263 		 session->gLimOverlapHt20Params.protectionEnabled);
1264 	pe_debug("detect: b_ap:%d, b_s:%d, g:%d, a:%d, htl:%d, htm:%d, ht20:%d",
1265 		 cur_detect->obss_11b_ap_detect_mode,
1266 		 cur_detect->obss_11b_sta_detect_mode,
1267 		 cur_detect->obss_11g_ap_detect_mode,
1268 		 cur_detect->obss_11a_detect_mode,
1269 		 cur_detect->obss_ht_legacy_detect_mode,
1270 		 cur_detect->obss_ht_mixed_detect_mode,
1271 		 cur_detect->obss_ht_20mhz_detect_mode);
1272 
1273 	if (rf_band == REG_BAND_2G) {
1274 		if ((phy_mode == WNI_CFG_PHY_MODE_11G ||
1275 		    session->htCapability) &&
1276 		    !session->gLim11bParams.protectionEnabled) {
1277 			if (!session->gLimOlbcParams.protectionEnabled &&
1278 			    !session->gLimOverlap11gParams.protectionEnabled) {
1279 				cfg->obss_11b_ap_detect_mode =
1280 					OBSS_OFFLOAD_DETECTION_PRESENT;
1281 				cfg->obss_11b_sta_detect_mode =
1282 					OBSS_OFFLOAD_DETECTION_PRESENT;
1283 			} else {
1284 				if (cur_detect->obss_11b_ap_detect_mode ==
1285 				    OBSS_OFFLOAD_DETECTION_PRESENT)
1286 					cfg->obss_11b_ap_detect_mode =
1287 						OBSS_OFFLOAD_DETECTION_ABSENT;
1288 				if (cur_detect->obss_11b_sta_detect_mode ==
1289 				    OBSS_OFFLOAD_DETECTION_PRESENT)
1290 					cfg->obss_11b_sta_detect_mode =
1291 						OBSS_OFFLOAD_DETECTION_ABSENT;
1292 			}
1293 		} else if (session->gLim11bParams.protectionEnabled) {
1294 			session->gLimOlbcParams.protectionEnabled = false;
1295 		}
1296 
1297 		if (session->htCapability &&
1298 		    session->cfgProtection.overlapFromllg &&
1299 		    !session->gLim11gParams.protectionEnabled) {
1300 			if (!session->gLimOverlap11gParams.protectionEnabled) {
1301 				cfg->obss_11g_ap_detect_mode =
1302 					OBSS_OFFLOAD_DETECTION_PRESENT;
1303 				cfg->obss_ht_legacy_detect_mode =
1304 					OBSS_OFFLOAD_DETECTION_PRESENT;
1305 				cfg->obss_ht_mixed_detect_mode =
1306 					OBSS_OFFLOAD_DETECTION_PRESENT;
1307 			} else {
1308 				if (cur_detect->obss_11g_ap_detect_mode ==
1309 				    OBSS_OFFLOAD_DETECTION_PRESENT)
1310 					cfg->obss_11g_ap_detect_mode =
1311 						OBSS_OFFLOAD_DETECTION_ABSENT;
1312 				if (cur_detect->obss_ht_legacy_detect_mode ==
1313 				    OBSS_OFFLOAD_DETECTION_PRESENT)
1314 					cfg->obss_ht_legacy_detect_mode =
1315 						OBSS_OFFLOAD_DETECTION_ABSENT;
1316 				if (cur_detect->obss_ht_mixed_detect_mode ==
1317 				    OBSS_OFFLOAD_DETECTION_PRESENT)
1318 					cfg->obss_ht_mixed_detect_mode =
1319 						OBSS_OFFLOAD_DETECTION_ABSENT;
1320 			}
1321 		} else if (session->gLim11gParams.protectionEnabled) {
1322 			session->gLimOverlap11gParams.protectionEnabled = false;
1323 		}
1324 
1325 		/* INI related settings */
1326 		if (mac_ctx->mlme_cfg->sta.ignore_peer_erp_info)
1327 			cfg->obss_11b_sta_detect_mode =
1328 				OBSS_OFFLOAD_DETECTION_DISABLED;
1329 
1330 		if (mac_ctx->mlme_cfg->sap_protection_cfg.ignore_peer_ht_opmode)
1331 			cfg->obss_ht_legacy_detect_mode =
1332 				OBSS_OFFLOAD_DETECTION_DISABLED;
1333 	}
1334 
1335 	if ((rf_band == REG_BAND_5G) && session->htCapability) {
1336 		if (!session->gLim11aParams.protectionEnabled) {
1337 			if (!session->gLimOverlap11aParams.protectionEnabled)
1338 				cfg->obss_11a_detect_mode =
1339 					OBSS_OFFLOAD_DETECTION_PRESENT;
1340 			else if (cur_detect->obss_11a_detect_mode ==
1341 				 OBSS_OFFLOAD_DETECTION_PRESENT)
1342 					cfg->obss_11a_detect_mode =
1343 						OBSS_OFFLOAD_DETECTION_ABSENT;
1344 		} else {
1345 			session->gLimOverlap11aParams.protectionEnabled = false;
1346 		}
1347 	}
1348 
1349 	if (((rf_band == REG_BAND_2G) || (rf_band == REG_BAND_5G)) &&
1350 	    session->htCapability) {
1351 
1352 		if (!session->gLimHt20Params.protectionEnabled) {
1353 			if (!session->gLimOverlapHt20Params.protectionEnabled) {
1354 				cfg->obss_ht_20mhz_detect_mode =
1355 					OBSS_OFFLOAD_DETECTION_PRESENT;
1356 			} else if (cur_detect->obss_ht_20mhz_detect_mode ==
1357 				   OBSS_OFFLOAD_DETECTION_PRESENT) {
1358 					cfg->obss_ht_20mhz_detect_mode =
1359 					OBSS_OFFLOAD_DETECTION_ABSENT;
1360 			}
1361 		} else {
1362 			session->gLimOverlapHt20Params.protectionEnabled =
1363 				false;
1364 		}
1365 	}
1366 
1367 	pe_debug("b_ap:%d, b_s:%d, g:%d, a:%d, ht_le:%d, ht_m:%d, ht_20:%d",
1368 		 cfg->obss_11b_ap_detect_mode,
1369 		 cfg->obss_11b_sta_detect_mode,
1370 		 cfg->obss_11g_ap_detect_mode,
1371 		 cfg->obss_11a_detect_mode,
1372 		 cfg->obss_ht_legacy_detect_mode,
1373 		 cfg->obss_ht_mixed_detect_mode,
1374 		 cfg->obss_ht_20mhz_detect_mode);
1375 
1376 	return QDF_STATUS_SUCCESS;
1377 }
1378 
lim_obss_send_detection_cfg(struct mac_context * mac_ctx,struct pe_session * session,bool force)1379 QDF_STATUS lim_obss_send_detection_cfg(struct mac_context *mac_ctx,
1380 				       struct pe_session *session, bool force)
1381 {
1382 	QDF_STATUS status;
1383 	struct obss_detection_cfg obss_cfg;
1384 	struct wmi_obss_detection_cfg_param *req_param;
1385 
1386 	if (!session) {
1387 		pe_err("Invalid session");
1388 		return QDF_STATUS_E_INVAL;
1389 	}
1390 
1391 	if (!session->is_session_obss_offload_enabled) {
1392 		pe_debug("obss offload protectiond disabled, session %d",
1393 		       session->smeSessionId);
1394 		/* Send success */
1395 		return QDF_STATUS_SUCCESS;
1396 	}
1397 
1398 	if (session->gLimProtectionControl ==
1399 	    MLME_FORCE_POLICY_PROTECTION_DISABLE) {
1400 		pe_debug("protectiond disabled, force from policy, session %d",
1401 		       session->smeSessionId);
1402 		/* Send success */
1403 		return QDF_STATUS_SUCCESS;
1404 	}
1405 
1406 	status = lim_obss_generate_detection_config(mac_ctx,
1407 						    session,
1408 						    &obss_cfg);
1409 	if (QDF_IS_STATUS_ERROR(status)) {
1410 		pe_err("Failed to generate obss detection cfg, session %d",
1411 		       session->smeSessionId);
1412 		return status;
1413 	}
1414 
1415 	if (qdf_mem_cmp(&session->obss_offload_cfg, &obss_cfg, sizeof(obss_cfg))
1416 	    || force) {
1417 		struct scheduler_msg msg = {0};
1418 		req_param = qdf_mem_malloc(sizeof(*req_param));
1419 		if (!req_param)
1420 			return QDF_STATUS_E_NOMEM;
1421 		qdf_mem_copy(&session->obss_offload_cfg, &obss_cfg,
1422 				sizeof(obss_cfg));
1423 		req_param->vdev_id = session->smeSessionId;
1424 		req_param->obss_detect_period_ms = OBSS_DETECTION_PERIOD_MS;
1425 		req_param->obss_11b_ap_detect_mode =
1426 			obss_cfg.obss_11b_ap_detect_mode;
1427 		req_param->obss_11b_sta_detect_mode =
1428 			obss_cfg.obss_11b_sta_detect_mode;
1429 		req_param->obss_11g_ap_detect_mode =
1430 			obss_cfg.obss_11g_ap_detect_mode;
1431 		req_param->obss_11a_detect_mode =
1432 			obss_cfg.obss_11a_detect_mode;
1433 		req_param->obss_ht_legacy_detect_mode =
1434 			obss_cfg.obss_ht_legacy_detect_mode;
1435 		req_param->obss_ht_20mhz_detect_mode =
1436 			obss_cfg.obss_ht_20mhz_detect_mode;
1437 		req_param->obss_ht_mixed_detect_mode =
1438 			obss_cfg.obss_ht_mixed_detect_mode;
1439 
1440 		msg.type = WMA_OBSS_DETECTION_REQ;
1441 		msg.bodyptr = req_param;
1442 		msg.reserved = 0;
1443 		status = scheduler_post_message(QDF_MODULE_ID_PE,
1444 						QDF_MODULE_ID_WMA,
1445 						QDF_MODULE_ID_WMA, &msg);
1446 		if (QDF_IS_STATUS_ERROR(status)) {
1447 			qdf_mem_free(req_param);
1448 			return status;
1449 		}
1450 	} else {
1451 		pe_debug("Skipping WMA_OBSS_DETECTION_REQ, force = %d", force);
1452 	}
1453 
1454 	return status;
1455 }
1456 
lim_process_obss_detection_ind(struct mac_context * mac_ctx,struct wmi_obss_detect_info * obss_detection)1457 QDF_STATUS lim_process_obss_detection_ind(struct mac_context *mac_ctx,
1458 					  struct wmi_obss_detect_info
1459 					  *obss_detection)
1460 {
1461 	QDF_STATUS status;
1462 	uint32_t detect_masks;
1463 	uint32_t reason;
1464 	struct obss_detection_cfg *obss_cfg;
1465 	bool enable;
1466 	struct pe_session *session;
1467 	tUpdateBeaconParams bcn_prm;
1468 	enum reg_wifi_band rf_band = REG_BAND_UNKNOWN;
1469 	struct obss_detection_cfg *cur_detect;
1470 
1471 	pe_debug("obss detect ind id %d, reason %d, msk 0x%x, " QDF_MAC_ADDR_FMT,
1472 		 obss_detection->vdev_id, obss_detection->reason,
1473 		 obss_detection->matched_detection_masks,
1474 		 QDF_MAC_ADDR_REF(obss_detection->matched_bssid_addr));
1475 
1476 	session = pe_find_session_by_vdev_id(mac_ctx, obss_detection->vdev_id);
1477 	if (!session) {
1478 		pe_err("Failed to get session for id %d",
1479 		       obss_detection->vdev_id);
1480 		return QDF_STATUS_E_INVAL;
1481 	}
1482 
1483 	if (!LIM_IS_AP_ROLE(session)) {
1484 		pe_err("session %d is not AP", obss_detection->vdev_id);
1485 		return QDF_STATUS_E_INVAL;
1486 	}
1487 
1488 	if (!session->is_session_obss_offload_enabled) {
1489 		pe_err("Offload already disabled for session %d",
1490 		       obss_detection->vdev_id);
1491 		return QDF_STATUS_SUCCESS;
1492 	}
1493 
1494 	reason = obss_detection->reason;
1495 	detect_masks = obss_detection->matched_detection_masks;
1496 
1497 	if (reason == OBSS_OFFLOAD_DETECTION_PRESENT) {
1498 		enable = true;
1499 	} else if (reason == OBSS_OFFLOAD_DETECTION_ABSENT) {
1500 		enable = false;
1501 	} else if (reason == OBSS_OFFLOAD_DETECTION_DISABLED) {
1502 		/*
1503 		 * Most common reason for this event-type from firmware
1504 		 * is insufficient memory.
1505 		 * Disable offload OBSS detection and enable legacy-way
1506 		 * of detecting OBSS by parsing beacons.
1507 		 **/
1508 		session->is_session_obss_offload_enabled = false;
1509 		pe_err("FW indicated obss offload disabled");
1510 		pe_err("Enabling host based detection, session %d",
1511 		       obss_detection->vdev_id);
1512 
1513 		status = qdf_mc_timer_start(&session->
1514 					    protection_fields_reset_timer,
1515 					    SCH_PROTECTION_RESET_TIME);
1516 		if (QDF_IS_STATUS_ERROR(status))
1517 			pe_err("cannot start protection reset timer");
1518 
1519 		return QDF_STATUS_SUCCESS;
1520 	} else {
1521 		pe_err("Invalid reason %d, session %d",
1522 		       obss_detection->reason,
1523 		       obss_detection->vdev_id);
1524 		return QDF_STATUS_E_INVAL;
1525 	}
1526 
1527 	rf_band = session->limRFBand;
1528 	qdf_mem_zero(&bcn_prm, sizeof(bcn_prm));
1529 	obss_cfg = &session->obss_offload_cfg;
1530 	cur_detect = &session->current_obss_detection;
1531 
1532 	if (OBSS_DETECTION_IS_11B_AP(detect_masks)) {
1533 		if (reason != obss_cfg->obss_11b_ap_detect_mode ||
1534 		    rf_band != REG_BAND_2G)
1535 			goto wrong_detection;
1536 
1537 		lim_enable11g_protection(mac_ctx, enable, true,
1538 					 &bcn_prm, session);
1539 		cur_detect->obss_11b_ap_detect_mode = reason;
1540 	}
1541 	if (OBSS_DETECTION_IS_11B_STA(detect_masks)) {
1542 		if (reason != obss_cfg->obss_11b_sta_detect_mode ||
1543 		    rf_band != REG_BAND_2G)
1544 			goto wrong_detection;
1545 
1546 		lim_enable11g_protection(mac_ctx, enable, true,
1547 					 &bcn_prm, session);
1548 		cur_detect->obss_11b_sta_detect_mode = reason;
1549 	}
1550 	if (OBSS_DETECTION_IS_11G_AP(detect_masks)) {
1551 		if (reason != obss_cfg->obss_11g_ap_detect_mode ||
1552 		    rf_band != REG_BAND_2G)
1553 			goto wrong_detection;
1554 
1555 		lim_enable_ht_protection_from11g(mac_ctx, enable, true,
1556 						 &bcn_prm, session);
1557 		cur_detect->obss_11g_ap_detect_mode = reason;
1558 	}
1559 	if (OBSS_DETECTION_IS_11A(detect_masks)) {
1560 		if (reason != obss_cfg->obss_11a_detect_mode ||
1561 		    rf_band != REG_BAND_5G)
1562 			goto wrong_detection;
1563 
1564 		lim_update_11a_protection(mac_ctx, enable, true,
1565 					  &bcn_prm, session);
1566 		cur_detect->obss_11a_detect_mode = reason;
1567 	}
1568 	if (OBSS_DETECTION_IS_HT_LEGACY(detect_masks)) {
1569 		/* for 5GHz, we have only 11a detection, which covers legacy */
1570 		if (reason != obss_cfg->obss_ht_legacy_detect_mode ||
1571 		    rf_band != REG_BAND_2G)
1572 			goto wrong_detection;
1573 
1574 		lim_enable_ht_protection_from11g(mac_ctx, enable, true,
1575 						 &bcn_prm, session);
1576 		cur_detect->obss_ht_legacy_detect_mode = reason;
1577 	}
1578 	if (OBSS_DETECTION_IS_HT_MIXED(detect_masks)) {
1579 		/* for 5GHz, we have only 11a detection, which covers ht mix */
1580 		if (reason != obss_cfg->obss_ht_mixed_detect_mode ||
1581 		    rf_band != REG_BAND_2G)
1582 			goto wrong_detection;
1583 
1584 		lim_enable_ht_protection_from11g(mac_ctx, enable, true,
1585 						 &bcn_prm, session);
1586 		cur_detect->obss_ht_mixed_detect_mode = reason;
1587 	}
1588 	if (OBSS_DETECTION_IS_HT_20MHZ(detect_masks)) {
1589 		if (reason != obss_cfg->obss_ht_20mhz_detect_mode)
1590 			goto wrong_detection;
1591 
1592 		lim_enable_ht20_protection(mac_ctx, enable, true,
1593 					   &bcn_prm, session);
1594 		cur_detect->obss_ht_20mhz_detect_mode = reason;
1595 	}
1596 
1597 	if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) &&
1598 	    bcn_prm.paramChangeBitmap) {
1599 		/* Update the bcn and apply the new settings to HAL */
1600 		sch_set_fixed_beacon_fields(mac_ctx, session);
1601 		pe_debug("Beacon for PE session: %d got changed: 0x%x",
1602 			 session->smeSessionId, bcn_prm.paramChangeBitmap);
1603 		if (!QDF_IS_STATUS_SUCCESS(lim_send_beacon_params(
1604 		     mac_ctx, &bcn_prm, session))) {
1605 			pe_err("Failed to send beacon param, session %d",
1606 				obss_detection->vdev_id);
1607 			return QDF_STATUS_E_FAULT;
1608 		}
1609 	}
1610 
1611 	status = lim_obss_send_detection_cfg(mac_ctx, session, true);
1612 	if (QDF_IS_STATUS_ERROR(status)) {
1613 		pe_err("Failed to send obss detection cfg, session %d",
1614 			obss_detection->vdev_id);
1615 		return status;
1616 	}
1617 
1618 	return QDF_STATUS_SUCCESS;
1619 
1620 wrong_detection:
1621 	/*
1622 	 * We may get this wrong detection before FW can update latest cfg,
1623 	 * So keeping log level debug
1624 	 **/
1625 	pe_debug("Wrong detection, session %d", obss_detection->vdev_id);
1626 
1627 	return QDF_STATUS_E_INVAL;
1628 }
1629