diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index 125ae0848..a6e7f952a 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -1168,6 +1168,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, u8 dtoken; u16 ielen; u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; + int tdls_prohibited = sm->tdls_prohibited; if (len < 3 + 3) return -1; @@ -1226,6 +1227,12 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, } #endif /* CONFIG_TDLS_TESTING */ + if (tdls_prohibited) { + wpa_printf(MSG_INFO, "TDLS: TDLS prohibited in this BSS"); + status = WLAN_STATUS_REQUEST_DECLINED; + goto error; + } + if (!wpa_tdls_get_privacy(sm)) { if (kde.rsn_ie) { wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M1 while " @@ -1808,6 +1815,13 @@ static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs) int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) { struct wpa_tdls_peer *peer; + int tdls_prohibited = sm->tdls_prohibited; + + if (tdls_prohibited) { + wpa_printf(MSG_DEBUG, "TDLS: TDLS is prohibited in this BSS - " + "reject request to start setup"); + return -1; + } /* Find existing entry and if found, use that instead of adding * a new one */ @@ -1984,3 +1998,39 @@ void wpa_tdls_disassoc(struct wpa_sm *sm) wpa_printf(MSG_DEBUG, "TDLS: Remove peers on disassociation"); wpa_tdls_remove_peers(sm); } + + +static int wpa_tdls_prohibited(const u8 *ies, size_t len) +{ + struct wpa_eapol_ie_parse elems; + + if (ies == NULL) + return 0; + + if (wpa_supplicant_parse_ies(ies, len, &elems) < 0) + return 0; + + if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5) + return 0; + + /* bit 38 - TDLS Prohibited */ + return !!(elems.ext_capab[2 + 4] & 0x40); +} + + +void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len) +{ + sm->tdls_prohibited = wpa_tdls_prohibited(ies, len); + wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS", + sm->tdls_prohibited ? "prohibited" : "allowed"); +} + + +void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len) +{ + if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) { + wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on " + "(Re)Association Response IEs"); + sm->tdls_prohibited = 1; + } +} diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index f14062b8f..41bafee63 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -338,6 +338,8 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len, /* tdls.c */ +void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len); +void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len); int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr); int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr); int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr, diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index b8bb6286d..590dea149 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -96,6 +96,7 @@ struct wpa_sm { #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_TDLS struct wpa_tdls_peer *tdls; + int tdls_prohibited; #endif /* CONFIG_TDLS */ #ifdef CONFIG_IEEE80211R diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 5db6f097c..654cc1f15 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -426,6 +426,9 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, } else if (*pos == WLAN_EID_LINK_ID) { ie->lnkid = pos; ie->lnkid_len = pos[1] + 2; + } else if (*pos == WLAN_EID_EXT_CAPAB) { + ie->ext_capab = pos; + ie->ext_capab_len = pos[1] + 2; } 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 62a2677e8..f939b13d1 100644 --- a/src/rsn_supp/wpa_ie.h +++ b/src/rsn_supp/wpa_ie.h @@ -49,6 +49,8 @@ struct wpa_eapol_ie_parse { const u8 *key_lifetime; const u8 *lnkid; size_t lnkid_len; + const u8 *ext_capab; + size_t ext_capab_len; }; int wpa_supplicant_parse_ies(const u8 *buf, size_t len, diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 5105955b5..1704e0670 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1024,9 +1024,14 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, if (data->assoc_info.req_ies) wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies, data->assoc_info.req_ies_len); - if (data->assoc_info.resp_ies) + if (data->assoc_info.resp_ies) { wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); +#ifdef CONFIG_TDLS + wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); +#endif /* CONFIG_TDLS */ + } if (data->assoc_info.beacon_ies) wpa_hexdump(MSG_DEBUG, "beacon_ies", data->assoc_info.beacon_ies, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 34798791c..60cda697f 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1046,6 +1046,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } +#ifdef CONFIG_TDLS + wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1), bss->ie_len); +#endif /* CONFIG_TDLS */ + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && ssid->mode == IEEE80211_MODE_INFRA) { sme_authenticate(wpa_s, bss, ssid);