]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
2-octet operating classes in Support Operating Classes element
authorJouni Malinen <quic_jouni@quicinc.com>
Tue, 5 Mar 2024 14:07:22 +0000 (16:07 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 5 Mar 2024 14:24:35 +0000 (16:24 +0200)
A previous workaround was used to move the special operating class 130
to the end of the Supported Operating Classes element to avoid getting
any following entry being ignored or misunderstood. That is not really
the correct way of encoding the special cases, i.e., 80+80 MHz channels
that use two nonadjacent frequency segments.

Add support for encoding the 80+80 MHz channel with the 2-octet
operating class design using the Operating Class Duple sequence field of
the Supported Operating Classes element instead of listing the operating
classes that have the 80+ behavior limit set indication in Table E-4
(i.e., opclass 130 and 135) as 1-octet operating classes in the
Operating Classes field.

Fixes: a92660a00e10 ("Work around Supported Operating Classes element issues for 6 GHz")
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
wpa_supplicant/op_classes.c

index 081723f7ca1cbd4fd6f2d9c474582492c821b023..0b2ad61f51877762fc2665b78f76553a59966e8d 100644 (file)
@@ -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 }
 };
 
index 24be71b456a7684c174f99e9631a797a8ddb0304..da057bdb294c465165f06c6d90c3b74782800f61 100644 (file)
@@ -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);
index d5742de7b3581265c4bb2372e27a310526fbd613..9eba67160e2fbf7ae52964a24490d0079e4445c7 100644 (file)
@@ -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;