]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P: Extend channel determination/validation to 6 GHz channels
authorSreeramya Soratkal <ssramya@codeaurora.org>
Tue, 4 May 2021 07:09:39 +0000 (12:39 +0530)
committerJouni Malinen <j@w1.fi>
Thu, 10 Jun 2021 20:43:03 +0000 (23:43 +0300)
Extend the previously 5 GHz specific 80 and 160 MHz channels helper
functions to support 6 GHz channels.

Signed-off-by: Sreeramya Soratkal <ssramya@codeaurora.org>
src/common/ieee802_11_common.c
src/drivers/driver_nl80211_event.c
wpa_supplicant/ap.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h

index 96681843e2582d2aec1122708d526d831291a1d2..3e5cfb01d5651790a7e3ba4540e269e4718fad85 100644 (file)
@@ -1894,7 +1894,7 @@ const struct oper_class_map global_op_class[] = {
         */
        { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP },
        { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP },
-       { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, NO_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 },
index d19586f06ead38533f2bb77af9da62a141216d03..0f0a01d0180bcb191d9393f603a31ef109b0e0f3 100644 (file)
@@ -1329,7 +1329,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
        struct nlattr *nl;
        int rem;
        struct scan_info *info;
-#define MAX_REPORT_FREQS 50
+#define MAX_REPORT_FREQS 100
        int freqs[MAX_REPORT_FREQS];
        int num_freqs = 0;
 
@@ -1361,7 +1361,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
                }
        }
        if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
-               char msg[300], *pos, *end;
+               char msg[500], *pos, *end;
                int res;
 
                pos = msg;
@@ -2273,7 +2273,7 @@ static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv,
        }
 
        if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
-               char msg[300], *pos, *end;
+               char msg[500], *pos, *end;
                int res;
 
                pos = msg;
index cfefa48d443e6bed1b875a6784a3120433e758b8..a2bd08d4c16ae1ca05a8dce5a6cdded2dcf79d04 100644 (file)
@@ -109,13 +109,15 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
        switch (hostapd_get_oper_chwidth(conf)) {
        case CHANWIDTH_80MHZ:
        case CHANWIDTH_80P80MHZ:
-               center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+               center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel,
+                                                       conf->op_class);
                wpa_printf(MSG_DEBUG,
                           "VHT center channel %u for 80 or 80+80 MHz bandwidth",
                           center_chan);
                break;
        case CHANWIDTH_160MHZ:
-               center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+               center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel,
+                                                        conf->op_class);
                wpa_printf(MSG_DEBUG,
                           "VHT center channel %u for 160 MHz bandwidth",
                           center_chan);
@@ -127,15 +129,25 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
                 * not supported.
                 */
                hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
-               center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+               ieee80211_freq_to_channel_ext(ssid->frequency, 0,
+                                             conf->vht_oper_chwidth,
+                                             &conf->op_class,
+                                             &conf->channel);
+               center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel,
+                                                        conf->op_class);
                if (center_chan && is_chanwidth160_supported(mode, conf)) {
                        wpa_printf(MSG_DEBUG,
                                   "VHT center channel %u for auto-selected 160 MHz bandwidth",
                                   center_chan);
                } else {
                        hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
+                       ieee80211_freq_to_channel_ext(ssid->frequency, 0,
+                                                     conf->vht_oper_chwidth,
+                                                     &conf->op_class,
+                                                     &conf->channel);
                        center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
-                                                               channel);
+                                                               channel,
+                                                               conf->op_class);
                        wpa_printf(MSG_DEBUG,
                                   "VHT center channel %u for auto-selected 80 MHz bandwidth",
                                   center_chan);
@@ -183,9 +195,15 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
                              struct wpa_ssid *ssid,
                              struct hostapd_config *conf)
 {
-       conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
-                                              &conf->channel);
-
+       conf->hw_mode = ieee80211_freq_to_channel_ext(ssid->frequency, 0,
+                                                     ssid->max_oper_chwidth,
+                                                     &conf->op_class,
+                                                     &conf->channel);
+       /* ssid->max_oper_chwidth is not valid in all cases, so fall back to the
+        * less specific mechanism, if needed, at least for now */
+       if (conf->hw_mode == NUM_HOSTAPD_MODES)
+               conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+                                                      &conf->channel);
        if (conf->hw_mode == NUM_HOSTAPD_MODES) {
                wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
                           ssid->frequency);
index be1b396fe0826460b87d1a709e86d85e416feffe..df676552c7afe2af26de9c658948a584ca2b70b7 100644 (file)
@@ -3546,19 +3546,18 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
 
 
 static enum chan_allowed has_channel(struct wpa_global *global,
-                                    struct hostapd_hw_modes *mode, u8 chan,
-                                    int *flags)
+                                    struct hostapd_hw_modes *mode, u8 op_class,
+                                    u8 chan, int *flags)
 {
        int i;
        unsigned int freq;
 
-       freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
-               chan * 5;
+       freq = ieee80211_chan_to_freq(NULL, op_class, chan);
        if (wpas_p2p_disallowed_freq(global, freq))
                return NOT_ALLOWED;
 
        for (i = 0; i < mode->num_channels; i++) {
-               if (mode->channels[i].chan == chan) {
+               if ((unsigned int) mode->channels[i].freq == freq) {
                        if (flags)
                                *flags = mode->channels[i].flag;
                        if (mode->channels[i].flag &
@@ -3577,15 +3576,15 @@ static enum chan_allowed has_channel(struct wpa_global *global,
 
 static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
                                     struct hostapd_hw_modes *mode,
-                                    u8 channel)
+                                    u8 channel, const u8 *center_channels,
+                                    size_t num_chan)
 {
-       u8 center_channels[] = { 42, 58, 106, 122, 138, 155, 171 };
        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.
@@ -3598,25 +3597,43 @@ static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
 }
 
 
+static const u8 center_channels_5ghz_80mhz[] = { 42, 58, 106, 122, 138,
+                                                155, 171 };
+static const u8 center_channels_6ghz_80mhz[] = { 7, 23, 39, 55, 71, 87, 103,
+                                                119, 135, 151, 167, 183, 199,
+                                                215 };
+
 static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
                                               struct hostapd_hw_modes *mode,
-                                              u8 channel, u8 bw)
+                                              u8 op_class, u8 channel, u8 bw)
 {
        u8 center_chan;
        int i, flags;
        enum chan_allowed res, ret = ALLOWED;
+       const u8 *chans;
+       size_t num_chans;
+       bool is_6ghz = is_6ghz_op_class(op_class);
 
-       center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+       if (is_6ghz) {
+               chans = center_channels_6ghz_80mhz;
+               num_chans = ARRAY_SIZE(center_channels_6ghz_80mhz);
+       } else {
+               chans = center_channels_5ghz_80mhz;
+               num_chans = ARRAY_SIZE(center_channels_5ghz_80mhz);
+       }
+       center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel,
+                                               chans, num_chans);
        if (!center_chan)
                return NOT_ALLOWED;
-       if (center_chan >= 58 && center_chan <= 138)
+       if (!is_6ghz && center_chan >= 58 && center_chan <= 138)
                return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
 
        /* check all the channels are available */
        for (i = 0; i < 4; i++) {
                int adj_chan = center_chan - 6 + i * 4;
 
-               res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+               res = has_channel(wpa_s->global, mode, op_class, adj_chan,
+                                 &flags);
                if (res == NOT_ALLOWED)
                        return NOT_ALLOWED;
                if (res == NO_IR)
@@ -3638,15 +3655,15 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
 
 static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s,
                                     struct hostapd_hw_modes *mode,
-                                    u8 channel)
+                                    u8 channel, const u8 *center_channels,
+                                    size_t num_chan)
 {
-       u8 center_channels[] = { 50, 114, 163 };
        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.
@@ -3659,15 +3676,29 @@ static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s,
 }
 
 
+static const u8 center_channels_5ghz_160mhz[] = { 50, 114, 163 };
+static const u8 center_channels_6ghz_160mhz[] = { 15, 47, 79, 111, 143, 175,
+                                                 207 };
+
 static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
                                               struct hostapd_hw_modes *mode,
-                                              u8 channel, u8 bw)
+                                              u8 op_class, u8 channel, u8 bw)
 {
        u8 center_chan;
        int i, flags;
        enum chan_allowed res, ret = ALLOWED;
+       const u8 *chans;
+       size_t num_chans;
 
-       center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+       if (is_6ghz_op_class(op_class)) {
+               chans = center_channels_6ghz_160mhz;
+               num_chans = ARRAY_SIZE(center_channels_6ghz_160mhz);
+       } else {
+               chans = center_channels_5ghz_160mhz;
+               num_chans = ARRAY_SIZE(center_channels_5ghz_160mhz);
+       }
+       center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel,
+                                                chans, num_chans);
        if (!center_chan)
                return NOT_ALLOWED;
        /* VHT 160 MHz uses DFS channels in most countries. */
@@ -3676,7 +3707,8 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
        for (i = 0; i < 8; i++) {
                int adj_chan = center_chan - 14 + i * 4;
 
-               res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+               res = has_channel(wpa_s->global, mode, op_class, adj_chan,
+                                 &flags);
                if (res == NOT_ALLOWED)
                        return NOT_ALLOWED;
 
@@ -3721,24 +3753,28 @@ static enum chan_allowed wpas_p2p_verify_edmg(struct wpa_supplicant *wpa_s,
 
 static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
                                                 struct hostapd_hw_modes *mode,
-                                                u8 channel, u8 bw)
+                                                u8 op_class, u8 channel, u8 bw)
 {
        int flag = 0;
        enum chan_allowed res, res2;
 
-       res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
+       res2 = res = has_channel(wpa_s->global, mode, op_class, channel, &flag);
        if (bw == BW40MINUS) {
                if (!(flag & HOSTAPD_CHAN_HT40MINUS))
                        return NOT_ALLOWED;
-               res2 = has_channel(wpa_s->global, mode, channel - 4, NULL);
+               res2 = has_channel(wpa_s->global, mode, op_class, channel - 4,
+                                  NULL);
        } else if (bw == BW40PLUS) {
                if (!(flag & HOSTAPD_CHAN_HT40PLUS))
                        return NOT_ALLOWED;
-               res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+               res2 = has_channel(wpa_s->global, mode, op_class, channel + 4,
+                                  NULL);
        } else if (bw == BW80) {
-               res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+               res2 = wpas_p2p_verify_80mhz(wpa_s, mode, op_class, channel,
+                                            bw);
        } else if (bw == BW160) {
-               res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw);
+               res2 = wpas_p2p_verify_160mhz(wpa_s, mode, op_class, channel,
+                                             bw);
        } else if (bw == BW4320 || bw == BW6480 || bw == BW8640) {
                return wpas_p2p_verify_edmg(wpa_s, mode, channel);
        }
@@ -3792,7 +3828,8 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
                            ch < 149 && ch + o->inc > 149)
                                ch = 149;
 
-                       res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+                       res = wpas_p2p_verify_channel(wpa_s, mode, o->op_class,
+                                                     ch, o->bw);
                        if (res == ALLOWED) {
                                if (reg == NULL) {
                                        if (cla == P2P_MAX_REG_CLASSES)
@@ -3862,7 +3899,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
                            (o->bw != BW40PLUS && o->bw != BW40MINUS) ||
                            ch != channel)
                                continue;
-                       ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+                       ret = wpas_p2p_verify_channel(wpa_s, mode, o->op_class,
+                                                     ch, o->bw);
                        if (ret == ALLOWED)
                                return (o->bw == BW40MINUS) ? -1 : 1;
                }
@@ -3872,21 +3910,45 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 
 
 int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
-                             struct hostapd_hw_modes *mode, u8 channel)
+                             struct hostapd_hw_modes *mode, u8 channel,
+                             u8 op_class)
 {
-       if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80))
+       const u8 *chans;
+       size_t num_chans;
+
+       if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW80))
                return 0;
 
-       return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+       if (is_6ghz_op_class(op_class)) {
+               chans = center_channels_6ghz_80mhz;
+               num_chans = ARRAY_SIZE(center_channels_6ghz_80mhz);
+       } else {
+               chans = center_channels_5ghz_80mhz;
+               num_chans = ARRAY_SIZE(center_channels_5ghz_80mhz);
+       }
+       return wpas_p2p_get_center_80mhz(wpa_s, mode, channel,
+                                        chans, num_chans);
 }
 
 
 int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
-                              struct hostapd_hw_modes *mode, u8 channel)
+                              struct hostapd_hw_modes *mode, u8 channel,
+                              u8 op_class)
 {
-       if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW160))
+       const u8 *chans;
+       size_t num_chans;
+
+       if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW160))
                return 0;
-       return wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+       if (is_6ghz_op_class(op_class)) {
+               chans = center_channels_6ghz_160mhz;
+               num_chans = ARRAY_SIZE(center_channels_6ghz_160mhz);
+       } else {
+               chans = center_channels_5ghz_160mhz;
+               num_chans = ARRAY_SIZE(center_channels_5ghz_160mhz);
+       }
+       return wpas_p2p_get_center_160mhz(wpa_s, mode, channel,
+                                         chans, num_chans);
 }
 
 
@@ -6440,14 +6502,16 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
                        enum hostapd_hw_mode mode;
                        struct hostapd_hw_modes *hwmode;
                        u8 chan;
+                       u8 op_class;
 
                        cand = wpa_s->p2p_group_common_freqs[i];
+                       op_class = is_6ghz_freq(cand) ? 133 : 128;
                        mode = ieee80211_freq_to_chan(cand, &chan);
                        hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
                                          mode, is_6ghz_freq(cand));
                        if (!hwmode ||
-                           wpas_p2p_verify_channel(wpa_s, hwmode, chan,
-                                                   BW80) != ALLOWED)
+                           wpas_p2p_verify_channel(wpa_s, hwmode, op_class,
+                                                   chan, BW80) != ALLOWED)
                                continue;
                        if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
                                params->freq = cand;
@@ -6466,20 +6530,44 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
                for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
                        enum hostapd_hw_mode mode;
                        struct hostapd_hw_modes *hwmode;
-                       u8 chan;
+                       u8 chan, op_class;
+                       bool is_6ghz, supported = false;
 
+                       is_6ghz = is_6ghz_freq(cand);
                        cand = wpa_s->p2p_group_common_freqs[i];
                        mode = ieee80211_freq_to_chan(cand, &chan);
                        hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
-                                         mode, is_6ghz_freq(cand));
+                                         mode, is_6ghz);
                        if (!wpas_same_band(wpa_s->current_ssid->frequency,
                                            cand) ||
-                           !hwmode ||
-                           (wpas_p2p_verify_channel(wpa_s, hwmode, chan,
-                                                    BW40MINUS) != ALLOWED &&
-                            wpas_p2p_verify_channel(wpa_s, hwmode, chan,
-                                                    BW40PLUS) != ALLOWED))
+                           !hwmode)
                                continue;
+                       if (is_6ghz &&
+                           wpas_p2p_verify_channel(wpa_s, hwmode, 132, chan,
+                                                   BW40) == ALLOWED)
+                               supported = true;
+
+                       if (!is_6ghz &&
+                           ieee80211_freq_to_channel_ext(
+                                   cand, -1, CHANWIDTH_USE_HT, &op_class,
+                                   &chan) != NUM_HOSTAPD_MODES &&
+                           wpas_p2p_verify_channel(
+                                   wpa_s, hwmode, op_class, chan,
+                                   BW40MINUS) == ALLOWED)
+                               supported = true;
+
+                       if (!supported && !is_6ghz &&
+                           ieee80211_freq_to_channel_ext(
+                                   cand, 1, CHANWIDTH_USE_HT, &op_class,
+                                   &chan) != NUM_HOSTAPD_MODES &&
+                           wpas_p2p_verify_channel(
+                                   wpa_s, hwmode, op_class, chan,
+                                   BW40PLUS) == ALLOWED)
+                               supported = true;
+
+                       if (!supported)
+                               continue;
+
                        if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
                                params->freq = cand;
                                wpa_printf(MSG_DEBUG,
index 941198e3afb00a59cbe90ca3e6a8125f80f652e1..61f2d5233316fb8cb5242c4c27b1d1cf2f24d117 100644 (file)
@@ -145,9 +145,11 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
 int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
                           struct hostapd_hw_modes *mode, u8 channel);
 int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
-                             struct hostapd_hw_modes *mode, u8 channel);
+                             struct hostapd_hw_modes *mode, u8 channel,
+                             u8 op_class);
 int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
-                              struct hostapd_hw_modes *mode, u8 channel);
+                              struct hostapd_hw_modes *mode, u8 channel,
+                              u8 op_class);
 unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
 void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
                         const u8 *p2p_dev_addr,