Merge branch 'feat/support_disable_dfs_channel_in_apsta' into 'master'

feat(wifi): support disable dfs channels in apsta

See merge request espressif/esp-idf!51774
This commit is contained in:
Jiang Jiang Jian
2026-09-01 10:14:25 +08:00
5 changed files with 120 additions and 2 deletions

View File

@@ -924,6 +924,7 @@ Wi-Fi Bandwidth Mode
1. If the STA connects to an AP on a DFS channel, the SoftAP is allowed to switch to the same DFS channel using CSA (Channel Switch Announcement).
2. When the STA disconnects, the SoftAP will switch back to a non-DFS channel via CSA to remain compliant with regulations.
3. To completely prevent the SoftAP from operating on DFS channels, call :cpp:func:`esp_wifi_set_country()` to set ``policy`` to ``WIFI_COUNTRY_POLICY_MANUAL`` and restrict ``wifi_5g_channel_mask`` to the non-DFS channels of the current country/region. ``wifi_5g_channel_mask`` takes effect only when policy is ``WIFI_COUNTRY_POLICY_MANUAL``. Note: in this case, if the target AP operates on a DFS channel, the STA cannot connect to that AP. See :component_file:`esp_wifi/regulatory/esp_wifi_regulatory.txt` for the DFS channel range of each country/region.
..
@@ -1058,7 +1059,7 @@ Wi-Fi Country Code
* - policy
- Country/region policy. When the configured country/region conflicts with that of the connected AP, this field determines which information to use. Details are explained below.
* - wifi_5g_channel_mask
- Bitmask indicating allowed 5 GHz channels for the station/AP. The mapping between channel numbers and bits can be found in :cpp:enum:`wifi_5g_channel_bit_t`.
- Bitmask indicating allowed 5 GHz channels for the station/AP. The mapping between channel numbers and bits can be found in :cpp:enum:`wifi_5g_channel_bit_t`. A mask of 0 means 5 GHz channels are allowed according to local regulatory rules. The configured mask takes effect only when ``policy`` is ``WIFI_COUNTRY_POLICY_MANUAL``. To disable DFS channels, restrict the mask to the non-DFS channels of the current country/region; the STA will then be unable to connect to an AP operating on a DFS channel.
A default configuration example::

View File

@@ -924,6 +924,7 @@ Wi-Fi 带宽模式
1. 当 STA 连接到位于 DFS 信道的 AP 时SoftAP 允许通过 CSA (Channel Switch Announcement) 切换至相同的 DFS 信道。
2. 当 STA 断开连接后SoftAP 将通过 CSA 切换回非 DFS 信道,确保符合监管要求。
3. 如需要完全禁止 SoftAP 工作在 DFS 信道上,可通过 :cpp:func:`esp_wifi_set_country()```policy`` 设为 ``WIFI_COUNTRY_POLICY_MANUAL``,并将 ``wifi_5g_channel_mask`` 限制为当前国家/地区的非 DFS 信道。``wifi_5g_channel_mask`` 仅在 policy 为 ``WIFI_COUNTRY_POLICY_MANUAL`` 时生效。注意:此时若目标 AP 工作在 DFS 信道上STA 将无法与该 AP 建立连接。各国 DFS 信道范围见 :component_file:`esp_wifi/regulatory/esp_wifi_regulatory.txt`
..
@@ -1058,7 +1059,7 @@ Wi-Fi 国家/地区代码
* - policy
- 国家/地区策略。当配置的国家/地区与连接 AP 的信息冲突时,此字段决定应使用哪一方的信息。详情见下文说明。
* - wifi_5g_channel_mask
- 表示 station/AP 在 5 GHz 频段中可使用的信道掩码。信道值与位的对应关系详见 :cpp:enum:`wifi_5g_channel_bit_t`
- 表示 station/AP 在 5 GHz 频段中可使用的信道掩码。信道值与位的对应关系详见 :cpp:enum:`wifi_5g_channel_bit_t`掩码为 0 时5 GHz 信道按当地监管规则允许使用。配置的掩码仅在 ``policy````WIFI_COUNTRY_POLICY_MANUAL`` 时生效。如需禁用 DFS 信道,请将掩码限制为当前国家/地区的非 DFS 信道;此时 STA 也无法连接到工作在 DFS 信道上的 AP。
默认配置示例如下::

View File

@@ -23,6 +23,15 @@ In the `Example Configuration` menu:
* Set `WiFi Remote AP SSID`.
* Set `WiFi Remote AP Password`.
* (5 GHz capable chips only) Set the DFS channel configuration under `DFS Channel Configuration`.
* Set `Country code` to select the regulatory domain (e.g. `US` for FCC, `DE` for CE, `01` for world safe mode).
* Enable `Disable DFS channels` to forbid both the STA and the SoftAP from using any DFS channel of the
selected regulatory domain. STA will not be able to connect to an AP that operates on a DFS channel.
The non-DFS channels are looked up from the esp_wifi regulatory table for the configured country, and
the 5 GHz channel bitmask (`wifi_country_t.wifi_5g_channel_mask`) is restricted to them with the
country policy switched to manual. This is useful for certification setups (e.g. FCC, CE) where DFS
channels must be avoided.
Optional: If necessary, modify the other choices to suit your needs.
### Build and Flash

View File

@@ -85,4 +85,28 @@ menu "Example Configuration"
endchoice
endmenu
menu "DFS Channel Configuration"
depends on SOC_WIFI_SUPPORT_5G
comment "DFS Channel Configuration (5 GHz capable chips only)"
config ESP_WIFI_COUNTRY_CODE
string "Country code"
default "01"
help
Country code used to configure the regulatory domain (e.g. "US" for FCC, "DE" for CE,
"01" for world safe mode). The set of DFS channels depends on this regulatory domain.
config ESP_WIFI_DISABLE_DFS_CHANNELS
bool "Disable DFS channels"
default n
help
If enabled, the device (both STA and SoftAP) will not use any DFS channel of the
configured regulatory domain. As a result, STA cannot connect to an AP that operates
on a DFS channel. The non-DFS channels are derived by looking up the country in the
esp_wifi regulatory table, and the 5 GHz channel bitmask
(wifi_country_t.wifi_5g_channel_mask) is restricted to them with the country policy
switched to manual. This can be useful for certification setups (e.g. FCC, CE)
where DFS channels must be avoided.
endmenu
endmenu

View File

@@ -170,6 +170,86 @@ esp_netif_t *wifi_init_sta(void)
return esp_netif_sta;
}
#if CONFIG_ESP_WIFI_DISABLE_DFS_CHANNELS
extern const wifi_regdomain_t regdomain_table[];
extern const wifi_regulatory_t regulatory_data[];
static const wifi_regulatory_t *wifi_lookup_regulatory(const char *cc)
{
for (int i = 0; regdomain_table[i].cn[0] != '#'; i++) {
if (regdomain_table[i].cn[0] == cc[0] && regdomain_table[i].cn[1] == cc[1]) {
return &regulatory_data[regdomain_table[i].regulatory_type];
}
}
return NULL;
}
static uint32_t wifi_get_non_dfs_5g_channel_mask(const wifi_regulatory_t *reg)
{
uint32_t mask = 0;
for (int i = 0; i < reg->n_reg_rules; i++) {
const wifi_reg_rule_t *rule = &reg->reg_rules[i];
if (rule->is_dfs || rule->start_channel <= 14) {
continue;
}
for (uint8_t ch = rule->start_channel; ch <= rule->end_channel; ch += 4) {
mask |= CHANNEL_TO_BIT(ch);
}
}
return mask;
}
// static uint32_t wifi_get_non_dfs_5g_channel_mask_by_type(uint8_t type)
// {
// return wifi_get_non_dfs_5g_channel_mask(&regulatory_data[type]);
// }
static esp_err_t wifi_configure_country_without_dfs_channels(void)
{
const char *cc = CONFIG_ESP_WIFI_COUNTRY_CODE;
const wifi_regulatory_t *reg = wifi_lookup_regulatory(cc);
if (!reg) {
ESP_LOGE(TAG_STA, "Unknown country code '%s'", cc);
return ESP_ERR_INVALID_ARG;
}
wifi_country_t country = {0};
memcpy(country.cc, cc, 2);
country.policy = WIFI_COUNTRY_POLICY_MANUAL;
uint8_t schan = 0;
uint8_t echan = 0;
for (int i = 0; i < reg->n_reg_rules; i++) {
const wifi_reg_rule_t *rule = &reg->reg_rules[i];
if (rule->start_channel > 14) {
continue;
}
if (schan == 0 || rule->start_channel < schan) {
schan = rule->start_channel;
}
if (rule->end_channel > echan) {
echan = rule->end_channel;
}
}
if (schan != 0) {
country.schan = schan;
country.nchan = echan - schan + 1;
}
/* A zero mask does not mean "no 5 GHz channel allowed", it means "fall back to
the local regulatory rules", which would leave the DFS channels usable. Some
domains (AM for instance) mark every 5 GHz rule as DFS, so there the only way
to stay off DFS is to stay off 5 GHz altogether. */
country.wifi_5g_channel_mask = wifi_get_non_dfs_5g_channel_mask(reg);
if (country.wifi_5g_channel_mask == 0) {
ESP_ERROR_CHECK(esp_wifi_set_band_mode(WIFI_BAND_MODE_2G_ONLY));
ESP_LOGW(TAG_STA, "'%s' has no non-DFS 5 GHz channel, restricting to 2.4 GHz", cc);
}
ESP_ERROR_CHECK(esp_wifi_set_country(&country));
return ESP_OK;
}
#endif /* CONFIG_ESP_WIFI_DISABLE_DFS_CHANNELS */
void softap_set_dns_addr(esp_netif_t *esp_netif_ap,esp_netif_t *esp_netif_sta)
{
esp_netif_dns_info_t dns;
@@ -231,6 +311,9 @@ void app_main(void)
/* Start WiFi */
ESP_ERROR_CHECK(esp_wifi_start() );
#if CONFIG_ESP_WIFI_DISABLE_DFS_CHANNELS
ESP_ERROR_CHECK(wifi_configure_country_without_dfs_channels());
#endif
/*
* Wait until either the connection is established (WIFI_CONNECTED_BIT) or
* connection failed for the maximum number of re-tries (WIFI_FAIL_BIT).