Accumulative patch from commit b618a469c42120e984ab1c85ed6058504d1fca78

  Author: Jouni Malinen <jouni@qca.qualcomm.com>
  Date:   Sat Feb 16 19:54:09 2013 +0200
    Interworking: Select highest priority cred if multiple matches

Interworking: Select highest priority cred if multiple matches
GAS server: Fix a regression in GAS server callback
hostapd: Fix Max SP Length derivation from QoS Info
nl80211: Configure STA Capabilities and Extended Capabilities
Synchronize with wireless-testing.git include/uapi/linux/nl80211.h
WPS: Fix build without CONFIG_WPS_NFC
WPS: Add support for NFC handover select generation with wpa_supplicant
WPS: Update NFC connection handover documentation
WPS: Add support for config token generation with wpa_supplicant
WPS: Allow password token to be written with nfcpy
WPS: Use pre-configured NFC password token instead of overriding it
TDLS: Pass peer's Capability and Ext Capability info during sta_add
TDLS: Pass peer's HT Capability and QOS information during sta_add
nl80211: Add debug prints for STA add/set operations
TDLS: Fix add/set STA operation
Synchronize with wireless-testing.git include/uapi/linux/nl80211.h
WPS: Allow Device Password to be changed from M1 to M2
WPS: Fix wps_reg nfc-pw option
TDLS: Tear down peers when disconnecting from the AP
P2P: Do not use old scan result data for peer discovery
Use more accurate timestamps for scan results
P2P: Postpone P2P-DEVICE-FOUND if config_methods not known
P2P: Do not allow peer update to clear config_methods
WPS: Report NFC connection handover completion differently
P2P: Avoid concurrent scans during all steps of group formation
P2P: Cancel group formation timeout on group removal (on client)
WPS: Change listen time to match nfcpy default (250 ms)
WPS: Report only the carrier record from NFC to wpa_supplicant
WPS: Fetch only the carrier record from wpa_supplicant for NFC
WPS: Update nfcpy script to support AP mode NFC connection handover
WPS: Add command for fetching carrier record for NFC handover
WPS: Clean up debug prints with nfcpy
WPS: Remove 0.5 sec extra wait from NFC handover with nfcpy
WPS: Use alternating poll/listen for NFC peer discovery with nfcpy
WPS: Configure logging to show nfcpy log message
WPS: Add an example python script for NFC operations with hostapd
hostapd: Do not change HT40 capability due to OBSS scan
dbus: Add missing signal description for WPS (7)
EAP peer: Add Session-Id derivation to more EAP methods
EAP peer: Add Session-Id derivation
EAP-IKEV2 server: Fix invalid memory freeing operation
eap_proxy: Add a dummy implementation for compilation testing
eap_proxy: Add mechanism for allowing EAP methods to be offloaded
Android: Allow setgroups to be overridden from build configuration
P2P: Send p2p_stop_find event on failure to start pending p2p_find
P2P: Fix GO Probe Response IEs when Wi-Fi Display is enabled
Capability matching for 60 GHz band
nl80211: Add ctrl_iface message for AP mode connection rejection
P2P: Allow local configuration to use 5 GHz band 40 MHz channels
Fix BSS RANGE command for no exact id match cases

Change-Id: Iac9284bba31db40911aecc3adf2843c9b1576db1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 9a79d28..09adc19 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -120,6 +120,13 @@
 
 	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 	size_t supp_rates_len;
+
+	struct ieee80211_ht_capabilities *ht_capabilities;
+
+	u8 qos_info;
+
+	u8 *ext_capab;
+	size_t ext_capab_len;
 };
 
 
@@ -611,6 +618,10 @@
 	peer->initiator = 0;
 	os_free(peer->sm_tmr.buf);
 	peer->sm_tmr.buf = NULL;
+	os_free(peer->ht_capabilities);
+	peer->ht_capabilities = NULL;
+	os_free(peer->ext_capab);
+	peer->ext_capab = NULL;
 	peer->rsnie_i_len = peer->rsnie_p_len = 0;
 	peer->cipher = 0;
 	peer->tpk_set = peer->tpk_success = 0;
@@ -681,8 +692,10 @@
 	pos = rbuf;
 
 	if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) {
-		/* Overwrite the reason code */
-		reason_code = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
+		if (reason_code != WLAN_REASON_DEAUTH_LEAVING) {
+			/* Overwrite the reason code */
+			reason_code = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
+		}
 		goto skip_ies;
 	}
 
@@ -1329,6 +1342,58 @@
 }
 
 
+static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde,
+			      struct wpa_tdls_peer *peer)
+{
+	if (!kde->ht_capabilities ||
+	    kde->ht_capabilities_len <
+	    sizeof(struct ieee80211_ht_capabilities) ) {
+		wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities "
+			   "received");
+		return 0;
+	}
+
+	if (!peer->ht_capabilities) {
+		peer->ht_capabilities =
+                        os_zalloc(sizeof(struct ieee80211_ht_capabilities));
+		if (peer->ht_capabilities == NULL)
+                        return -1;
+	}
+
+	os_memcpy(peer->ht_capabilities, kde->ht_capabilities,
+                  sizeof(struct ieee80211_ht_capabilities));
+	wpa_hexdump(MSG_DEBUG, "TDLS: Peer HT capabilities",
+		    (u8 *) peer->ht_capabilities,
+		    sizeof(struct ieee80211_ht_capabilities));
+
+	return 0;
+}
+
+
+static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde,
+			       struct wpa_tdls_peer *peer)
+{
+	if (!kde->ext_capab) {
+		wpa_printf(MSG_DEBUG, "TDLS: No extended capabilities "
+			   "received");
+		return 0;
+	}
+
+	if (!peer->ext_capab || peer->ext_capab_len < kde->ext_capab_len - 2) {
+		/* Need to allocate buffer to fit the new information */
+		os_free(peer->ext_capab);
+		peer->ext_capab = os_zalloc(kde->ext_capab_len - 2);
+		if (peer->ext_capab == NULL)
+			return -1;
+	}
+
+	peer->ext_capab_len = kde->ext_capab_len - 2;
+	os_memcpy(peer->ext_capab, kde->ext_capab + 2, peer->ext_capab_len);
+
+	return 0;
+}
+
+
 static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
 				   const u8 *buf, size_t len)
 {
@@ -1398,6 +1463,14 @@
 	if (copy_supp_rates(&kde, peer) < 0)
 		goto error;
 
+	if (copy_peer_ht_capab(&kde, peer) < 0)
+		goto error;
+
+	if (copy_peer_ext_capab(&kde, peer) < 0)
+		goto error;
+
+	peer->qos_info = kde.qosinfo;
+
 #ifdef CONFIG_TDLS_TESTING
 	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
 		peer = wpa_tdls_add_peer(sm, src_addr, NULL);
@@ -1621,7 +1694,8 @@
 
 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, NULL, 0);
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0, NULL, 0,
+				NULL, 0);
 
 	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
 	if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
@@ -1661,9 +1735,11 @@
 #endif /* CONFIG_TDLS_TESTING */
 	}
 
-	/* add supported rates and capabilities to the TDLS peer */
+	/* add supported rates, capabilities, and qos_info to the TDLS peer */
 	wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
-				peer->supp_rates, peer->supp_rates_len);
+				peer->supp_rates, peer->supp_rates_len,
+				peer->ht_capabilities, peer->qos_info,
+				peer->ext_capab, peer->ext_capab_len);
 
 	wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
 }
@@ -1759,6 +1835,14 @@
 	if (copy_supp_rates(&kde, peer) < 0)
 		goto error;
 
+	if (copy_peer_ht_capab(&kde, peer) < 0)
+		goto error;
+
+	if (copy_peer_ext_capab(&kde, peer) < 0)
+		goto error;
+
+	peer->qos_info = kde.qosinfo;
+
 	if (!wpa_tdls_get_privacy(sm)) {
 		peer->rsnie_p_len = 0;
 		peer->cipher = WPA_CIPHER_NONE;
@@ -2062,7 +2146,8 @@
 	peer->initiator = 1;
 
 	/* add the peer to the driver as a "setup in progress" peer */
-	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0, NULL, 0,
+				NULL, 0);
 
 	if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
 		wpa_tdls_disable_link(sm, peer->addr);
@@ -2207,6 +2292,28 @@
 }
 
 
+void wpa_tdls_teardown_peers(struct wpa_sm *sm)
+{
+	struct wpa_tdls_peer *peer;
+
+	peer = sm->tdls;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
+
+	while (peer) {
+		wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR,
+			   MAC2STR(peer->addr));
+		if (sm->tdls_external_setup)
+			wpa_tdls_send_teardown(sm, peer->addr,
+					       WLAN_REASON_DEAUTH_LEAVING);
+		else
+			wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+
+		peer = peer->next;
+	}
+}
+
+
 static void wpa_tdls_remove_peers(struct wpa_sm *sm)
 {
 	struct wpa_tdls_peer *peer, *tmp;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 2c989b7..6679dda 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -12,6 +12,7 @@
 #include "common/defs.h"
 #include "common/eapol_common.h"
 #include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
 
 struct wpa_sm;
 struct eapol_sm;
@@ -57,7 +58,10 @@
 	int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
 	int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
 				u16 capability, const u8 *supp_rates,
-				size_t supp_rates_len);
+				size_t supp_rates_len,
+				const struct ieee80211_ht_capabilities *ht_capab,
+				u8 qosinfo, const u8 *ext_capab,
+				size_t ext_capab_len);
 #endif /* CONFIG_TDLS */
 	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
 				  const u8 *replay_ctr);
@@ -360,6 +364,7 @@
 int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
 int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
 int wpa_tdls_init(struct wpa_sm *sm);
+void wpa_tdls_teardown_peers(struct wpa_sm *sm);
 void wpa_tdls_deinit(struct wpa_sm *sm);
 void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
 void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 9f9e641..5dae5de 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -283,12 +283,16 @@
 static inline int
 wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
 			u16 capability, const u8 *supp_rates,
-			size_t supp_rates_len)
+			size_t supp_rates_len,
+			const struct ieee80211_ht_capabilities *ht_capab,
+			u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
 {
 	if (sm->ctx->tdls_peer_addset)
 		return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
 						 capability, supp_rates,
-						 supp_rates_len);
+						 supp_rates_len, ht_capab,
+						 qosinfo, ext_capab,
+						 ext_capab_len);
 	return -1;
 }
 #endif /* CONFIG_TDLS */
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 3d75365..252737f 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -427,6 +427,11 @@
 		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
 			ie->ext_supp_rates = pos;
 			ie->ext_supp_rates_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_HT_CAP) {
+			ie->ht_capabilities = pos + 2;
+			ie->ht_capabilities_len = pos[1];
+		} else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+			ie->qosinfo = pos[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 5afdfe9..b212711 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -49,6 +49,9 @@
 	size_t supp_rates_len;
 	const u8 *ext_supp_rates;
 	size_t ext_supp_rates_len;
+	const u8 *ht_capabilities;
+	size_t ht_capabilities_len;
+	u8 qosinfo;
 };
 
 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,