diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 85d4b720e..081723f7c 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -2416,6 +2416,9 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP }, + /* IEEE P802.11be/D5.0, Table E-4 (Global operating classes) */ + { HOSTAPD_MODE_IEEE80211A, 137, 31, 191, 32, BW320, NO_P2P_SUPP }, + /* * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes. * Class 180 has the legacy channels 1-6. Classes 181-183 include @@ -2737,6 +2740,8 @@ int oper_class_bw_to_int(const struct oper_class_map *map) case BW80P80: case BW160: return 160; + case BW320: + return 320; case BW2160: return 2160; default: diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 38cc09174..24be71b45 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -253,7 +253,7 @@ struct oper_class_map { u8 max_chan; u8 inc; enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80, - BW4320, BW6480, BW8640} bw; + BW320, BW4320, BW6480, BW8640} bw; enum { P2P_SUPP, NO_P2P_SUPP } p2p; }; diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c index b4ad3caef..d5742de7b 100644 --- a/wpa_supplicant/op_classes.c +++ b/wpa_supplicant/op_classes.c @@ -22,13 +22,12 @@ static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, unsigned int *flags) { int i; - bool is_6ghz = op_class >= 131 && op_class <= 136; + bool is_6ghz = is_6ghz_op_class(op_class); for (i = 0; i < mode->num_channels; i++) { bool chan_is_6ghz; - chan_is_6ghz = mode->channels[i].freq >= 5935 && - mode->channels[i].freq <= 7115; + chan_is_6ghz = is_6ghz_freq(mode->channels[i].freq); if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan) break; } @@ -187,6 +186,69 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode, } +static int get_center_320mhz(struct hostapd_hw_modes *mode, u8 channel, + const u8 *center_channels, size_t num_chan) +{ + unsigned int i; + + if (mode->mode != HOSTAPD_MODE_IEEE80211A || !mode->is_6ghz) + return 0; + + for (i = 0; i < num_chan; i++) { + /* + * In 320 MHz, the bandwidth "spans" 60 channels (e.g., 65-125), + * so the center channel is 30 channels away from the start/end. + */ + if (channel >= center_channels[i] - 30 && + channel <= center_channels[i] + 30) + return center_channels[i]; + } + + return 0; +} + + +static enum chan_allowed verify_320mhz(struct hostapd_hw_modes *mode, + u8 op_class, u8 channel) +{ + u8 center_chan; + unsigned int i; + bool no_ir = false; + const u8 *center_channels; + size_t num_chan; + const u8 center_channels_6ghz[] = { 31, 63, 95, 127, 159, 191 }; + + center_channels = center_channels_6ghz; + num_chan = ARRAY_SIZE(center_channels_6ghz); + + center_chan = get_center_320mhz(mode, channel, center_channels, + num_chan); + if (!center_chan) + return NOT_ALLOWED; + + /* Check all the channels are available */ + for (i = 0; i < 16; i++) { + unsigned int flags; + u8 adj_chan = center_chan - 30 + i * 4; + + if (allow_channel(mode, op_class, adj_chan, &flags) == + NOT_ALLOWED) + return NOT_ALLOWED; + + if (!(flags & HOSTAPD_CHAN_EHT_320MHZ_SUBCHANNEL)) + return NOT_ALLOWED; + + if (flags & HOSTAPD_CHAN_NO_IR) + no_ir = true; + } + + if (no_ir) + return NO_IR; + + return ALLOWED; +} + + enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class, u8 channel, u8 bw) { @@ -228,6 +290,13 @@ enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class, * result and use only the 80 MHz specific version. */ res2 = res = verify_80mhz(mode, op_class, channel); + } else if (bw == BW320) { + /* + * channel is a center channel and as such, not necessarily a + * valid 20 MHz channels. Override earlier allow_channel() + * result and use only the 320 MHz specific version. + */ + res2= res = verify_320mhz(mode, op_class, channel); } if (res == NOT_ALLOWED || res2 == NOT_ALLOWED) diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c index 9673b29de..2ec43105c 100644 --- a/wpa_supplicant/rrm.c +++ b/wpa_supplicant/rrm.c @@ -515,6 +515,8 @@ static int * wpas_add_channels(const struct oper_class_map *op, num_primary_channels = 4; else if (op->bw == BW160) num_primary_channels = 8; + else if (op->bw == BW320) + num_primary_channels = 16; else num_primary_channels = 1; @@ -561,6 +563,7 @@ static int * wpas_op_class_freqs(const struct oper_class_map *op, u8 channels_80mhz_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183, 199, 215 }; u8 channels_160mhz_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 }; + u8 channels_320mhz_6ghz[] = { 31, 63, 95, 127, 159, 191 }; const u8 *channels = NULL; size_t num_chan = 0; bool is_6ghz = is_6ghz_op_class(op->op_class); @@ -579,6 +582,9 @@ static int * wpas_op_class_freqs(const struct oper_class_map *op, channels_160mhz_5ghz; num_chan = is_6ghz ? ARRAY_SIZE(channels_160mhz_6ghz) : ARRAY_SIZE(channels_160mhz_5ghz); + } else if (op->bw == BW320) { + channels = channels_320mhz_6ghz; + num_chan = ARRAY_SIZE(channels_320mhz_6ghz); } return wpas_add_channels(op, mode, channels, num_chan);