From: Sven Eckelmann <seckelmann@xxxxxxxxx> 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@xxxxxxxxx> --- 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, ¶ms); 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap