From 29d8bd1dec79d4093eab7f19135167cdf96e6adc Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 14 Jun 2019 16:49:20 +0200 Subject: [PATCH] nl80211: Add driver multi iftype HE capability parsing 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 --- src/ap/ap_drv_ops.c | 14 ++++---- src/ap/beacon.c | 12 ++++--- src/ap/dfs.c | 5 +-- src/ap/hostapd.c | 3 +- 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, 99 insertions(+), 52 deletions(-) diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 7c9dcf9b9..c0ededabe 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -546,14 +546,15 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, int center_segment0, int center_segment1) { struct hostapd_freq_params data; + struct hostapd_hw_modes *cmode = hapd->iface->current_mode; if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled, vht_enabled, he_enabled, sec_channel_offset, oper_chwidth, center_segment0, center_segment1, - hapd->iface->current_mode ? - hapd->iface->current_mode->vht_capab : 0, - &hapd->iface->current_mode->he_capab)) + cmode ? cmode->vht_capab : 0, + cmode ? + &cmode->he_capab[IEEE80211_MODE_AP] : NULL)) return -1; if (hapd->driver == NULL) @@ -798,8 +799,9 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, struct hostapd_data *hapd = iface->bss[0]; struct hostapd_freq_params data; int res; + struct hostapd_hw_modes *cmode = iface->current_mode; - if (!hapd->driver || !hapd->driver->start_dfs_cac) + if (!hapd->driver || !hapd->driver->start_dfs_cac || !cmode) return 0; if (!iface->conf->ieee80211h) { @@ -812,8 +814,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, vht_enabled, he_enabled, sec_channel_offset, oper_chwidth, center_segment0, center_segment1, - iface->current_mode->vht_capab, - &iface->current_mode->he_capab)) { + cmode->vht_capab, + &cmode->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..a51b94960 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -510,7 +510,7 @@ 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 +1226,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); @@ -1398,6 +1399,7 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) struct hostapd_freq_params freq; struct hostapd_iface *iface = hapd->iface; struct hostapd_config *iconf = iface->conf; + struct hostapd_hw_modes *cmode = iface->current_mode; struct wpabuf *beacon, *proberesp, *assocresp; int res, ret = -1; @@ -1421,7 +1423,7 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) params.reenable = hapd->reenable_beacon; hapd->reenable_beacon = 0; - if (iface->current_mode && + if (cmode && hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq, iconf->channel, iconf->ieee80211n, iconf->ieee80211ac, iconf->ieee80211ax, @@ -1429,8 +1431,8 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) hostapd_get_oper_chwidth(iconf), 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) + cmode->vht_capab, + &cmode->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..ac23c2b1b 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -888,6 +888,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) struct csa_settings csa_settings; unsigned int i; int err = 1; + struct hostapd_hw_modes *cmode = iface->current_mode; wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", __func__, iface->cac_started ? "yes" : "no", @@ -966,8 +967,8 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) hostapd_get_oper_chwidth(iface->conf), oper_centr_freq_seg0_idx, oper_centr_freq_seg1_idx, - iface->current_mode->vht_capab, - &iface->current_mode->he_capab); + cmode->vht_capab, + &cmode->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..cc75a7765 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -3241,7 +3241,8 @@ 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 4aef59e88..c85a28db4 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2990,7 +2990,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; @@ -3583,7 +3584,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 8822a1785..b8453c992 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 ieee80211_op_mode; 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 ieee80211_op_mode 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 ieee80211_op_mode 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 d3d3c1db3..a51f3fcb0 100644 --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -44,7 +44,8 @@ static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) } -u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid) +u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid, + enum ieee80211_op_mode opmode) { struct ieee80211_he_capabilities *cap; struct hostapd_hw_modes *mode = hapd->iface->current_mode; @@ -56,8 +57,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: @@ -86,14 +87,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] |= @@ -260,7 +261,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 ieee80211_op_mode opmode) { u16 sta_rx_mcs_set, ap_tx_mcs_set; u8 mcs_count = 0; @@ -269,7 +271,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; @@ -318,10 +320,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 ieee80211_op_mode 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) || he_capab_len > sizeof(struct ieee80211_he_capabilities)) { sta->flags &= ~WLAN_STA_HE; os_free(sta->he_capab); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index d0f449f72..ee11387e9 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 ieee80211_op_mode { + 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..8318b10ab 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 ieee80211_op_mode 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); + 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 (!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; - - 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; }