From 4cb83cf30b75ca1351614e0eabe7105449cb5681 Mon Sep 17 00:00:00 2001 From: Ramasamy Kaliappan Date: Mon, 28 Nov 2022 11:38:07 +0530 Subject: [PATCH] hostapd: Puncturing support for interference affected dfs sub channels When receive the dfs interference affected event from nl80211 with affected sub 20Mhz channels bitmap will be validate in the valid puncturing pattern. If puncturing pattern is valid, Send CSA with the corresponding reduced bandwidth for the legacy devices and do the switch channel with current oper channel with same bandwidth with valid puncturing bitmap. If not valid, then fall back to default switch channel behavior using random channel selection. Signed-off-by: Ramasamy Kaliappan --- hostapd/ctrl_iface.c | 25 ++++- src/ap/dfs.c | 126 +++++++++++++++++++++++- src/ap/dfs.h | 6 ++ src/ap/hostapd.c | 47 +++++++++ src/ap/hostapd.h | 3 + src/ap/ieee802_11.c | 30 +++++- 6 files changed, 230 insertions(+), 7 deletions(-) --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -20,6 +20,7 @@ #include "crypto/crypto.h" #include "beacon.h" #include "eloop.h" +#include "ieee802_11.h" enum dfs_channel_type { DFS_ANY_CHANNEL, @@ -1127,7 +1128,8 @@ static int hostapd_dfs_request_channel_s &cmode->he_capab[ieee80211_mode], &cmode->eht_capab[ieee80211_mode], iface->conf->he_6ghz_reg_pwr_type, - iface->conf->ru_punct_bitmap, + iface->conf->ru_punct_bitmap | + iface->radar_bit_pattern, iface->conf->ru_punct_ofdma); if (err) { @@ -1648,14 +1650,48 @@ static int hostapd_dfs_start_channel_swi oper_centr_freq_seg1_idx); } +/*convert common width(chan_width) to oper channel width*/ +enum oper_chan_width convert_to_oper_chan_width(int chan_width) +{ + switch (chan_width) { + case CHAN_WIDTH_20_NOHT: + case CHAN_WIDTH_20: + case CHAN_WIDTH_40: + return CONF_OPER_CHWIDTH_USE_HT; + case CHAN_WIDTH_80: + return CONF_OPER_CHWIDTH_80MHZ; + case CHAN_WIDTH_80P80: + return CONF_OPER_CHWIDTH_80P80MHZ; + case CHAN_WIDTH_160: + return CONF_OPER_CHWIDTH_160MHZ; + case CHAN_WIDTH_320: + return CONF_OPER_CHWIDTH_320MHZ; + } + + return CHAN_WIDTH_UNKNOWN; +} int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2, u16 radar_bitmap) { + u16 radar_bit_pattern; + u16 cur_punct_bits = iface->conf->ru_punct_bitmap; + wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED - "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", - freq, ht_enabled, chan_offset, chan_width, cf1, cf2); + "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d radar_bitmap:%d", + freq, ht_enabled, chan_offset, chan_width, cf1, cf2, radar_bitmap); + + if (iface->conf->use_ru_puncture_dfs) { + radar_bit_pattern = iface->radar_bit_pattern | iface->conf->ru_punct_bitmap; + + /* Radar detected already punctured sub channel*/ + if (radar_bit_pattern & radar_bitmap) + return 0; + + radar_bit_pattern |= radar_bitmap; + iface->conf->ru_punct_bitmap = radar_bit_pattern; + } /* Proceed only if DFS is not offloaded to the driver */ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) @@ -1678,10 +1714,54 @@ int hostapd_dfs_radar_detected(struct ho if (!hostapd_dfs_is_background_event(iface, freq)) { /* Skip if reported radar event not overlapped our channels */ if (!dfs_are_channels_overlapped(iface, freq, chan_width, - cf1, cf2)) + cf1, cf2)) { + iface->conf->ru_punct_bitmap = cur_punct_bits; return 0; + } } + if (iface->conf->use_ru_puncture_dfs && hostapd_is_usable_ru_punct_bitmap(iface)) { + iface->radar_bit_pattern = radar_bitmap; + iface->conf->ru_punct_bitmap = cur_punct_bits; + u8 oper_centr_freq_seg0_idx = iface->conf->vht_oper_centr_freq_seg0_idx; + u8 oper_centr_freq_seg1_idx = iface->conf->vht_oper_centr_freq_seg1_idx; + + chan_width = convert_to_oper_chan_width(chan_width); + + if (iface->cac_started) { + + wpa_printf(MSG_DEBUG, "radar detected during cac," + "it restarted with valid puncturing bitmap :%d", + iface->conf->ru_punct_bitmap | + iface->radar_bit_pattern); + + iface->cac_started = 0; + return hostapd_start_dfs_cac(iface, iface->conf->hw_mode, + iface->freq, iface->conf->channel, + iface->conf->ieee80211n, + iface->conf->ieee80211ac, + iface->conf->ieee80211ax, + iface->conf->ieee80211be, + iface->conf->secondary_channel, + hostapd_get_oper_chwidth(iface->conf), + hostapd_get_oper_centr_freq_seg0_idx(iface->conf), + hostapd_get_oper_centr_freq_seg1_idx(iface->conf), + dfs_use_radar_background(iface), + iface->conf->ru_punct_bitmap | + iface->radar_bit_pattern, + iface->conf->ru_punct_ofdma); + } + + return hostapd_dfs_request_channel_switch( + iface, iface->conf->channel, freq, + iface->conf->secondary_channel, chan_width, + oper_centr_freq_seg0_idx, oper_centr_freq_seg1_idx); + } + + /* Switch channel with random channel selection for invalid puncturing pattern */ + iface->radar_bit_pattern = 0; + iface->conf->ru_punct_bitmap = 0; + if (hostapd_dfs_background_start_channel_switch(iface, freq)) { if (!iface->conf->disable_csa_dfs) { /* Radar detected while operating, switch the channel. */ --- a/src/ap/dfs.h +++ b/src/ap/dfs.h @@ -14,6 +14,11 @@ /* Wait duration between radar detection and channel switch*/ #define HAPD_DFS_RADAR_CH_SWITCH_WAIT_DUR 500000 +/*identify freq using channel number*/ +#define BASE_FREQ_5G 5160 +#define BASE_CHAN_5G 32 +#define GET_FREQ_CHAN_5G(chan) (BASE_FREQ_5G + ((chan - BASE_CHAN_5G) * 5)) + void hostapd_dfs_test_mode_csa_timeout(void *eloop_data, void *user_data); int hostapd_handle_dfs(struct hostapd_iface *iface); --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -3972,6 +3972,9 @@ static int hostapd_fill_csa_settings(str u16 old_punct_bitmap; #endif /* CONFIG_IEEE80211BE */ u8 chan, bandwidth; + u8 oper_centr_freq0_idx = 0; + u8 oper_centr_freq1_idx = 0; + int sec_channel_offset = settings->freq_params.sec_channel_offset; os_memset(&old_freq, 0, sizeof(old_freq)); if (!iface || !iface->freq || hapd->csa_in_progress) @@ -3995,16 +3998,39 @@ static int hostapd_fill_csa_settings(str break; } + if (iface->radar_bit_pattern) { + enum oper_chan_width chan_op_bw = bandwidth; + + ieee80211_freq_to_chan(settings->freq_params.center_freq1, + &oper_centr_freq0_idx); + ieee80211_freq_to_chan(settings->freq_params.center_freq2, + &oper_centr_freq1_idx); + + punct_update_legacy_bw(settings->freq_params.ru_punct_bitmap, + iface->conf->channel, + &chan_op_bw, + &oper_centr_freq0_idx, + &oper_centr_freq1_idx); + if (oper_centr_freq0_idx == 0) + sec_channel_offset = 0; + else if (oper_centr_freq0_idx > iface->conf->channel) + sec_channel_offset = 1; + else + sec_channel_offset = -1; + + bandwidth = chan_op_bw; + } + if (ieee80211_freq_to_channel_ext( settings->freq_params.freq, - settings->freq_params.sec_channel_offset, + sec_channel_offset, bandwidth, &hapd->iface->cs_oper_class, &chan) == NUM_HOSTAPD_MODES) { wpa_printf(MSG_DEBUG, "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d)", settings->freq_params.freq, - settings->freq_params.sec_channel_offset, + sec_channel_offset, settings->freq_params.vht_enabled, settings->freq_params.he_enabled, settings->freq_params.eht_enabled); @@ -4035,6 +4061,39 @@ static int hostapd_fill_csa_settings(str if (ret) return ret; + if (iface->radar_bit_pattern) { + settings->freq_params.center_freq1 = ieee80211_chan_to_freq(NULL, + hapd->iface->cs_oper_class, + oper_centr_freq0_idx); + if (settings->freq_params.center_freq1 == -1) + settings->freq_params.center_freq1 = 0; + settings->freq_params.center_freq2 = ieee80211_chan_to_freq(NULL, + hapd->iface->cs_oper_class, + oper_centr_freq1_idx); + if (settings->freq_params.center_freq2 == -1) + settings->freq_params.center_freq2 = 0; + + settings->freq_params.sec_channel_offset = sec_channel_offset; + + if (bandwidth == CONF_OPER_CHWIDTH_80MHZ) + settings->freq_params.bandwidth = 80; + else if (bandwidth == CONF_OPER_CHWIDTH_160MHZ || + bandwidth == CONF_OPER_CHWIDTH_80P80MHZ) + settings->freq_params.bandwidth = 160; + else if (bandwidth == CONF_OPER_CHWIDTH_320MHZ) + settings->freq_params.bandwidth = 320; + else if (settings->freq_params.sec_channel_offset) + settings->freq_params.bandwidth = 40; + else + settings->freq_params.bandwidth = 20; + wpa_printf(MSG_DEBUG, + "Fill csa beacon with updated bw:%d cf1:%d cf2:%d oper class:%d ch:%d", + bandwidth, + settings->freq_params.center_freq1, + settings->freq_params.center_freq2, + hapd->iface->cs_oper_class, chan); + } + /* set channel switch parameters for csa ie */ hapd->cs_freq_params = settings->freq_params; hapd->cs_count = settings->cs_count; @@ -4103,16 +4162,28 @@ int hostapd_switch_channel(struct hostap struct csa_settings *settings) { int ret; + int oper_centr_freq0_idx; + int cur_bandwidth; if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) { wpa_printf(MSG_INFO, "CSA is not supported"); return -1; } + cur_bandwidth = settings->freq_params.bandwidth; + oper_centr_freq0_idx = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf); + ret = hostapd_fill_csa_settings(hapd, settings); if (ret) return ret; + if (hapd->iface->radar_bit_pattern) { + hapd->iface->conf->ru_punct_bitmap = hapd->iface->conf->ru_punct_bitmap | + hapd->iface->radar_bit_pattern; + settings->freq_params.bandwidth = cur_bandwidth; + settings->freq_params.center_freq1 = GET_FREQ_CHAN_5G(oper_centr_freq0_idx); + } + ret = hostapd_drv_switch_channel(hapd, settings); free_beacon_data(&settings->beacon_csa); free_beacon_data(&settings->beacon_after); --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -687,6 +687,9 @@ struct hostapd_iface { /* Minimum bandwidth the driver supports RU puncturing */ u8 ru_punct_supp_bw; + /* Radar infected sub channel bit pattern */ + u16 radar_bit_pattern; + int (*enable_iface_cb)(struct hostapd_iface *iface); int (*disable_iface_cb)(struct hostapd_iface *iface); @@ -797,6 +800,7 @@ void fst_hostapd_fill_iface_obj(struct h #endif /* CONFIG_FST */ int hostapd_set_acl(struct hostapd_data *hapd); +int hostapd_is_usable_ru_punct_bitmap(struct hostapd_iface *iface); struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd); int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd); struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd, --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -937,7 +937,7 @@ static int hostapd_is_usable_edmg(struct return 1; } -static int hostapd_is_usable_ru_punct_bitmap(struct hostapd_iface *iface) +int hostapd_is_usable_ru_punct_bitmap(struct hostapd_iface *iface) { struct hostapd_config *conf = iface->conf; int bw, start_chan; --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -914,12 +914,17 @@ bool is_ru_punct_bitmap_valid(u16 bw, u1 switch (bw) { case 80: + /* Subchannel bits outside operating BW shouldn't be set */ + if (ru_punct_bitmap & 0xFFF0) + return false; bitmap &= 0xF; non_ofdma_bitmap = &ru_punct_bitmap_80[0]; non_ofdma_bitmap_count = ARRAY_SIZE(ru_punct_bitmap_80); break; case 160: + if (ru_punct_bitmap & 0xFF00) + return false; bitmap &= 0xFF; non_ofdma_bitmap = &ru_punct_bitmap_160[0]; non_ofdma_bitmap_count = ARRAY_SIZE(ru_punct_bitmap_160); --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -1218,6 +1218,7 @@ struct hostapd_config { MBSSID_ENABLED = 1, ENHANCED_MBSSID_ENABLED = 2, } mbssid; + int use_ru_puncture_dfs; }; --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -243,6 +243,9 @@ channel=1 # during radar detection #disable_csa_dfs=1 +# Enable dfs sub channel punturing when radar infected sub channel +#use_ru_puncture_dfs=1 + # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535) beacon_int=100 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4814,6 +4814,8 @@ static int hostapd_config_fill(struct ho #endif /* CONFIG_IEEE80211BE */ } else if (os_strcmp(buf, "disable_csa_dfs") == 0) { conf->disable_csa_dfs = atoi(pos); + } else if (os_strcmp(buf, "use_ru_puncture_dfs") == 0) { + conf->use_ru_puncture_dfs = atoi(pos); } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration item '%s'", --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2817,6 +2817,7 @@ static const struct parse_data ssid_fiel { INT_RANGE(enable_160mhz_bw, 0, 1)}, { INT_RANGE(enable_320mhz_bw, 0, 1)}, { INT(ru_punct_bitmap) }, + { INT_RANGE(use_ru_puncture_dfs, 0, 1) }, { INT_RANGE(disable_eht, 0, 1)}, { INT_RANGE(enable_4addr_mode, 0, 1)}, }; --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -426,6 +426,7 @@ int wpa_supplicant_conf_ap_ht(struct wpa ssid->eht) { conf->ieee80211be = 1; conf->ru_punct_bitmap = ssid->ru_punct_bitmap; + conf->use_ru_puncture_dfs = ssid->use_ru_puncture_dfs; } if (mode->vht_capab && ssid->vht) { --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -1288,6 +1288,11 @@ struct wpa_ssid { u16 ru_punct_bitmap; /** + * Enable dfs punctuing - set it 1 to enable dfs sub channel puncturing + */ + int use_ru_puncture_dfs; + + /** * disable_eht - Disable EHT (IEEE 802.11be) for this network * * By default, use it if it is available, but this can be configured --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -8093,6 +8093,27 @@ static void punct_update_legacy_bw_160(u } } +static void punct_update_legacy_bw_320(u16 bitmap, u8 pri, + enum oper_chan_width *width, u8 *seg0) +{ + if (pri < *seg0) { + *seg0 -= 16; + if (bitmap & 0x00FF) { + *width = 1; + punct_update_legacy_bw_160(bitmap & 0xFF, + pri, width, + seg0); + } + } else { + *seg0 += 16; + if (bitmap & 0xFF00) { + *width = 1; + punct_update_legacy_bw_160((bitmap & 0xFF00) >> 8, + pri, width, + seg0); + } + } +} void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width, u8 *seg0, u8 *seg1) @@ -8108,7 +8129,11 @@ void punct_update_legacy_bw(u16 bitmap, punct_update_legacy_bw_160(bitmap & 0xFF, pri, width, seg0); } - /* TODO: 320 MHz */ + /* 320 MHz */ + if ((*width) == 9 && (bitmap & 0xFFFF)) { + *width = 2; + punct_update_legacy_bw_320(bitmap & 0xFFFF, pri, width, seg0); + } } #endif /* CONFIG_NATIVE_WINDOWS */