Some deployed stations incorrectly consider nsts capability in
(Re)Association Response frame as required capability instead of maximum
capability and if it is greater than station's capability then beamform
will not happen in uplink traffic.
This commit adds support for an optional workaround to use station's
nsts capability in (Re)Association Response frame if the station's nsts
is less than AP by using the use_sta_nsts=1 configuration parameter.
This configuration is introduced in this commit and it is disabled by
default.
Signed-off-by: Tamizh chelvam <c_traja@qti.qualcomm.com>
conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
} else if (os_strcmp(buf, "vendor_vht") == 0) {
bss->vendor_vht = atoi(pos);
conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
} else if (os_strcmp(buf, "vendor_vht") == 0) {
bss->vendor_vht = atoi(pos);
+ } else if (os_strcmp(buf, "use_sta_nsts") == 0) {
+ bss->use_sta_nsts = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
#
#vht_oper_centr_freq_seg1_idx=159
#
#vht_oper_centr_freq_seg1_idx=159
+# Workaround to use station's nsts capability in (Re)Association Response frame
+# This may be needed with some deployed devices as an interoperability
+# workaround for beamforming if the AP's capability is greater than the
+# station's capability. This is disabled by default and can be enabled by
+# setting use_sta_nsts=1.
+#use_sta_nsts=0
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
int vendor_vht;
u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
int vendor_vht;
char *no_probe_resp_if_seen_on;
char *no_auth_if_seen_on;
char *no_probe_resp_if_seen_on;
char *no_auth_if_seen_on;
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- p = hostapd_eid_vht_capabilities(hapd, p);
+ u32 nsts = 0, sta_nsts;
+
+ if (hapd->conf->use_sta_nsts && sta->vht_capabilities) {
+ struct ieee80211_vht_capabilities *capa;
+
+ nsts = (hapd->iface->conf->vht_capab >>
+ VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+ capa = sta->vht_capabilities;
+ sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
+ VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+
+ if (nsts < sta_nsts)
+ nsts = 0;
+ else
+ nsts = sta_nsts;
+ }
+ p = hostapd_eid_vht_capabilities(hapd, p, nsts);
p = hostapd_eid_vht_operation(hapd, p);
}
#endif /* CONFIG_IEEE80211AC */
p = hostapd_eid_vht_operation(hapd, p);
}
#endif /* CONFIG_IEEE80211AC */
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
{
struct ieee80211_vht_capabilities *cap;
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
{
struct ieee80211_vht_capabilities *cap;
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
cap->vht_capabilities_info = host_to_le32(
hapd->iface->conf->vht_capab);
cap->vht_capabilities_info = host_to_le32(
hapd->iface->conf->vht_capab);
+ if (nsts != 0) {
+ u32 hapd_nsts;
+
+ hapd_nsts = le_to_host32(cap->vht_capabilities_info);
+ hapd_nsts = (hapd_nsts >> VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+ cap->vht_capabilities_info &=
+ ~(host_to_le32(hapd_nsts <<
+ VHT_CAP_BEAMFORMEE_STS_OFFSET));
+ cap->vht_capabilities_info |=
+ host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+ }
+
/* Supported MCS set comes from hw */
os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
/* Supported MCS set comes from hw */
os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
pos += 4;
*pos++ = VENDOR_VHT_SUBTYPE;
WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
pos += 4;
*pos++ = VENDOR_VHT_SUBTYPE;
- pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
return pos;
pos = hostapd_eid_vht_operation(hapd, pos);
return pos;
if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
u8 vht_capa_oper[2 + 12 + 2 + 5];
if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
u8 vht_capa_oper[2 + 12 + 2 + 5];
- pos = hostapd_eid_vht_capabilities(bss, vht_capa_oper);
+ pos = hostapd_eid_vht_capabilities(bss, vht_capa_oper, 0);
pos = hostapd_eid_vht_operation(bss, pos);
wpabuf_put_data(buf, vht_capa_oper, pos - vht_capa_oper);
}
pos = hostapd_eid_vht_operation(bss, pos);
wpabuf_put_data(buf, vht_capa_oper, pos - vht_capa_oper);
}