--- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2465,6 +2465,8 @@ static int hostapd_config_fill(struct ho conf->ieee80211d = atoi(pos); } else if (os_strcmp(buf, "ieee80211h") == 0) { conf->ieee80211h = atoi(pos); + } else if (os_strcmp(buf, "dfs_test_mode") == 0) { + conf->dfs_test_mode = atoi(pos); } else if (os_strcmp(buf, "ieee8021x") == 0) { bss->ieee802_1x = atoi(pos); } else if (os_strcmp(buf, "eapol_version") == 0) { --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -981,6 +981,7 @@ struct hostapd_config { int ieee80211d; int ieee80211h; /* DFS */ + int dfs_test_mode; /* * Local power constraint is an octet encoded as an unsigned integer in --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -18,6 +18,8 @@ #include "drivers/driver.h" #include "dfs.h" #include "crypto/crypto.h" +#include "beacon.h" +#include "eloop.h" static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) @@ -1036,6 +1038,73 @@ static int hostapd_dfs_start_channel_swi return err; } +void hostapd_dfs_test_mode_csa_timeout(void *eloop_data, void *user_data) +{ + struct hostapd_data *hapd = eloop_data; + + wpa_printf(MSG_INFO, "Stopping CSA in dfs test mode"); + hostapd_cleanup_cs_params(hapd); + ieee802_11_set_beacon(hapd); +} + +static int hostapd_dfs_testmode_set_beacon_csa(struct hostapd_iface *iface) +{ + struct hostapd_data *hapd = iface->bss[0]; + struct csa_settings csa_settings; + int secondary_channel; + u8 vht_oper_centr_freq_seg0_idx; + u8 vht_oper_centr_freq_seg1_idx; + int err = 0; + + eloop_cancel_timeout(hostapd_dfs_test_mode_csa_timeout, hapd, NULL); + secondary_channel = iface->conf->secondary_channel; + vht_oper_centr_freq_seg0_idx = + iface->conf->vht_oper_centr_freq_seg0_idx; + vht_oper_centr_freq_seg1_idx = + iface->conf->vht_oper_centr_freq_seg1_idx; + + /* Setup CSA request */ + os_memset(&csa_settings, 0, sizeof(csa_settings)); + err = hostapd_set_freq_params(&csa_settings.freq_params, + iface->conf->hw_mode, + iface->freq, + iface->conf->channel, + iface->conf->ieee80211n, + iface->conf->ieee80211ac, + secondary_channel, + iface->conf->vht_oper_chwidth, + vht_oper_centr_freq_seg0_idx, + vht_oper_centr_freq_seg1_idx, + iface->current_mode->vht_capab); + + if (err) { + wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); + goto fail; + } + + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) { + wpa_printf(MSG_INFO, "CSA is not supported"); + hostapd_disable_iface(iface); + return -1; + } + + hapd->cs_freq_params = csa_settings.freq_params; + hapd->cs_count = 3; + hapd->cs_block_tx = 1; + err = ieee802_11_set_beacon(hapd); + if (err) + goto fail; + wpa_printf(MSG_DEBUG, "CSA beacon configured for dfs mode, count %d", + hapd->cs_count); + hapd->csa_in_progress = 1; + eloop_register_timeout(HOSTAPD_DFS_TEST_MODE_CSA_DUR, 0, + hostapd_dfs_test_mode_csa_timeout, hapd, NULL); + return 0; + +fail: + hostapd_disable_iface(iface); + return err; +} static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) { @@ -1071,6 +1140,9 @@ static int hostapd_dfs_start_channel_swi if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI) skip_radar = 0; + if (iface->conf->dfs_test_mode) + return hostapd_dfs_testmode_set_beacon_csa(iface); + /* Perform channel switch/CSA */ channel = dfs_get_valid_channel(iface, &secondary_channel, &oper_centr_freq_seg0_idx, @@ -1206,6 +1278,12 @@ int hostapd_dfs_radar_detected(struct ho if (!res) return 0; + if (iface->conf->dfs_test_mode) { + set_dfs_state(iface, freq, ht_enabled, chan_offset, + chan_width, cf1, cf2, + HOSTAPD_CHAN_DFS_AVAILABLE); + } + /* Skip if reported radar event not overlapped our channels */ res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); if (!res) --- a/src/ap/dfs.h +++ b/src/ap/dfs.h @@ -9,6 +9,11 @@ #ifndef DFS_H #define DFS_H +/* CSA beacon duration in seconds for dfs testing mode */ +#define HOSTAPD_DFS_TEST_MODE_CSA_DUR 1 + +void hostapd_dfs_test_mode_csa_timeout(void *eloop_data, void *user_data); + int hostapd_handle_dfs(struct hostapd_iface *iface); int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -2901,6 +2901,7 @@ int hostapd_disable_iface(struct hostapd hostapd_cleanup_cs_params(hapd_iface->bss[j]); #endif /* NEED_AP_MLME */ + eloop_cancel_timeout(hostapd_dfs_test_mode_csa_timeout, hapd_iface, NULL); /* same as hostapd_interface_deinit without deinitializing ctrl-iface */ for (j = 0; j < hapd_iface->num_bss; j++) { struct hostapd_data *hapd = hapd_iface->bss[j];