瀏覽代碼

qcacld-3.0: Enable obss detection offload

Enable firmware based obss detection.

Change-Id: I218337092e553bca0737864214c16b0dacbfa3be
CRs-Fixed: 2171944
Arif Hussain 7 年之前
父節點
當前提交
1513cb2384

+ 1 - 1
core/mac/inc/ani_global.h

@@ -828,7 +828,7 @@ typedef struct sAniSirLim {
 	uint8_t scan_disabled;
 	uint8_t beacon_probe_rsp_cnt_per_scan;
 	wlan_scan_requester req_id;
-	uint8_t obss_detection_offloaded;
+	bool global_obss_offload_enabled;
 } tAniSirLim, *tpAniSirLim;
 
 struct mgmt_frm_reg_info {

+ 4 - 1
core/mac/src/pe/include/lim_session.h

@@ -115,6 +115,7 @@ struct bss_color_info {
  * @obss_ht_legacy_detect_mode: detection mode for ht ap with legacy mode.
  * @obss_ht_mixed_detect_mode: detection mode for ht ap with mixed mode.
  * @obss_ht_20mhz_detect_mode: detection mode for ht ap with 20mhz mode.
+ * @obss_current_detection_masks: current detection masks.
  */
 struct obss_detection_cfg {
 	uint8_t obss_11b_ap_detect_mode;
@@ -124,6 +125,7 @@ struct obss_detection_cfg {
 	uint8_t obss_ht_legacy_detect_mode;
 	uint8_t obss_ht_mixed_detect_mode;
 	uint8_t obss_ht_20mhz_detect_mode;
+	uint32_t obss_current_detection_masks;
 };
 
 typedef struct sPESession       /* Added to Support BT-AMP */
@@ -547,7 +549,8 @@ typedef struct sPESession       /* Added to Support BT-AMP */
 	/* previous auth frame's sequence number */
 	uint16_t prev_auth_seq_num;
 	struct obss_detection_cfg obss_offload_cfg;
-	bool enable_obss_detection_offload;
+	bool is_session_obss_offload_enabled;
+	bool is_obss_reset_timer_initialized;
 } tPESession, *tpPESession;
 
 /*-------------------------------------------------------------------------

+ 1 - 1
core/mac/src/pe/lim/lim_api.c

@@ -470,7 +470,7 @@ static tSirRetStatus __lim_init_config(tpAniSirGlobal pMac)
 	if (eSIR_SUCCESS != wlan_cfg_get_int(pMac,
 					     WNI_CFG_OBSS_DETECTION_OFFLOAD,
 					     (uint32_t *)&pMac->lim.
-					     obss_detection_offloaded)) {
+					     global_obss_offload_enabled)) {
 		pe_err("cfg get obss_detection_offloaded failed");
 		return eSIR_FAILURE;
 	}

+ 4 - 1
core/mac/src/pe/lim/lim_assoc_utils.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -3087,6 +3087,9 @@ lim_delete_dph_hash_entry(tpAniSirGlobal mac_ctx, tSirMacAddr sta_addr,
 			lim_send_beacon_params(mac_ctx, &beacon_params,
 					       session_entry);
 		}
+
+		lim_obss_send_detection_cfg(mac_ctx, session_entry, false);
+
 #ifdef WLAN_FEATURE_11W
 		if (sta_ds->rmfEnabled) {
 			pe_debug("delete pmf timer sta-idx:%d assoc-id:%d",

+ 1 - 0
core/mac/src/pe/lim/lim_process_message_queue.c

@@ -1901,6 +1901,7 @@ static void lim_process_messages(tpAniSirGlobal mac_ctx,
 		msg->bodyptr = NULL;
 		break;
 	case WMA_OBSS_DETECTION_INFO:
+		lim_process_obss_detection_ind(mac_ctx, msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		msg->bodyptr = NULL;
 		break;

+ 1 - 0
core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c

@@ -255,6 +255,7 @@ void lim_process_mlm_start_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf)
 					psessionEntry->ssId.ssId,
 					psessionEntry->currentOperChannel);
 			lim_send_beacon_ind(pMac, psessionEntry);
+			lim_enable_obss_detection_config (pMac, psessionEntry);
 		}
 	}
 }

+ 1 - 0
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -5072,6 +5072,7 @@ static void lim_process_sme_start_beacon_req(tpAniSirGlobal pMac, uint32_t *pMsg
 			  psessionEntry->ssId.ssId,
 			  psessionEntry->currentOperChannel);
 		lim_send_beacon_ind(pMac, psessionEntry);
+		lim_enable_obss_detection_config(pMac, psessionEntry);
 	} else {
 		pe_err("Invalid Beacon Start Indication");
 		return;

+ 2 - 0
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -1323,6 +1323,8 @@ lim_send_assoc_rsp_mgmt_frame(tpAniSirGlobal mac_ctx,
 		lim_send_beacon_params(mac_ctx, &beacon_params, pe_session);
 	}
 
+	lim_obss_send_detection_cfg(mac_ctx, pe_session, false);
+
 	if (assoc_req != NULL) {
 		addn_ie_len = pe_session->addIeParams.assocRespDataLen;
 

+ 2 - 0
core/mac/src/pe/lim/lim_send_sme_rsp_messages.c

@@ -2492,6 +2492,8 @@ lim_send_sme_ap_channel_switch_resp(tpAniSirGlobal pMac,
 			pe_debug("Failed to Transmit Beacons on channel: %d after AP channel change response",
 				       psessionEntry->bcnLen);
 		}
+
+		lim_obss_send_detection_cfg(pMac, psessionEntry, true);
 	}
 	return;
 }

+ 13 - 11
core/mac/src/pe/lim/lim_session.c

@@ -515,18 +515,20 @@ pe_create_session(tpAniSirGlobal pMac, uint8_t *bssid, uint8_t *sessionId,
 
 	if (eSIR_INFRA_AP_MODE == bssType) {
 		session_ptr->old_protection_state = 0;
+		session_ptr->is_session_obss_offload_enabled = false;
+		session_ptr->is_obss_reset_timer_initialized = false;
 		session_ptr->mac_ctx = (void *)pMac;
-		status = qdf_mc_timer_init(
-			&session_ptr->protection_fields_reset_timer,
-			QDF_TIMER_TYPE_SW, pe_reset_protection_callback,
-			(void *)&pMac->lim.gpSession[i]);
-		if (status == QDF_STATUS_SUCCESS) {
-			status = qdf_mc_timer_start(
-				&session_ptr->protection_fields_reset_timer,
-				SCH_PROTECTION_RESET_TIME);
-		}
-		if (status != QDF_STATUS_SUCCESS)
-			pe_err("cannot create or start protectionFieldsResetTimer");
+
+		status = qdf_mc_timer_init(&session_ptr->
+					   protection_fields_reset_timer,
+					   QDF_TIMER_TYPE_SW,
+					   pe_reset_protection_callback,
+					   (void *)&pMac->lim.gpSession[i]);
+
+		if (QDF_IS_STATUS_ERROR(status))
+			pe_err("cannot create protection fields reset timer");
+		else
+			session_ptr->is_obss_reset_timer_initialized = true;
 	}
 	pe_init_fils_info(session_ptr);
 	pe_init_pmf_comeback_timer(pMac, session_ptr, *sessionId);

+ 4 - 0
core/mac/src/pe/lim/lim_utils.c

@@ -1041,6 +1041,10 @@ void lim_handle_update_olbc_cache(tpAniSirGlobal mac_ctx)
 		return;
 	}
 
+	if (psessionEntry->is_session_obss_offload_enabled) {
+		pe_debug("protection offloaded");
+		return;
+	}
 	qdf_mem_set((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams), 0);
 	beaconParams.bssIdx = psessionEntry->bssIdx;
 

+ 93 - 0
core/mac/src/pe/lim/lim_utils.h

@@ -71,6 +71,43 @@ typedef enum {
 
 #define MGMT_RX_PACKETS_THRESHOLD 200
 
+/* 11B AP detection bit position */
+#define OBSS_DETECTION_11B_AP_BIT_MASK       0x0001
+/* 11B STA detection bit position */
+#define OBSS_DETECTION_11B_STA_BIT_MASK      0x0002
+/* 11G AP detection bit position */
+#define OBSS_DETECTION_11G_AP_BIT_MASK       0x0004
+/* 11A AP detection bit position */
+#define OBSS_DETECTION_11A_BIT_MASK          0x0008
+/* HT legacy detection bit position */
+#define OBSS_DETECTION_HT_LEGACY_BIT_MASK    0x0010
+/* HT mixed detection bit position */
+#define OBSS_DETECTION_HT_MIXED_BIT_MASK     0x0020
+/* HT 20mhz detection bit position */
+#define OBSS_DETECTION_HT_20MHZ_BIT_MASK     0x0040
+
+/**
+ * OBSS detection period in ms, used by firmware to decide
+ * absent detection and also gap between same detection ind.
+ */
+#define OBSS_DETECTION_PERIOD_MS             4000
+
+/* To check if 11B AP detection bit set */
+#define OBSS_DETECTION_IS_11B_AP(_m) ((_m) & OBSS_DETECTION_11B_AP_BIT_MASK)
+/* To check if 11B STA detection bit set */
+#define OBSS_DETECTION_IS_11B_STA(_m) ((_m) & OBSS_DETECTION_11B_STA_BIT_MASK)
+/* To check if 11G AP detection bit set */
+#define OBSS_DETECTION_IS_11G_AP(_m) ((_m) & OBSS_DETECTION_11G_AP_BIT_MASK)
+/* To check if 11A AP detection bit set */
+#define OBSS_DETECTION_IS_11A(_m) ((_m) & OBSS_DETECTION_11A_BIT_MASK)
+/* To check if HT legacy detection bit set */
+#define OBSS_DETECTION_IS_HT_LEGACY(_m) \
+	((_m) & OBSS_DETECTION_HT_LEGACY_BIT_MASK)
+/* To check if HT mixed detection bit set */
+#define OBSS_DETECTION_IS_HT_MIXED(_m) ((_m) & OBSS_DETECTION_HT_MIXED_BIT_MASK)
+/* To check if HT 20mhz detection bit set */
+#define OBSS_DETECTION_IS_HT_20MHZ(_m) ((_m) & OBSS_DETECTION_HT_20MHZ_BIT_MASK)
+
 #ifdef WLAN_FEATURE_11W
 typedef union uPmfSaQueryTimerId {
 	struct {
@@ -1235,4 +1272,60 @@ void lim_send_chan_switch_action_frame(tpAniSirGlobal mac_ctx,
 				       uint8_t ch_bandwidth,
 				       tpPESession session_entry);
 
+/**
+ * lim_process_obss_detection_ind() - Process obss detection indication
+ * @mac_ctx: Pointer to Global MAC structure.
+ * @obss_detection: obss detection info.
+ *
+ * Process obss detection indication and apply necessary protection for
+ * the given AP session.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS lim_process_obss_detection_ind(tpAniSirGlobal mac_ctx,
+					  struct wmi_obss_detect_info
+					  *obss_detection);
+
+/**
+ * lim_obss_send_detection_cfg() - Send obss detection configuration to firmware
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session: Pointer to session
+ * @force: Force to send new configuration even if new cfg same as old
+ *
+ * Generate new cfg based on current protection status and send new cfg to
+ * firmware.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS lim_obss_send_detection_cfg(tpAniSirGlobal mac_ctx,
+				       tpPESession session,
+				       bool force);
+
+/**
+ * lim_obss_generate_detection_config() - get new obss offload detection cfg
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session: Pointer to session
+ * @cfg: Obss detection cfg buffer pointer
+ *
+ * Generate new cfg based on current protection status.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS lim_obss_generate_detection_config(tpAniSirGlobal mac_ctx,
+					      tpPESession session,
+					      struct obss_detection_cfg *cfg);
+
+/**
+ * lim_enable_obss_detection_config() - Enable obss detection
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session: Pointer to session
+ *
+ * This function will enable legacy obss detection (by starting timer)
+ * or also offload based detection based on support.
+ *
+ * Return: None
+ */
+void lim_enable_obss_detection_config(tpAniSirGlobal mac_ctx,
+				      tpPESession session);
+
 #endif /* __LIM_UTILS_H */

+ 428 - 2
core/mac/src/pe/sch/sch_beacon_process.c

@@ -1057,8 +1057,9 @@ sch_beacon_process(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info,
 
 		sch_check_bss_color_ie(mac_ctx, ap_session, &bcn, &bcn_prm);
 
-		if (ap_session->gLimProtectionControl !=
-		    WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE)
+		if ((ap_session->gLimProtectionControl !=
+		     WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) &&
+		    !ap_session->is_session_obss_offload_enabled)
 			ap_beacon_process(mac_ctx, rx_pkt_info,
 					  &bcn, &bcn_prm, ap_session);
 
@@ -1187,3 +1188,428 @@ sch_beacon_edca_process(tpAniSirGlobal pMac, tSirMacEdcaParamSetIE *edca,
 	}
 	return eSIR_SUCCESS;
 }
+
+void lim_enable_obss_detection_config(tpAniSirGlobal mac_ctx,
+				      tpPESession session)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!session) {
+		pe_err("Invalid session, protection not enabled");
+		return;
+	}
+
+	if (session->gLimProtectionControl ==
+	    WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) {
+		pe_err("protectiond disabled, force policy, session %d",
+		       session->smeSessionId);
+		return;
+	}
+
+	if (mac_ctx->lim.global_obss_offload_enabled) {
+		status = lim_obss_send_detection_cfg(mac_ctx, session, true);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_err("vdev %d: offload enable failed, trying legacy",
+			       session->smeSessionId);
+			session->is_session_obss_offload_enabled = false;
+		} else {
+			pe_debug("vdev %d: offload detection enabled",
+				 session->smeSessionId);
+			session->is_session_obss_offload_enabled = true;
+			lim_obss_send_detection_cfg(mac_ctx, session, true);
+		}
+	}
+
+	if (!mac_ctx->lim.global_obss_offload_enabled ||
+	    QDF_IS_STATUS_ERROR(status)) {
+		status = qdf_mc_timer_start(&session->
+					    protection_fields_reset_timer,
+					    SCH_PROTECTION_RESET_TIME);
+		if (QDF_IS_STATUS_ERROR(status))
+			pe_err("vdev %d: start timer failed",
+			       session->smeSessionId);
+		else
+			pe_debug("vdev %d: legacy detection enabled",
+				 session->smeSessionId);
+	}
+}
+
+QDF_STATUS lim_obss_generate_detection_config(tpAniSirGlobal mac_ctx,
+					      tpPESession session,
+					      struct obss_detection_cfg *cfg)
+{
+	uint32_t phy_mode;
+	enum band_info rf_band = BAND_UNKNOWN;
+	uint32_t detect_masks;
+
+	if (!mac_ctx || !session || !cfg) {
+		pe_err("Invalid params mac_ctx %pK, session %pK, cfg %pK",
+			mac_ctx, session, cfg);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	lim_get_phy_mode(mac_ctx, &phy_mode, session);
+	rf_band = session->limRFBand;
+	qdf_mem_zero(cfg, sizeof(*cfg));
+	detect_masks = session->obss_offload_cfg.obss_current_detection_masks;
+
+	pe_debug("band:%d, phy_mode:%d, ht_cap:%d, ht_oper_mode:%d",
+		 rf_band, phy_mode, session->htCapability,
+		 mac_ctx->lim.gHTOperMode);
+	pe_debug("assoc_sta: 11b:%d, 11g:%d, 11a:%d, ht20:%d",
+		 session->gLim11bParams.protectionEnabled,
+		 session->gLim11gParams.protectionEnabled,
+		 session->gLim11aParams.protectionEnabled,
+		 session->gLimHt20Params.protectionEnabled);
+	pe_debug("obss: 11b:%d, 11g:%d, 11a:%d, ht20:%d, masks:0x%0x",
+		 session->gLimOlbcParams.protectionEnabled,
+		 session->gLimOverlap11gParams.protectionEnabled,
+		 session->gLimOverlap11aParams.protectionEnabled,
+		 session->gLimOverlapHt20Params.protectionEnabled,
+		 detect_masks);
+
+	if ((rf_band == BAND_2G)) {
+		if ((phy_mode == WNI_CFG_PHY_MODE_11G ||
+		    session->htCapability) &&
+		    !session->gLim11bParams.protectionEnabled) {
+			if (!session->gLimOlbcParams.protectionEnabled &&
+			    !session->gLimOverlap11gParams.protectionEnabled) {
+				cfg->obss_11b_ap_detect_mode =
+					OBSS_OFFLOAD_DETECTION_PRESENT;
+				cfg->obss_11b_sta_detect_mode =
+					OBSS_OFFLOAD_DETECTION_PRESENT;
+			} else {
+				if (OBSS_DETECTION_IS_11B_AP(detect_masks))
+					cfg->obss_11b_ap_detect_mode =
+						OBSS_OFFLOAD_DETECTION_ABSENT;
+				if (OBSS_DETECTION_IS_11B_STA(detect_masks))
+					cfg->obss_11b_sta_detect_mode =
+						OBSS_OFFLOAD_DETECTION_ABSENT;
+			}
+		} else if (session->gLim11bParams.protectionEnabled) {
+			session->gLimOlbcParams.protectionEnabled = false;
+		}
+
+		if (session->htCapability &&
+		    session->cfgProtection.overlapFromllg &&
+		    !session->gLim11gParams.protectionEnabled) {
+			if (!session->gLimOverlap11gParams.protectionEnabled) {
+				cfg->obss_11g_ap_detect_mode =
+					OBSS_OFFLOAD_DETECTION_PRESENT;
+				cfg->obss_ht_legacy_detect_mode =
+					OBSS_OFFLOAD_DETECTION_PRESENT;
+				cfg->obss_ht_mixed_detect_mode =
+					OBSS_OFFLOAD_DETECTION_PRESENT;
+			} else {
+				if (OBSS_DETECTION_IS_11G_AP(detect_masks))
+					cfg->obss_11g_ap_detect_mode =
+						OBSS_OFFLOAD_DETECTION_ABSENT;
+				if (OBSS_DETECTION_IS_HT_LEGACY(detect_masks))
+					cfg->obss_ht_legacy_detect_mode =
+						OBSS_OFFLOAD_DETECTION_ABSENT;
+				if (OBSS_DETECTION_IS_HT_MIXED(detect_masks))
+					cfg->obss_ht_mixed_detect_mode =
+						OBSS_OFFLOAD_DETECTION_ABSENT;
+			}
+		} else if (session->gLim11gParams.protectionEnabled) {
+			session->gLimOverlap11gParams.protectionEnabled = false;
+		}
+
+		/* INI related settings */
+		if (mac_ctx->roam.configParam.ignore_peer_erp_info)
+			cfg->obss_11b_sta_detect_mode =
+				OBSS_OFFLOAD_DETECTION_DISABLED;
+
+		if (mac_ctx->roam.configParam.ignore_peer_ht_opmode)
+			cfg->obss_ht_legacy_detect_mode =
+				OBSS_OFFLOAD_DETECTION_DISABLED;
+	}
+
+	if ((rf_band == BAND_5G) && session->htCapability) {
+		if (!session->gLim11aParams.protectionEnabled) {
+			if (!session->gLimOverlap11aParams.protectionEnabled)
+				cfg->obss_11a_detect_mode =
+					OBSS_OFFLOAD_DETECTION_PRESENT;
+			else if (OBSS_DETECTION_IS_11A(detect_masks))
+					cfg->obss_11a_detect_mode =
+						OBSS_OFFLOAD_DETECTION_ABSENT;
+		} else {
+			session->gLimOverlap11aParams.protectionEnabled = false;
+		}
+	}
+
+	if (((rf_band == BAND_2G) || (rf_band == BAND_5G)) &&
+	    session->htCapability) {
+
+		if (!session->gLimHt20Params.protectionEnabled) {
+			if (!session->gLimOverlapHt20Params.protectionEnabled) {
+				cfg->obss_ht_20mhz_detect_mode =
+					OBSS_OFFLOAD_DETECTION_PRESENT;
+			} else if (OBSS_DETECTION_IS_HT_20MHZ(detect_masks)) {
+					cfg->obss_ht_20mhz_detect_mode =
+					OBSS_OFFLOAD_DETECTION_ABSENT;
+			}
+		} else {
+			session->gLimOverlapHt20Params.protectionEnabled =
+				false;
+		}
+	}
+
+	pe_debug("b_ap:%d, b_s:%d, g:%d, a:%d, ht_le:%d, ht_m:%d, ht_20:%d",
+		 cfg->obss_11b_ap_detect_mode,
+		 cfg->obss_11b_sta_detect_mode,
+		 cfg->obss_11g_ap_detect_mode,
+		 cfg->obss_11a_detect_mode,
+		 cfg->obss_ht_legacy_detect_mode,
+		 cfg->obss_ht_mixed_detect_mode,
+		 cfg->obss_ht_20mhz_detect_mode);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS lim_obss_send_detection_cfg(tpAniSirGlobal mac_ctx,
+				       tpPESession session, bool force)
+{
+	QDF_STATUS status;
+	struct obss_detection_cfg obss_cfg;
+	struct wmi_obss_detection_cfg_param *req_param;
+
+	if (!session) {
+		pe_err("Invalid session");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!session->is_session_obss_offload_enabled) {
+		pe_debug("obss offload protectiond disabled, session %d",
+		       session->smeSessionId);
+		/* Send success */
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (session->gLimProtectionControl ==
+	    WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) {
+		pe_debug("protectiond disabled, force from policy, session %d",
+		       session->smeSessionId);
+		/* Send success */
+		return QDF_STATUS_SUCCESS;
+	}
+
+	status = lim_obss_generate_detection_config(mac_ctx,
+						    session,
+						    &obss_cfg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to generate obss detection cfg, session %d",
+		       session->smeSessionId);
+		return status;
+	}
+
+	if (qdf_mem_cmp(&session->obss_offload_cfg, &obss_cfg, sizeof(obss_cfg))
+	    || force) {
+		struct scheduler_msg msg = {0};
+		req_param = qdf_mem_malloc(sizeof(*req_param));
+		if (!req_param) {
+			pe_err("Failed to allocate memory");
+			return QDF_STATUS_E_NOMEM;
+		}
+		qdf_mem_copy(&session->obss_offload_cfg, &obss_cfg,
+				sizeof(obss_cfg));
+		req_param->vdev_id = session->smeSessionId;
+		req_param->obss_detect_period_ms = OBSS_DETECTION_PERIOD_MS;
+		req_param->obss_11b_ap_detect_mode =
+			obss_cfg.obss_11b_ap_detect_mode;
+		req_param->obss_11b_sta_detect_mode =
+			obss_cfg.obss_11b_sta_detect_mode;
+		req_param->obss_11g_ap_detect_mode =
+			obss_cfg.obss_11g_ap_detect_mode;
+		req_param->obss_11a_detect_mode =
+			obss_cfg.obss_11a_detect_mode;
+		req_param->obss_ht_legacy_detect_mode =
+			obss_cfg.obss_ht_legacy_detect_mode;
+		req_param->obss_ht_20mhz_detect_mode =
+			obss_cfg.obss_ht_20mhz_detect_mode;
+		req_param->obss_ht_mixed_detect_mode =
+			obss_cfg.obss_ht_mixed_detect_mode;
+
+		msg.type = WMA_OBSS_DETECTION_REQ;
+		msg.bodyptr = req_param;
+		msg.reserved = 0;
+		status = scheduler_post_msg(QDF_MODULE_ID_WMA, &msg);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_err("Failed to post WMA_OBSS_DETECTION_REQ to WMA");
+			qdf_mem_free(req_param);
+			return status;
+		}
+	} else {
+		pe_debug("Skiping WMA_OBSS_DETECTION_REQ, force = %d", force);
+	}
+
+	return status;
+}
+
+QDF_STATUS lim_process_obss_detection_ind(tpAniSirGlobal mac_ctx,
+					  struct wmi_obss_detect_info
+					  *obss_detection)
+{
+	QDF_STATUS status;
+	uint32_t detect_masks;
+	uint32_t reason;
+	struct obss_detection_cfg *obss_cfg;
+	bool enable;
+	tpPESession session;
+	tUpdateBeaconParams bcn_prm;
+	enum band_info rf_band = BAND_UNKNOWN;
+
+	pe_debug("obss detect ind id %d, reason %d, msk 0x%x, " MAC_ADDRESS_STR,
+		 obss_detection->vdev_id, obss_detection->reason,
+		 obss_detection->matched_detection_masks,
+		 MAC_ADDR_ARRAY(obss_detection->matched_bssid_addr));
+
+	session = pe_find_session_by_sme_session_id(mac_ctx,
+						    obss_detection->vdev_id);
+	if (!session) {
+		pe_err("Failed to get session for id %d",
+		       obss_detection->vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!LIM_IS_AP_ROLE(session)) {
+		pe_err("session %d is not AP", obss_detection->vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!session->is_session_obss_offload_enabled) {
+		pe_err("Offload already disabled for session %d",
+		       obss_detection->vdev_id);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	reason = obss_detection->reason;
+	detect_masks = obss_detection->matched_detection_masks;
+
+	if (reason == OBSS_OFFLOAD_DETECTION_PRESENT) {
+		enable = true;
+	} else if (reason == OBSS_OFFLOAD_DETECTION_ABSENT) {
+		enable = false;
+	} else if (reason == OBSS_OFFLOAD_DETECTION_DISABLED) {
+		/*
+		 * Most common reason for this event-type from firmware
+		 * is insufficient memory.
+		 * Disable offload OBSS detection and enable legacy-way
+		 * of detecting OBSS by parsing beacons.
+		 **/
+		session->is_session_obss_offload_enabled = false;
+		pe_err("FW indicated obss offload disabled");
+		pe_err("Enabling host based detection, session %d",
+		       obss_detection->vdev_id);
+
+		status = qdf_mc_timer_start(&session->
+					    protection_fields_reset_timer,
+					    SCH_PROTECTION_RESET_TIME);
+		if (QDF_IS_STATUS_ERROR(status))
+			pe_err("cannot start protection reset timer");
+
+		return QDF_STATUS_SUCCESS;
+	} else {
+		pe_err("Invalid reason %d, session %d",
+		       obss_detection->reason,
+		       obss_detection->vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	rf_band = session->limRFBand;
+	qdf_mem_zero(&bcn_prm, sizeof(bcn_prm));
+	obss_cfg = &session->obss_offload_cfg;
+
+	if (OBSS_DETECTION_IS_11B_AP(detect_masks)) {
+		if (reason != obss_cfg->obss_11b_ap_detect_mode ||
+		    rf_band != BAND_2G)
+			goto wrong_detection;
+
+		lim_enable11g_protection(mac_ctx, enable, true,
+					 &bcn_prm, session);
+	}
+	if (OBSS_DETECTION_IS_11B_STA(detect_masks)) {
+		if (reason != obss_cfg->obss_11b_sta_detect_mode ||
+		    rf_band != BAND_2G)
+			goto wrong_detection;
+
+		lim_enable11g_protection(mac_ctx, enable, true,
+					 &bcn_prm, session);
+	}
+	if (OBSS_DETECTION_IS_11G_AP(detect_masks)) {
+		if (reason != obss_cfg->obss_11g_ap_detect_mode ||
+		    rf_band != BAND_2G)
+			goto wrong_detection;
+
+		lim_enable_ht_protection_from11g(mac_ctx, enable, true,
+						 &bcn_prm, session);
+	}
+	if (OBSS_DETECTION_IS_11A(detect_masks)) {
+		if (reason != obss_cfg->obss_11a_detect_mode ||
+		    rf_band != BAND_5G)
+			goto wrong_detection;
+
+		lim_update_11a_protection(mac_ctx, enable, true,
+					  &bcn_prm, session);
+	}
+	if (OBSS_DETECTION_IS_HT_LEGACY(detect_masks)) {
+		/* for 5GHz, we have only 11a detection, which covers legacy */
+		if (reason != obss_cfg->obss_ht_legacy_detect_mode ||
+		    rf_band != BAND_2G)
+			goto wrong_detection;
+
+		lim_enable_ht_protection_from11g(mac_ctx, enable, true,
+						 &bcn_prm, session);
+	}
+	if (OBSS_DETECTION_IS_HT_MIXED(detect_masks)) {
+		/* for 5GHz, we have only 11a detection, which covers ht mix */
+		if (reason != obss_cfg->obss_ht_mixed_detect_mode ||
+		    rf_band != BAND_2G)
+			goto wrong_detection;
+
+		lim_enable_ht_protection_from11g(mac_ctx, enable, true,
+						 &bcn_prm, session);
+	}
+	if (OBSS_DETECTION_IS_HT_20MHZ(detect_masks)) {
+		if (reason != obss_cfg->obss_ht_20mhz_detect_mode)
+			goto wrong_detection;
+
+		lim_enable_ht20_protection(mac_ctx, enable, true,
+					   &bcn_prm, session);
+	}
+
+	/* save current detection */
+	session->obss_offload_cfg.obss_current_detection_masks = detect_masks;
+
+	if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) &&
+	    bcn_prm.paramChangeBitmap) {
+		/* Update the bcn and apply the new settings to HAL */
+		sch_set_fixed_beacon_fields(mac_ctx, session);
+		pe_debug("Beacon for PE session: %d got changed: 0x%x",
+			 session->smeSessionId, bcn_prm.paramChangeBitmap);
+		if (!IS_SIR_STATUS_SUCCESS(lim_send_beacon_params(
+		     mac_ctx, &bcn_prm, session))) {
+			pe_err("Failed to send beacon param, session %d",
+				obss_detection->vdev_id);
+			return QDF_STATUS_E_FAULT;
+		}
+	}
+
+	status = lim_obss_send_detection_cfg(mac_ctx, session, true);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to send obss detection cfg, session %d",
+			obss_detection->vdev_id);
+		return status;
+	}
+
+	return QDF_STATUS_SUCCESS;
+
+wrong_detection:
+	/*
+	 * We may get this wrong detection before FW can update latest cfg,
+	 * So keeping log level debug
+	 **/
+	pe_debug("Wrong detection, session %d", obss_detection->vdev_id);
+
+	return QDF_STATUS_E_INVAL;
+}