diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 55b1ed356..7eaa8dcc2 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -412,6 +412,18 @@ void p2p_reselect_channel(struct p2p_data *p2p, } } + /* Try a channel where we might be able to use VHT */ + for (i = 0; i < intersection->reg_classes; i++) { + struct p2p_reg_class *c = &intersection->reg_class[i]; + if (c->reg_class == 128) { + p2p_dbg(p2p, "Pick possible VHT channel (reg_class %u channel %u) from intersection", + c->reg_class, c->channel[0]); + p2p->op_reg_class = c->reg_class; + p2p->op_channel = c->channel[0]; + return; + } + } + /* Try a channel where we might be able to use HT40 */ for (i = 0; i < intersection->reg_classes; i++) { struct p2p_reg_class *c = &intersection->reg_class[i]; diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index 94b5d0b28..a3dcdebb0 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -94,6 +94,10 @@ int p2p_channel_to_freq(int op_class, int channel) if (channel < 149 || channel > 161) return -1; return 5000 + 5 * channel; + case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */ + if (channel < 36 || channel > 161) + return -1; + return 5000 + 5 * channel; } return -1; } diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index fdbe248a7..b55c068b7 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -42,6 +42,31 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); #endif /* CONFIG_WPS */ +static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, + struct hostapd_config *conf, + struct hostapd_hw_modes *mode) +{ + u8 center_chan = 0; + u8 channel = conf->channel; + + if (!conf->secondary_channel) + goto no_vht; + + center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel); + if (!center_chan) + goto no_vht; + + /* Use 80 MHz channel */ + conf->vht_oper_chwidth = 1; + conf->vht_oper_centr_freq_seg0_idx = center_chan; + return; + +no_vht: + conf->vht_oper_centr_freq_seg0_idx = + channel + conf->secondary_channel * 2; +} + + static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct hostapd_config *conf) @@ -114,6 +139,11 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, HT_CAP_INFO_SHORT_GI40MHZ | HT_CAP_INFO_RX_STBC_MASK | HT_CAP_INFO_MAX_AMSDU_SIZE); + + if (mode->vht_capab && ssid->vht) { + conf->ieee80211ac = 1; + wpas_conf_ap_vht(wpa_s, conf, mode); + } } } #endif /* CONFIG_IEEE80211N */ diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index c22113a04..0ebf332ca 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -3038,7 +3038,7 @@ struct p2p_oper_class_map { u8 min_chan; u8 max_chan; u8 inc; - enum { BW20, BW40PLUS, BW40MINUS } bw; + enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw; }; static struct p2p_oper_class_map op_class[] = { @@ -3053,10 +3053,81 @@ static struct p2p_oper_class_map op_class[] = { { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS }, { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS }, { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS }, + + /* + * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center + * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of + * 80 MHz, but currently use the following definition for simplicity + * (these center frequencies are not actual channels, which makes + * has_channel() fail). wpas_p2p_verify_80mhz() should take care of + * removing invalid channels. + */ + { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 }, { -1, 0, 0, 0, 0, BW20 } }; +static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, + u8 channel) +{ + u8 center_channels[] = { 42, 58, 106, 122, 138, 155 }; + unsigned int i; + + if (mode->mode != HOSTAPD_MODE_IEEE80211A) + return 0; + + for (i = 0; i < ARRAY_SIZE(center_channels); 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. + */ + if (channel >= center_channels[i] - 6 && + channel <= center_channels[i] + 6) + return center_channels[i]; + + return 0; +} + + +static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, + u8 channel, u8 bw) +{ + u8 center_chan; + int i, flags; + enum chan_allowed res, ret = ALLOWED; + + center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel); + if (!center_chan) + return NOT_ALLOWED; + if (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); + if (res == NOT_ALLOWED) + return NOT_ALLOWED; + if (res == PASSIVE_ONLY) + ret = PASSIVE_ONLY; + + if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) + return NOT_ALLOWED; + if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) + return NOT_ALLOWED; + if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) + return NOT_ALLOWED; + if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)) + return NOT_ALLOWED; + } + + return ret; +} + + static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel, u8 bw) @@ -3073,6 +3144,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, if (!(flag & HOSTAPD_CHAN_HT40PLUS)) return NOT_ALLOWED; res2 = has_channel(wpa_s->global, mode, channel + 4, NULL); + } else if (bw == BW80) { + res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw); } if (res == NOT_ALLOWED || res2 == NOT_ALLOWED) @@ -3173,6 +3246,16 @@ 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) +{ + if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80)) + return 0; + + return wpas_p2p_get_center_80mhz(wpa_s, mode, channel); +} + + static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf, size_t buf_len) { diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index c0ad29eae..785062d98 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -152,6 +152,8 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, 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); 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,