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/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index e1f58a6..3602b07 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -42,6 +42,10 @@
 #endif
 
 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+static struct wpa_cred * interworking_credentials_available_realm(
+	struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+static struct wpa_cred * interworking_credentials_available_3gpp(
+	struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
 
 
 static void interworking_reconnect(struct wpa_supplicant *wpa_s)
@@ -740,10 +744,10 @@
 
 
 static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
+				     struct wpa_cred *cred,
 				     struct wpa_bss *bss)
 {
 #ifdef INTERWORKING_3GPP
-	struct wpa_cred *cred;
 	struct wpa_ssid *ssid;
 	const u8 *ie;
 	int eap_type;
@@ -753,40 +757,6 @@
 	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
 		return -1;
 
-	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
-		char *sep;
-		const char *imsi;
-		int mnc_len;
-
-#ifdef PCSC_FUNCS
-		if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
-		    wpa_s->imsi[0]) {
-			imsi = wpa_s->imsi;
-			mnc_len = wpa_s->mnc_len;
-			goto compare;
-		}
-#endif /* PCSC_FUNCS */
-
-		if (cred->imsi == NULL || !cred->imsi[0] ||
-		    cred->milenage == NULL || !cred->milenage[0])
-			continue;
-
-		sep = os_strchr(cred->imsi, '-');
-		if (sep == NULL ||
-		    (sep - cred->imsi != 5 && sep - cred->imsi != 6))
-			continue;
-		mnc_len = sep - cred->imsi - 3;
-		imsi = cred->imsi;
-
-#ifdef PCSC_FUNCS
-	compare:
-#endif /* PCSC_FUNCS */
-		if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
-			break;
-	}
-	if (cred == NULL)
-		return -1;
-
 	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
 	if (ie == NULL)
 		return -1;
@@ -1167,7 +1137,7 @@
 
 int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
-	struct wpa_cred *cred;
+	struct wpa_cred *cred, *cred_rc, *cred_3gpp;
 	struct wpa_ssid *ssid;
 	struct nai_realm *realm;
 	struct nai_realm_eap *eap = NULL;
@@ -1194,39 +1164,61 @@
 		return -1;
 	}
 
-	cred = interworking_credentials_available_roaming_consortium(wpa_s,
-								     bss);
-	if (cred)
-		return interworking_connect_roaming_consortium(wpa_s, cred,
+	cred_rc = interworking_credentials_available_roaming_consortium(wpa_s,
+									bss);
+	if (cred_rc) {
+		wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
+			   "consortium matching credential priority %d",
+			   cred_rc->priority);
+	}
+
+	cred = interworking_credentials_available_realm(wpa_s, bss);
+	if (cred) {
+		wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
+			   "matching credential priority %d",
+			   cred->priority);
+	}
+
+	cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss);
+	if (cred_3gpp) {
+		wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
+			   "credential priority %d", cred_3gpp->priority);
+	}
+
+	if (cred_rc &&
+	    (cred == NULL || cred_rc->priority >= cred->priority) &&
+	    (cred_3gpp == NULL || cred_rc->priority >= cred_3gpp->priority))
+		return interworking_connect_roaming_consortium(wpa_s, cred_rc,
 							       bss, ie);
 
+	if (cred_3gpp &&
+	    (cred == NULL || cred_3gpp->priority >= cred->priority)) {
+		return interworking_connect_3gpp(wpa_s, cred_3gpp, bss);
+	}
+
+	if (cred == NULL) {
+		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
+			   "found for " MACSTR, MAC2STR(bss->bssid));
+		return -1;
+	}
+
 	realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
 				&count);
 	if (realm == NULL) {
 		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
 			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
-		count = 0;
+		return -1;
 	}
 
-	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
-		for (i = 0; i < count; i++) {
-			if (!nai_realm_match(&realm[i], cred->realm))
-				continue;
-			eap = nai_realm_find_eap(cred, &realm[i]);
-			if (eap)
-				break;
-		}
+	for (i = 0; i < count; i++) {
+		if (!nai_realm_match(&realm[i], cred->realm))
+			continue;
+		eap = nai_realm_find_eap(cred, &realm[i]);
 		if (eap)
 			break;
 	}
 
 	if (!eap) {
-		if (interworking_connect_3gpp(wpa_s, bss) == 0) {
-			if (realm)
-				nai_realm_free(realm, count);
-			return 0;
-		}
-
 		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
 			   "and EAP method found for " MACSTR,
 			   MAC2STR(bss->bssid));