Browse Source

qcacmn: Don't disable connected 6 GHz channels

Currently host disables 6 GHz band when set_fcc_channel cmd
is received hence existing STA/P2P client 6 GHz connections
get disabled.
Add changes to keep existing STA/P2P client 6 GHz connections
intact and also keep SAP up on 6 GHz if STA+SAP SCC on 6 GHz
channel was present before receiving this command. Disable all
other 6 GHz operations.

Change-Id: I0e2d4715f78eb797eb93ed90a07028c5b7723211
CRs-Fixed: 3480979
Asutosh Mohapatra 2 years ago
parent
commit
e3e58e72e3

+ 120 - 13
umac/regulatory/core/src/reg_build_chan_list.c

@@ -445,6 +445,64 @@ static void reg_modify_chan_list_for_dfs_channels(
 	}
 	}
 }
 }
 
 
+#ifdef CONFIG_BAND_6GHZ
+#ifdef CONFIG_REG_CLIENT
+/**
+ * reg_is_6ghz_chan_connected() - Check if given 6 GHz channel is in connected
+ *                                channel list
+ * @pdev_priv_obj: Pdev privect object pointer
+ * @chn_idx: Channel Index
+ *
+ * Return: True if channel present in connected channel list else false
+ */
+static bool
+reg_is_6ghz_chan_connected(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+			   uint16_t chn_idx)
+{
+	qdf_freq_t freq;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+	reg_is_chan_connected_callback callback = NULL;
+
+	freq = pdev_priv_obj->cur_chan_list[chn_idx].center_freq;
+
+	pdev = pdev_priv_obj->pdev_ptr;
+	if (!pdev) {
+		reg_err("pdev is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	psoc_priv_obj = reg_get_psoc_obj(psoc);
+	if (!psoc_priv_obj) {
+		reg_err("reg psoc private obj is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
+	if (psoc_priv_obj->conn_chan_cb.cbk)
+		callback = psoc_priv_obj->conn_chan_cb.cbk;
+	qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
+
+	if (callback) {
+		if (callback(psoc, QDF_STA_MODE, freq) ||
+		    callback(psoc, QDF_P2P_CLIENT_MODE, freq))
+			return true;
+	}
+
+	return false;
+}
+#else
+static inline bool
+reg_is_6ghz_chan_connected(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+			   uint16_t chn_idx)
+{
+	return false;
+}
+#endif
+#endif
+
 #if defined(CONFIG_BAND_6GHZ) && defined(CONFIG_REG_CLIENT)
 #if defined(CONFIG_BAND_6GHZ) && defined(CONFIG_REG_CLIENT)
 /**
 /**
  * reg_is_lpi_cli_supp_pwr_mode() - Check if the input supported power mode is a
  * reg_is_lpi_cli_supp_pwr_mode() - Check if the input supported power mode is a
@@ -511,7 +569,8 @@ static void reg_modify_super_chan_list_for_indoor_channels(
 static void
 static void
 reg_dis_6g_chan_in_super_chan_list(struct wlan_objmgr_pdev *pdev,
 reg_dis_6g_chan_in_super_chan_list(struct wlan_objmgr_pdev *pdev,
 				   struct super_chan_info *chan_info,
 				   struct super_chan_info *chan_info,
-				   enum supported_6g_pwr_types pwr_type)
+				   enum supported_6g_pwr_types pwr_type,
+				   uint16_t chn_idx)
 {
 {
 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
 	uint32_t band_bitmap;
 	uint32_t band_bitmap;
@@ -529,7 +588,10 @@ reg_dis_6g_chan_in_super_chan_list(struct wlan_objmgr_pdev *pdev,
 	pdev_priv_obj = reg_get_pdev_obj(pdev);
 	pdev_priv_obj = reg_get_pdev_obj(pdev);
 	band_bitmap = pdev_priv_obj->band_capability;
 	band_bitmap = pdev_priv_obj->band_capability;
 
 
-	if (!(band_bitmap & BIT(REG_BAND_6G)))
+	if (!(band_bitmap & BIT(REG_BAND_6G)) &&
+	    !(pdev_priv_obj->keep_6ghz_sta_cli_connection &&
+	     reg_is_6ghz_chan_connected(pdev_priv_obj,
+					chn_idx + MIN_6GHZ_CHANNEL)))
 		reg_dis_chan_state_and_flags(
 		reg_dis_chan_state_and_flags(
 					&chan_info->state_arr[pwr_type],
 					&chan_info->state_arr[pwr_type],
 					&chan_info->chan_flags_arr[pwr_type]);
 					&chan_info->chan_flags_arr[pwr_type]);
@@ -552,7 +614,8 @@ reg_modify_super_chan_list_for_indoor_channels(
 static inline void
 static inline void
 reg_dis_6g_chan_in_super_chan_list(struct wlan_objmgr_pdev *pdev,
 reg_dis_6g_chan_in_super_chan_list(struct wlan_objmgr_pdev *pdev,
 				   struct super_chan_info *chan_info,
 				   struct super_chan_info *chan_info,
-				   enum supported_6g_pwr_types pwr_type)
+				   enum supported_6g_pwr_types pwr_type,
+				   uint16_t chn_idx)
 {
 {
 }
 }
 #endif /* CONFIG_BAND_6GHZ && CONFIG_REG_CLIENT */
 #endif /* CONFIG_BAND_6GHZ && CONFIG_REG_CLIENT */
@@ -669,22 +732,59 @@ static void reg_modify_chan_list_for_indoor_concurrency(
 #endif
 #endif
 
 
 #ifdef CONFIG_BAND_6GHZ
 #ifdef CONFIG_BAND_6GHZ
+/**
+ * reg_modify_chan_list_for_band_6G() - Modify 6 GHz band channels
+ * @pdev_priv_obj: pointer to pdev privet object
+ * @chan_list: pointer to channel list
+ *
+ * Return: None
+ */
 static void reg_modify_chan_list_for_band_6G(
 static void reg_modify_chan_list_for_band_6G(
-					struct regulatory_channel *chan_list)
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+		struct regulatory_channel *chan_list)
 {
 {
 	enum channel_enum chan_enum;
 	enum channel_enum chan_enum;
 
 
 	reg_debug("disabling 6G");
 	reg_debug("disabling 6G");
 	for (chan_enum = MIN_6GHZ_CHANNEL;
 	for (chan_enum = MIN_6GHZ_CHANNEL;
 	     chan_enum <= MAX_6GHZ_CHANNEL; chan_enum++) {
 	     chan_enum <= MAX_6GHZ_CHANNEL; chan_enum++) {
+		if (pdev_priv_obj->keep_6ghz_sta_cli_connection &&
+		    reg_is_6ghz_chan_connected(pdev_priv_obj,
+					       chan_enum))
+			continue;
 		chan_list[chan_enum].chan_flags |=
 		chan_list[chan_enum].chan_flags |=
 			REGULATORY_CHAN_DISABLED;
 			REGULATORY_CHAN_DISABLED;
 		chan_list[chan_enum].state = CHANNEL_STATE_DISABLE;
 		chan_list[chan_enum].state = CHANNEL_STATE_DISABLE;
 	}
 	}
 }
 }
+
+#ifdef CONFIG_REG_CLIENT
+/**
+ * reg_modify_secondary_cur_chan_list() - Disable secondary current channel
+ * 6 GHz channels if 6 GHz band is disabled
+ *
+ * @pdev_priv_obj: pointer to pdev private object
+ *
+ * Return: None
+ */
+static void reg_modify_secondary_cur_chan_list(
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
+	uint32_t band_bitmap;
+
+	band_bitmap = pdev_priv_obj->band_capability;
+	if (!band_bitmap)
+		return;
+
+	if (!(band_bitmap & BIT(REG_BAND_6G)))
+		reg_modify_chan_list_for_band_6G(pdev_priv_obj,
+				pdev_priv_obj->secondary_cur_chan_list);
+}
+#endif
 #else
 #else
 static inline void reg_modify_chan_list_for_band_6G(
 static inline void reg_modify_chan_list_for_band_6G(
-					struct regulatory_channel *chan_list)
+			struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+			struct regulatory_channel *chan_list)
 {
 {
 }
 }
 #endif
 #endif
@@ -692,17 +792,23 @@ static inline void reg_modify_chan_list_for_band_6G(
 /**
 /**
  * reg_modify_chan_list_for_band() - Based on the input band bitmap, either
  * reg_modify_chan_list_for_band() - Based on the input band bitmap, either
  * disable 2GHz, 5GHz, or 6GHz channels.
  * disable 2GHz, 5GHz, or 6GHz channels.
- * @chan_list: Pointer to regulatory channel list.
- * @band_bitmap: Input bitmap of reg_wifi_band values.
+ * @pdev_priv_obj: pointer to pdev private object
+ *
+ * Return: None
  */
  */
-static void reg_modify_chan_list_for_band(struct regulatory_channel *chan_list,
-					  uint32_t band_bitmap)
+static void reg_modify_chan_list_for_band(
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
 {
 {
 	enum channel_enum chan_enum;
 	enum channel_enum chan_enum;
+	struct regulatory_channel *chan_list;
+	uint32_t band_bitmap;
 
 
+	band_bitmap = pdev_priv_obj->band_capability;
 	if (!band_bitmap)
 	if (!band_bitmap)
 		return;
 		return;
 
 
+	chan_list = pdev_priv_obj->cur_chan_list;
+
 	if (!(band_bitmap & BIT(REG_BAND_5G))) {
 	if (!(band_bitmap & BIT(REG_BAND_5G))) {
 		reg_debug("disabling 5G");
 		reg_debug("disabling 5G");
 		for (chan_enum = MIN_5GHZ_CHANNEL;
 		for (chan_enum = MIN_5GHZ_CHANNEL;
@@ -724,7 +830,7 @@ static void reg_modify_chan_list_for_band(struct regulatory_channel *chan_list,
 	}
 	}
 
 
 	if (!(band_bitmap & BIT(REG_BAND_6G)))
 	if (!(band_bitmap & BIT(REG_BAND_6G)))
-		reg_modify_chan_list_for_band_6G(chan_list);
+		reg_modify_chan_list_for_band_6G(pdev_priv_obj, chan_list);
 
 
 }
 }
 
 
@@ -1792,6 +1898,8 @@ reg_populate_secondary_cur_chan_list(struct wlan_regulatory_pdev_priv_obj
 		     chan_list,
 		     chan_list,
 		     len_6ghz);
 		     len_6ghz);
 	qdf_mem_free(chan_list);
 	qdf_mem_free(chan_list);
+
+	reg_modify_secondary_cur_chan_list(pdev_priv_obj);
 	reg_dump_valid_6ghz_cur_chan_list(pdev_priv_obj);
 	reg_dump_valid_6ghz_cur_chan_list(pdev_priv_obj);
 }
 }
 #else /* CONFIG_REG_CLIENT */
 #else /* CONFIG_REG_CLIENT */
@@ -2856,7 +2964,7 @@ static void reg_update_sup_ch_entry_for_mode(
 						       supp_pwr_mode);
 						       supp_pwr_mode);
 
 
 	reg_dis_6g_chan_in_super_chan_list(pdev, &super_chan_list[chn_idx],
 	reg_dis_6g_chan_in_super_chan_list(pdev, &super_chan_list[chn_idx],
-					   supp_pwr_mode);
+					   supp_pwr_mode, chn_idx);
 
 
 	reg_dis_6g_edge_chan_in_enh_chan(pdev, &super_chan_list[chn_idx],
 	reg_dis_6g_edge_chan_in_enh_chan(pdev, &super_chan_list[chn_idx],
 					 chn_idx, supp_pwr_mode);
 					 chn_idx, supp_pwr_mode);
@@ -2964,8 +3072,7 @@ void reg_compute_pdev_current_chan_list(struct wlan_regulatory_pdev_priv_obj
 					    pdev_priv_obj->range_5g_low,
 					    pdev_priv_obj->range_5g_low,
 					    pdev_priv_obj->range_5g_high);
 					    pdev_priv_obj->range_5g_high);
 
 
-	reg_modify_chan_list_for_band(pdev_priv_obj->cur_chan_list,
-				      pdev_priv_obj->band_capability);
+	reg_modify_chan_list_for_band(pdev_priv_obj);
 
 
 	reg_modify_disable_chan_list_for_unii1_and_unii2a(pdev_priv_obj);
 	reg_modify_disable_chan_list_for_unii1_and_unii2a(pdev_priv_obj);
 
 

+ 36 - 0
umac/regulatory/core/src/reg_callbacks.c

@@ -477,3 +477,39 @@ void reg_unregister_ctry_change_callback(struct wlan_objmgr_psoc *psoc,
 		psoc_priv_obj->cc_cbk.cbk = NULL;
 		psoc_priv_obj->cc_cbk.cbk = NULL;
 	qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
 	qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
 }
 }
+
+void
+reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					reg_is_chan_connected_callback cbk)
+{
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+
+	psoc_priv_obj = reg_get_psoc_obj(psoc);
+	if (!psoc_priv_obj) {
+		reg_err("reg psoc private obj is NULL");
+		return;
+	}
+
+	qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
+	if (!psoc_priv_obj->conn_chan_cb.cbk)
+		psoc_priv_obj->conn_chan_cb.cbk = cbk;
+	qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
+}
+
+void
+reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					  reg_is_chan_connected_callback cbk)
+{
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+
+	psoc_priv_obj = reg_get_psoc_obj(psoc);
+	if (!psoc_priv_obj) {
+		reg_err("reg psoc private obj is NULL");
+		return;
+	}
+
+	qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
+	if (psoc_priv_obj->conn_chan_cb.cbk == cbk)
+		psoc_priv_obj->conn_chan_cb.cbk = NULL;
+	qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
+}

+ 37 - 1
umac/regulatory/core/src/reg_callbacks.h

@@ -1,6 +1,6 @@
 /*
 /*
  * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * any purpose with or without fee is hereby granted, provided that the
@@ -87,6 +87,30 @@ QDF_STATUS reg_send_scheduler_msg_sb(struct wlan_objmgr_psoc *psoc,
  */
  */
 QDF_STATUS reg_send_scheduler_msg_nb(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS reg_send_scheduler_msg_nb(struct wlan_objmgr_psoc *psoc,
 				     struct wlan_objmgr_pdev *pdev);
 				     struct wlan_objmgr_pdev *pdev);
+/**
+ * reg_register_is_chan_connected_callback() - Register callback to check if
+ *                                             channel is connected
+ * @psoc: Pointer to global psoc structure.
+ * @cbk: Pointer to callback function
+ *
+ * Return: None
+ */
+void
+reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					reg_is_chan_connected_callback cbk);
+
+/**
+ * reg_unregister_is_chan_connected_callback() - Unregister callback to check
+ *                                               if channel is connected
+ * @psoc: Pointer to global psoc structure.
+ * @cbk: Pointer to callback function
+ *
+ * Return: None
+ */
+void
+reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					  reg_is_chan_connected_callback cbk);
+
 #else
 #else
 static inline void reg_register_chan_change_callback(
 static inline void reg_register_chan_change_callback(
 		struct wlan_objmgr_psoc *psoc, reg_chan_change_callback cbk,
 		struct wlan_objmgr_psoc *psoc, reg_chan_change_callback cbk,
@@ -120,5 +144,17 @@ static inline QDF_STATUS reg_send_scheduler_msg_nb(
 {
 {
 	return QDF_STATUS_SUCCESS;
 	return QDF_STATUS_SUCCESS;
 }
 }
+
+static inline void
+reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					reg_is_chan_connected_callback cbk)
+{
+}
+
+static inline void
+reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					  reg_is_chan_connected_callback cbk)
+{
+}
 #endif
 #endif
 #endif
 #endif

+ 1 - 0
umac/regulatory/core/src/reg_priv_objs.c

@@ -346,6 +346,7 @@ QDF_STATUS wlan_regulatory_pdev_obj_created_notification(
 	pdev_priv_obj->pdev_ptr = pdev;
 	pdev_priv_obj->pdev_ptr = pdev;
 	pdev_priv_obj->dfs_enabled = psoc_priv_obj->dfs_enabled;
 	pdev_priv_obj->dfs_enabled = psoc_priv_obj->dfs_enabled;
 	pdev_priv_obj->set_fcc_channel = psoc_priv_obj->set_fcc_channel;
 	pdev_priv_obj->set_fcc_channel = psoc_priv_obj->set_fcc_channel;
+	pdev_priv_obj->keep_6ghz_sta_cli_connection = false;
 	pdev_priv_obj->band_capability = psoc_priv_obj->band_capability;
 	pdev_priv_obj->band_capability = psoc_priv_obj->band_capability;
 	pdev_priv_obj->indoor_chan_enabled =
 	pdev_priv_obj->indoor_chan_enabled =
 		psoc_priv_obj->indoor_chan_enabled;
 		psoc_priv_obj->indoor_chan_enabled;

+ 23 - 0
umac/regulatory/core/src/reg_priv_objs.h

@@ -100,6 +100,25 @@ struct ctry_change_cbk_entry {
 	reg_ctry_change_callback cbk;
 	reg_ctry_change_callback cbk;
 };
 };
 
 
+/**
+ * typedef reg_is_chan_connected_callback() - Regulatory callback to check if
+ *                                            channel is connected
+ * @psoc: Pointer to psoc object
+ * @opmode: vdev operating mode
+ * @freq: Frequency
+ */
+typedef bool (*reg_is_chan_connected_callback)(
+		struct wlan_objmgr_psoc *psoc,
+		enum QDF_OPMODE opmode,
+		uint32_t      freq);
+
+/* struct is_chan_connected_cbk_entry - Is channel connected callback entry
+ * @cbk: Callback
+ */
+struct is_chan_connected_cbk_entry {
+	reg_is_chan_connected_callback cbk;
+};
+
 #ifdef CONFIG_REG_CLIENT
 #ifdef CONFIG_REG_CLIENT
 #define MAX_INDOOR_LIST_SIZE 3
 #define MAX_INDOOR_LIST_SIZE 3
 
 
@@ -160,6 +179,7 @@ struct indoor_concurrency_list {
  * @cbk_list:
  * @cbk_list:
  * @num_chan_change_cbks:
  * @num_chan_change_cbks:
  * @cc_cbk:
  * @cc_cbk:
+ * @conn_chan_cb:
  * @ch_avoid_ind:
  * @ch_avoid_ind:
  * @unsafe_chan_list:
  * @unsafe_chan_list:
  * @avoid_freq_list:
  * @avoid_freq_list:
@@ -238,6 +258,7 @@ struct wlan_regulatory_psoc_priv_obj {
 	bool user_ctry_priority;
 	bool user_ctry_priority;
 	bool user_ctry_set;
 	bool user_ctry_set;
 	struct chan_change_cbk_entry cbk_list[REG_MAX_CHAN_CHANGE_CBKS];
 	struct chan_change_cbk_entry cbk_list[REG_MAX_CHAN_CHANGE_CBKS];
+	struct is_chan_connected_cbk_entry conn_chan_cb;
 	uint8_t num_chan_change_cbks;
 	uint8_t num_chan_change_cbks;
 	struct ctry_change_cbk_entry cc_cbk;
 	struct ctry_change_cbk_entry cc_cbk;
 	uint8_t ch_avoid_ind;
 	uint8_t ch_avoid_ind;
@@ -366,6 +387,7 @@ struct wlan_regulatory_psoc_priv_obj {
  * @fcc_rules_ptr : Value of fcc channel frequency and tx_power list received
  * @fcc_rules_ptr : Value of fcc channel frequency and tx_power list received
  * from firmware
  * from firmware
  * @indoor_list: List of current indoor station interfaces
  * @indoor_list: List of current indoor station interfaces
+ * @keep_6ghz_sta_cli_connection: Keep current STA/P2P client connection
  */
  */
 struct wlan_regulatory_pdev_priv_obj {
 struct wlan_regulatory_pdev_priv_obj {
 	struct regulatory_channel cur_chan_list[NUM_CHANNELS];
 	struct regulatory_channel cur_chan_list[NUM_CHANNELS];
@@ -449,6 +471,7 @@ struct wlan_regulatory_pdev_priv_obj {
 	struct cur_fcc_rule fcc_rules_ptr[MAX_NUM_FCC_RULES];
 	struct cur_fcc_rule fcc_rules_ptr[MAX_NUM_FCC_RULES];
 	struct indoor_concurrency_list indoor_list[MAX_INDOOR_LIST_SIZE];
 	struct indoor_concurrency_list indoor_list[MAX_INDOOR_LIST_SIZE];
 #endif
 #endif
+	bool keep_6ghz_sta_cli_connection;
 };
 };
 
 
 /**
 /**

+ 67 - 1
umac/regulatory/core/src/reg_utils.c

@@ -586,11 +586,30 @@ QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev, uint32_t band_bitmap)
 		return QDF_STATUS_E_INVAL;
 		return QDF_STATUS_E_INVAL;
 	}
 	}
 
 
-	if (pdev_priv_obj->band_capability == band_bitmap) {
+	/*
+	 * If SET_FCC_CHANNEL 0 command is received first then 6 GHz band would
+	 * be disabled and band_capability would be set to 3 but existing 6 GHz
+	 * STA and P2P client connections won't be disconnected.
+	 * If set band comes again for 6 GHz band disabled and band_bitmap is
+	 * equal to band_capability, proceed to disable 6 GHz band completely.
+	 */
+	if (pdev_priv_obj->band_capability == band_bitmap &&
+	    !reg_get_keep_6ghz_sta_cli_connection(pdev)) {
 		reg_info("same band %d", band_bitmap);
 		reg_info("same band %d", band_bitmap);
 		return QDF_STATUS_SUCCESS;
 		return QDF_STATUS_SUCCESS;
 	}
 	}
 
 
+	/*
+	 * If in current band_capability 6 GHz bit is not set, in current
+	 * request 6 GHz band might be enabled/disabled. Hence reset
+	 * reg_set_keep_6ghz_sta_cli_connection flag.
+	 */
+	if (!wlan_reg_is_6ghz_band_set(pdev)) {
+		status = reg_set_keep_6ghz_sta_cli_connection(pdev, false);
+		if (QDF_IS_STATUS_ERROR(status))
+			return status;
+	}
+
 	psoc = wlan_pdev_get_psoc(pdev);
 	psoc = wlan_pdev_get_psoc(pdev);
 	if (!psoc) {
 	if (!psoc) {
 		reg_err("psoc is NULL");
 		reg_err("psoc is NULL");
@@ -739,6 +758,37 @@ QDF_STATUS reg_cache_channel_freq_state(struct wlan_objmgr_pdev *pdev,
 #endif
 #endif
 
 
 #ifdef CONFIG_REG_CLIENT
 #ifdef CONFIG_REG_CLIENT
+bool reg_get_keep_6ghz_sta_cli_connection(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+		reg_err("pdev reg component is NULL");
+		return false;
+	}
+
+	return pdev_priv_obj->keep_6ghz_sta_cli_connection;
+}
+
+QDF_STATUS reg_set_keep_6ghz_sta_cli_connection(struct wlan_objmgr_pdev *pdev,
+					bool keep_6ghz_sta_cli_connection)
+{
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+		reg_err("pdev reg component is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev_priv_obj->keep_6ghz_sta_cli_connection =
+			keep_6ghz_sta_cli_connection;
+
+	reg_debug("set keep_6ghz_sta_cli_connection = %d",
+		  keep_6ghz_sta_cli_connection);
+	return QDF_STATUS_SUCCESS;
+}
 
 
 QDF_STATUS reg_set_fcc_constraint(struct wlan_objmgr_pdev *pdev,
 QDF_STATUS reg_set_fcc_constraint(struct wlan_objmgr_pdev *pdev,
 				  bool fcc_constraint)
 				  bool fcc_constraint)
@@ -783,6 +833,22 @@ QDF_STATUS reg_set_fcc_constraint(struct wlan_objmgr_pdev *pdev,
 	return status;
 	return status;
 }
 }
 
 
+bool reg_is_6ghz_band_set(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+		reg_err("pdev reg component is NULL");
+		return false;
+	}
+
+	if (!(pdev_priv_obj->band_capability & BIT(REG_BAND_6G)))
+		return false;
+
+	return true;
+}
+
 bool reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq)
 bool reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq)
 {
 {
 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;

+ 47 - 0
umac/regulatory/core/src/reg_utils.h

@@ -138,6 +138,27 @@ QDF_STATUS reg_cache_channel_freq_state(struct wlan_objmgr_pdev *pdev,
 #endif /* defined(DISABLE_CHANNEL_LIST) && defined(CONFIG_CHAN_FREQ_API) */
 #endif /* defined(DISABLE_CHANNEL_LIST) && defined(CONFIG_CHAN_FREQ_API) */
 
 
 #ifdef CONFIG_REG_CLIENT
 #ifdef CONFIG_REG_CLIENT
+/**
+ * reg_get_keep_6ghz_sta_cli_connection() - Get keep 6ghz sta cli
+ *                                               connection flag
+ * @pdev: The physical pdev to get keep_6ghz_sta_cli_connection
+ *
+ * Return: Return true if keep_6ghz_sta_cli_connection set else return false
+ */
+bool reg_get_keep_6ghz_sta_cli_connection(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * reg_set_keep_6ghz_sta_cli_connection() - Set keep 6ghz sta cli connection
+ *                                          flag
+ * @pdev: The physical pdev to get keep_6ghz_sta_cli_connection
+ * @keep_6ghz_sta_cli_connection: Parameter to set
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS reg_set_keep_6ghz_sta_cli_connection(
+					struct wlan_objmgr_pdev *pdev,
+					bool keep_6ghz_sta_cli_connection);
+
 /**
 /**
  * reg_set_band() - Sets the band information for the PDEV
  * reg_set_band() - Sets the band information for the PDEV
  * @pdev: The physical dev to set the band for
  * @pdev: The physical dev to set the band for
@@ -179,6 +200,13 @@ QDF_STATUS reg_set_fcc_constraint(struct wlan_objmgr_pdev *pdev,
  */
  */
 bool reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq);
 bool reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq);
 
 
+/**
+ * reg_is_6ghz_band_set - Check if 6 GHz band set
+ * @pdev: Pointer to pdev
+ *
+ * Return: True if 6 GHz band set else return flase
+ */
+bool reg_is_6ghz_band_set(struct wlan_objmgr_pdev *pdev);
 /**
 /**
  * reg_read_current_country() - Get the current regulatory country
  * reg_read_current_country() - Get the current regulatory country
  * @psoc: The physical SoC to get current country from
  * @psoc: The physical SoC to get current country from
@@ -469,11 +497,30 @@ bool reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq)
 	return false;
 	return false;
 }
 }
 
 
+static inline
+bool reg_is_6ghz_band_set(struct wlan_objmgr_pdev *pdev)
+{
+	return true;
+}
+
 static inline enum reg_6g_ap_type
 static inline enum reg_6g_ap_type
 reg_decide_6g_ap_pwr_type(struct wlan_objmgr_pdev *pdev)
 reg_decide_6g_ap_pwr_type(struct wlan_objmgr_pdev *pdev)
 {
 {
 	return REG_CURRENT_MAX_AP_TYPE;
 	return REG_CURRENT_MAX_AP_TYPE;
 }
 }
+
+static inline
+bool reg_get_keep_6ghz_sta_cli_connection(struct wlan_objmgr_pdev *pdev)
+{
+	return false;
+}
+
+static inline
+QDF_STATUS reg_set_keep_6ghz_sta_cli_connection(struct wlan_objmgr_pdev *pdev,
+					bool keep_6ghz_sta_cli_connection)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif /* CONFIG_REG_CLIENT */
 #endif /* CONFIG_REG_CLIENT */
 
 
 #if defined(WLAN_FEATURE_DSRC) && defined(CONFIG_REG_CLIENT)
 #if defined(WLAN_FEATURE_DSRC) && defined(CONFIG_REG_CLIENT)

+ 40 - 0
umac/regulatory/dispatcher/inc/wlan_reg_services_api.h

@@ -573,6 +573,22 @@ bool wlan_reg_is_regdb_offloaded(struct wlan_objmgr_psoc *psoc);
  */
  */
 bool wlan_reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq);
 bool wlan_reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq);
 
 
+/**
+ * wlan_reg_is_6ghz_band_set - Check if 6 GHz band set
+ * @pdev: Pointer to pdev
+ *
+ * Return: True if 6 GHz band set else return flase
+ */
+bool wlan_reg_is_6ghz_band_set(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * wlan_reg_get_keep_6ghz_sta_cli_connection() - Get keep 6ghz sta cli
+ *                                               connection flag
+ * @pdev: Pointer to pdev
+ *
+ * Return: Return true if keep 6ghz sta cli connection set else return false
+ */
+bool wlan_reg_get_keep_6ghz_sta_cli_connection(struct wlan_objmgr_pdev *pdev);
 #ifdef CONFIG_REG_CLIENT
 #ifdef CONFIG_REG_CLIENT
 /**
 /**
  * wlan_reg_read_current_country() - Read the current country for the regdomain
  * wlan_reg_read_current_country() - Read the current country for the regdomain
@@ -2857,4 +2873,28 @@ wlan_reg_display_super_chan_list(struct wlan_objmgr_pdev *pdev)
 uint8_t
 uint8_t
 wlan_reg_get_num_rules_of_ap_pwr_type(struct wlan_objmgr_pdev *pdev,
 wlan_reg_get_num_rules_of_ap_pwr_type(struct wlan_objmgr_pdev *pdev,
 				      enum reg_6g_ap_type ap_pwr_type);
 				      enum reg_6g_ap_type ap_pwr_type);
+
+/**
+ * wlan_reg_register_is_chan_connected_callback() - Register callback to check
+ *                                                  if channel is connected.
+ * @psoc: Pointer to global psoc structure.
+ * @cbk: Pointer to callback function.
+ *
+ * Return: None
+ */
+void
+wlan_reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					     void *cbk);
+
+/**
+ * wlan_reg_unregister_is_chan_connected_callback() - Unregister callback to
+ * check if channel is connected.
+ * @psoc: Pointer to global psoc structure.
+ * @cbk: Pointer to callback function.
+ *
+ * Return: None
+ */
+void
+wlan_reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					       void *cbk);
 #endif
 #endif

+ 22 - 0
umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h

@@ -115,6 +115,28 @@ void ucfg_reg_restore_cached_channels(struct wlan_objmgr_pdev *pdev)
 }
 }
 #endif
 #endif
 
 
+/**
+ * ucfg_reg_get_keep_6ghz_sta_cli_connection() - Get keep 6ghz sta cli
+ *                                               connection flag
+ * @pdev: The physical pdev to get keep_6ghz_sta_cli_connection
+ *
+ * Return: Return true if keep 6ghz sta cli connection set else return flase
+ */
+bool ucfg_reg_get_keep_6ghz_sta_cli_connection(
+					struct wlan_objmgr_pdev *pdev);
+
+/**
+ * ucfg_reg_set_keep_6ghz_sta_cli_connection() - Set keep 6ghz sta cli
+ *                                               connection flag
+ * @pdev: The physical pdev to get keep_6ghz_sta_cli_connection
+ * @keep_6ghz_sta_cli_connection: Parameter to set
+ *
+ * Return: QDF_STATUS
+ */
+
+QDF_STATUS ucfg_reg_set_keep_6ghz_sta_cli_connection(
+					struct wlan_objmgr_pdev *pdev,
+					bool keep_6ghz_sta_cli_connection);
 /**
 /**
  * ucfg_reg_set_fcc_constraint() - apply fcc constraints on channels 12/13
  * ucfg_reg_set_fcc_constraint() - apply fcc constraints on channels 12/13
  * @pdev: The physical pdev to reduce tx power for
  * @pdev: The physical pdev to reduce tx power for

+ 25 - 0
umac/regulatory/dispatcher/src/wlan_reg_services_api.c

@@ -730,6 +730,15 @@ bool wlan_reg_is_etsi13_srd_chan_allowed_master_mode(struct wlan_objmgr_pdev
 	return reg_is_etsi13_srd_chan_allowed_master_mode(pdev);
 	return reg_is_etsi13_srd_chan_allowed_master_mode(pdev);
 }
 }
 
 
+bool wlan_reg_is_6ghz_band_set(struct wlan_objmgr_pdev *pdev)
+{
+	return reg_is_6ghz_band_set(pdev);
+}
+
+bool wlan_reg_get_keep_6ghz_sta_cli_connection(struct wlan_objmgr_pdev *pdev)
+{
+	return reg_get_keep_6ghz_sta_cli_connection(pdev);
+}
 bool wlan_reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq)
 bool wlan_reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq)
 {
 {
 	return reg_get_fcc_constraint(pdev, freq);
 	return reg_get_fcc_constraint(pdev, freq);
@@ -1942,3 +1951,19 @@ wlan_reg_modify_indoor_concurrency(struct wlan_objmgr_pdev *pdev,
 		return reg_remove_indoor_concurrency(pdev, vdev_id, freq);
 		return reg_remove_indoor_concurrency(pdev, vdev_id, freq);
 }
 }
 #endif
 #endif
+
+void
+wlan_reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					     void *cbk)
+{
+	reg_register_is_chan_connected_callback(psoc,
+					(reg_is_chan_connected_callback)cbk);
+}
+
+void
+wlan_reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
+					       void *cbk)
+{
+	reg_unregister_is_chan_connected_callback(psoc,
+					(reg_is_chan_connected_callback)cbk);
+}

+ 14 - 0
umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c

@@ -157,6 +157,20 @@ QDF_STATUS ucfg_reg_set_default_country(struct wlan_objmgr_psoc *psoc,
 {
 {
 	return reg_set_default_country(psoc, country);
 	return reg_set_default_country(psoc, country);
 }
 }
+
+bool ucfg_reg_get_keep_6ghz_sta_cli_connection(
+					struct wlan_objmgr_pdev *pdev)
+{
+	return reg_get_keep_6ghz_sta_cli_connection(pdev);
+}
+
+QDF_STATUS ucfg_reg_set_keep_6ghz_sta_cli_connection(
+					struct wlan_objmgr_pdev *pdev,
+					bool keep_6ghz_sta_cli_connection)
+{
+	return reg_set_keep_6ghz_sta_cli_connection(pdev,
+						keep_6ghz_sta_cli_connection);
+}
 #endif
 #endif
 
 
 QDF_STATUS ucfg_reg_get_default_country(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS ucfg_reg_get_default_country(struct wlan_objmgr_psoc *psoc,