[PATCH 2/3] nl80211: Add driver multi iftype HE capability parsing

Sven Eckelmann sven at narfation.org
Fri Jun 14 07:49:20 PDT 2019


From: Sven Eckelmann <seckelmann at datto.com>

The HE capabilities are no longer per PHY but per iftype on this specific
PHY. It is therefore no longer enough to just parse the AP capabilities.

The he_capabilities are now duplicated to store all information for
IEEE80211_MODE_* which hostap cares about. The nl80211 driver fills in this
information when the iftype supports HE. The rest of the code still only
uses the IEEE80211_HE_AP portion but can be extended later to also use
other HE capabilities.

Signed-off-by: Sven Eckelmann <seckelmann at datto.com>
---
 src/ap/ap_drv_ops.c               |  4 +--
 src/ap/beacon.c                   |  8 +++--
 src/ap/dfs.c                      |  2 +-
 src/ap/hostapd.c                  |  2 +-
 src/ap/ieee802_11.c               |  5 +--
 src/ap/ieee802_11.h               |  7 ++--
 src/ap/ieee802_11_he.c            | 27 +++++++-------
 src/drivers/driver.h              | 18 ++++++----
 src/drivers/driver_nl80211_capa.c | 60 ++++++++++++++++++++++---------
 9 files changed, 88 insertions(+), 45 deletions(-)

diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index dced3371d..f0859505e 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -553,7 +553,7 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
 				    center_segment0, center_segment1,
 				    hapd->iface->current_mode ?
 				    hapd->iface->current_mode->vht_capab : 0,
-				    &hapd->iface->current_mode->he_capab))
+				    &hapd->iface->current_mode->he_capab[IEEE80211_MODE_AP]))
 		return -1;
 
 	if (hapd->driver == NULL)
@@ -813,7 +813,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
 				    oper_chwidth, center_segment0,
 				    center_segment1,
 				    iface->current_mode->vht_capab,
-				    &iface->current_mode->he_capab)) {
+				    &iface->current_mode->he_capab[IEEE80211_MODE_AP])) {
 		wpa_printf(MSG_ERROR, "Can't set freq params");
 		return -1;
 	}
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 1838c1c84..832b2755e 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -510,7 +510,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 
 #ifdef CONFIG_IEEE80211AX
 	if (hapd->iconf->ieee80211ax) {
-		pos = hostapd_eid_he_capab(hapd, pos);
+		pos = hostapd_eid_he_capab(hapd, pos,
+					   IEEE80211_MODE_AP);
 		pos = hostapd_eid_he_operation(hapd, pos);
 		pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
 		pos = hostapd_eid_spatial_reuse(hapd, pos);
@@ -1226,7 +1227,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 
 #ifdef CONFIG_IEEE80211AX
 	if (hapd->iconf->ieee80211ax) {
-		tailpos = hostapd_eid_he_capab(hapd, tailpos);
+		tailpos = hostapd_eid_he_capab(hapd, tailpos,
+					       IEEE80211_MODE_AP);
 		tailpos = hostapd_eid_he_operation(hapd, tailpos);
 		tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
 		tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
@@ -1430,7 +1432,7 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
 				    hostapd_get_oper_centr_freq_seg0_idx(iconf),
 				    hostapd_get_oper_centr_freq_seg1_idx(iconf),
 				    iface->current_mode->vht_capab,
-				    &iface->current_mode->he_capab) == 0)
+				    &iface->current_mode->he_capab[IEEE80211_MODE_AP]) == 0)
 		params.freq = &freq;
 
 	res = hostapd_drv_set_ap(hapd, &params);
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index a3c9aa26f..cf0e1020b 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -967,7 +967,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
 				      oper_centr_freq_seg0_idx,
 				      oper_centr_freq_seg1_idx,
 				      iface->current_mode->vht_capab,
-				      &iface->current_mode->he_capab);
+				      &iface->current_mode->he_capab[IEEE80211_MODE_AP]);
 
 	if (err) {
 		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index c83fb2a46..f77ca488c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -3241,7 +3241,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
 				    hostapd_get_oper_centr_freq_seg0_idx(conf),
 				    hostapd_get_oper_centr_freq_seg1_idx(conf),
 				    conf->vht_capab,
-				    mode ? &mode->he_capab : NULL))
+				    mode ? &mode->he_capab[IEEE80211_MODE_AP] : NULL))
 		return -1;
 
 	switch (params->bandwidth) {
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 02f56701e..c54149c39 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2872,7 +2872,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_IEEE80211AC */
 #ifdef CONFIG_IEEE80211AX
 	if (hapd->iconf->ieee80211ax) {
-		resp = copy_sta_he_capab(hapd, sta, elems.he_capabilities,
+		resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
+					 elems.he_capabilities,
 					 elems.he_capabilities_len);
 		if (resp != WLAN_STATUS_SUCCESS)
 			return resp;
@@ -3465,7 +3466,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 
 #ifdef CONFIG_IEEE80211AX
 	if (hapd->iconf->ieee80211ax) {
-		p = hostapd_eid_he_capab(hapd, p);
+		p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
 		p = hostapd_eid_he_operation(hapd, p);
 		p = hostapd_eid_spatial_reuse(hapd, p);
 		p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 914cd1f19..ba26ac384 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -18,6 +18,7 @@ struct ieee80211_vht_capabilities;
 struct ieee80211_mgmt;
 struct vlan_description;
 struct hostapd_sta_wpa_psk_short;
+enum ieee8021_opmode;
 
 int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
 		    struct hostapd_frame_info *fi);
@@ -57,7 +58,8 @@ 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_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
+			  enum ieee8021_opmode opmode);
 u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid);
@@ -91,7 +93,8 @@ u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *vht_opmode);
 u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
-		      const u8 *he_capab, size_t he_capab_len);
+		      enum ieee8021_opmode opmode, const u8 *he_capab,
+		      size_t he_capab_len);
 void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
 		       const u8 *buf, size_t len, int ack);
 void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index fb02fa013..02dc3f9c8 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -77,7 +77,8 @@ static inline int ieee80211_check_he_cap_size(const u8 *buf, int len)
 	return (len != cap_len);
 }
 
-u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
+u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
+			  enum ieee8021_opmode opmode)
 {
 	struct ieee80211_he_capabilities *cap;
 	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
@@ -89,8 +90,8 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
 		return eid;
 
 	ie_size = sizeof(struct ieee80211_he_capabilities);
-	ppet_size = ieee80211_he_ppet_size(mode->he_capab.ppet[0],
-					   mode->he_capab.phy_cap);
+	ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
+					   mode->he_capab[opmode].phy_cap);
 
 	switch (hapd->iface->conf->he_oper_chwidth) {
 	case CHANWIDTH_80P80MHZ:
@@ -119,14 +120,14 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
 	cap = (struct ieee80211_he_capabilities *) pos;
 	os_memset(cap, 0, sizeof(*cap));
 
-	os_memcpy(cap->he_mac_capab_info, mode->he_capab.mac_cap,
+	os_memcpy(cap->he_mac_capab_info, mode->he_capab[opmode].mac_cap,
 		  HE_MAX_MAC_CAPAB_SIZE);
-	os_memcpy(cap->he_phy_capab_info, mode->he_capab.phy_cap,
+	os_memcpy(cap->he_phy_capab_info, mode->he_capab[opmode].phy_cap,
 		  HE_MAX_PHY_CAPAB_SIZE);
-	os_memcpy(cap->optional, mode->he_capab.mcs, mcs_nss_size);
+	os_memcpy(cap->optional, mode->he_capab[opmode].mcs, mcs_nss_size);
 	if (ppet_size)
-		os_memcpy(&cap->optional[mcs_nss_size], mode->he_capab.ppet,
-			  ppet_size);
+		os_memcpy(&cap->optional[mcs_nss_size],
+			  mode->he_capab[opmode].ppet,  ppet_size);
 
 	if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
 		cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
@@ -293,7 +294,8 @@ void hostapd_get_he_capab(struct hostapd_data *hapd,
 }
 
 
-static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab)
+static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
+			      enum ieee8021_opmode opmode)
 {
 	u16 sta_rx_mcs_set, ap_tx_mcs_set;
 	u8 mcs_count = 0;
@@ -302,7 +304,7 @@ static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab)
 
 	if (!hapd->iface->current_mode)
 		return 1;
-	ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab.mcs;
+	ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs;
 	sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *)
 			       sta_he_capab)->optional;
 
@@ -351,10 +353,11 @@ static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab)
 
 
 u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
-		      const u8 *he_capab, size_t he_capab_len)
+		      enum ieee8021_opmode opmode, const u8 *he_capab,
+		      size_t he_capab_len)
 {
 	if (!he_capab || !hapd->iconf->ieee80211ax ||
-	    !check_valid_he_mcs(hapd, he_capab) ||
+	    !check_valid_he_mcs(hapd, he_capab, opmode) ||
 	    ieee80211_check_he_cap_size(he_capab, he_capab_len)) {
 		sta->flags &= ~WLAN_STA_HE;
 		os_free(sta->he_capab);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 5f870a1f2..6a9dfefc9 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -200,6 +200,17 @@ struct he_capabilities {
 #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
 #define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
 
+
+enum ieee8021_opmode {
+	IEEE80211_MODE_INFRA	= 0,
+	IEEE80211_MODE_IBSS	= 1,
+	IEEE80211_MODE_AP	= 2,
+	IEEE80211_MODE_MESH	= 5,
+
+	/* only add new entries before IEEE80211_MODE_NUM */
+	IEEE80211_MODE_NUM,
+};
+
 /**
  * struct hostapd_hw_modes - Supported hardware mode information
  */
@@ -259,15 +270,10 @@ struct hostapd_hw_modes {
 	/**
 	 * he_capab - HE (IEEE 802.11ax) capabilities
 	 */
-	struct he_capabilities he_capab;
+	struct he_capabilities he_capab[IEEE80211_MODE_NUM];
 };
 
 
-#define IEEE80211_MODE_INFRA	0
-#define IEEE80211_MODE_IBSS	1
-#define IEEE80211_MODE_AP	2
-#define IEEE80211_MODE_MESH	5
-
 #define IEEE80211_CAP_ESS	0x0001
 #define IEEE80211_CAP_IBSS	0x0002
 #define IEEE80211_CAP_PRIVACY	0x0010
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index ab9b19f39..871ba827b 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1551,26 +1551,32 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
 }
 
 
-static int phy_info_iftype(struct hostapd_hw_modes *mode,
-			   struct nlattr *nl_iftype)
+static void phy_info_iftype_copy(struct he_capabilities *he_capab,
+				 enum ieee8021_opmode opmode,
+				 struct nlattr **tb, struct nlattr **tb_flags)
 {
-	struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1];
-	struct he_capabilities *he_capab = &mode->he_capab;
-	struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1];
+	enum nl80211_iftype iftype;
 	size_t len;
 
-	nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
-		  nla_data(nl_iftype), nla_len(nl_iftype), NULL);
-
-	if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES])
-		return NL_STOP;
-
-	if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX,
-			     tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL))
-		return NL_STOP;
+	switch (opmode) {
+	case IEEE80211_MODE_INFRA:
+		iftype = NL80211_IFTYPE_STATION;
+		break;
+	case IEEE80211_MODE_IBSS:
+		iftype = NL80211_IFTYPE_ADHOC;
+		break;
+	case IEEE80211_MODE_AP:
+		iftype = NL80211_IFTYPE_AP;
+		break;
+	case IEEE80211_MODE_MESH:
+		iftype = NL80211_IFTYPE_MESH_POINT;
+		break;
+	default:
+		return;
+	}
 
-	if (!nla_get_flag(tb_flags[NL80211_IFTYPE_AP]))
-		return NL_OK;
+	if (!nla_get_flag(tb_flags[iftype]))
+		return;
 
 	he_capab->he_supported = 1;
 
@@ -1613,6 +1619,28 @@ static int phy_info_iftype(struct hostapd_hw_modes *mode,
 			  nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]),
 			  len);
 	}
+}
+
+
+static int phy_info_iftype(struct hostapd_hw_modes *mode,
+			   struct nlattr *nl_iftype)
+{
+	struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1];
+	struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1];
+	unsigned int i;
+
+	nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
+		  nla_data(nl_iftype), nla_len(nl_iftype), NULL);
+
+	if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES])
+		return NL_STOP;
+
+	if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX,
+			     tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL))
+		return NL_STOP;
+
+	for (i = 0; i < IEEE80211_MODE_NUM; i++)
+		phy_info_iftype_copy(&mode->he_capab[i], i, tb, tb_flags);
 
 	return NL_OK;
 }
-- 
2.20.1




More information about the Hostap mailing list