qcacld-3.0: Add support for 11AX BSS color change

Add support for handling BSS color collision and select new BSS
color. Update beacon template and set new BSS color to FW.

Change-Id: If441990916753bdcf4daaded031e16f0460a0e8f
CRs-Fixed: 2039284
diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h
index 4c05a4d..3289066 100644
--- a/core/mac/src/include/parser_api.h
+++ b/core/mac/src/include/parser_api.h
@@ -200,6 +200,9 @@
 	tSirQCNIE QCN_IE;
 	tDot11fIEvendor_he_cap vendor_he_cap;
 	tDot11fIEvendor_he_op vendor_he_op;
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+	tDot11fIEbss_color_change vendor_he_bss_color_change;
+#endif
 } tSirProbeRespBeacon, *tpSirProbeRespBeacon;
 
 /* probe Request structure */
@@ -1012,6 +1015,19 @@
 				   tDot11fIEvendor_he_cap *);
 QDF_STATUS populate_dot11f_he_operation(tpAniSirGlobal , tpPESession ,
 					tDot11fIEvendor_he_op *);
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+QDF_STATUS populate_dot11f_he_bss_color_change(tpAniSirGlobal mac_ctx,
+				tpPESession session,
+				tDot11fIEbss_color_change *bss_color);
+#else
+static inline QDF_STATUS populate_dot11f_he_bss_color_change(
+				tpAniSirGlobal mac_ctx,
+				tpPESession session,
+				tDot11fIEbss_color_change *bss_color)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 #else
 static inline QDF_STATUS populate_dot11f_he_caps(tpAniSirGlobal mac_ctx,
 			tpPESession session, tDot11fIEvendor_he_cap *he_cap)
@@ -1025,5 +1041,12 @@
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline QDF_STATUS populate_dot11f_he_bss_color_change(
+				tpAniSirGlobal mac_ctx,
+				tpPESession session,
+				tDot11fIEbss_color_change *bss_color)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 #endif /* __PARSE_H__ */
diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h
index 707dc7a..205e5fd 100644
--- a/core/mac/src/include/sir_params.h
+++ b/core/mac/src/include/sir_params.h
@@ -773,6 +773,7 @@
 #define PARAM_RIFS_MODE_CHANGED                            (1<<8)
 #define PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED   (1<<9)
 #define PARAM_OBSS_MODE_CHANGED                               (1<<10)
+#define PARAM_BSS_COLOR_CHANGED			(1 << 11)
 #define PARAM_BEACON_UPDATE_MASK    (PARAM_BCN_INTERVAL_CHANGED | \
 				     PARAM_SHORT_PREAMBLE_CHANGED | \
 				     PARAM_SHORT_SLOT_TIME_CHANGED | \
@@ -783,6 +784,7 @@
 				     PARAM_NON_GF_DEVICES_PRESENT_CHANGED | \
 				     PARAM_RIFS_MODE_CHANGED | \
 				     PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED | \
-				     PARAM_OBSS_MODE_CHANGED)
+				     PARAM_OBSS_MODE_CHANGED | \
+				     PARAM_BSS_COLOR_CHANGED)
 
 #endif
diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h
index f54f5a2..33d3fc3 100644
--- a/core/mac/src/pe/include/lim_session.h
+++ b/core/mac/src/pe/include/lim_session.h
@@ -96,6 +96,16 @@
 	tSirResultCodes result_code;
 } join_params;
 
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+#define MAX_BSS_COLOR_VALUE 63
+#define TIME_BEACON_NOT_UPDATED 30000
+#define BSS_COLOR_SWITCH_COUNTDOWN 5
+struct bss_color_info {
+	qdf_time_t timestamp;
+	uint64_t seen_count;
+};
+#endif
+
 typedef struct sPESession       /* Added to Support BT-AMP */
 {
 	/* To check session table is in use or free */
@@ -497,6 +507,11 @@
 	bool he_capable;
 	tDot11fIEvendor_he_cap he_config;
 	tDot11fIEvendor_he_op he_op;
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+	tDot11fIEbss_color_change he_bss_color_change;
+	struct bss_color_info bss_color_info[MAX_BSS_COLOR_VALUE];
+	uint8_t bss_color_changing;
+#endif
 #endif
 } tPESession, *tpPESession;
 
diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
index dd1aa2e..8456e0a 100644
--- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
+++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
@@ -2499,6 +2499,59 @@
 	return;
 }
 
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+/**
+ *  lim_send_bss_color_change_ie_update() - update bss color change IE in
+ *   beacon template
+ *
+ *  @mac_ctx: pointer to global adapter context
+ *  @session: session pointer
+ *
+ *  Return: none
+ */
+static void
+lim_send_bss_color_change_ie_update(tpAniSirGlobal mac_ctx,
+						tpPESession session)
+{
+	/* Update the beacon template and send to FW */
+	if (sch_set_fixed_beacon_fields(mac_ctx, session) != eSIR_SUCCESS) {
+		pe_err("Unable to set BSS color change IE in beacon");
+	       return;
+	}
+
+	/* Send update beacon template message */
+	lim_send_beacon_ind(mac_ctx, session);
+	pe_info("Updated BSS color change countdown = %d",
+		session->he_bss_color_change.countdown);
+}
+
+static void
+lim_handle_bss_color_change_ie(tpAniSirGlobal mac_ctx,
+					tpPESession session)
+{
+	/* handle bss color change IE */
+	if (LIM_IS_AP_ROLE(session) &&
+			session->he_op.bss_col_disabled) {
+		if (session->he_bss_color_change.countdown > 0) {
+			session->he_bss_color_change.countdown--;
+		} else {
+			session->bss_color_changing = 0;
+			if (session->he_bss_color_change.new_color != 0)
+				session->he_op.bss_col_disabled = 0;
+		}
+
+		lim_send_bss_color_change_ie_update(mac_ctx, session);
+	}
+}
+
+#else
+static void
+lim_handle_bss_color_change_ie(tpAniSirGlobal mac_ctx,
+					tpPESession session)
+{
+}
+#endif
+
 /** -----------------------------------------------------------------
    \brief lim_process_beacon_tx_success_ind() - This function is used
    explicitely to handle successful beacon transmission indication
@@ -2592,5 +2645,8 @@
 		mmhMsg.bodyval = 0;
 		lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT);
 	}
+
+	lim_handle_bss_color_change_ie(pMac, psessionEntry);
+
 	return;
 }
diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c
index dee8558..852f8ae 100644
--- a/core/mac/src/pe/lim/lim_utils.c
+++ b/core/mac/src/pe/lim/lim_utils.c
@@ -7449,6 +7449,15 @@
 			vht_info->center_freq_seg1);
 }
 
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+void lim_log_he_bss_color(tpAniSirGlobal mac,
+				tDot11fIEbss_color_change *he_bss_color)
+{
+	pe_debug("countdown: %d, new_color: %d",
+			he_bss_color->countdown, he_bss_color->new_color);
+}
+#endif
+
 void lim_update_sta_he_capable(tpAniSirGlobal mac,
 	tpAddStaParams add_sta_params, tpDphHashNode sta_ds,
 	tpPESession session_entry)
diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h
index d7021a8..7f2b162 100644
--- a/core/mac/src/pe/lim/lim_utils.h
+++ b/core/mac/src/pe/lim/lim_utils.h
@@ -767,6 +767,20 @@
  */
 void lim_log_he_op(tpAniSirGlobal mac, tDot11fIEvendor_he_op *he_ops);
 
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+/**
+ * lim_log_he_bss_color() - Print HE bss color
+ * @mac: pointer to MAC context
+ * @he_bss_color: pointer to HE bss color
+ *
+ * Print HE bss color IE
+ *
+ * Return: None
+ */
+void lim_log_he_bss_color(tpAniSirGlobal mac,
+			tDot11fIEbss_color_change *he_bss_color);
+#endif
+
 /**
  * lim_log_he_cap() - Print HE capabilities
  * @mac: pointer to MAC context
diff --git a/core/mac/src/pe/sch/sch_beacon_gen.c b/core/mac/src/pe/sch/sch_beacon_gen.c
index c023683..ad6ebf0 100644
--- a/core/mac/src/pe/sch/sch_beacon_gen.c
+++ b/core/mac/src/pe/sch/sch_beacon_gen.c
@@ -383,6 +383,8 @@
 					&bcn_2->vendor_he_cap);
 		populate_dot11f_he_operation(mac_ctx, session,
 					&bcn_2->vendor_he_op);
+		populate_dot11f_he_bss_color_change(mac_ctx, session,
+					&bcn_2->bss_color_change);
 	}
 
 	if (session->limSystemRole != eLIM_STA_IN_IBSS_ROLE)
diff --git a/core/mac/src/pe/sch/sch_beacon_process.c b/core/mac/src/pe/sch/sch_beacon_process.c
index dcfb0a1..1d162ba 100644
--- a/core/mac/src/pe/sch/sch_beacon_process.c
+++ b/core/mac/src/pe/sch/sch_beacon_process.c
@@ -835,6 +835,99 @@
 	}
 }
 
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+static void ap_update_bss_color_info(tpAniSirGlobal mac_ctx,
+						tpPESession session,
+						uint8_t bss_color)
+{
+	if (!session)
+		return;
+
+	if (bss_color < 1 || bss_color > 63) {
+		pe_warn("Invalid BSS color");
+		return;
+	}
+
+	session->bss_color_info[bss_color - 1].seen_count++;
+	session->bss_color_info[bss_color - 1].timestamp =
+					qdf_get_system_timestamp();
+}
+
+static uint8_t ap_get_new_bss_color(tpAniSirGlobal mac_ctx, tpPESession session)
+{
+	int i;
+	uint8_t new_bss_color;
+	struct bss_color_info color_info;
+	qdf_time_t cur_timestamp;
+
+	if (!session)
+		return 0;
+
+	color_info = session->bss_color_info[0];
+	new_bss_color = 0;
+	cur_timestamp = qdf_get_system_timestamp();
+	for (i = 1; i < MAX_BSS_COLOR_VALUE; i++) {
+		if (session->bss_color_info[i].seen_count == 0) {
+			new_bss_color = i + 1;
+			return new_bss_color;
+		}
+
+		if (color_info.seen_count >
+				session->bss_color_info[i].seen_count &&
+				(cur_timestamp - session->bss_color_info[i].
+					timestamp) > TIME_BEACON_NOT_UPDATED) {
+			color_info = session->bss_color_info[i];
+			new_bss_color = i + 1;
+		}
+	}
+	pe_debug("new bss color: %d", new_bss_color);
+	return new_bss_color;
+}
+
+static void sch_check_bss_color_ie(tpAniSirGlobal mac_ctx,
+					tpPESession ap_session,
+					tSchBeaconStruct *bcn,
+					tUpdateBeaconParams *bcn_prm)
+{
+	/* check bss color in the beacon */
+	if (ap_session->he_op.present && !ap_session->he_op.bss_color) {
+		if (bcn->vendor_he_op.present &&
+			(bcn->vendor_he_op.bss_color ==
+					ap_session->he_op.bss_color)) {
+			ap_session->he_op.bss_col_disabled = 1;
+			bcn_prm->paramChangeBitmap |=
+						PARAM_BSS_COLOR_CHANGED;
+			ap_session->he_bss_color_change.countdown =
+						BSS_COLOR_SWITCH_COUNTDOWN;
+			ap_session->he_bss_color_change.new_color =
+					ap_get_new_bss_color(mac_ctx,
+								ap_session);
+			ap_session->he_op.bss_color = ap_session->
+						he_bss_color_change.new_color;
+			WMI_HEOPS_COLOR_SET(bcn_prm->he_ops,
+						ap_session->he_op.bss_color);
+			WMI_HEOPS_BSSCOLORDISABLE_SET(bcn_prm->he_ops,
+					ap_session->he_op.bss_col_disabled);
+			ap_session->bss_color_changing = 1;
+		} else {
+			/* update info for the bss color */
+			if (bcn->vendor_he_op.present)
+				ap_update_bss_color_info(mac_ctx,
+						ap_session,
+						bcn->vendor_he_op.bss_color);
+		}
+	}
+}
+
+#else
+static void  sch_check_bss_color_ie(tpAniSirGlobal mac_ctx,
+					tpPESession ap_session,
+					tSchBeaconStruct *bcn,
+					tUpdateBeaconParams *bcn_prm)
+{
+}
+#endif
+
 /**
  * sch_beacon_process() - process the beacon frame
  * @mac_ctx:        mac global context
@@ -885,6 +978,9 @@
 			continue;
 
 		bcn_prm.bssIdx = ap_session->bssIdx;
+
+		sch_check_bss_color_ie(mac_ctx, ap_session, &bcn, &bcn_prm);
+
 		if (ap_session->gLimProtectionControl !=
 		    WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE)
 			ap_beacon_process(mac_ctx, rx_pkt_info,
diff --git a/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/core/mac/src/sys/legacy/src/utils/src/parser_api.c
index 8d0c060..a8e3c83 100644
--- a/core/mac/src/sys/legacy/src/utils/src/parser_api.c
+++ b/core/mac/src/sys/legacy/src/utils/src/parser_api.c
@@ -6010,6 +6010,34 @@
 
 	return QDF_STATUS_SUCCESS;
 }
+
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+/**
+ * populate_dot11f_he_bss_color_change() - pouldate HE BSS color change IE
+ * @mac_ctx: Global MAC context
+ * @session: PE session
+ * @he_bss_color: pointer to HE BSS color change IE
+ *
+ * Populdate the HE BSS color change IE based on the session.
+ */
+QDF_STATUS populate_dot11f_he_bss_color_change(tpAniSirGlobal mac_ctx,
+				tpPESession session,
+				tDot11fIEbss_color_change *he_bss_color)
+{
+	if (!session->bss_color_changing) {
+		he_bss_color->present = 0;
+		return QDF_STATUS_SUCCESS;
+	}
+
+	he_bss_color->present = 1;
+	he_bss_color->countdown = session->he_bss_color_change.countdown;
+	he_bss_color->new_color = session->he_bss_color_change.new_color;
+
+	lim_log_he_bss_color(mac_ctx, he_bss_color);
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 #endif
 
 /* parser_api.c ends here. */
diff --git a/core/wma/inc/wma_if.h b/core/wma/inc/wma_if.h
index 14a3566..3f1236a 100644
--- a/core/wma/inc/wma_if.h
+++ b/core/wma/inc/wma_if.h
@@ -806,6 +806,7 @@
 	uint8_t fRIFSMode;
 	uint16_t paramChangeBitmap;
 	uint8_t smeSessionId;
+	uint32_t he_ops;
 } tUpdateBeaconParams, *tpUpdateBeaconParams;
 
 /**
diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c
index 08e5818..0acbc20 100644
--- a/core/wma/src/wma_mgmt.c
+++ b/core/wma/src/wma_mgmt.c
@@ -1343,6 +1343,39 @@
 			 beaconInterval, vdev_id);
 }
 
+#ifdef WLAN_FEATURE_11AX_BSS_COLOR
+/**
+ * wma_update_bss_color() - update beacon bss color in fw
+ * @wma: wma handle
+ * @vdev_id: vdev id
+ * @he_ops: HE operation, only the bss_color and bss_color_disabled fields
+ * are updated.
+ *
+ * Return: none
+ */
+static void
+wma_update_bss_color(tp_wma_handle wma, uint8_t vdev_id,
+			   uint32_t he_ops)
+{
+	QDF_STATUS ret;
+
+	ret = wma_vdev_set_param(wma->wmi_handle, vdev_id,
+					      WMI_VDEV_PARAM_BSS_COLOR,
+					      he_ops);
+
+	if (QDF_IS_STATUS_ERROR(ret))
+		WMA_LOGE("Failed to update HE operations");
+	else
+		WMA_LOGI("Updated HE operations %x for vdev %d",
+			 he_ops, vdev_id);
+}
+#else
+static void wma_update_bss_color(tp_wma_handle wma, uint8_t vdev_id,
+			   uint32_t he_ops)
+{
+}
+#endif
+
 /**
  * wma_process_update_beacon_params() - update beacon parameters to target
  * @wma: wma handle
@@ -1372,6 +1405,10 @@
 	if (bcn_params->paramChangeBitmap & PARAM_llBCOEXIST_CHANGED)
 		wma_update_protection_mode(wma, bcn_params->smeSessionId,
 					   bcn_params->llbCoexist);
+
+	if (bcn_params->paramChangeBitmap & PARAM_BSS_COLOR_CHANGED)
+		wma_update_bss_color(wma, bcn_params->smeSessionId,
+					   bcn_params->he_ops);
 }
 
 /**