diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 081723f7c..0b2ad61f5 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -2040,6 +2040,13 @@ int is_dfs_global_op_class(u8 op_class) } +bool is_80plus_op_class(u8 op_class) +{ + /* Operating classes with "80+" behavior indication in Table E-4 */ + return op_class == 130 || op_class == 135; +} + + static int is_11b(u8 rate) { return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; @@ -2406,9 +2413,17 @@ const struct oper_class_map global_op_class[] = { * channel center frequency index value, but it happens to be a 20 MHz * channel and the channel number in the channel set would match the * value in for the frequency center. + * + * Operating class value pair 128 and 130 is used to describe a 80+80 + * MHz channel on the 5 GHz band. 130 is identified with "80+", so this + * is encoded with two octets 130 and 128. Similarly, operating class + * value pair 133 and 135 is used to describe a 80+80 MHz channel on + * the 6 GHz band (135 being the one with "80+" indication). All other + * operating classes listed here are used as 1-octet values. */ { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, P2P_SUPP }, @@ -2429,11 +2444,6 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP }, - /* Keep the operating class 130 as the last entry as a workaround for - * the OneHundredAndThirty Delimiter value used in the Supported - * Operating Classes element to indicate the end of the Operating - * Classes field. */ - { HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP }, { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP } }; diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 24be71b45..da057bdb2 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -235,6 +235,7 @@ int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, u16 num_modes); int is_dfs_global_op_class(u8 op_class); +bool is_80plus_op_class(u8 op_class); enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht); int supp_rates_11b_only(struct ieee802_11_elems *elems); diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c index d5742de7b..9eba67160 100644 --- a/wpa_supplicant/op_classes.c +++ b/wpa_supplicant/op_classes.c @@ -522,6 +522,7 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, u8 op, current, chan; u8 *ie_len; size_t res; + bool op128 = false, op130 = false, op133 = false, op135 = false; /* * Determine the current operating class correct mode based on @@ -549,8 +550,50 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, wpabuf_put_u8(buf, current); for (op = 0; global_op_class[op].op_class; op++) { - if (wpas_op_class_supported(wpa_s, ssid, &global_op_class[op])) - wpabuf_put_u8(buf, global_op_class[op].op_class); + bool supp; + u8 op_class = global_op_class[op].op_class; + + supp = wpas_op_class_supported(wpa_s, ssid, + &global_op_class[op]); + if (!supp) + continue; + switch (op_class) { + case 128: + op128 = true; + break; + case 130: + op130 = true; + break; + case 133: + op133 = true; + break; + case 135: + op135 = true; + break; + } + if (is_80plus_op_class(op_class)) + continue; + + /* Add a 1-octet operating class to the Operating Class field */ + wpabuf_put_u8(buf, global_op_class[op].op_class); + } + + /* Add the 2-octet operating classes (i.e., 80+80 MHz cases), if any */ + if ((op128 && op130) || (op133 && op135)) { + /* Operating Class Duple Sequence field */ + + /* Zero Delimiter */ + wpabuf_put_u8(buf, 0); + + /* Operating Class Duple List */ + if (op128 && op130) { + wpabuf_put_u8(buf, 130); + wpabuf_put_u8(buf, 128); + } + if (op133 && op135) { + wpabuf_put_u8(buf, 135); + wpabuf_put_u8(buf, 133); + } } *ie_len = wpabuf_len(buf) - 2;