--- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -2658,9 +2658,9 @@ static int hostapd_ctrl_iface_chan_switc for (i = 0; i < iface->num_bss; i++) { - /* Save CHAN_SWITCH VHT config */ - hostapd_chan_switch_vht_config( - iface->bss[i], settings.freq_params.vht_enabled); + /* Save CHAN_SWITCH VHT and HE config */ + hostapd_chan_switch_config( + iface->bss[i], &settings.freq_params); ret = hostapd_switch_channel(iface->bss[i], &settings); if (ret) { --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -1039,6 +1039,13 @@ struct hostapd_config { u8 he_oper_centr_freq_seg1_idx; #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211AX + /* HE enable/disable config from CHAN_SWITCH */ +#define CH_SWITCH_HE_ENABLED BIT(0) +#define CH_SWITCH_HE_DISABLED BIT(1) + unsigned int ch_switch_he_config; +#endif /* CONFIG_IEEE80211AX */ + /* VHT enable/disable config from CHAN_SWITCH */ #define CH_SWITCH_VHT_ENABLED BIT(0) #define CH_SWITCH_VHT_DISABLED BIT(1) --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -1084,6 +1084,7 @@ int hostapd_parse_csa_settings(const cha SET_CSA_SETTING(sec_channel_offset); settings->freq_params.ht_enabled = !!os_strstr(pos, " ht"); settings->freq_params.vht_enabled = !!os_strstr(pos, " vht"); + settings->freq_params.he_enabled = !!os_strstr(pos, " he"); settings->block_tx = !!os_strstr(pos, " blocktx"); #undef SET_CSA_SETTING --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -3546,15 +3546,22 @@ void hostapd_cleanup_cs_params(struct ho } -void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled) +void hostapd_chan_switch_config(struct hostapd_data *hapd, struct hostapd_freq_params *freq_params) { - if (vht_enabled) + if (freq_params->he_enabled) + hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED; + else + hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_DISABLED; + + if (freq_params->vht_enabled) hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED; else hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED; hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x", + HOSTAPD_LEVEL_INFO, "CHAN_SWITCH HE CONFIG 0x%x " + "CHAN_SWITCH VHT CONFIG 0x%x", + hapd->iconf->ch_switch_he_config, hapd->iconf->ch_switch_vht_config); } --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -870,10 +870,10 @@ enum hostapd_hw_mode ieee80211_freq_to_c /** * ieee80211_freq_to_channel_ext - Convert frequency into channel info - * for HT40 and VHT. DFS channels are not covered. + * for HT40 VHT and HE, DFS channels are not covered. * @freq: Frequency (MHz) to convert * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below - * @chanwidth: VHT/EDMG channel width (CHANWIDTH_*) + * @chanwidth: VHT/HE channel width (CHANWIDTH_*) * @op_class: Buffer for returning operating class * @channel: Buffer for returning channel number * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -209,7 +209,7 @@ int hostapd_config_tx_queue(struct hosta enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel); int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan); enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, - int sec_channel, int vht, + int sec_channel, int chan_width, u8 *op_class, u8 *channel); int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, int sec_channel, u8 *op_class, u8 *channel); --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1293,7 +1293,7 @@ struct ieee80211_ampe_ie { #define VHT_RX_NSS_MAX_STREAMS 8 -/* VHT/EDMG channel widths */ +/* HE and VHT channel widths */ #define CHANWIDTH_USE_HT 0 #define CHANWIDTH_80MHZ 1 #define CHANWIDTH_160MHZ 2 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -862,9 +862,10 @@ void hostapd_event_ch_switch(struct host hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, - "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", + "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", finished ? "had" : "starting", - freq, ht, hapd->iconf->ch_switch_vht_config, offset, + freq, ht, hapd->iconf->ch_switch_vht_config, + hapd->iconf->ch_switch_he_config, offset, width, channel_width_to_string(width), cf1, cf2); if (!hapd->iface->current_mode) { @@ -919,16 +920,30 @@ void hostapd_event_ch_switch(struct host hapd->iconf->ieee80211n = ht; if (!ht) { hapd->iconf->ieee80211ac = 0; - } else if (hapd->iconf->ch_switch_vht_config) { - /* CHAN_SWITCH VHT config */ - if (hapd->iconf->ch_switch_vht_config & - CH_SWITCH_VHT_ENABLED) - hapd->iconf->ieee80211ac = 1; - else if (hapd->iconf->ch_switch_vht_config & - CH_SWITCH_VHT_DISABLED) - hapd->iconf->ieee80211ac = 0; + hapd->iconf->ieee80211ax = 0; + } else { + if (hapd->iconf->ch_switch_vht_config) { + /* CHAN_SWITCH VHT config */ + if (hapd->iconf->ch_switch_vht_config & + CH_SWITCH_VHT_ENABLED) + hapd->iconf->ieee80211ac = 1; + else if (hapd->iconf->ch_switch_vht_config & + CH_SWITCH_VHT_DISABLED) + hapd->iconf->ieee80211ac = 0; + } + if (hapd->iconf->ch_switch_he_config) { + /* CHAN_SWITCH HE config */ + if (hapd->iconf->ch_switch_he_config & + CH_SWITCH_HE_ENABLED){ + hapd->iconf->ieee80211ax = 1; + hapd->iconf->ieee80211ac = 1; + } else if (hapd->iconf->ch_switch_he_config & + CH_SWITCH_HE_DISABLED) + hapd->iconf->ieee80211ax = 0; + } } hapd->iconf->ch_switch_vht_config = 0; + hapd->iconf->ch_switch_he_config = 0; hapd->iconf->secondary_channel = offset; hostapd_set_oper_chwidth(hapd->iconf, chwidth); --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -627,7 +627,7 @@ void hostapd_channel_list_updated(struct void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s); const char * hostapd_state_text(enum hostapd_iface_state s); int hostapd_csa_in_progress(struct hostapd_iface *iface); -void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled); +void hostapd_chan_switch_config(struct hostapd_data *hapd, struct hostapd_freq_params *freq_params); int hostapd_switch_channel(struct hostapd_data *hapd, struct csa_settings *settings); void --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -4672,7 +4672,7 @@ static int nl80211_put_freq_params(struc nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, freq->center_freq2))) return -ENOBUFS; - } else if (freq->ht_enabled) { + } else if (freq->ht_enabled || (freq->he_enabled && is_24ghz)) { enum nl80211_channel_type ct; wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",