diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 471db43c7..9b3782e26 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1886,6 +1886,11 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP }, /* * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes. @@ -2199,6 +2204,7 @@ int oper_class_bw_to_int(const struct oper_class_map *map) switch (map->bw) { case BW20: return 20; + case BW40: case BW40PLUS: case BW40MINUS: return 40; diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 0ddba0692..0ae0fa4d1 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -232,8 +232,8 @@ struct oper_class_map { u8 min_chan; u8 max_chan; u8 inc; - enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80, BW4320, - BW6480, BW8640} bw; + enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80, + BW4320, BW6480, BW8640} bw; enum { P2P_SUPP, NO_P2P_SUPP } p2p; }; diff --git a/src/common/ocv.c b/src/common/ocv.c index 4bc2749a7..c9dc14fa6 100644 --- a/src/common/ocv.c +++ b/src/common/ocv.c @@ -45,6 +45,8 @@ int ocv_derive_all_parameters(struct oci_info *oci) oci->sec_channel = 1; else if (op_class_map->bw == BW40MINUS) oci->sec_channel = -1; + else if (op_class_map->bw == BW40) + oci->sec_channel = (((oci->channel - 1) / 4) % 2) ? -1 : 1; return 0; } diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c index 91e15e799..461ae5458 100644 --- a/wpa_supplicant/op_classes.c +++ b/wpa_supplicant/op_classes.c @@ -47,15 +47,15 @@ static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, } -static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel) +static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel, + const u8 *center_channels, size_t num_chan) { - u8 center_channels[] = { 42, 58, 106, 122, 138, 155 }; size_t i; if (mode->mode != HOSTAPD_MODE_IEEE80211A) return 0; - for (i = 0; i < ARRAY_SIZE(center_channels); i++) { + for (i = 0; i < num_chan; i++) { /* * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48), * so the center channel is 6 channels away from the start/end. @@ -75,8 +75,22 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 center_chan; unsigned int i; unsigned int no_ir = 0; + const u8 *center_channels; + size_t num_chan; + const u8 center_channels_5ghz[] = { 42, 58, 106, 122, 138, 155 }; + const u8 center_channels_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119, + 135, 151, 167, 183, 199, 215 }; - center_chan = get_center_80mhz(mode, channel); + if (is_6ghz_op_class(op_class)) { + center_channels = center_channels_6ghz; + num_chan = ARRAY_SIZE(center_channels_6ghz); + } else { + center_channels = center_channels_5ghz; + num_chan = ARRAY_SIZE(center_channels_5ghz); + } + + center_chan = get_center_80mhz(mode, channel, center_channels, + num_chan); if (!center_chan) return NOT_ALLOWED; @@ -106,15 +120,15 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, } -static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel) +static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel, + const u8 *center_channels, size_t num_chan) { - u8 center_channels[] = { 50, 114 }; unsigned int i; if (mode->mode != HOSTAPD_MODE_IEEE80211A) return 0; - for (i = 0; i < ARRAY_SIZE(center_channels); i++) { + for (i = 0; i < num_chan; i++) { /* * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64), * so the center channel is 14 channels away from the start/end. @@ -134,8 +148,21 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode, u8 center_chan; unsigned int i; unsigned int no_ir = 0; + const u8 *center_channels; + size_t num_chan; + const u8 center_channels_5ghz[] = { 50, 114 }; + const u8 center_channels_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 }; - center_chan = get_center_160mhz(mode, channel); + if (is_6ghz_op_class(op_class)) { + center_channels = center_channels_6ghz; + num_chan = ARRAY_SIZE(center_channels_6ghz); + } else { + center_channels = center_channels_5ghz; + num_chan = ARRAY_SIZE(center_channels_5ghz); + } + + center_chan = get_center_160mhz(mode, channel, center_channels, + num_chan); if (!center_chan) return NOT_ALLOWED; @@ -176,11 +203,12 @@ enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class, enum chan_allowed res, res2; res2 = res = allow_channel(mode, op_class, channel, &flag); - if (bw == BW40MINUS) { + if (bw == BW40MINUS || (bw == BW40 && (((channel - 1) / 4) % 2))) { if (!(flag & HOSTAPD_CHAN_HT40MINUS)) return NOT_ALLOWED; res2 = allow_channel(mode, op_class, channel - 4, NULL); - } else if (bw == BW40PLUS) { + } else if (bw == BW40PLUS || + (bw == BW40 && !(((channel - 1) / 4) % 2))) { if (!(flag & HOSTAPD_CHAN_HT40PLUS)) return NOT_ALLOWED; res2 = allow_channel(mode, op_class, channel + 4, NULL); @@ -343,6 +371,41 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s, return 0; } + if (op_class->op_class == 135) { + /* Need at least two 80 MHz segments which do not fall under the + * same 160 MHz segment to support 80+80 in 6 GHz. + */ + int first_seg = 0; + int curr_seg = 0; + + for (chan = op_class->min_chan; chan <= op_class->max_chan; + chan += op_class->inc) { + curr_seg++; + if (verify_channel(mode, op_class->op_class, chan, + op_class->bw) != NOT_ALLOWED) { + if (!first_seg) { + first_seg = curr_seg; + continue; + } + + /* Supported if at least two non-consecutive 80 + * MHz segments allowed. + */ + if ((curr_seg - first_seg) > 1) + return 1; + + /* Supported even if the 80 MHz segments are + * consecutive when they do not fall under the + * same 160 MHz segment. + */ + if ((first_seg % 2) == 0) + return 1; + } + } + + return 0; + } + found = 0; for (chan = op_class->min_chan; chan <= op_class->max_chan; chan += op_class->inc) { diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c index afc117275..f08726636 100644 --- a/wpa_supplicant/rrm.c +++ b/wpa_supplicant/rrm.c @@ -556,23 +556,32 @@ static int * wpas_add_channels(const struct oper_class_map *op, static int * wpas_op_class_freqs(const struct oper_class_map *op, struct hostapd_hw_modes *mode, int active) { - u8 channels_80mhz[] = { 42, 58, 106, 122, 138, 155 }; - u8 channels_160mhz[] = { 50, 114 }; + u8 channels_80mhz_5ghz[] = { 42, 58, 106, 122, 138, 155 }; + u8 channels_160mhz_5ghz[] = { 50, 114 }; + 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 }; + const u8 *channels = NULL; + size_t num_chan = 0; + int is_6ghz = is_6ghz_op_class(op->op_class); /* * When adding all channels in the operating class, 80 + 80 MHz * operating classes are like 80 MHz channels because we add all valid * channels anyway. */ - if (op->bw == BW80 || op->bw == BW80P80) - return wpas_add_channels(op, mode, active, channels_80mhz, - ARRAY_SIZE(channels_80mhz)); + if (op->bw == BW80 || op->bw == BW80P80) { + channels = is_6ghz ? channels_80mhz_6ghz : channels_80mhz_5ghz; + num_chan = is_6ghz ? ARRAY_SIZE(channels_80mhz_6ghz) : + ARRAY_SIZE(channels_80mhz_5ghz); + } else if (op->bw == BW160) { + channels = is_6ghz ? channels_160mhz_6ghz : + channels_160mhz_5ghz; + num_chan = is_6ghz ? ARRAY_SIZE(channels_160mhz_6ghz) : + ARRAY_SIZE(channels_160mhz_5ghz); + } - if (op->bw == BW160) - return wpas_add_channels(op, mode, active, channels_160mhz, - ARRAY_SIZE(channels_160mhz)); - - return wpas_add_channels(op, mode, active, NULL, 0); + return wpas_add_channels(op, mode, active, channels, num_chan); }