diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 96681843e..3e5cfb01d 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -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 }, diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index d19586f06..0f0a01d01 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -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; diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index cfefa48d4..a2bd08d4c 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -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); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index be1b396fe..df676552c 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -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, diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 941198e3a..61f2d5233 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -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,