MBO: Improve supported operating class generation
authorJouni Malinen <j@w1.fi>
Thu, 30 Jun 2016 18:59:09 +0000 (21:59 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 30 Jun 2016 22:13:54 +0000 (01:13 +0300)
Previously, 2.4 GHz operating class 81 was not added for US due to not
all of the channels (1-13 in this operating class) being supported.
Still, this operating class is the main operating class in the global
table for 2.4 GHz and it is the only option for indicating support for
the 2.4 GHz band channels in US.

Change the supported operating class building rules to include all
operating classes for which at least one channel is enabled. In
addition, fix the 80, 80+80, and 160 MHz channel checks (checking the
center frequency channel was failing since it is not a valid 20 MHz
channel).

Signed-off-by: Jouni Malinen <j@w1.fi>
wpa_supplicant/mbo.c

index c37d547..dcf07a9 100644 (file)
@@ -532,9 +532,26 @@ static enum chan_allowed verify_channel(struct hostapd_hw_modes *mode,
                        return NOT_ALLOWED;
                res2 = allow_channel(mode, channel + 4, NULL);
        } else if (bw == BW80) {
-               res2 = verify_80mhz(mode, channel);
+               /*
+                * channel is a center channel and as such, not necessarily a
+                * valid 20 MHz channels. Override earlier allow_channel()
+                * result and use only the 80 MHz specific version.
+                */
+               res2 = res = verify_80mhz(mode, channel);
        } else if (bw == BW160) {
-               res2 = verify_160mhz(mode, channel);
+               /*
+                * channel is a center channel and as such, not necessarily a
+                * valid 20 MHz channels. Override earlier allow_channel()
+                * result and use only the 160 MHz specific version.
+                */
+               res2 = res = verify_160mhz(mode, channel);
+       } else if (bw == BW80P80) {
+               /*
+                * channel is a center channel and as such, not necessarily a
+                * valid 20 MHz channels. Override earlier allow_channel()
+                * result and use only the 80 MHz specific version.
+                */
+               res2 = res = verify_80mhz(mode, channel);
        }
 
        if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -550,38 +567,64 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
        int chan;
        size_t i;
        struct hostapd_hw_modes *mode;
+       int found;
 
        mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
        if (!mode)
                return 0;
 
-       if (op_class->op_class == 128 || op_class->op_class == 130) {
+       if (op_class->op_class == 128) {
                u8 channels[] = { 42, 58, 106, 122, 138, 155 };
 
+               found = 0;
                for (i = 0; i < ARRAY_SIZE(channels); i++) {
                        if (verify_channel(mode, channels[i], op_class->bw) ==
-                           NOT_ALLOWED)
-                               return 0;
+                           ALLOWED)
+                               return 1;
                }
 
-               return 1;
+               return 0;
        }
 
        if (op_class->op_class == 129) {
-               if (verify_channel(mode, 50, op_class->bw) == NOT_ALLOWED ||
-                   verify_channel(mode, 114, op_class->bw) == NOT_ALLOWED)
-                       return 0;
+               /* Check if either 160 MHz channels is allowed */
+               return verify_channel(mode, 50, op_class->bw) == ALLOWED ||
+                       verify_channel(mode, 114, op_class->bw) == ALLOWED;
+       }
+
+       if (op_class->op_class == 130) {
+               /* Need at least two non-contiguous 80 MHz segments */
+               found = 0;
+
+               if (verify_channel(mode, 42, op_class->bw) == ALLOWED ||
+                   verify_channel(mode, 58, op_class->bw) == ALLOWED)
+                       found++;
+               if (verify_channel(mode, 106, op_class->bw) == ALLOWED ||
+                   verify_channel(mode, 122, op_class->bw) == ALLOWED ||
+                   verify_channel(mode, 138, op_class->bw) == ALLOWED)
+                       found++;
+               if (verify_channel(mode, 106, op_class->bw) == ALLOWED &&
+                   verify_channel(mode, 138, op_class->bw) == ALLOWED)
+                       found++;
+               if (verify_channel(mode, 155, op_class->bw) == ALLOWED)
+                       found++;
+
+               if (found >= 2)
+                       return 1;
 
-               return 1;
+               return 0;
        }
 
+       found = 0;
        for (chan = op_class->min_chan; chan <= op_class->max_chan;
             chan += op_class->inc) {
-               if (verify_channel(mode, chan, op_class->bw) == NOT_ALLOWED)
-                       return 0;
+               if (verify_channel(mode, chan, op_class->bw) == ALLOWED) {
+                       found = 1;
+                       break;
+               }
        }
 
-       return 1;
+       return found;
 }