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; }