diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 7d7864833..12dc83ec0 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -227,6 +227,7 @@ #define WLAN_EID_FAST_BSS_TRANSITION 55 #define WLAN_EID_TIMEOUT_INTERVAL 56 #define WLAN_EID_RIC_DATA 57 +#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59 #define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 #define WLAN_EID_WAPI 68 diff --git a/src/drivers/driver.h b/src/drivers/driver.h index db34ed130..4fd16edc9 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1012,6 +1012,10 @@ struct hostapd_sta_add_params { u8 qosinfo; const u8 *ext_capab; size_t ext_capab_len; + const u8 *supp_channels; + size_t supp_channels_len; + const u8 *supp_oper_classes; + size_t supp_oper_classes_len; }; struct hostapd_freq_params { diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index efc643139..8a978f747 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -136,6 +136,12 @@ struct wpa_tdls_peer { u8 *ext_capab; size_t ext_capab_len; + + u8 *supp_channels; + size_t supp_channels_len; + + u8 *supp_oper_classes; + size_t supp_oper_classes_len; }; @@ -633,6 +639,10 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) peer->vht_capabilities = NULL; os_free(peer->ext_capab); peer->ext_capab = NULL; + os_free(peer->supp_channels); + peer->supp_channels = NULL; + os_free(peer->supp_oper_classes); + peer->supp_oper_classes = NULL; peer->rsnie_i_len = peer->rsnie_p_len = 0; peer->cipher = 0; peer->tpk_set = peer->tpk_success = 0; @@ -1456,6 +1466,58 @@ static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde, } +static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde, + struct wpa_tdls_peer *peer) +{ + if (!kde->supp_channels) { + wpa_printf(MSG_DEBUG, "TDLS: No supported channels received"); + return 0; + } + + if (!peer->supp_channels || + peer->supp_channels_len < kde->supp_channels_len) { + os_free(peer->supp_channels); + peer->supp_channels = os_zalloc(kde->supp_channels_len); + if (peer->supp_channels == NULL) + return -1; + } + + peer->supp_channels_len = kde->supp_channels_len; + + os_memcpy(peer->supp_channels, kde->supp_channels, + peer->supp_channels_len); + wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Channels", + (u8 *) peer->supp_channels, peer->supp_channels_len); + return 0; +} + + +static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde, + struct wpa_tdls_peer *peer) +{ + if (!kde->supp_oper_classes) { + wpa_printf(MSG_DEBUG, "TDLS: No supported operating classes received"); + return 0; + } + + if (!peer->supp_oper_classes || + peer->supp_oper_classes_len < kde->supp_oper_classes_len) { + os_free(peer->supp_oper_classes); + peer->supp_oper_classes = os_zalloc(kde->supp_oper_classes_len); + if (peer->supp_oper_classes == NULL) + return -1; + } + + peer->supp_oper_classes_len = kde->supp_oper_classes_len; + os_memcpy(peer->supp_oper_classes, kde->supp_oper_classes, + peer->supp_oper_classes_len); + wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Operating Classes", + (u8 *) peer->supp_oper_classes, + peer->supp_oper_classes_len); + return 0; +} + + static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len) { @@ -1568,6 +1630,12 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, if (copy_peer_ext_capab(&kde, peer) < 0) goto error; + if (copy_peer_supp_channels(&kde, peer) < 0) + goto error; + + if (copy_peer_supp_oper_classes(&kde, peer) < 0) + goto error; + peer->qos_info = kde.qosinfo; peer->aid = kde.aid; @@ -1761,7 +1829,7 @@ skip_rsn: skip_rsn_check: /* add the peer to the driver as a "setup in progress" peer */ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, - NULL, 0); + NULL, 0, NULL, 0, NULL, 0); peer->tpk_in_progress = 1; wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2"); @@ -1810,7 +1878,11 @@ static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) peer->ht_capabilities, peer->vht_capabilities, peer->qos_info, peer->ext_capab, - peer->ext_capab_len) < 0) + peer->ext_capab_len, + peer->supp_channels, + peer->supp_channels_len, + peer->supp_oper_classes, + peer->supp_oper_classes_len) < 0) return -1; if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) { @@ -1938,6 +2010,12 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, if (copy_peer_ext_capab(&kde, peer) < 0) goto error; + if (copy_peer_supp_channels(&kde, peer) < 0) + goto error; + + if (copy_peer_supp_oper_classes(&kde, peer) < 0) + goto error; + peer->qos_info = kde.qosinfo; peer->aid = kde.aid; @@ -2289,7 +2367,7 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) /* add the peer to the driver as a "setup in progress" peer */ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, - NULL, 0); + NULL, 0, NULL, 0, NULL, 0); peer->tpk_in_progress = 1; diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index e189a585f..9884ce12d 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -62,7 +62,10 @@ struct wpa_sm_ctx { const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, u8 qosinfo, const u8 *ext_capab, - size_t ext_capab_len); + size_t ext_capab_len, const u8 *supp_channels, + size_t supp_channels_len, + const u8 *supp_oper_classes, + size_t supp_oper_classes_len); #endif /* CONFIG_TDLS */ void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck, const u8 *replay_ctr); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 0e0d373f4..cad6c8d96 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -286,14 +286,21 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, size_t supp_rates_len, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, - u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len) + u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len, + const u8 *supp_channels, size_t supp_channels_len, + const u8 *supp_oper_classes, + size_t supp_oper_classes_len) { if (sm->ctx->tdls_peer_addset) return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add, aid, capability, supp_rates, supp_rates_len, ht_capab, vht_capab, qosinfo, - ext_capab, ext_capab_len); + ext_capab, ext_capab_len, + supp_channels, + supp_channels_len, + supp_oper_classes, + supp_oper_classes_len); return -1; } #endif /* CONFIG_TDLS */ diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 50b9272b2..ab8d104dd 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -434,6 +434,12 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, ie->vht_capabilities_len = pos[1]; } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) { ie->qosinfo = pos[2]; + } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) { + ie->supp_channels = pos + 2; + ie->supp_channels_len = pos[1]; + } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) { + ie->supp_oper_classes = pos + 2; + ie->supp_oper_classes_len = pos[1]; } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { ret = wpa_parse_generic(pos, end, ie); if (ret < 0) diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h index 2c788012e..0375767d6 100644 --- a/src/rsn_supp/wpa_ie.h +++ b/src/rsn_supp/wpa_ie.h @@ -53,6 +53,10 @@ struct wpa_eapol_ie_parse { size_t ht_capabilities_len; const u8 *vht_capabilities; size_t vht_capabilities_len; + const u8 *supp_channels; + size_t supp_channels_len; + const u8 *supp_oper_classes; + size_t supp_oper_classes_len; u8 qosinfo; u16 aid; }; diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 999d66762..ad0895be5 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -579,7 +579,9 @@ static int wpa_supplicant_tdls_peer_addset( const u8 *supp_rates, size_t supp_rates_len, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, - u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len) + u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len, + const u8 *supp_channels, size_t supp_channels_len, + const u8 *supp_oper_classes, size_t supp_oper_classes_len) { struct wpa_supplicant *wpa_s = ctx; struct hostapd_sta_add_params params; @@ -607,6 +609,10 @@ static int wpa_supplicant_tdls_peer_addset( params.set = !add; params.ext_capab = ext_capab; params.ext_capab_len = ext_capab_len; + params.supp_channels = supp_channels; + params.supp_channels_len = supp_channels_len; + params.supp_oper_classes = supp_oper_classes; + params.supp_oper_classes_len = supp_oper_classes_len; return wpa_drv_sta_add(wpa_s, ¶ms); }