diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 274eecaa2..1a53db329 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -568,6 +568,19 @@ struct wpa_driver_associate_params { */ const u8 *htcaps; /* struct ieee80211_ht_capabilities * */ const u8 *htcaps_mask; /* struct ieee80211_ht_capabilities * */ + +#ifdef CONFIG_VHT_OVERRIDES + /** + * disable_vht - Disable VHT for this connection + */ + int disable_vht; + + /** + * VHT capability overrides. + */ + const struct ieee80211_vht_capabilities *vhtcaps; + const struct ieee80211_vht_capabilities *vhtcaps_mask; +#endif /* CONFIG_VHT_OVERRIDES */ }; enum hide_ssid { diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index af228ea0a..4635d05e9 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -7175,6 +7175,20 @@ skip_auth_type: params->htcaps_mask); } +#ifdef CONFIG_VHT_OVERRIDES + if (params->disable_vht) { + wpa_printf(MSG_DEBUG, " * VHT disabled"); + NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT); + } + + if (params->vhtcaps && params->vhtcaps_mask) { + int sz = sizeof(struct ieee80211_vht_capabilities); + NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps); + NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz, + params->vhtcaps_mask); + } +#endif /* CONFIG_VHT_OVERRIDES */ + ret = nl80211_set_conn_keys(params, msg); if (ret) goto nla_put_failure; @@ -7361,6 +7375,20 @@ static int wpa_driver_nl80211_associate( params->htcaps_mask); } +#ifdef CONFIG_VHT_OVERRIDES + if (params->disable_vht) { + wpa_printf(MSG_DEBUG, " * VHT disabled"); + NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT); + } + + if (params->vhtcaps && params->vhtcaps_mask) { + int sz = sizeof(struct ieee80211_vht_capabilities); + NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps); + NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz, + params->vhtcaps_mask); + } +#endif /* CONFIG_VHT_OVERRIDES */ + if (params->p2p) wpa_printf(MSG_DEBUG, " * P2P group"); diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index da2abfce3..0634219b6 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -126,6 +126,10 @@ ifdef CONFIG_HT_OVERRIDES CFLAGS += -DCONFIG_HT_OVERRIDES endif +ifdef CONFIG_VHT_OVERRIDES +CFLAGS += -DCONFIG_VHT_OVERRIDES +endif + ifndef CONFIG_BACKEND CONFIG_BACKEND=file endif diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config index 43881fe48..df5efe2a4 100644 --- a/wpa_supplicant/android.config +++ b/wpa_supplicant/android.config @@ -224,6 +224,9 @@ CONFIG_SMARTCARD=y # Support HT overrides (disable HT/HT40, mask MCS rates, etc.) #CONFIG_HT_OVERRIDES=y +# Support VHT overrides (disable VHT, mask MCS rates, etc.) +#CONFIG_VHT_OVERRIDES=y + # Development testing #CONFIG_EAPOL_TEST=y diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 139fa9dbf..68607654b 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1550,6 +1550,27 @@ static const struct parse_data ssid_fields[] = { { INT_RANGE(ampdu_density, -1, 7) }, { STR(ht_mcs) }, #endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + { INT_RANGE(disable_vht, 0, 1) }, + { INT(vht_capa) }, + { INT(vht_capa_mask) }, + { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) }, + { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) }, + { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) }, + { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) }, + { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) }, + { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) }, + { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) }, + { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) }, + { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) }, + { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) }, + { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) }, + { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) }, + { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) }, + { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) }, + { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) }, + { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) }, +#endif /* CONFIG_VHT_OVERRIDES */ { INT(ap_max_inactivity) }, { INT(dtim_period) }, { INT(beacon_int) }, @@ -1953,6 +1974,24 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR; ssid->ampdu_density = DEFAULT_AMPDU_DENSITY; #endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + ssid->vht_rx_mcs_nss_1 = -1; + ssid->vht_rx_mcs_nss_2 = -1; + ssid->vht_rx_mcs_nss_3 = -1; + ssid->vht_rx_mcs_nss_4 = -1; + ssid->vht_rx_mcs_nss_5 = -1; + ssid->vht_rx_mcs_nss_6 = -1; + ssid->vht_rx_mcs_nss_7 = -1; + ssid->vht_rx_mcs_nss_8 = -1; + ssid->vht_tx_mcs_nss_1 = -1; + ssid->vht_tx_mcs_nss_2 = -1; + ssid->vht_tx_mcs_nss_3 = -1; + ssid->vht_tx_mcs_nss_4 = -1; + ssid->vht_tx_mcs_nss_5 = -1; + ssid->vht_tx_mcs_nss_6 = -1; + ssid->vht_tx_mcs_nss_7 = -1; + ssid->vht_tx_mcs_nss_8 = -1; +#endif /* CONFIG_VHT_OVERRIDES */ ssid->proactive_key_caching = -1; #ifdef CONFIG_IEEE80211W ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT; diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 8cab88f30..1340dcec6 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -534,6 +534,35 @@ struct wpa_ssid { char *ht_mcs; #endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + /** + * disable_vht - Disable VHT (IEEE 802.11ac) for this network + * + * By default, use it if it is available, but this can be configured + * to 1 to have it disabled. + */ + int disable_vht; + + /** + * vht_capa - VHT capabilities to use + */ + unsigned int vht_capa; + + /** + * vht_capa_mask - mask for VHT capabilities + */ + unsigned int vht_capa_mask; + + int vht_rx_mcs_nss_1, vht_rx_mcs_nss_2, + vht_rx_mcs_nss_3, vht_rx_mcs_nss_4, + vht_rx_mcs_nss_5, vht_rx_mcs_nss_6, + vht_rx_mcs_nss_7, vht_rx_mcs_nss_8; + int vht_tx_mcs_nss_1, vht_tx_mcs_nss_2, + vht_tx_mcs_nss_3, vht_tx_mcs_nss_4, + vht_tx_mcs_nss_5, vht_tx_mcs_nss_6, + vht_tx_mcs_nss_7, vht_tx_mcs_nss_8; +#endif /* CONFIG_VHT_OVERRIDES */ + /** * ap_max_inactivity - Timeout in seconds to detect STA's inactivity * diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 711b4073a..e867bae6c 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -225,6 +225,9 @@ CONFIG_SMARTCARD=y # Support HT overrides (disable HT/HT40, mask MCS rates, etc.) #CONFIG_HT_OVERRIDES=y +# Support VHT overrides (disable VHT, mask MCS rates, etc.) +#CONFIG_VHT_OVERRIDES=y + # Development testing #CONFIG_EAPOL_TEST=y diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 30f9779ee..92762ef43 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -632,6 +632,10 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, struct ieee80211_ht_capabilities htcaps; struct ieee80211_ht_capabilities htcaps_mask; #endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + struct ieee80211_vht_capabilities vhtcaps; + struct ieee80211_vht_capabilities vhtcaps_mask; +#endif /* CONFIG_VHT_OVERRIDES */ os_memset(¶ms, 0, sizeof(params)); params.bssid = bssid; @@ -653,6 +657,13 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, params.htcaps_mask = (u8 *) &htcaps_mask; wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); #endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + os_memset(&vhtcaps, 0, sizeof(vhtcaps)); + os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask)); + params.vhtcaps = &vhtcaps; + params.vhtcaps_mask = &vhtcaps_mask; + wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); +#endif /* CONFIG_VHT_OVERRIDES */ #ifdef CONFIG_IEEE80211R if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { params.wpa_ie = wpa_s->sme.ft_ies; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 30f85f8a9..42a475f12 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2625,6 +2625,54 @@ void wpa_supplicant_apply_ht_overrides( #endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES +void wpa_supplicant_apply_vht_overrides( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + struct wpa_driver_associate_params *params) +{ + struct ieee80211_vht_capabilities *vhtcaps; + struct ieee80211_vht_capabilities *vhtcaps_mask; + + if (!ssid) + return; + + params->disable_vht = ssid->disable_vht; + + vhtcaps = (void *) params->vhtcaps; + vhtcaps_mask = (void *) params->vhtcaps_mask; + + if (!vhtcaps || !vhtcaps_mask) + return; + + vhtcaps->vht_capabilities_info = ssid->vht_capa; + vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask; + +#define OVERRIDE_MCS(i) \ + if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \ + vhtcaps_mask->vht_supported_mcs_set.tx_map |= \ + 3 << 2 * (i - 1); \ + vhtcaps->vht_supported_mcs_set.tx_map |= \ + ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1); \ + } \ + if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \ + vhtcaps_mask->vht_supported_mcs_set.rx_map |= \ + 3 << 2 * (i - 1); \ + vhtcaps->vht_supported_mcs_set.rx_map |= \ + ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \ + } + + OVERRIDE_MCS(1); + OVERRIDE_MCS(2); + OVERRIDE_MCS(3); + OVERRIDE_MCS(4); + OVERRIDE_MCS(5); + OVERRIDE_MCS(6); + OVERRIDE_MCS(7); + OVERRIDE_MCS(8); +} +#endif /* CONFIG_VHT_OVERRIDES */ + + static int pcsc_reader_init(struct wpa_supplicant *wpa_s) { #ifdef PCSC_FUNCS diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index c9deb4b8a..1ded4e12a 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -869,6 +869,20 @@ fast_reauth=1 # -1 = Do not make any changes. # 0-3 = Set AMPDU density (aka factor) to specified value. +# disable_vht: Whether VHT should be disabled. +# 0 = VHT enabled (if AP supports it) +# 1 = VHT disabled +# +# vht_capa: VHT capabilities to set in the override +# vht_capa_mask: mask of VHT capabilities +# +# vht_rx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for RX NSS 1-8 +# vht_tx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for TX NSS 1-8 +# 0: MCS 0-7 +# 1: MCS 0-8 +# 2: MCS 0-9 +# 3: not supported + # Example blocks: # Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 0f51f8e2e..4ec15c128 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -681,6 +681,9 @@ struct wpa_supplicant { void wpa_supplicant_apply_ht_overrides( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_driver_associate_params *params); +void wpa_supplicant_apply_vht_overrides( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + struct wpa_driver_associate_params *params); int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);