]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
6 GHz: Add support for missing 6 GHz operating classes
authorVeerendranath Jakkam <vjakkam@codeaurora.org>
Wed, 16 Sep 2020 08:21:47 +0000 (13:51 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 30 Oct 2020 20:52:47 +0000 (22:52 +0200)
Add support for missing 6 GHz operating classes as defined in
IEEE P802.11ax/D7.0.

This is needed to avoid OCV failures on the 6 GHz band when the channel
width is larger than 20 MHz.

Signed-off-by: Veerendranath Jakkam <vjakkam@codeaurora.org>
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/common/ocv.c
wpa_supplicant/op_classes.c
wpa_supplicant/rrm.c

index 471db43c7b96f1a4e2912e78294e35709dd70265..9b3782e265c2c93fa3096dcab7c2a1782902b9e5 100644 (file)
@@ -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;
index 0ddba06924c2f505abc8e89ffb013972d11d6ef8..0ae0fa4d1b2b0fae828ef738a5b384f21c378185 100644 (file)
@@ -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;
 };
 
index 4bc2749a7cc36d64605620a78a184f74506edfb0..c9dc14fa6c09352b799a3a03825530e69da5e0a1 100644 (file)
@@ -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;
 }
index 91e15e7995538421193d10cd23cab013b8bc4ef5..461ae545838905dbface8c8257f4a5d7ad1e05f7 100644 (file)
@@ -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 };
+
+       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_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 };
+
+       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_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) {
index afc11727572400995f6195faa7d41b7631fb3013..f0872663617819f03db171fa33f93a254975ad85 100644 (file)
@@ -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 == BW160)
-               return wpas_add_channels(op, mode, active, channels_160mhz,
-                                        ARRAY_SIZE(channels_160mhz));
+       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);
+       }
 
-       return wpas_add_channels(op, mode, active, NULL, 0);
+       return wpas_add_channels(op, mode, active, channels, num_chan);
 }