This patch adds the HE handling to the assoc request parsing and response generation. Signed-off-by: Shashidhar Lakkavalli <slakkavalli@xxxxxxxxx> Signed-off-by: John Crispin <john@xxxxxxxxxxx> --- Changes in V2 * fix the comment for the basic NSS rates was wrong * add SPR IE to assoc responses src/ap/ap_drv_ops.c | 6 ++ src/ap/ap_drv_ops.h | 4 ++ src/ap/ieee802_11.c | 35 ++++++++++- src/ap/ieee802_11.h | 12 ++++ src/ap/ieee802_11_he.c | 130 +++++++++++++++++++++++++++++++++++++++++ src/ap/sta_info.c | 2 + src/ap/sta_info.h | 5 ++ src/common/ieee802_11_common.c | 4 ++ src/common/ieee802_11_common.h | 2 + src/common/ieee802_11_defs.h | 5 +- src/drivers/driver.h | 4 ++ src/drivers/driver_nl80211.c | 10 ++++ 12 files changed, 217 insertions(+), 2 deletions(-) diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 067cf863e..3628f3b22 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -413,6 +413,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, u16 listen_interval, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, + const struct ieee80211_he_capabilities *he_capab, int he_capab_len, + const struct ieee80211_he_operation *he_oper, int he_oper_len, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, int set) { @@ -432,6 +434,10 @@ int hostapd_sta_add(struct hostapd_data *hapd, params.listen_interval = listen_interval; params.ht_capabilities = ht_capab; params.vht_capabilities = vht_capab; + params.he_capabilities = he_capab; + params.he_capabilities_len = he_capab_len; + params.he_operation = he_oper; + params.he_operation_len = he_oper_len; params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED); params.vht_opmode = vht_opmode; params.flags = hostapd_sta_flags_to_drv(flags); diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index de40171e1..db9653868 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -41,6 +41,10 @@ int hostapd_sta_add(struct hostapd_data *hapd, u16 listen_interval, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, + const struct ieee80211_he_capabilities *he_capab, + int he_capab_len, + const struct ieee80211_he_operation *he_oper, + int he_oper_len, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, int set); int hostapd_set_privacy(struct hostapd_data *hapd, int enabled); diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 56f6363a3..82917ebea 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2325,7 +2325,8 @@ static void handle_auth(struct hostapd_data *hapd, WLAN_STA_AUTHORIZED); if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0, - NULL, NULL, sta->flags, 0, 0, 0, 0)) { + NULL, NULL, NULL, 0, NULL, 0, + sta->flags, 0, 0, 0, 0)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, @@ -2870,6 +2871,17 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, return resp; } #endif /* CONFIG_IEEE80211AC */ +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax) { + resp = copy_sta_he_capab(hapd, sta, elems.he_capabilities, elems.he_capabilities_len); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + + resp = copy_sta_he_oper(hapd, sta, elems.he_operation, elems.he_operation_len); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + } +#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_P2P if (elems.p2p) { @@ -3232,6 +3244,8 @@ static int add_associated_sta(struct hostapd_data *hapd, { struct ieee80211_ht_capabilities ht_cap; struct ieee80211_vht_capabilities vht_cap; + struct ieee80211_he_capabilities he_cap; + struct ieee80211_he_operation he_oper; int set = 1; /* @@ -3284,6 +3298,12 @@ static int add_associated_sta(struct hostapd_data *hapd, if (sta->flags & WLAN_STA_VHT) hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap); #endif /* CONFIG_IEEE80211AC */ +#ifdef CONFIG_IEEE80211AX + if (sta->flags & WLAN_STA_HE) { + hostapd_get_he_capab(hapd, sta->he_capabilities, &he_cap, sta->he_capabilities_len); + hostapd_get_he_oper(hapd, sta->he_operation, &he_oper, sta->he_operation_len); + } +#endif /* CONFIG_IEEE80211AX */ /* * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags @@ -3295,6 +3315,10 @@ static int add_associated_sta(struct hostapd_data *hapd, sta->listen_interval, sta->flags & WLAN_STA_HT ? &ht_cap : NULL, sta->flags & WLAN_STA_VHT ? &vht_cap : NULL, + sta->flags & WLAN_STA_HE ? &he_cap : NULL, + sta->flags & WLAN_STA_HE ? sta->he_capabilities_len : 0, + sta->flags & WLAN_STA_HE ? &he_oper : NULL, + sta->flags & WLAN_STA_HE ? sta->he_operation_len : 0, sta->flags | WLAN_STA_ASSOC, sta->qosinfo, sta->vht_opmode, sta->p2p_ie ? 1 : 0, set)) { @@ -3435,6 +3459,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_IEEE80211AC */ +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax) { + p = hostapd_eid_he_capab(hapd, p); + p = hostapd_eid_he_operation(hapd, p); + p = hostapd_eid_he_mu_edca_parameter_set(hapd, p); + p = hostapd_eid_spatial_reuse(hapd, p); + } +#endif /* CONFIG_IEEE80211AX */ + p = hostapd_eid_ext_capab(hapd, p); p = hostapd_eid_bss_max_idle_period(hapd, p); if (sta && sta->qos_map_enabled) diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 3699246b3..830d0586f 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -71,6 +71,14 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd, void hostapd_get_vht_capab(struct hostapd_data *hapd, struct ieee80211_vht_capabilities *vht_cap, struct ieee80211_vht_capabilities *neg_vht_cap); +void hostapd_get_he_capab(struct hostapd_data *hapd, + struct ieee80211_he_capabilities *he_cap, + struct ieee80211_he_capabilities *neg_he_cap, + int he_capab_len); +void hostapd_get_he_oper(struct hostapd_data *hapd, + struct ieee80211_he_operation *he_oper, + struct ieee80211_he_operation *neg_he_oper, + int he_oper_len); int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta); u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *ht_capab); @@ -86,6 +94,10 @@ u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta, const u8 *vht_oper); 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, int he_capab_len); +u16 copy_sta_he_oper(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *he_oper, int he_oper_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 72d88b0a2..b32e5aa2f 100644 --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -1,6 +1,7 @@ /* * hostapd / IEEE 802.11ax HE * Copyright (c) 2016-2017, Qualcomm Atheros, Inc. + * Copyright (c) 2019 John Crispin <john@xxxxxxxxxxx> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -13,6 +14,7 @@ #include "hostapd.h" #include "ap_config.h" #include "beacon.h" +#include "sta_info.h" #include "ieee802_11.h" #include "dfs.h" @@ -91,6 +93,10 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) (hapd->iface->conf->he_op.he_bss_color << HE_OPERATION_BSS_COLOR_OFFSET); + /* Basic NSS rates. Make no special requirements */ + oper->he_mcs_nss_set[0] = 0xff; + oper->he_mcs_nss_set[1] = 0xff; + /* TODO: conditional MaxBSSID Indicator subfield */ pos += oper_size; @@ -170,3 +176,127 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid) return pos; } + +void hostapd_get_he_capab(struct hostapd_data *hapd, + struct ieee80211_he_capabilities *he_cap, + struct ieee80211_he_capabilities *neg_he_cap, + int he_capab_len) +{ + if (he_cap == NULL) + return; + + /* TODO: mask out unsupported features */ + + os_memcpy(neg_he_cap, he_cap, he_capab_len); +} + + +void hostapd_get_he_oper(struct hostapd_data *hapd, + struct ieee80211_he_operation *he_oper, + struct ieee80211_he_operation *neg_he_oper, + int he_oper_len) +{ + if (he_oper == NULL) + return; + + /* TODO: mask out unsupported features */ + + os_memcpy(neg_he_oper, he_oper, he_oper_len); +} + + +static int check_valid_he_mcs(struct hostapd_hw_modes *mode, + const u8 *sta_he_capab) +{ + const struct ieee80211_he_capabilities *he_cap; + struct ieee80211_he_capabilities ap_he_cap; + u16 sta_rx_mcs_set, ap_tx_mcs_set; + int i; + + if (!mode) + return 1; + + /* + * Disable HE caps for STAs for which there is not even a single + * allowed MCS in any supported number of streams, i.e., STA is + * advertising 3 (not supported) as HE MCS rates for all supported + * band/stream cases. + */ + os_memcpy(&ap_he_cap.he_txrx_mcs_support, mode->he_capab.mcs, + HE_MAX_MCS_CAPAB_SIZE); + he_cap = (const struct ieee80211_he_capabilities *) sta_he_capab; + + for (i = 0; i < HE_NSS_MAX_BANDS; i++) { + int j; + + /* AP Tx MCS map vs. STA Rx MCS map */ + sta_rx_mcs_set = le_to_host16(he_cap->he_txrx_mcs_support[i * 2]); + ap_tx_mcs_set = le_to_host16(ap_he_cap.he_txrx_mcs_support[(i * 2) + 1]); + + for (j = 0; j < HE_NSS_MAX_STREAMS; j++) { + if ((ap_tx_mcs_set & (0x3 << (j * 2))) == 3) + continue; + + if ((sta_rx_mcs_set & (0x3 << (j * 2))) == 3) + continue; + + return 1; + } + } + + wpa_printf(MSG_DEBUG, + "No matching HE MCS found between AP TX and STA RX"); + + return 0; +} + + +u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *he_capab, int he_capab_len) +{ + if (!he_capab || !hapd->iconf->ieee80211ax || + !check_valid_he_mcs(hapd->iface->current_mode, he_capab)) { + sta->flags &= ~WLAN_STA_HE; + os_free(sta->he_capabilities); + sta->he_capabilities = NULL; + return WLAN_STATUS_SUCCESS; + } + + if (sta->he_capabilities == NULL) { + sta->he_capabilities = + os_zalloc(sizeof(struct ieee80211_he_capabilities)); + if (sta->he_capabilities == NULL) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + sta->flags |= WLAN_STA_HE; + os_memset(sta->he_capabilities, 0, sizeof(struct ieee80211_he_capabilities)); + os_memcpy(sta->he_capabilities, he_capab, he_capab_len); + sta->he_capabilities_len = he_capab_len; + + return WLAN_STATUS_SUCCESS; +} + + +u16 copy_sta_he_oper(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *he_oper, int he_oper_len) +{ + if (!he_oper) { + os_free(sta->he_operation); + sta->he_operation = NULL; + return WLAN_STATUS_SUCCESS; + } + + if (!sta->he_operation) { + sta->he_operation = + os_zalloc(sizeof(struct ieee80211_he_operation)); + if (!sta->he_operation) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + os_memset(sta->he_operation, 0, sizeof(struct ieee80211_he_operation)); + os_memcpy(sta->he_operation, he_oper, he_oper_len); + sta->he_operation_len = he_oper_len; + + return WLAN_STATUS_SUCCESS; +} diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 4f9eae847..6de858449 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -330,6 +330,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) os_free(sta->ht_capabilities); os_free(sta->vht_capabilities); os_free(sta->vht_operation); + os_free(sta->he_capabilities); + os_free(sta->he_operation); hostapd_free_psk_list(sta->psk); os_free(sta->identity); os_free(sta->radius_cui); diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index ece0c60ab..2d28c2589 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -37,6 +37,7 @@ #define WLAN_STA_VENDOR_VHT BIT(21) #define WLAN_STA_PENDING_FILS_ERP BIT(22) #define WLAN_STA_MULTI_AP BIT(23) +#define WLAN_STA_HE BIT(24) #define WLAN_STA_PENDING_DISASSOC_CB BIT(29) #define WLAN_STA_PENDING_DEAUTH_CB BIT(30) #define WLAN_STA_NONERP BIT(31) @@ -166,6 +167,10 @@ struct sta_info { struct ieee80211_vht_capabilities *vht_capabilities; struct ieee80211_vht_operation *vht_operation; u8 vht_opmode; + struct ieee80211_he_capabilities *he_capabilities; + int he_capabilities_len; + struct ieee80211_he_operation *he_operation; + int he_operation_len; #ifdef CONFIG_IEEE80211W int sa_query_count; /* number of pending SA Query requests; diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index c02b99dbc..4de539935 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -274,6 +274,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, elems->he_capabilities = pos; elems->he_capabilities_len = elen; break; + case WLAN_EID_EXT_HE_OPERATION: + elems->he_operation = pos; + elems->he_operation_len = elen; + break; case WLAN_EID_EXT_OCV_OCI: elems->oci = pos; elems->oci_len = elen; diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 930d45420..9b045b41a 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -94,6 +94,7 @@ struct ieee802_11_elems { const u8 *oci; const u8 *multi_ap; const u8 *he_capabilities; + const u8 *he_operation; u8 ssid_len; u8 supp_rates_len; @@ -143,6 +144,7 @@ struct ieee802_11_elems { u8 oci_len; u8 multi_ap_len; u8 he_capabilities_len; + u8 he_operation_len; struct mb_ies_info mb_ies; }; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 90615ece6..54bb35520 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1280,6 +1280,9 @@ struct ieee80211_ampe_ie { #define VHT_CHANWIDTH_160MHZ 2 #define VHT_CHANWIDTH_80P80MHZ 3 +#define HE_NSS_MAX_BANDS 3 +#define HE_NSS_MAX_STREAMS 8 + #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) * 00:50:F2 */ #define WPA_IE_VENDOR_TYPE 0x0050f201 @@ -2105,7 +2108,7 @@ enum nr_chan_width { struct ieee80211_he_capabilities { u8 he_mac_capab_info[6]; u8 he_phy_capab_info[11]; - u8 he_txrx_mcs_support[12]; /* TODO: 4, 8, or 12 octets */ + u16 he_txrx_mcs_support[6]; /* TODO: 2, 4, or 6 words */ /* PPE Thresholds (optional) */ } STRUCT_PACKED; diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 0acc0958a..376e65c4d 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1788,6 +1788,10 @@ struct hostapd_sta_add_params { const struct ieee80211_vht_capabilities *vht_capabilities; int vht_opmode_enabled; u8 vht_opmode; + const struct ieee80211_he_capabilities *he_capabilities; + int he_capabilities_len; + const struct ieee80211_he_operation *he_operation; + int he_operation_len; u32 flags; /* bitmask of WPA_STA_* flags */ u32 flags_mask; /* unset bits in flags */ #ifdef CONFIG_MESH diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 5da8a793b..94c77b470 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -4563,6 +4563,16 @@ static int wpa_driver_nl80211_sta_add(void *priv, goto fail; } + if (params->he_capabilities) { + wpa_hexdump(MSG_DEBUG, " * he_capabilities", + (u8 *) params->he_capabilities, + params->he_capabilities_len); + if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY, + params->he_capabilities_len, + params->he_capabilities)) + goto fail; + } + if (params->ext_capab) { wpa_hexdump(MSG_DEBUG, " * ext_capab", params->ext_capab, params->ext_capab_len); -- 2.11.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap