diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 664c59df7..4e464da73 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -2527,6 +2527,9 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, case 160: bandwidth = CHAN_WIDTH_160; break; + case 320: + bandwidth = CHAN_WIDTH_320; + break; default: bandwidth = CHAN_WIDTH_20; break; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 876a1bbd9..9b9212feb 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -1163,6 +1163,8 @@ hostapd_set_oper_chwidth(struct hostapd_config *conf, #ifdef CONFIG_IEEE80211BE if (conf->ieee80211be) conf->eht_oper_chwidth = oper_chwidth; + if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) + oper_chwidth = CONF_OPER_CHWIDTH_160MHZ; #endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) @@ -1192,6 +1194,9 @@ hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf, #ifdef CONFIG_IEEE80211BE if (conf->ieee80211be) conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx; + if (center_idx_to_bw_6ghz(oper_centr_freq_seg0_idx) == 4) + oper_centr_freq_seg0_idx += + conf->channel > oper_centr_freq_seg0_idx ? 16 : -16; #endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index a7079f6ab..87c3b9006 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -986,6 +986,8 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ || oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) params.ch_width = 160; + else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) + params.ch_width = 320; } if (hapd->iface->conf->op_class) diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 4b321a9b9..a673fae09 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -838,6 +838,9 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr, case CHAN_WIDTH_160: txt = "160"; break; + case CHAN_WIDTH_320: + txt = "320"; + break; default: txt = NULL; break; @@ -899,6 +902,9 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, case CHAN_WIDTH_160: chwidth = CONF_OPER_CHWIDTH_160MHZ; break; + case CHAN_WIDTH_320: + chwidth = CONF_OPER_CHWIDTH_320MHZ; + break; case CHAN_WIDTH_20_NOHT: case CHAN_WIDTH_20: case CHAN_WIDTH_40: @@ -1173,6 +1179,15 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd, } } +#ifdef CONFIG_IEEE80211BE + if (hapd->iface->conf->ieee80211be && acs_res->ch_width == 320) { + hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_320MHZ); + hostapd_set_oper_centr_freq_seg0_idx( + hapd->iconf, acs_res->vht_seg1_center_ch); + hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0); + } +#endif /* CONFIG_IEEE80211BE */ + out: ret = hostapd_acs_completed(hapd->iface, err); if (ret) { diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index f6e45274b..05faa0f14 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -3516,6 +3516,9 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, case 160: hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_160MHZ); break; + case 320: + hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_320MHZ); + break; default: return -1; } @@ -3715,6 +3718,9 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, case 160: bw = CONF_OPER_CHWIDTH_160MHZ; break; + case 320: + bw = CONF_OPER_CHWIDTH_320MHZ; + break; default: wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d", freq_params->bandwidth); diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index cbd659219..ed5ff41d3 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -1087,13 +1087,14 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G || iface->conf->ieee80211n || iface->conf->ieee80211ac || - iface->conf->ieee80211ax) && + iface->conf->ieee80211ax || iface->conf->ieee80211be) && iface->conf->channel == 14) { - wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14"); + wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE/EHT on channel 14"); iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B; iface->conf->ieee80211n = 0; iface->conf->ieee80211ac = 0; iface->conf->ieee80211ax = 0; + iface->conf->ieee80211be = 0; } iface->current_mode = NULL; diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c index 547ccd329..ec36a9e7a 100644 --- a/src/ap/ieee802_11_eht.c +++ b/src/ap/ieee802_11_eht.c @@ -197,9 +197,7 @@ u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid) seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf); switch (chwidth) { -#if 0 /* FIX: Need to clean up CHANWIDTH_* use for protocol vs. internal - * needs to be able to define this. */ - case CHANWIDTH_320MHZ: + case CONF_OPER_CHWIDTH_320MHZ: oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_320MHZ; seg1 = seg0; if (hapd->iconf->channel < seg0) @@ -207,7 +205,6 @@ u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid) else seg0 += 16; break; -#endif case CONF_OPER_CHWIDTH_160MHZ: oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ; seg1 = seg0; @@ -286,10 +283,12 @@ static bool check_valid_eht_mcs(struct hostapd_data *hapd, EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY); switch (hapd->iface->conf->eht_oper_chwidth) { - /* TODO: CHANWIDTH_320MHZ */ + case CONF_OPER_CHWIDTH_320MHZ: + mcs_count++; + /* fall through */ case CONF_OPER_CHWIDTH_80P80MHZ: case CONF_OPER_CHWIDTH_160MHZ: - mcs_count = 2; + mcs_count++; break; default: break; diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c index e9be2d3ed..b5b7e5d46 100644 --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -219,7 +219,7 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) pos += 6; /* skip the fixed part */ if (is_6ghz_op_class(hapd->iconf->op_class)) { - u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf); + u8 seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx; u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf); u8 control; diff --git a/src/common/defs.h b/src/common/defs.h index ce7487988..4e6305382 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -429,6 +429,7 @@ enum chan_width { CHAN_WIDTH_4320, CHAN_WIDTH_6480, CHAN_WIDTH_8640, + CHAN_WIDTH_320, CHAN_WIDTH_UNKNOWN }; @@ -445,6 +446,7 @@ enum oper_chan_width { CONF_OPER_CHWIDTH_6480MHZ, CONF_OPER_CHWIDTH_8640MHZ, CONF_OPER_CHWIDTH_40MHZ_6GHZ, + CONF_OPER_CHWIDTH_320MHZ, }; enum key_flag { diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c index e2bf3afc6..6646301df 100644 --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -392,6 +392,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, { if (!he_cap || !he_cap->he_supported) he_enabled = 0; + if (!eht_cap || !eht_cap->eht_supported) + eht_enabled = 0; os_memset(data, 0, sizeof(*data)); data->mode = mode; data->freq = freq; @@ -408,6 +410,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ || oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) data->bandwidth = 160; + else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) + data->bandwidth = 320; else if (sec_channel_offset) data->bandwidth = 40; else @@ -483,9 +487,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return 0; } -#if 0 /* FIX: Figure out how to handle CHANWIDTH_320MHZ */ if (data->eht_enabled) switch (oper_chwidth) { - case CHANWIDTH_320MHZ: + case CONF_OPER_CHWIDTH_320MHZ: if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] & EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) { wpa_printf(MSG_ERROR, @@ -493,8 +496,9 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return -1; } break; + default: + break; } -#endif if (data->he_enabled || data->eht_enabled) switch (oper_chwidth) { case CONF_OPER_CHWIDTH_USE_HT: @@ -673,6 +677,41 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return -1; } break; + case CONF_OPER_CHWIDTH_320MHZ: + data->bandwidth = 320; + if (!data->eht_enabled || !is_6ghz_freq(freq)) { + wpa_printf(MSG_ERROR, + "320 MHz: EHT not enabled or not a 6 GHz channel"); + return -1; + } + if (center_segment1) { + wpa_printf(MSG_ERROR, + "320 MHz: center segment 1 should not be set"); + return -1; + } + if (center_segment0 == channel + 30 || + center_segment0 == channel + 26 || + center_segment0 == channel + 22 || + center_segment0 == channel + 18 || + center_segment0 == channel + 14 || + center_segment0 == channel + 10 || + center_segment0 == channel + 6 || + center_segment0 == channel + 2 || + center_segment0 == channel - 2 || + center_segment0 == channel - 6 || + center_segment0 == channel - 10 || + center_segment0 == channel - 14 || + center_segment0 == channel - 18 || + center_segment0 == channel - 22 || + center_segment0 == channel - 26 || + center_segment0 == channel - 30) + data->center_freq1 = 5000 + center_segment0 * 5; + else { + wpa_printf(MSG_ERROR, + "320 MHz: wrong center segment 0"); + return -1; + } + break; default: break; } @@ -785,6 +824,7 @@ u32 num_chan_to_bw(int num_chans) case 2: case 4: case 8: + case 16: return num_chans * 20; default: return 20; @@ -818,6 +858,9 @@ int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw, case 160: bw_mask = HOSTAPD_CHAN_WIDTH_160; break; + case 320: + bw_mask = HOSTAPD_CHAN_WIDTH_320; + break; default: bw_mask = 0; break; diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index dfc035df7..c8ee90cd7 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1060,6 +1060,9 @@ ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel, case CONF_OPER_CHWIDTH_80P80MHZ: *op_class = 135; break; + case CONF_OPER_CHWIDTH_320MHZ: + *op_class = 137; + break; default: if (sec_channel) *op_class = 132; @@ -1157,6 +1160,9 @@ int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, case CHAN_WIDTH_8640: cw = CONF_OPER_CHWIDTH_8640MHZ; break; + case CHAN_WIDTH_320: + cw = CONF_OPER_CHWIDTH_320MHZ; + break; } if (ieee80211_freq_to_channel_ext(freq, sec_channel, cw, op_class, @@ -1452,6 +1458,7 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */ + case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */ if (chan < 1 || chan > 233) return -1; return 5950 + chan * 5; @@ -2265,6 +2272,9 @@ int center_idx_to_bw_6ghz(u8 idx) /* channels 15, 47, 79...*/ if ((idx & 0x1f) == 0xf) return 3; /* 160 MHz */ + /* channels 31, 63, 95, 127, 159, 191 */ + if ((idx & 0x1f) == 0x1f && idx < 192) + return 4; /* 320 MHz */ return -1; } @@ -2287,7 +2297,7 @@ bool is_6ghz_freq(int freq) bool is_6ghz_op_class(u8 op_class) { - return op_class >= 131 && op_class <= 136; + return op_class >= 131 && op_class <= 137; } @@ -2593,6 +2603,8 @@ int op_class_to_bandwidth(u8 op_class) return 160; case 136: /* UHB channels, 20 MHz: 2 */ return 20; + case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */ + return 320; case 180: /* 60 GHz band, channels 1..8 */ return 2160; case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */ @@ -2655,6 +2667,8 @@ enum oper_chan_width op_class_to_ch_width(u8 op_class) return CONF_OPER_CHWIDTH_80P80MHZ; case 136: /* UHB channels, 20 MHz: 2 */ return CONF_OPER_CHWIDTH_USE_HT; + case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */ + return CONF_OPER_CHWIDTH_320MHZ; case 180: /* 60 GHz band, channels 1..8 */ return CONF_OPER_CHWIDTH_2160MHZ; case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index f069b74e1..52ee8dfdd 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -66,6 +66,7 @@ enum hostapd_chan_width_attr { HOSTAPD_CHAN_WIDTH_40M = BIT(3), HOSTAPD_CHAN_WIDTH_80 = BIT(4), HOSTAPD_CHAN_WIDTH_160 = BIT(5), + HOSTAPD_CHAN_WIDTH_320 = BIT(6), }; /* Filter gratuitous ARP */ diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 8db786168..84e6a9ebd 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -117,6 +117,8 @@ const char * channel_width_to_string(enum chan_width width) return "80+80 MHz"; case CHAN_WIDTH_160: return "160 MHz"; + case CHAN_WIDTH_320: + return "320 MHz"; default: return "unknown"; } @@ -136,6 +138,8 @@ int channel_width_to_int(enum chan_width width) case CHAN_WIDTH_80P80: case CHAN_WIDTH_160: return 160; + case CHAN_WIDTH_320: + return 320; default: return 0; } diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 60e44a1a9..78c0658a0 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -215,6 +215,8 @@ enum chan_width convert2width(int width) return CHAN_WIDTH_80P80; case NL80211_CHAN_WIDTH_160: return CHAN_WIDTH_160; + case NL80211_CHAN_WIDTH_320: + return CHAN_WIDTH_320; } return CHAN_WIDTH_UNKNOWN; } @@ -4941,6 +4943,9 @@ static int nl80211_put_freq_params(struct nl_msg *msg, case 160: cw = NL80211_CHAN_WIDTH_160; break; + case 320: + cw = NL80211_CHAN_WIDTH_320; + break; default: return -EINVAL; } diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 00f8b0cbb..70a10655d 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -674,6 +674,9 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2) case CHAN_WIDTH_80P80: freq1 = cf1 - 30; break; + case CHAN_WIDTH_320: + freq1 = cf1 - 150; + break; case CHAN_WIDTH_UNKNOWN: case CHAN_WIDTH_2160: case CHAN_WIDTH_4320: @@ -2791,6 +2794,9 @@ static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv, case NL80211_CHAN_WIDTH_160: ed.sta_opmode.chan_width = CHAN_WIDTH_160; break; + case NL80211_CHAN_WIDTH_320: + ed.sta_opmode.chan_width = CHAN_WIDTH_320; + break; default: ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN; break; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 2bbbaab20..7adb7687b 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -5989,6 +5989,8 @@ static int parse_freq(int chwidth, int freq2) return CONF_OPER_CHWIDTH_80MHZ; case 160: return CONF_OPER_CHWIDTH_160MHZ; + case 320: + return CONF_OPER_CHWIDTH_320MHZ; default: wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d", chwidth);