diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index b8a54457b..4cbe45190 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -146,7 +146,8 @@ ssid=test # Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz), # g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used # with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this -# needs to be set to hw_mode=a. When using ACS (see channel parameter), a +# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6 GHz this needs +# to be set to hw_mode=a. When using ACS (see channel parameter), a # special value "any" can be used to indicate that any support band can be used. # This special case is currently supported only with drivers with which # offloaded ACS is used. @@ -805,6 +806,11 @@ wmm_ac_vo_acm=0 #he_rts_threshold=0 # HE operating channel information; see matching vht_* parameters for details. +# On the 6 GHz band the center freq calculation starts from 5.940 GHz offset. +# For example idx=3 would result in 5955 MHz center frequency. In addition, +# he_oper_chwidth is ignored, and the channel width is derived from the +# configured operating class or center frequency indexes (see +# IEEE P802.11ax/D4.3 Annex E, Table E-4). #he_oper_chwidth #he_oper_centr_freq_seg0_idx #he_oper_centr_freq_seg1_idx diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c index 57f5e3981..1ad8d7c3e 100644 --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -385,6 +385,71 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, hostapd_encode_edmg_chan(enable_edmg, edmg_channel, channel, &data->edmg); + if (is_6ghz_freq(freq)) { + if (!data->he_enabled) { + wpa_printf(MSG_ERROR, + "Can't set 6 GHz mode - HE isn't enabled"); + return -1; + } + + if (center_idx_to_bw_6ghz(channel) != 0) { + wpa_printf(MSG_ERROR, + "Invalid control channel for 6 GHz band"); + return -1; + } + + if (!center_segment0) { + if (center_segment1) { + wpa_printf(MSG_ERROR, + "Segment 0 center frequency isn't set"); + return -1; + } + + data->center_freq1 = data->freq; + data->bandwidth = 20; + } else { + int freq1, freq2 = 0; + int bw = center_idx_to_bw_6ghz(center_segment0); + + if (bw < 0) { + wpa_printf(MSG_ERROR, + "Invalid center frequency index for 6 GHz"); + return -1; + } + + freq1 = ieee80211_chan_to_freq(NULL, 131, + center_segment0); + if (freq1 < 0) { + wpa_printf(MSG_ERROR, + "Invalid segment 0 center frequency for 6 GHz"); + return -1; + } + + if (center_segment1) { + if (center_idx_to_bw_6ghz(center_segment1) != 2 || + bw != 2) { + wpa_printf(MSG_ERROR, + "6 GHz 80+80 MHz configuration doesn't use valid 80 MHz channels"); + return -1; + } + + freq2 = ieee80211_chan_to_freq(NULL, 131, + center_segment1); + if (freq2 < 0) { + wpa_printf(MSG_ERROR, + "Invalid segment 1 center frequency for UHB"); + return -1; + } + } + + data->bandwidth = (1 << (u8) bw) * 20; + data->center_freq1 = freq1; + data->center_freq2 = freq2; + } + + return 0; + } + if (data->vht_enabled) switch (oper_chwidth) { case CHANWIDTH_USE_HT: if (center_segment1 || diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 6bb5e4313..f75ce1e30 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -882,6 +882,19 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, return HOSTAPD_MODE_IEEE80211AD; } + if (freq > 5940 && freq <= 7105) { + int bw; + u8 idx = (freq - 5940) / 5; + + bw = center_idx_to_bw_6ghz(idx); + if (bw < 0) + return NUM_HOSTAPD_MODES; + + *channel = idx; + *op_class = 131 + bw; + return HOSTAPD_MODE_IEEE80211A; + } + return NUM_HOSTAPD_MODES; } @@ -1161,6 +1174,14 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) if (chan < 36 || chan > 128) return -1; return 5000 + 5 * chan; + case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */ + case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */ + 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.. */ + if (chan < 1 || chan > 233) + return -1; + return 5940 + chan * 5; case 180: /* 60 GHz band, channels 1..6 */ if (chan < 1 || chan > 6) return -1; @@ -1591,6 +1612,7 @@ 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, 130, 36, 161, 4, BW80P80, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP }, { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP } }; @@ -1905,6 +1927,37 @@ int oper_class_bw_to_int(const struct oper_class_map *map) } +int center_idx_to_bw_6ghz(u8 idx) +{ + /* channels: 1, 5, 9, 13... */ + if ((idx & 0x3) == 0x1) + return 0; /* 20 MHz */ + /* channels 3, 11, 19... */ + if ((idx & 0x7) == 0x3) + return 1; /* 40 MHz */ + /* channels 7, 23, 39.. */ + if ((idx & 0xf) == 0x7) + return 2; /* 80 MHz */ + /* channels 15, 47, 79...*/ + if ((idx & 0x1f) == 0xf) + return 3; /* 160 MHz */ + + return -1; +} + + +int is_6ghz_freq(int freq) +{ + if (freq < 5940 || freq > 7105) + return 0; + + if (center_idx_to_bw_6ghz((freq - 5940) / 5) < 0) + return 0; + + return 1; +} + + int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, size_t nei_rep_len) { diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 2452b82b9..d8b6fa216 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -220,6 +220,8 @@ u8 country_to_global_op_class(const char *country, u8 op_class); const struct oper_class_map * get_oper_class(const char *country, u8 op_class); int oper_class_bw_to_int(const struct oper_class_map *map); +int center_idx_to_bw_6ghz(u8 idx); +int is_6ghz_freq(int freq); int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, size_t nei_rep_len);