qcacld-3.0: Channel hopping for 2_4G and 5G band

qcacld-2.0 to qcacld-3.0 propagation

Allow device switch to a different channel if the current channel is
congested, using the 11h channel switch announcement.

Change-Id: I1766785017e43f17cc800039b383ee5dabcd6ea5
CRs-Fixed: 2082632
diff --git a/Kbuild b/Kbuild
index b890a39..19c71b8 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2029,6 +2029,10 @@
 CDEFINES += -DCONFIG_TUFELLO_DUAL_FW_SUPPORT
 endif
 
+ifeq ($(CONFIG_ARCH_MSM8996), y)
+CDEFINES += -DCHANNEL_HOPPING_ALL_BANDS
+endif
+
 #Enable Signed firmware support for split binary format
 ifeq ($(CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT), 1)
 CDEFINES += -DQCA_SIGNED_SPLIT_BINARY_SUPPORT
diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index 33ccd19..27b1cf3 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/core/hdd/inc/wlan_hdd_cfg.h
@@ -11053,6 +11053,26 @@
 
 /*
  * <ini>
+ * g_sap_chanswitch_mode - channel switch mode
+ * @Min: 0
+ * @Max: 1
+ * @Default: 1
+ *
+ * This ini is used to configure channel switch mode
+ *
+ * Related: none
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_SAP_CH_SWITCH_MODE         "g_sap_chanswitch_mode"
+#define CFG_SAP_CH_SWITCH_MODE_MIN     (0)
+#define CFG_SAP_CH_SWITCH_MODE_MAX     (1)
+#define CFG_SAP_CH_SWITCH_MODE_DEFAULT (1)
+
+/*
+ * <ini>
  * g_fils_max_chan_guard_time - Set maximum channel guard time(ms)
  * @Min: 0
  * @Max: 10
@@ -12170,6 +12190,7 @@
 	bool fw_timeout_crash;
 	/* beacon count before channel switch */
 	uint8_t sap_chanswitch_beacon_cnt;
+	uint8_t sap_chanswitch_mode;
 	uint32_t rx_wakelock_timeout;
 	uint32_t max_sched_scan_plan_interval;
 	uint32_t max_sched_scan_plan_iterations;
diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c
index abf780d..5f532ca 100644
--- a/core/hdd/src/wlan_hdd_cfg.c
+++ b/core/hdd/src/wlan_hdd_cfg.c
@@ -4255,6 +4255,12 @@
 		     CFG_SAP_CH_SWITCH_BEACON_CNT_DEFAULT,
 		     CFG_SAP_CH_SWITCH_BEACON_CNT_MIN,
 		     CFG_SAP_CH_SWITCH_BEACON_CNT_MAX),
+	REG_VARIABLE(CFG_SAP_CH_SWITCH_MODE, WLAN_PARAM_Integer,
+		     struct hdd_config, sap_chanswitch_mode,
+		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+		     CFG_SAP_CH_SWITCH_MODE_DEFAULT,
+		     CFG_SAP_CH_SWITCH_MODE_MIN,
+		     CFG_SAP_CH_SWITCH_MODE_MAX),
 	REG_VARIABLE(CFG_MAX_SCHED_SCAN_PLAN_INT_NAME, WLAN_PARAM_Integer,
 		struct hdd_config, max_sched_scan_plan_interval,
 		VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index 2d29dfc..4ec97cc 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -5137,22 +5137,28 @@
 	for (i = 0; i <= maxSta; i++) {
 		hdd_station_info_t *sta_info_ptr = &pAdapter->aStaInfo[i];
 
-		if (sta_info_ptr->isUsed) {
-			len = scnprintf(pBuf, buf_len,
-					"%d %x:%x:%x:%x:%x:%x \t ecsa=%d\n",
-					sta_info_ptr->ucSTAId,
-					sta_info_ptr->macAddrSTA.bytes[0],
-					sta_info_ptr->macAddrSTA.bytes[1],
-					sta_info_ptr->macAddrSTA.bytes[2],
-					sta_info_ptr->macAddrSTA.bytes[3],
-					sta_info_ptr->macAddrSTA.bytes[4],
-					sta_info_ptr->macAddrSTA.bytes[5],
-					sta_info_ptr->ecsa_capable);
-			pBuf += len;
-			buf_len -= len;
-		}
+		if (!sta_info_ptr->isUsed)
+			continue;
+
+		if (CHAN_HOP_ALL_BANDS_ENABLE &&
+		    (i == (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->uBCStaId))
+			continue;
+
 		if (WE_GET_STA_INFO_SIZE > buf_len)
 			break;
+
+		len = scnprintf(pBuf, buf_len,
+				"%5d %02x:%02x:%02x:%02x:%02x:%02x ecsa=%d\n",
+				sta_info_ptr->ucSTAId,
+				sta_info_ptr->macAddrSTA.bytes[0],
+				sta_info_ptr->macAddrSTA.bytes[1],
+				sta_info_ptr->macAddrSTA.bytes[2],
+				sta_info_ptr->macAddrSTA.bytes[3],
+				sta_info_ptr->macAddrSTA.bytes[4],
+				sta_info_ptr->macAddrSTA.bytes[5],
+				sta_info_ptr->ecsa_capable);
+		pBuf += len;
+		buf_len -= len;
 	}
 
 	EXIT();
@@ -7528,6 +7534,7 @@
 	pConfig->disableDFSChSwitch = iniConfig->disableDFSChSwitch;
 	pConfig->sap_chanswitch_beacon_cnt =
 			    iniConfig->sap_chanswitch_beacon_cnt;
+	pConfig->sap_chanswitch_mode = iniConfig->sap_chanswitch_mode;
 
 	/* channel is already set in the set_channel Call back */
 	/* pConfig->channel = pCommitConfig->channel; */
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index dbcd36b..e22adfa 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -3986,6 +3986,8 @@
 	uint8_t bssid[QDF_MAC_ADDR_SIZE];
 	struct ch_params ch_params;
 	uint8_t  ch_switch_beacon_cnt;
+	uint8_t  ch_switch_mode;
+	uint8_t  dfs_ch_switch_disable;
 } tSirDfsCsaIeRequest, *tpSirDfsCsaIeRequest;
 
 /* Indication from lower layer indicating the completion of first beacon send
diff --git a/core/mac/src/pe/include/lim_global.h b/core/mac/src/pe/include/lim_global.h
index 2958b58..fe98ac7 100644
--- a/core/mac/src/pe/include/lim_global.h
+++ b/core/mac/src/pe/include/lim_global.h
@@ -67,6 +67,11 @@
 	((LIntrvl * LIM_TIM_WAIT_COUNT_FACTOR) > LIM_MIN_TIM_WAIT_COUNT ? \
 	(LIntrvl * LIM_TIM_WAIT_COUNT_FACTOR) : LIM_MIN_TIM_WAIT_COUNT)
 
+#ifdef CHANNEL_HOPPING_ALL_BANDS
+#define CHAN_HOP_ALL_BANDS_ENABLE        1
+#else
+#define CHAN_HOP_ALL_BANDS_ENABLE        0
+#endif
 
 /* enums exported by LIM are as follows */
 
diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
index 1d7cd4f..b74f7c3 100644
--- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c
+++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
@@ -1078,8 +1078,9 @@
 
 		/* Initialize 11h Enable Flag */
 		session->lim11hEnable = 0;
-		if ((mlm_start_req->bssType != eSIR_IBSS_MODE) &&
-		    (SIR_BAND_5_GHZ == session->limRFBand)) {
+		if (mlm_start_req->bssType != eSIR_IBSS_MODE &&
+		    (CHAN_HOP_ALL_BANDS_ENABLE ||
+		     SIR_BAND_5_GHZ == session->limRFBand)) {
 			if (wlan_cfg_get_int(mac_ctx,
 				WNI_CFG_11H_ENABLED, &val) != eSIR_SUCCESS)
 				pe_err("Fail to get WNI_CFG_11H_ENABLED");
@@ -5387,7 +5388,8 @@
 	session_entry->limRFBand =
 		lim_get_rf_band(session_entry->currentOperChannel);
 	/* Initialize 11h Enable Flag */
-	if (SIR_BAND_5_GHZ == session_entry->limRFBand) {
+	if (CHAN_HOP_ALL_BANDS_ENABLE ||
+	    SIR_BAND_5_GHZ == session_entry->limRFBand) {
 		if (wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, &val) !=
 				eSIR_SUCCESS)
 			pe_err("Fail to get WNI_CFG_11H_ENABLED");
@@ -5813,7 +5815,7 @@
 
 	if (LIM_IS_AP_ROLE(session_entry) &&
 		(mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false))
-		switch_mode = 1;
+		switch_mode = session_entry->gLimChannelSwitch.switchMode;
 
 	switch_count = session_entry->gLimChannelSwitch.switchCount;
 
@@ -5838,6 +5840,65 @@
 }
 
 /**
+ * lim_send_chan_switch_action_frame()- Send an action frame
+ * containing CSA IE or ECSA IE depending on the connected
+ * sta capability.
+ *
+ * @mac_ctx: pointer to global mac structure
+ * @new_channel: new channel to switch to.
+ * @ch_bandwidth: BW of channel to calculate op_class
+ * @session_entry: pe session
+ *
+ * Return: void
+ */
+static
+void lim_send_chan_switch_action_frame(tpAniSirGlobal mac_ctx,
+				       uint16_t new_channel,
+				       uint8_t ch_bandwidth,
+				       tpPESession session_entry)
+{
+	uint16_t op_class;
+	uint8_t switch_mode = 0, i;
+	uint8_t switch_count;
+	tpDphHashNode psta;
+	tpDphHashNode dph_node_array_ptr;
+
+	dph_node_array_ptr = session_entry->dph.dphHashTable.pDphNodeArray;
+
+	op_class = wlan_reg_dmn_get_opclass_from_channel(
+			mac_ctx->scan.countryCodeCurrent,
+			new_channel, ch_bandwidth);
+
+	if (LIM_IS_AP_ROLE(session_entry) &&
+	    (false == mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch))
+		switch_mode = session_entry->gLimChannelSwitch.switchMode;
+
+	switch_count = session_entry->gLimChannelSwitch.switchCount;
+
+	if (LIM_IS_AP_ROLE(session_entry)) {
+		for (i = 0; i < mac_ctx->lim.maxStation; i++) {
+			psta = dph_node_array_ptr + i;
+			if (!(psta && psta->added))
+				continue;
+			if (session_entry->lim_non_ecsa_cap_num == 0)
+				lim_send_extended_chan_switch_action_frame
+					(mac_ctx, psta->staAddr, switch_mode,
+					 op_class, new_channel, switch_count,
+					 session_entry);
+			else
+				lim_send_channel_switch_mgmt_frame
+					(mac_ctx, psta->staAddr, switch_mode,
+					 new_channel, switch_count,
+					 session_entry);
+		}
+	} else if (LIM_IS_STA_ROLE(session_entry)) {
+		lim_send_extended_chan_switch_action_frame
+			(mac_ctx, session_entry->bssId, switch_mode, op_class,
+			 new_channel, switch_count, session_entry);
+	}
+}
+
+/**
  * lim_process_sme_dfs_csa_ie_request() - process sme dfs csa ie req
  *
  * @mac_ctx: Pointer to Global MAC structure
@@ -5890,7 +5951,8 @@
 	session_entry->gLimChannelSwitch.sec_ch_offset =
 				 dfs_csa_ie_req->ch_params.sec_ch_offset;
 	if (mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false)
-		session_entry->gLimChannelSwitch.switchMode = 1;
+		session_entry->gLimChannelSwitch.switchMode =
+			 dfs_csa_ie_req->ch_switch_mode;
 
 	/*
 	 * Validate if SAP is operating HT or VHT mode and set the Channel
@@ -5980,10 +6042,15 @@
 			session_entry->dfsIncludeChanWrapperIe,
 			ch_offset);
 
-	/* Send ECSA Action frame after updating the beacon */
-	send_extended_chan_switch_action_frame(mac_ctx,
-		session_entry->gLimChannelSwitch.primaryChannel,
-		ch_offset, session_entry);
+	/* Send ECSA/CSA Action frame after updating the beacon */
+	if (CHAN_HOP_ALL_BANDS_ENABLE)
+		lim_send_chan_switch_action_frame(mac_ctx,
+			session_entry->gLimChannelSwitch.primaryChannel,
+			ch_offset, session_entry);
+	else
+		send_extended_chan_switch_action_frame(mac_ctx,
+			session_entry->gLimChannelSwitch.primaryChannel,
+			ch_offset, session_entry);
 	session_entry->gLimChannelSwitch.switchCount--;
 }
 
diff --git a/core/mac/src/pe/sch/sch_beacon_gen.c b/core/mac/src/pe/sch/sch_beacon_gen.c
index 7f668dd..d7f9872 100644
--- a/core/mac/src/pe/sch/sch_beacon_gen.c
+++ b/core/mac/src/pe/sch/sch_beacon_gen.c
@@ -277,14 +277,17 @@
 
 	if ((session->limSystemRole == eLIM_AP_ROLE) &&
 		session->dfsIncludeChanSwIe == true) {
-		populate_dot_11_f_ext_chann_switch_ann(mac_ctx,
+		if (!CHAN_HOP_ALL_BANDS_ENABLE ||
+		    session->lim_non_ecsa_cap_num == 0) {
+			populate_dot_11_f_ext_chann_switch_ann(mac_ctx,
 				&bcn_2->ext_chan_switch_ann,
 				session);
-		pe_info("ecsa: mode:%d reg:%d chan:%d count:%d",
-			bcn_2->ext_chan_switch_ann.switch_mode,
-			bcn_2->ext_chan_switch_ann.new_reg_class,
-			bcn_2->ext_chan_switch_ann.new_channel,
-			bcn_2->ext_chan_switch_ann.switch_count);
+			pe_info("ecsa: mode:%d reg:%d chan:%d count:%d",
+				bcn_2->ext_chan_switch_ann.switch_mode,
+				bcn_2->ext_chan_switch_ann.new_reg_class,
+				bcn_2->ext_chan_switch_ann.new_channel,
+				bcn_2->ext_chan_switch_ann.switch_count);
+	    }
 	}
 
 	populate_dot11_supp_operating_classes(mac_ctx,
@@ -307,13 +310,15 @@
 			 * and SAP has instructed to announce channel switch IEs
 			 * in beacon and probe responses
 			 */
-			populate_dot11f_chan_switch_ann(mac_ctx,
+			if (!CHAN_HOP_ALL_BANDS_ENABLE ||
+			    session->lim_non_ecsa_cap_num > 0) {
+				populate_dot11f_chan_switch_ann(mac_ctx,
 						&bcn_2->ChanSwitchAnn, session);
-			pe_debug("csa: mode:%d chan:%d count:%d",
-				bcn_2->ChanSwitchAnn.switchMode,
-				bcn_2->ChanSwitchAnn.newChannel,
-				bcn_2->ChanSwitchAnn.switchCount);
-
+				pe_debug("csa: mode:%d chan:%d count:%d",
+					 bcn_2->ChanSwitchAnn.switchMode,
+					 bcn_2->ChanSwitchAnn.newChannel,
+					 bcn_2->ChanSwitchAnn.switchCount);
+			 }
 			/*
 			 * TODO: depending the CB mode, extended channel switch
 			 * announcement need to be called
diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h
index 9e93f18..a4cec67 100644
--- a/core/sap/inc/sap_api.h
+++ b/core/sap/inc/sap_api.h
@@ -630,6 +630,7 @@
 	bool dfs_cac_offload;
 	/* beacon count before channel switch */
 	uint8_t sap_chanswitch_beacon_cnt;
+	uint8_t sap_chanswitch_mode;
 } tsap_Config_t;
 
 #ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
@@ -738,6 +739,7 @@
 	uint16_t tx_leakage_threshold;
 	/* beacon count before channel switch */
 	uint8_t sap_ch_switch_beacon_cnt;
+	uint8_t sap_ch_switch_mode;
 } tSapDfsInfo;
 
 typedef struct tagSapCtxList {
diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c
index 84baa76..bd15e3a 100644
--- a/core/sap/src/sap_module.c
+++ b/core/sap/src/sap_module.c
@@ -949,6 +949,8 @@
 				pConfig->disableDFSChSwitch;
 	pmac->sap.SapDfsInfo.sap_ch_switch_beacon_cnt =
 				pConfig->sap_chanswitch_beacon_cnt;
+	pmac->sap.SapDfsInfo.sap_ch_switch_mode =
+			pConfig->sap_chanswitch_mode;
 
 	pmac->sap.sapCtxList[pSapCtx->sessionId].pSapContext = pSapCtx;
 	pmac->sap.sapCtxList[pSapCtx->sessionId].sapPersona =
diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c
index 8db2b64..ab78f4f 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -19191,6 +19191,9 @@
 	msg->csaIeRequired = csa_ie_reqd;
 	msg->ch_switch_beacon_cnt =
 		 mac_ctx->sap.SapDfsInfo.sap_ch_switch_beacon_cnt;
+	msg->ch_switch_mode = mac_ctx->sap.SapDfsInfo.sap_ch_switch_mode;
+	msg->dfs_ch_switch_disable =
+		mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch;
 	qdf_mem_copy(msg->bssid, bssid.bytes, QDF_MAC_ADDR_SIZE);
 	qdf_mem_copy(&msg->ch_params, ch_params, sizeof(struct ch_params));