[PATCH] hostapd: take configured antenna set into consideration

greearb at candelatech.com greearb at candelatech.com
Wed Dec 9 12:20:33 PST 2015


From: Ben Greear <greearb at candelatech.com>

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 at candelatech.com>
---
 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




More information about the Hostap mailing list