From: Ben Greear <greearb@xxxxxxxxxxxxxxx> If user has configured TX antennas to be less than what hardware advertises, the MCS reported by hardware will be too large. So, remove MCS sets accordingly. Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx> --- src/ap/ieee802_11_ht.c | 21 +++++++++++++++++++++ src/ap/ieee802_11_vht.c | 19 +++++++++++++++++++ src/drivers/driver.h | 10 ++++++++++ src/drivers/driver_nl80211_capa.c | 32 ++++++++++++++++++++++++++++++-- 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index 11fde2a..1aebb3a 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -25,6 +25,7 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid) { struct ieee80211_ht_capabilities *cap; u8 *pos = eid; + int i; if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode || hapd->conf->disable_11n) @@ -40,6 +41,26 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid) os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set, 16); + /* Disable all MCS rates that are out of the configured + nss (antenna) range. */ + if (hapd->iface->current_mode->conf_tx_ant && + hapd->iface->current_mode->conf_rx_ant) { + int msk = hapd->iface->current_mode->conf_tx_ant & + hapd->iface->current_mode->conf_rx_ant; + for (i = 7; i >= 0; i--) { + if (msk & (1<<i)) + break; + if (cap->supported_mcs_set[i]) { + wpa_printf(MSG_DEBUG, "Decreasing MCS set due to configured antennas:" + " conf-tx-ant: 0x%x conf-rx-ant: 0x%x mcs-set for nss: %i", + hapd->iface->current_mode->conf_tx_ant, + hapd->iface->current_mode->conf_rx_ant, + i + 1); + cap->supported_mcs_set[i] = 0; + } + } + } + /* TODO: ht_extended_capabilities (now fully disabled) */ /* TODO: tx_bf_capability_info (now fully disabled) */ /* TODO: asel_capabilities (now fully disabled) */ diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c index 5bf1b5d..cdd5f55 100644 --- a/src/ap/ieee802_11_vht.c +++ b/src/ap/ieee802_11_vht.c @@ -24,6 +24,7 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid) struct ieee80211_vht_capabilities *cap; struct hostapd_hw_modes *mode = hapd->iface->current_mode; u8 *pos = eid; + int i; if (!mode) return eid; @@ -52,6 +53,24 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid) /* Supported MCS set comes from hw */ os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8); + /* Disable all MCS rates that are out of the configured + nss (antenna) range. */ + if (mode->conf_tx_ant) { + for (i = 7; i > 0; i--) { + if (mode->conf_tx_ant & (1 << (i - 1))) + break; + cap->vht_supported_mcs_set.tx_map |= (0x3 << i); + } + } + + if (mode->conf_rx_ant) { + for (i = 7; i > 0; i--) { + if (mode->conf_rx_ant & (1 << (i - 1))) + break; + cap->vht_supported_mcs_set.rx_map |= (0x3 << i); + } + } + pos += sizeof(*cap); return pos; diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 9413733..e58c112 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -155,6 +155,16 @@ struct hostapd_hw_modes { u16 ht_capab; /** + * conf_tx_ant - Configured TX Antenna mask. 0 means not reported by driver + */ + int conf_tx_ant; + + /** + * conf_rx_ant - Configured RX Antenna mask. 0 means not reported by driver + */ + int conf_rx_ant; + + /** * mcs_set - MCS (IEEE 802.11n) rate parameters */ u8 mcs_set[16]; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 4cf3123..9008a50 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -933,6 +933,8 @@ struct phy_info_arg { u16 *num_modes; struct hostapd_hw_modes *modes; int last_mode, last_chan_idx; + int conf_tx_ant; + int conf_rx_ant; }; static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa, @@ -1115,7 +1117,8 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb) } -static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band) +static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band, + struct hostapd_hw_modes **mode_used) { struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; struct hostapd_hw_modes *mode; @@ -1152,6 +1155,8 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band) } else mode = &phy_info->modes[*(phy_info->num_modes) - 1]; + *mode_used = mode; + nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL); @@ -1183,14 +1188,35 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + if (tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX] && + tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX]) + wpa_printf(MSG_DEBUG, "Available Antennas: TX %#x RX %#x", + nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX]), + nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX])); + + if (tb_msg[NL80211_ATTR_WIPHY_ANTENNA_TX] && + tb_msg[NL80211_ATTR_WIPHY_ANTENNA_RX]) { + wpa_printf(MSG_DEBUG, "Configured Antennas: TX %#x RX %#x", + nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_TX]), + nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_RX])); + phy_info->conf_tx_ant = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_TX]); + phy_info->conf_rx_ant = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_RX]); + } + if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) return NL_SKIP; nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { - int res = phy_info_band(phy_info, nl_band); + struct hostapd_hw_modes *mode = NULL; + int res = phy_info_band(phy_info, nl_band, &mode); if (res != NL_OK) return res; + + if (mode) { + mode->conf_tx_ant = phy_info->conf_tx_ant; + mode->conf_rx_ant = phy_info->conf_rx_ant; + } } return NL_SKIP; @@ -1566,6 +1592,8 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) .num_modes = num_modes, .modes = NULL, .last_mode = -1, + .conf_tx_ant = 0, + .conf_rx_ant = 0, }; *num_modes = 0; -- 2.1.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap