Browse Source

qcacld-3.0: Let country IE take band channel info as need

When verifying WNM BSS transition function, it's possible to
ask peer STA to transition across multiple band. Some vendor
BTM implementation is needed to check country IE to get all
supported band channel info. Without full channel list in
country IE, it cannot make a transition across multiple band.
To solve the interop issue, let country IE take all supported
band channel info when the specific vendor OUI is detected in
association request.

Change-Id: I78dd4b88937277b54a7da4d72d8a94706965e9a6
CRs-Fixed: 3196957
Qun Zhang 2 years ago
parent
commit
04f01b2cea

+ 2 - 0
components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h

@@ -97,6 +97,7 @@
  * New Firmware related "ACTION" needs to be added before this placeholder.
  * @ACTION_OUI_HOST_RECONN: reconnect to the same BSSID when wait for
  * association response timeout from AP
+ * @ACTION_OUI_TAKE_ALL_BAND_INFO: let AP country ie take all band info
  * @ACTION_OUI_MAXIMUM_ID: maximum number of action oui types
  */
 enum action_oui_id {
@@ -113,6 +114,7 @@ enum action_oui_id {
 	ACTION_OUI_DISABLE_MU_EDCA = 10,
 	ACTION_OUI_HOST_ONLY,
 	ACTION_OUI_HOST_RECONN = ACTION_OUI_HOST_ONLY,
+	ACTION_OUI_TAKE_ALL_BAND_INFO,
 	ACTION_OUI_MAXIMUM_ID
 };
 

+ 2 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -436,6 +436,7 @@ struct wait_for_key_timer {
  * @notify_co_located_ap_upt_rnr: Notify co located AP to update RNR or not
  * @max_mcs_index: Max supported mcs index of vdev
  * @vdev_traffic_type: to set if vdev is LOW_LATENCY or HIGH_TPUT
+ * @country_ie_for_all_band: take all band channel info in country ie
  */
 struct mlme_legacy_priv {
 	bool chan_switch_in_progress;
@@ -484,6 +485,7 @@ struct mlme_legacy_priv {
 	uint8_t max_mcs_index;
 #endif
 	uint8_t vdev_traffic_type;
+	bool country_ie_for_all_band;
 };
 
 /**

+ 37 - 0
core/hdd/inc/hdd_config.h

@@ -1421,6 +1421,42 @@ struct dhcp_server {
 	"001018 00 01 000986 00 01 000ce7 00 01 00e0fc 00 01", \
 	"Used to specify action OUIs to control TWT configuration")
 
+/*
+ * <ini>
+ * gActionOUITakeAllBandInfo - Used to specify action OUIs to check
+ * whether country ie need take all band channel information.
+ *
+ * This ini is used to specify STA association request OUIs. Some STA
+ * need AP country ie take all band channel information when do BSS
+ * transition across band. Thus, AP will take all band channel info
+ * when we receive association request with this OUIs.
+ * Note: User should strictly add new action OUIs at the end of this
+ * default value.
+ *
+ * Default OUIs: (All values in Hex)
+ * OUI 1: 0017f2
+ *   OUI data Len: 01
+ *   OUI Data : 0a
+ *   OUI data Mask: 80 - 10000000
+ *   Info Mask : 01 - only OUI present in Info mask
+ *
+ * Refer to gEnableActionOUI for more detail about the format.
+ *
+ * Related: gEnableActionOUI
+ *
+ * Supported Feature: Action OUIs
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_ACTION_OUI_TAKE_ALL_BAND_INFO CFG_INI_STRING( \
+	"gActionOUITakeAllBandInfo", \
+	0, \
+	ACTION_OUI_MAX_STR_LEN, \
+	"0017f2 01 0a 80 01", \
+	"Used to specify action OUIs to control country ie")
+
 /* End of action oui inis */
 
 #ifdef ENABLE_MTRACE_LOG
@@ -1843,6 +1879,7 @@ enum host_log_level {
 	CFG(CFG_ACTION_OUI_SWITCH_TO_11N_MODE) \
 	CFG(CFG_ACTION_OUI_RECONN_ASSOCTIMEOUT) \
 	CFG(CFG_ACTION_OUI_DISABLE_TWT) \
+	CFG(CFG_ACTION_OUI_TAKE_ALL_BAND_INFO) \
 	CFG(CFG_ADVERTISE_CONCURRENT_OPERATION) \
 	CFG(CFG_BUG_ON_REINIT_FAILURE) \
 	CFG(CFG_DBS_SCAN_SELECTION) \

+ 2 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1085,6 +1085,7 @@ struct hdd_fw_txrx_stats {
  * @bss_stop_reason: Reason why the BSS was stopped
  * @acs_in_progress: In progress acs flag for an adapter
  * @client_count: client count per dot11_mode
+ * @country_ie_updated: country ie is updated or not by hdd hostapd
  */
 struct hdd_ap_ctx {
 	struct hdd_hostapd_state hostapd_state;
@@ -1104,6 +1105,7 @@ struct hdd_ap_ctx {
 	enum bss_stop_reason bss_stop_reason;
 	qdf_atomic_t acs_in_progress;
 	uint16_t client_count[QCA_WLAN_802_11_MODE_INVALID];
+	bool country_ie_updated;
 };
 
 /**

+ 77 - 0
core/hdd/src/wlan_hdd_hostapd.c

@@ -1780,6 +1780,79 @@ hdd_hostapd_sap_register_mlo_sta(struct hdd_adapter *adapter,
 }
 #endif /* WLAN_FEATURE_11BE_MLO */
 
+static inline void
+hdd_hostapd_update_beacon_country_ie(struct hdd_adapter *adapter)
+{
+	struct hdd_station_info *sta_info, *tmp = NULL;
+	struct hdd_context *hdd_ctx;
+	struct hdd_ap_ctx *ap_ctx;
+	struct action_oui_search_attr attr;
+	QDF_STATUS status;
+	bool found = false;
+
+	if (!adapter) {
+		hdd_err("invalid adapter");
+		return;
+	}
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	if (!hdd_ctx) {
+		hdd_err("HDD context is null");
+		return;
+	}
+
+	ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
+
+	hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp,
+				  STA_INFO_HOSTAPD_SAP_EVENT_CB) {
+		if (!sta_info->assoc_req_ies.len)
+			goto release_ref;
+
+		qdf_mem_zero(&attr, sizeof(struct action_oui_search_attr));
+		attr.ie_data = sta_info->assoc_req_ies.ptr;
+		attr.ie_length = sta_info->assoc_req_ies.len;
+
+		found = ucfg_action_oui_search(hdd_ctx->psoc,
+					       &attr,
+					       ACTION_OUI_TAKE_ALL_BAND_INFO);
+		if (found) {
+			if (!ap_ctx->country_ie_updated) {
+				status = sme_update_beacon_country_ie(
+						hdd_ctx->mac_handle,
+						adapter->vdev_id,
+						true);
+				if (status == QDF_STATUS_SUCCESS)
+					ap_ctx->country_ie_updated = true;
+				else
+					hdd_err("fail to update country ie");
+			}
+			hdd_put_sta_info_ref(&adapter->sta_info_list,
+					     &sta_info, true,
+					     STA_INFO_HOSTAPD_SAP_EVENT_CB);
+			if (tmp)
+				hdd_put_sta_info_ref(
+					&adapter->sta_info_list,
+					&tmp, true,
+					STA_INFO_HOSTAPD_SAP_EVENT_CB);
+			return;
+		}
+release_ref:
+		hdd_put_sta_info_ref(&adapter->sta_info_list,
+				     &sta_info, true,
+				     STA_INFO_HOSTAPD_SAP_EVENT_CB);
+	}
+
+	if (ap_ctx->country_ie_updated) {
+		status = sme_update_beacon_country_ie(
+						hdd_ctx->mac_handle,
+						adapter->vdev_id, false);
+		if (status == QDF_STATUS_SUCCESS)
+			ap_ctx->country_ie_updated = false;
+		else
+			hdd_err("fail to update country ie");
+	}
+}
+
 QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 				    void *context)
 {
@@ -2381,6 +2454,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 		}
 		ap_ctx->ap_active = true;
 
+		hdd_hostapd_update_beacon_country_ie(adapter);
+
 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
 		wlan_hdd_auto_shutdown_enable(hdd_ctx, false);
 #endif
@@ -2558,6 +2633,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 					     STA_INFO_HOSTAPD_SAP_EVENT_CB);
 		}
 
+		hdd_hostapd_update_beacon_country_ie(adapter);
+
 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
 		wlan_hdd_auto_shutdown_enable(hdd_ctx, true);
 #endif

+ 3 - 0
core/hdd/src/wlan_hdd_main.c

@@ -13348,6 +13348,9 @@ static void hdd_cfg_params_init(struct hdd_context *hdd_ctx)
 	qdf_str_lcopy(config->action_oui_str[ACTION_OUI_HOST_RECONN],
 		      cfg_get(psoc, CFG_ACTION_OUI_RECONN_ASSOCTIMEOUT),
 		      ACTION_OUI_MAX_STR_LEN);
+	qdf_str_lcopy(config->action_oui_str[ACTION_OUI_TAKE_ALL_BAND_INFO],
+		      cfg_get(psoc, CFG_ACTION_OUI_TAKE_ALL_BAND_INFO),
+		      ACTION_OUI_MAX_STR_LEN);
 
 	config->is_unit_test_framework_enabled =
 			cfg_get(psoc, CFG_ENABLE_UNIT_TEST_FRAMEWORK);

+ 39 - 19
core/mac/src/sys/legacy/src/utils/src/parser_api.c

@@ -607,38 +607,55 @@ populate_dot11f_country(struct mac_context *mac,
 {
 	uint8_t code[REG_ALPHA2_LEN + 1];
 	uint8_t cur_triplet_num_chans = 0;
-	int chan_enum, chan_num, chan_spacing = 0;
+	int chan_enum, chan_num;
 	struct regulatory_channel *sec_cur_chan_list;
 	struct regulatory_channel *cur_chan, *start, *prev;
-	enum reg_wifi_band rf_band = REG_BAND_UNKNOWN;
 	uint8_t buffer_triplets[81][3];
 	uint8_t i, j, num_triplets = 0;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	bool six_gig_started = false;
+	uint8_t band_bitmap;
+	uint32_t band_capability;
+	uint8_t chan_spacing_for_2ghz = 1;
+	uint8_t chan_spacing_for_5ghz_6ghz = 4;
+	struct mlme_legacy_priv *mlme_priv = NULL;
 
 	sec_cur_chan_list = qdf_mem_malloc(NUM_CHANNELS *
 					   sizeof(*sec_cur_chan_list));
 	if (!sec_cur_chan_list)
 		return QDF_STATUS_E_NOMEM;
 
-	lim_get_rf_band_new(mac, &rf_band, pe_session);
-	switch (rf_band) {
-	case REG_BAND_2G:
-		chan_spacing = 1;
-		break;
-	case REG_BAND_5G:
-	case REG_BAND_6G:
-		chan_spacing = 4;
-		break;
-	case REG_BAND_UNKNOWN:
-		pe_err("Wrong reg band for country info");
-		status = QDF_STATUS_E_FAILURE;
-		goto out;
+	if (pe_session) {
+		mlme_priv = wlan_vdev_mlme_get_ext_hdl(pe_session->vdev);
+		if (!mlme_priv) {
+			pe_err("Invalid mlme priv object");
+			status = QDF_STATUS_E_FAILURE;
+			goto out;
+		}
+	}
+
+	if (!pe_session ||
+	    (mlme_priv && mlme_priv->country_ie_for_all_band)) {
+		status = wlan_mlme_get_band_capability(mac->psoc,
+						       &band_capability);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_err("Failed to get MLME Band Capability");
+			goto out;
+		}
+		band_bitmap = (uint8_t)band_capability;
+	} else {
+		if (pe_session->limRFBand == REG_BAND_UNKNOWN) {
+			pe_err("Wrong reg band for country info");
+			status = QDF_STATUS_E_FAILURE;
+			goto out;
+		}
+		band_bitmap = BIT(pe_session->limRFBand);
 	}
 
-	chan_num = wlan_reg_get_secondary_band_channel_list(mac->pdev,
-							    BIT(rf_band),
-							    sec_cur_chan_list);
+	chan_num = wlan_reg_get_secondary_band_channel_list(
+						mac->pdev,
+						band_bitmap,
+						sec_cur_chan_list);
 	if (!chan_num) {
 		pe_err("failed to get cur_chan list");
 		status = QDF_STATUS_E_FAILURE;
@@ -668,7 +685,10 @@ populate_dot11f_country(struct mac_context *mac,
 		}
 
 		if (start && prev &&
-		    prev->chan_num + chan_spacing == cur_chan->chan_num &&
+		    ((prev->chan_num + chan_spacing_for_2ghz ==
+		      cur_chan->chan_num) ||
+		     (prev->chan_num + chan_spacing_for_5ghz_6ghz ==
+		      cur_chan->chan_num)) &&
 		    start->tx_power == cur_chan->tx_power) {
 			/* Can use same entry */
 			prev = cur_chan;

+ 14 - 0
core/sme/inc/sme_api.h

@@ -4558,4 +4558,18 @@ void sme_fill_channel_change_request(mac_handle_t mac_handle,
  */
 QDF_STATUS sme_send_channel_change_req(mac_handle_t mac_handle,
 				      struct channel_change_req *req);
+
+/**
+ * sme_update_beacon_country_ie() - SME API to update beacon
+ * country ie
+ * @mac_handle: mac handle
+ * @vdev_id: vdev id
+ * @country_ie_for_all_band: country ie should take all band channel
+ *			     or only the current band channel
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_update_beacon_country_ie(mac_handle_t mac_handle,
+					uint8_t vdev_id,
+					bool country_ie_for_all_band);
 #endif /* #if !defined( __SME_API_H ) */

+ 29 - 0
core/sme/src/common/sme_api.c

@@ -16275,3 +16275,32 @@ void sme_fill_channel_change_request(mac_handle_t mac_handle,
 				dot11_cfg.ext_rates.numRates;
 	}
 }
+
+QDF_STATUS sme_update_beacon_country_ie(mac_handle_t mac_handle,
+					uint8_t vdev_id,
+					bool country_ie_for_all_band)
+{
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
+	struct wlan_objmgr_vdev *vdev;
+	struct mlme_legacy_priv *mlme_priv;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id,
+						    WLAN_MLME_NB_ID);
+	if (!vdev) {
+		sme_err("vdev object is NULL for vdev_id %d", vdev_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlme_priv->country_ie_for_all_band = country_ie_for_all_band;
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID);
+
+	csr_update_beacon(mac);
+
+	return QDF_STATUS_SUCCESS;
+}