Browse Source

TDLS: Do not allow setup to be started if AP prohibits TDLS

Jouni Malinen 14 years ago
parent
commit
52c9e6f3f5

+ 50 - 0
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;
+	}
+}

+ 2 - 0
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,

+ 1 - 0
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

+ 3 - 0
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)

+ 2 - 0
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,

+ 6 - 1
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,

+ 4 - 0
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);