diff --git a/components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h b/components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h index 146d45f1b6..d5d9ce9c33 100644 --- a/components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h +++ b/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 }; diff --git a/components/mlme/core/inc/wlan_mlme_main.h b/components/mlme/core/inc/wlan_mlme_main.h index 066494be55..9103cec6c5 100644 --- a/components/mlme/core/inc/wlan_mlme_main.h +++ b/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; }; /** diff --git a/core/hdd/inc/hdd_config.h b/core/hdd/inc/hdd_config.h index d2d844509f..8df4fa99ae 100644 --- a/core/hdd/inc/hdd_config.h +++ b/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") +/* + * + * 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 + * + * + */ +#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) \ diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 2b859ffbc6..a3002f8931 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/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; }; /** diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index c5612fce66..ab8eccb268 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/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 diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 0d80c23e59..205854ad91 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/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); 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 d35347a3f3..78337b1604 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 @@ -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; + } } - chan_num = wlan_reg_get_secondary_band_channel_list(mac->pdev, - BIT(rf_band), - sec_cur_chan_list); + 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, + 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; diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index cf4a54312f..b5a7178815 100644 --- a/core/sme/inc/sme_api.h +++ b/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 ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 3202b1ca11..40f0f50b22 100644 --- a/core/sme/src/common/sme_api.c +++ b/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; +}