Cumulative patch from commit 538922a628d4f5403b9a96b171a59235bcb3d921

538922a dbus: Add boolean AllowRoam option to Scan() method options dictionary
c6f5dec Don't start second scan when changing scan interval
cd3b070 nl80211: Fix DFS radar event parsing
2b72df6 nl80211: Free BSS structure even if netdev does not exists
41cc50d nl80211: Update send_action_cookie on AP-offchannel-TX path
313424d GAS: Add support for multiple pending queries for the same destination
cbc5484 GAS: Do not start new scan operation during an ongoing GAS query
c377514 GAS: Delay GAS query Tx while scanning/connecting
24c694b GAS: Delay GAS query Tx while another query is in progress
7255983 WPS: Clear after_wps from number of new locations
73b54d6 P2P: Fix Operating Channel in Invitation Request for operating group
dc46fd6 P2P: Cancel offchannel TX wait on Invitation Response RX
0c92963 D-Bus: Clean up debug print for P2P invitation result
8d82c21 P2P: Fix PD retry channel on join-a-group case
d285888 P2P: Add GO BSS entry details to debug log on join-a-group
512629a P2P: Accept Invitation Response non-success without Channel List
e241b1b eap_proxy: Fix IMSI fetch for home vs. visited network determination
db13605 EAP-AKA/AKA' peer: Allow external USIM processing to be used
569ccf7 EAP-SIM peer: Allow external SIM processing to be used
84dc137 hlr_auc_gw: Add GSM-AUTH-REQ command
a5d44ac EAP peer: Add framework for external SIM/USIM processing
7e8bc7d eapol_test: Initialize BSS lists
bceb843 Send CTRL-RSP command response before processing EAPOL update
b607796 eapol_test: Fix external EAP request mechanism
94de082 eapol_test: Initialize wpa_s->global to fix ctrl_iface
f07bba3 Android: Add dfs.c into build
0cf0af2 WNM: Set Disassoc Imminent flag in ESS Disassoc Imminent frame
f47c145 Interworking: Add required_roaming_consortium parameter for credentials
a83e574 GAS: Update timeout from TX status handler
e88060e HTTP server: Allow TCP socket to be reused
9bc3386 Add test option for specifying hardcoded BSS Load element
9c7e43a Define BSS Load element id
56f5af4 Interworking: Add support for QoS Mapping functionality for the STA
850e1c2 atheros: Add support for QoS Mapping configuration
c551700 Interworking: Add support for QoS Mapping functionality for the AP
ac1bc54 Interworking: Add domain_suffix_match for credentials
463c8ff Interworking: Add support for multiple home FQDNs
01f809c Add AAA server domain name suffix matching constraint
be7963b OpenSSL: Fix code indentation in OCSP processing
899cc14 hostapd: Add support for DFS with 160 MHz channel width
6de0e0c Mark DFS functions static and rename them
58b73e3 hostapd: DFS with 40/80 MHz channel width support
846de15 DFS: Add more parameters to radar events
04e8003 nl80211: Use struct hostapd_freq_params with start_dfs_cac
72c753d hostapd: Split hostapd_set_freq to helper function
e76da50 hostapd: Add AP DFS support

Change-Id: Ie9ed4662ba6d81e6d8b14bccb29ffa192becf0f2
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 8515b5a..5075976 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -794,6 +794,7 @@
 OBJS += src/ap/ap_list.c
 OBJS += src/ap/ieee802_11.c
 OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
 L_CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_WPS
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 5698619..7c44241 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -772,6 +772,7 @@
 OBJS += ../src/ap/ap_list.o
 OBJS += ../src/ap/ieee802_11.o
 OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
 CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_WPS
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 5669c55..61e4a4d 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -166,9 +166,25 @@
 # milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
 #	format
 #
-# domain: Home service provider FQDN
+# domain_suffix_match: Constraint for server domain name
+#	If set, this FQDN is used as a suffix match requirement for the AAA
+#	server certificate in SubjectAltName dNSName element(s). If a
+#	matching dNSName is found, this constraint is met. If no dNSName
+#	values are present, this constraint is matched against SubjetName CN
+#	using same suffix match comparison. Suffix match here means that the
+#	host/domain name is compared one label at a time starting from the
+#	top-level domain and all the labels in @domain_suffix_match shall be
+#	included in the certificate. The certificate may include additional
+#	sub-level labels in addition to the required labels.
+#
+#	For example, domain_suffix_match=example.com would match
+#	test.example.com but would not match test-example.com.
+#
+# domain: Home service provider FQDN(s)
 #	This is used to compare against the Domain Name List to figure out
-#	whether the AP is operated by the Home SP.
+#	whether the AP is operated by the Home SP. Multiple domain entries can
+#	be used to configure alternative FQDNs that will be considered home
+#	networks.
 #
 # roaming_consortium: Roaming Consortium OI
 #	If roaming_consortium_len is non-zero, this field contains the
@@ -203,6 +219,7 @@
 #	password="password"
 #	ca_cert="/etc/wpa_supplicant/ca.pem"
 #	domain="example.com"
+#	domain_suffix_match="example.com"
 #}
 #
 #cred={
@@ -267,6 +284,17 @@
 Note: the return value of add_cred is used as the first argument to
 the following set_cred commands.
 
+Add a SIM credential using a external SIM/USIM processing:
+
+> set external_sim 1
+OK
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 eap SIM
+OK
+
 
 Add a WPA2-Enterprise network:
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2b17365..ea7ac5a 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1579,6 +1579,7 @@
 	{ STRe(dh_file) },
 	{ STRe(subject_match) },
 	{ STRe(altsubject_match) },
+	{ STRe(domain_suffix_match) },
 	{ STRe(ca_cert2) },
 	{ STRe(ca_path2) },
 	{ STRe(client_cert2) },
@@ -1587,6 +1588,7 @@
 	{ STRe(dh_file2) },
 	{ STRe(subject_match2) },
 	{ STRe(altsubject_match2) },
+	{ STRe(domain_suffix_match2) },
 	{ STRe(phase1) },
 	{ STRe(phase2) },
 	{ STRe(pcsc) },
@@ -1786,6 +1788,7 @@
 	os_free(eap->dh_file);
 	os_free(eap->subject_match);
 	os_free(eap->altsubject_match);
+	os_free(eap->domain_suffix_match);
 	os_free(eap->ca_cert2);
 	os_free(eap->ca_path2);
 	os_free(eap->client_cert2);
@@ -1794,6 +1797,7 @@
 	os_free(eap->dh_file2);
 	os_free(eap->subject_match2);
 	os_free(eap->altsubject_match2);
+	os_free(eap->domain_suffix_match2);
 	os_free(eap->phase1);
 	os_free(eap->phase2);
 	os_free(eap->pcsc);
@@ -1811,6 +1815,7 @@
 	os_free(eap->pending_req_otp);
 	os_free(eap->pac_file);
 	os_free(eap->new_password);
+	os_free(eap->external_sim_resp);
 }
 #endif /* IEEE8021X_EAPOL */
 
@@ -1851,6 +1856,8 @@
 
 void wpa_config_free_cred(struct wpa_cred *cred)
 {
+	size_t i;
+
 	os_free(cred->realm);
 	os_free(cred->username);
 	os_free(cred->password);
@@ -1860,7 +1867,10 @@
 	os_free(cred->private_key_passwd);
 	os_free(cred->imsi);
 	os_free(cred->milenage);
+	for (i = 0; i < cred->num_domain; i++)
+		os_free(cred->domain[i]);
 	os_free(cred->domain);
+	os_free(cred->domain_suffix_match);
 	os_free(cred->eap_method);
 	os_free(cred->phase1);
 	os_free(cred->phase2);
@@ -2432,9 +2442,23 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "domain_suffix_match") == 0) {
+		os_free(cred->domain_suffix_match);
+		cred->domain_suffix_match = val;
+		return 0;
+	}
+
 	if (os_strcmp(var, "domain") == 0) {
-		os_free(cred->domain);
-		cred->domain = val;
+		char **new_domain;
+		new_domain = os_realloc_array(cred->domain,
+					      cred->num_domain + 1,
+					      sizeof(char *));
+		if (new_domain == NULL) {
+			os_free(val);
+			return -1;
+		}
+		new_domain[cred->num_domain++] = val;
+		cred->domain = new_domain;
 		return 0;
 	}
 
@@ -2464,6 +2488,21 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "required_roaming_consortium") == 0) {
+		if (len < 3 || len > sizeof(cred->required_roaming_consortium))
+		{
+			wpa_printf(MSG_ERROR, "Line %d: invalid "
+				   "required_roaming_consortium length %d "
+				   "(3..15 expected)", line, (int) len);
+			os_free(val);
+			return -1;
+		}
+		os_memcpy(cred->required_roaming_consortium, val, len);
+		cred->required_roaming_consortium_len = len;
+		os_free(val);
+		return 0;
+	}
+
 	if (os_strcmp(var, "excluded_ssid") == 0) {
 		struct excluded_ssid *e;
 
@@ -3156,6 +3195,7 @@
 	{ STR(pkcs11_module_path), 0 },
 	{ STR(pcsc_reader), 0 },
 	{ STR(pcsc_pin), 0 },
+	{ INT(external_sim), 0 },
 	{ STR(driver_param), 0 },
 	{ INT(dot11RSNAConfigPMKLifetime), 0 },
 	{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 1748cf3..2e558fd 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -150,12 +150,37 @@
 	char *milenage;
 
 	/**
-	 * domain - Home service provider FQDN
+	 * domain_suffix_match - Constraint for server domain name
+	 *
+	 * If set, this FQDN is used as a suffix match requirement for the AAA
+	 * server certificate in SubjectAltName dNSName element(s). If a
+	 * matching dNSName is found, this constraint is met. If no dNSName
+	 * values are present, this constraint is matched against SubjetName CN
+	 * using same suffix match comparison. Suffix match here means that the
+	 * host/domain name is compared one label at a time starting from the
+	 * top-level domain and all the labels in @domain_suffix_match shall be
+	 * included in the certificate. The certificate may include additional
+	 * sub-level labels in addition to the required labels.
+	 *
+	 * For example, domain_suffix_match=example.com would match
+	 * test.example.com but would not match test-example.com.
+	 */
+	char *domain_suffix_match;
+
+	/**
+	 * domain - Home service provider FQDN(s)
 	 *
 	 * This is used to compare against the Domain Name List to figure out
-	 * whether the AP is operated by the Home SP.
+	 * whether the AP is operated by the Home SP. Multiple domain entries
+	 * can be used to configure alternative FQDNs that will be considered
+	 * home networks.
 	 */
-	char *domain;
+	char **domain;
+
+	/**
+	 * num_domain - Number of FQDNs in the domain array
+	 */
+	size_t num_domain;
 
 	/**
 	 * roaming_consortium - Roaming Consortium OI
@@ -175,6 +200,9 @@
 	 */
 	size_t roaming_consortium_len;
 
+	u8 required_roaming_consortium[15];
+	size_t required_roaming_consortium_len;
+
 	/**
 	 * eap_method - EAP method to use
 	 *
@@ -425,6 +453,11 @@
 	char *pcsc_pin;
 
 	/**
+	 * external_sim - Use external processing for SIM/USIM operations
+	 */
+	int external_sim;
+
+	/**
 	 * driver_param - Driver interface parameters
 	 *
 	 * This text string is passed to the selected driver interface with the
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 0d2bd8c..b8fff70 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -667,6 +667,7 @@
 	STR(dh_file);
 	STR(subject_match);
 	STR(altsubject_match);
+	STR(domain_suffix_match);
 	STR(ca_cert2);
 	STR(ca_path2);
 	STR(client_cert2);
@@ -675,6 +676,7 @@
 	STR(dh_file2);
 	STR(subject_match2);
 	STR(altsubject_match2);
+	STR(domain_suffix_match2);
 	STR(phase1);
 	STR(phase2);
 	STR(pcsc);
@@ -726,6 +728,8 @@
 
 static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
 {
+	size_t i;
+
 	if (cred->priority)
 		fprintf(f, "\tpriority=%d\n", cred->priority);
 	if (cred->pcsc)
@@ -751,10 +755,12 @@
 		fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
 	if (cred->milenage)
 		fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
-	if (cred->domain)
-		fprintf(f, "\tdomain=\"%s\"\n", cred->domain);
+	for (i = 0; i < cred->num_domain; i++)
+		fprintf(f, "\tdomain=\"%s\"\n", cred->domain[i]);
+	if (cred->domain_suffix_match)
+		fprintf(f, "\tdomain_suffix_match=\"%s\"",
+			cred->domain_suffix_match);
 	if (cred->roaming_consortium_len) {
-		size_t i;
 		fprintf(f, "\troaming_consortium=");
 		for (i = 0; i < cred->roaming_consortium_len; i++)
 			fprintf(f, "%02x", cred->roaming_consortium[i]);
@@ -771,7 +777,7 @@
 	if (cred->phase2)
 		fprintf(f, "\tphase2=\"%s\"\n", cred->phase2);
 	if (cred->excluded_ssid) {
-		size_t i, j;
+		size_t j;
 		for (i = 0; i < cred->num_excluded_ssid; i++) {
 			struct excluded_ssid *e = &cred->excluded_ssid[i];
 			fprintf(f, "\texcluded_ssid=");
@@ -1049,6 +1055,9 @@
 	if (config->sched_scan_interval)
 		fprintf(f, "sched_scan_interval=%u\n",
 			config->sched_scan_interval);
+
+	if (config->external_sim)
+		fprintf(f, "external_sim=%d\n", config->external_sim);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 1b5e237..00a1004 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -623,6 +623,9 @@
 	wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
 	wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
 
+	wpa_config_write_reg_dword(hk, TEXT("external_sim"),
+				   config->external_sim, 0);
+
 	return 0;
 }
 
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 4aa67f7..15f5268 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1565,16 +1565,21 @@
 		char *type;
 
 		for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+			size_t i;
+
 			if (wpa_s->current_ssid->parent_cred != cred)
 				continue;
 			if (!cred->domain)
 				continue;
 
-			ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
-					  cred->domain);
-			if (ret < 0 || ret >= end - pos)
-				return pos - buf;
-			pos += ret;
+			for (i = 0; i < cred->num_domain; i++) {
+				ret = os_snprintf(pos, end - pos,
+						  "home_sp=%s\n",
+						  cred->domain[i]);
+				if (ret < 0 || ret >= end - pos)
+					return pos - buf;
+				pos += ret;
+			}
 
 			if (wpa_s->current_bss == NULL ||
 			    wpa_s->current_bss->anqp == NULL)
@@ -2467,7 +2472,7 @@
 		ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
 				  cred->id, cred->realm ? cred->realm : "",
 				  cred->username ? cred->username : "",
-				  cred->domain ? cred->domain : "",
+				  cred->domain ? cred->domain[0] : "",
 				  cred->imsi ? cred->imsi : "");
 		if (ret < 0 || ret >= end - pos)
 			return pos - buf;
@@ -2552,9 +2557,16 @@
 		while (cred) {
 			prev = cred;
 			cred = cred->next;
-			if (prev->domain &&
-			    os_strcmp(prev->domain, cmd + 8) == 0)
-				wpas_ctrl_remove_cred(wpa_s, prev);
+			if (prev->domain) {
+				size_t i;
+				for (i = 0; i < prev->num_domain; i++) {
+					if (os_strcmp(prev->domain[i], cmd + 8)
+					    != 0)
+						continue;
+					wpas_ctrl_remove_cred(wpa_s, prev);
+					break;
+				}
+			}
 		}
 		return 0;
 	}
@@ -5194,6 +5206,7 @@
 #ifdef CONFIG_WPS
 	wpas_wps_cancel(wpa_s);
 #endif /* CONFIG_WPS */
+	wpa_s->after_wps = 0;
 
 #ifdef CONFIG_TDLS_TESTING
 	extern unsigned int tdls_testing;
@@ -5229,12 +5242,18 @@
 }
 
 
+static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	eapol_sm_notify_ctrl_response(wpa_s->eapol);
+}
+
+
 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 					 char *buf, size_t *resp_len)
 {
 	char *reply;
 	const int reply_size = 4096;
-	int ctrl_rsp = 0;
 	int reply_len;
 
 	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
@@ -5573,8 +5592,14 @@
 		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
 			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
 			reply_len = -1;
-		else
-			ctrl_rsp = 1;
+		else {
+			/*
+			 * Notify response from timeout to allow the control
+			 * interface response to be sent first.
+			 */
+			eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
+					       wpa_s, NULL);
+		}
 	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
 		if (wpa_supplicant_reload_configuration(wpa_s))
 			reply_len = -1;
@@ -5615,6 +5640,7 @@
 			     (wpa_s->wpa_state == WPA_COMPLETED))) {
 				wpa_s->normal_scans = 0;
 				wpa_s->scan_req = MANUAL_SCAN_REQ;
+				wpa_s->after_wps = 0;
 				wpa_supplicant_req_scan(wpa_s, 0, 0);
 			} else if (wpa_s->sched_scanning) {
 				wpa_printf(MSG_DEBUG, "Stop ongoing "
@@ -5777,9 +5803,6 @@
 		reply_len = 5;
 	}
 
-	if (ctrl_rsp)
-		eapol_sm_notify_ctrl_response(wpa_s->eapol);
-
 	*resp_len = reply_len;
 	return reply;
 }
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index ddd2c82..f9521f6 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1362,7 +1362,7 @@
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface;
 
-	wpa_printf(MSG_INFO, "%s\n", __func__);
+	wpa_printf(MSG_DEBUG, "%s", __func__);
 
 	iface = wpa_s->global->dbus;
 	/* Do nothing if the control interface is not turned on */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 478d02f..bb6b7b9 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1236,6 +1236,23 @@
 }
 
 
+static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
+					 DBusMessageIter *var,
+					 dbus_bool_t *allow,
+					 DBusMessage **reply)
+{
+	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+			   "Type must be a boolean");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong Type value type. Boolean required");
+		return -1;
+	}
+	dbus_message_iter_get_basic(var, allow);
+	return 0;
+}
+
+
 /**
  * wpas_dbus_handler_scan - Request a wireless scan on an interface
  * @message: Pointer to incoming dbus message
@@ -1254,6 +1271,7 @@
 	char *key = NULL, *type = NULL;
 	struct wpa_driver_scan_params params;
 	size_t i;
+	dbus_bool_t allow_roam = 1;
 
 	os_memset(&params, 0, sizeof(params));
 
@@ -1284,6 +1302,12 @@
 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
 							&params, &reply) < 0)
 				goto out;
+		} else if (os_strcmp(key, "AllowRoam") == 0) {
+			if (wpas_dbus_get_scan_allow_roam(message,
+							  &variant_iter,
+							  &allow_roam,
+							  &reply) < 0)
+				goto out;
 		} else {
 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
 				   "Unknown argument %s", key);
@@ -1332,6 +1356,9 @@
 		goto out;
 	}
 
+	if (!allow_roam)
+		wpa_s->scan_res_handler = scan_only_handler;
+
 out:
 	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
 		os_free((u8 *) params.ssids[i].ssid);
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 6a96331..628b81b 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -718,4 +718,13 @@
 	return wpa_s->driver->status(wpa_s->drv_priv, buf, buflen);
 }
 
+static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s,
+				      const u8 *qos_map_set, u8 qos_map_set_len)
+{
+	if (!wpa_s->driver->set_qos_map)
+		return -1;
+	return wpa_s->driver->set_qos_map(wpa_s->drv_priv, qos_map_set,
+					  qos_map_set_len);
+}
+
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index dad2765..9024f23 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - test code
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,6 +27,7 @@
 #include "common/wpa_ctrl.h"
 #include "ctrl_iface.h"
 #include "pcsc_funcs.h"
+#include "wpas_glue.h"
 
 
 extern int wpa_debug_level;
@@ -395,6 +396,54 @@
 }
 
 
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void eapol_test_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
+					const char *default_txt)
+{
+	struct eapol_test_data *e = ctx;
+	struct wpa_supplicant *wpa_s = e->wpa_s;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const char *field_name, *txt = NULL;
+	char *buf;
+	size_t buflen;
+	int len;
+
+	if (ssid == NULL)
+		return;
+
+	field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+						       &txt);
+	if (field_name == NULL) {
+		wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+			   field);
+		return;
+	}
+
+	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	len = os_snprintf(buf, buflen,
+			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
+			  field_name, ssid->id, txt);
+	if (len < 0 || (size_t) len >= buflen) {
+		os_free(buf);
+		return;
+	}
+	if (ssid->ssid && buflen > len + ssid->ssid_len) {
+		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+		len += ssid->ssid_len;
+		buf[len] = '\0';
+	}
+	buf[buflen - 1] = '\0';
+	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
+	os_free(buf);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eapol_test_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
 static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
 			       const char *cert_hash,
 			       const struct wpabuf *cert)
@@ -484,6 +533,7 @@
 	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	ctx->eap_param_needed = eapol_test_eap_param_needed;
 	ctx->cert_cb = eapol_test_cert_cb;
 	ctx->cert_in_cb = 1;
 	ctx->set_anon_id = eapol_test_set_anon_id;
@@ -501,6 +551,7 @@
 	eapol_conf.required_keys = 0;
 	eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
 	eapol_conf.workaround = ssid->eap_workaround;
+	eapol_conf.external_sim = wpa_s->conf->external_sim;
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
 
@@ -1094,6 +1145,7 @@
 
 int main(int argc, char *argv[])
 {
+	struct wpa_global global;
 	struct wpa_supplicant wpa_s;
 	int c, ret = 1, wait_for_monitor = 0, save_config = 0;
 	char *as_addr = "127.0.0.1";
@@ -1230,8 +1282,12 @@
 		return -1;
 	}
 
+	os_memset(&global, 0, sizeof(global));
 	os_memset(&wpa_s, 0, sizeof(wpa_s));
+	wpa_s.global = &global;
 	eapol_test.wpa_s = &wpa_s;
+	dl_list_init(&wpa_s.bss);
+	dl_list_init(&wpa_s.bss_id);
 	wpa_s.conf = wpa_config_read(conf, NULL);
 	if (wpa_s.conf == NULL) {
 		printf("Failed to parse configuration file '%s'.\n", conf);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7700595..fdf25b5 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -278,7 +278,8 @@
 #ifdef PCSC_FUNCS
 	int aka = 0, sim = 0;
 
-	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
+	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL ||
+	    wpa_s->conf->external_sim)
 		return 0;
 
 	if (ssid->eap.eap_methods == NULL) {
@@ -1506,6 +1507,43 @@
 }
 
 
+#ifdef CONFIG_INTERWORKING
+
+static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map,
+			    size_t len)
+{
+	int res;
+
+	wpa_hexdump(MSG_DEBUG, "Interworking: QoS Map Set", qos_map, len);
+	res = wpa_drv_set_qos_map(wpa_s, qos_map, len);
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Interworking: Failed to configure QoS Map Set to the driver");
+	}
+
+	return res;
+}
+
+
+static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
+					    const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+
+	if (ies == NULL)
+		return;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+		return;
+
+	if (elems.qos_map_set) {
+		wpas_qos_map_set(wpa_s, elems.qos_map_set,
+				 elems.qos_map_set_len);
+	}
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
 static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 					  union wpa_event_data *data)
 {
@@ -1530,6 +1568,10 @@
 		wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
 				       data->assoc_info.resp_ies_len);
 #endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+		interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+						data->assoc_info.resp_ies_len);
+#endif /* CONFIG_INTERWORKING */
 	}
 	if (data->assoc_info.beacon_ies)
 		wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -2958,6 +3000,19 @@
 			break;
 		}
 #endif /* CONFIG_TDLS */
+#ifdef CONFIG_INTERWORKING
+		if (data->rx_action.category == WLAN_ACTION_QOS &&
+		    data->rx_action.len >= 1 &&
+		    data->rx_action.data[0] == QOS_QOS_MAP_CONFIG) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from "
+				MACSTR, MAC2STR(data->rx_action.sa));
+			if (os_memcmp(data->rx_action.sa, wpa_s->bssid, ETH_ALEN)
+			    == 0)
+				wpas_qos_map_set(wpa_s, data->rx_action.data + 1,
+						 data->rx_action.len - 1);
+			break;
+		}
+#endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_P2P
 		wpas_p2p_rx_action(wpa_s, data->rx_action.da,
 				   data->rx_action.sa,
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 06a97d3..f9885e3 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -1,7 +1,7 @@
 /*
  * Generic advertisement service (GAS) query
  * Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -21,6 +21,8 @@
 
 /** GAS query timeout in seconds */
 #define GAS_QUERY_TIMEOUT_PERIOD 2
+/** Retry period for GAS query requests in milliseconds */
+#define GAS_SERVICE_RETRY_PERIOD_MS 500
 
 
 /**
@@ -35,6 +37,7 @@
 	unsigned int offchannel_tx_started:1;
 	int freq;
 	u16 status_code;
+	struct wpabuf *req;
 	struct wpabuf *adv_proto;
 	struct wpabuf *resp;
 	void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
@@ -50,11 +53,13 @@
 struct gas_query {
 	struct wpa_supplicant *wpa_s;
 	struct dl_list pending; /* struct gas_query_pending */
+	struct gas_query_pending *current;
 };
 
 
 static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
 static void gas_query_timeout(void *eloop_data, void *user_ctx);
+static void gas_service_timeout(void *eloop_data, void *user_ctx);
 
 
 /**
@@ -81,13 +86,17 @@
 			   struct gas_query_pending *query,
 			   enum gas_query_result result)
 {
+	if (gas->current == query)
+		gas->current = NULL;
 	if (query->offchannel_tx_started)
 		offchannel_send_action_done(gas->wpa_s);
 	eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
 	eloop_cancel_timeout(gas_query_timeout, gas, query);
+	eloop_cancel_timeout(gas_service_timeout, gas, query);
 	dl_list_del(&query->list);
 	query->cb(query->ctx, query->addr, query->dialog_token, result,
 		  query->adv_proto, query->resp, query->status_code);
+	wpabuf_free(query->req);
 	wpabuf_free(query->adv_proto);
 	wpabuf_free(query->resp);
 	os_free(query);
@@ -138,6 +147,44 @@
 }
 
 
+static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
+				unsigned int freq, const u8 *dst,
+				const u8 *src, const u8 *bssid,
+				const u8 *data, size_t data_len,
+				enum offchannel_send_action_result result)
+{
+	struct gas_query_pending *query;
+	struct gas_query *gas = wpa_s->gas;
+
+	if (gas->current == NULL) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst="
+			   MACSTR " result=%d - no query in progress",
+			   freq, MAC2STR(dst), result);
+		return;
+	}
+
+	query = gas->current;
+
+	wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
+		   " result=%d query=%p dialog_token=%u",
+		   freq, MAC2STR(dst), result, query, query->dialog_token);
+	if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
+		return;
+	}
+
+	if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+		eloop_cancel_timeout(gas_query_timeout, gas, query);
+		eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+				       gas_query_timeout, gas, query);
+	}
+	if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+		eloop_cancel_timeout(gas_query_timeout, gas, query);
+		eloop_register_timeout(0, 0, gas_query_timeout, gas, query);
+	}
+}
+
+
 static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
 			struct wpabuf *req)
 {
@@ -148,7 +195,7 @@
 	res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
 				     gas->wpa_s->own_addr, query->addr,
 				     wpabuf_head(req), wpabuf_len(req), 1000,
-				     NULL, 0);
+				     gas_query_tx_status, 0);
 	if (res == 0)
 		query->offchannel_tx_started = 1;
 	return res;
@@ -426,12 +473,50 @@
 	struct gas_query *gas = eloop_data;
 	struct gas_query_pending *query = user_ctx;
 
-	wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
-		   MAC2STR(query->addr));
+	wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR
+		   " dialog token %u",
+		   MAC2STR(query->addr), query->dialog_token);
 	gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
 }
 
 
+static void gas_service_timeout(void *eloop_data, void *user_ctx)
+{
+	struct gas_query *gas = eloop_data;
+	struct wpa_supplicant *wpa_s = gas->wpa_s;
+	struct gas_query_pending *query = user_ctx;
+	int conn;
+
+	conn = wpas_wpa_is_in_progress(wpa_s, 1);
+	if (conn || wpa_s->scanning || gas->current) {
+		wpa_printf(MSG_DEBUG, "GAS: Delaying GAS query Tx while another operation is in progress:%s%s%s",
+			   conn ? " connection" : "",
+			   wpa_s->scanning ? " scanning" : "",
+			   gas->current ? " gas_query" : "");
+		eloop_register_timeout(
+			GAS_SERVICE_RETRY_PERIOD_MS / 1000,
+			(GAS_SERVICE_RETRY_PERIOD_MS % 1000) * 1000,
+			gas_service_timeout, gas, query);
+		return;
+	}
+
+	if (gas_query_tx(gas, query, query->req) < 0) {
+		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+			   MACSTR, MAC2STR(query->addr));
+		dl_list_del(&query->list);
+		wpabuf_free(query->req);
+		os_free(query);
+		return;
+	}
+	gas->current = query;
+
+	wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u",
+		   query->dialog_token);
+	eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+			       gas_query_timeout, gas, query);
+}
+
+
 static int gas_query_dialog_token_available(struct gas_query *gas,
 					    const u8 *dst, u8 dialog_token)
 {
@@ -451,7 +536,8 @@
  * @gas: GAS query data from gas_query_init()
  * @dst: Destination MAC address for the query
  * @freq: Frequency (in MHz) for the channel on which to send the query
- * @req: GAS query payload
+ * @req: GAS query payload (to be freed by gas_query module in case of success
+ *	return)
  * @cb: Callback function for reporting GAS query result and response
  * @ctx: Context pointer to use with the @cb call
  * Returns: dialog token (>= 0) on success or -1 on failure
@@ -490,22 +576,15 @@
 	query->freq = freq;
 	query->cb = cb;
 	query->ctx = ctx;
+	query->req = req;
 	dl_list_add(&gas->pending, &query->list);
 
 	*(wpabuf_mhead_u8(req) + 2) = dialog_token;
 
 	wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
 		   " dialog_token %u", MAC2STR(dst), dialog_token);
-	if (gas_query_tx(gas, query, req) < 0) {
-		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
-			   MACSTR, MAC2STR(query->addr));
-		dl_list_del(&query->list);
-		os_free(query);
-		return -1;
-	}
 
-	eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
-			       gas, query);
+	eloop_register_timeout(0, 0, gas_service_timeout, gas, query);
 
 	return dialog_token;
 }
@@ -526,3 +605,9 @@
 		gas_query_done(gas, query, GAS_QUERY_CANCELLED);
 
 }
+
+
+int gas_query_in_progress(struct gas_query *gas)
+{
+	return gas->current != NULL;
+}
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index 5c3d161..6b6c77c 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -18,6 +18,7 @@
 void gas_query_deinit(struct gas_query *gas);
 int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
 		 const u8 *bssid, const u8 *data, size_t len, int freq);
+int gas_query_in_progress(struct gas_query *gas);
 
 /**
  * enum gas_query_result - GAS query result
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 4048cf7..5f30313 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -125,12 +125,12 @@
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 	} else
 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
 
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 36f75a1..e294917 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -112,6 +112,8 @@
 	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
 		if (cred->roaming_consortium_len)
 			return 1;
+		if (cred->required_roaming_consortium_len)
+			return 1;
 	}
 	return 0;
 }
@@ -242,6 +244,7 @@
 			    interworking_anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 		eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
 				       NULL);
@@ -249,7 +252,6 @@
 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
 
@@ -944,6 +946,27 @@
 }
 
 
+static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
+{
+	const u8 *ie;
+
+	if (cred->required_roaming_consortium_len == 0)
+		return 0;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+	if (ie == NULL &&
+	    (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+		return 1;
+
+	return !roaming_consortium_match(ie,
+					 bss->anqp ?
+					 bss->anqp->roaming_consortium : NULL,
+					 cred->required_roaming_consortium,
+					 cred->required_roaming_consortium_len);
+}
+
+
 static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
 {
 	size_t i;
@@ -991,6 +1014,8 @@
 
 		if (cred_excluded_ssid(cred, bss))
 			continue;
+		if (cred_no_required_oi_match(cred, bss))
+			continue;
 
 		if (selected == NULL ||
 		    selected->priority < cred->priority)
@@ -1100,6 +1125,11 @@
 	    wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
 		return -1;
 
+	if (cred->domain_suffix_match && cred->domain_suffix_match[0] &&
+	    wpa_config_set_quoted(ssid, "domain_suffix_match",
+				  cred->domain_suffix_match) < 0)
+		return -1;
+
 	return 0;
 }
 
@@ -1377,7 +1407,8 @@
 #endif /* CONFIG_EAP_PROXY */
 
 		if (cred->imsi == NULL || !cred->imsi[0] ||
-		    cred->milenage == NULL || !cred->milenage[0])
+		    (!wpa_s->conf->external_sim &&
+		     (cred->milenage == NULL || !cred->milenage[0])))
 			continue;
 
 		sep = os_strchr(cred->imsi, '-');
@@ -1404,6 +1435,8 @@
 		if (ret) {
 			if (cred_excluded_ssid(cred, bss))
 				continue;
+			if (cred_no_required_oi_match(cred, bss))
+				continue;
 			if (selected == NULL ||
 			    selected->priority < cred->priority)
 				selected = cred;
@@ -1446,6 +1479,8 @@
 			if (nai_realm_find_eap(cred, &realm[i])) {
 				if (cred_excluded_ssid(cred, bss))
 					continue;
+				if (cred_no_required_oi_match(cred, bss))
+					continue;
 				if (selected == NULL ||
 				    selected->priority < cred->priority)
 					selected = cred;
@@ -1514,6 +1549,7 @@
 			      struct wpa_cred *cred,
 			      struct wpabuf *domain_names)
 {
+	size_t i;
 #ifdef INTERWORKING_3GPP
 	char nai[100], *realm;
 
@@ -1528,6 +1564,12 @@
 		mnc_len = wpa_s->mnc_len;
 	}
 #endif /* CONFIG_PCSC */
+#ifdef CONFIG_EAP_PROXY
+	else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+		imsi = wpa_s->imsi;
+		mnc_len = wpa_s->mnc_len;
+	}
+#endif /* CONFIG_EAP_PROXY */
 	if (domain_names &&
 	    imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
 		realm = os_strchr(nai, '@');
@@ -1544,10 +1586,12 @@
 	if (domain_names == NULL || cred->domain == NULL)
 		return 0;
 
-	wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
-		   "home SP FQDN %s", cred->domain);
-	if (domain_name_list_contains(domain_names, cred->domain))
-		return 1;
+	for (i = 0; i < cred->num_domain; i++) {
+		wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+			   "home SP FQDN %s", cred->domain[i]);
+		if (domain_name_list_contains(domain_names, cred->domain[i]))
+			return 1;
+	}
 
 	return 0;
 }
@@ -1833,12 +1877,12 @@
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 	} else
 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
 
@@ -2133,11 +2177,11 @@
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 	} else
 		wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 86bcf87..48cd429 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3794,7 +3794,8 @@
 	if (bss) {
 		freq = bss->freq;
 		wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
-			   "from BSS table: %d MHz", freq);
+			   "from BSS table: %d MHz (SSID %s)", freq,
+			   wpa_ssid_txt(bss->ssid, bss->ssid_len));
 	}
 	if (freq > 0) {
 		u16 method;
@@ -4009,6 +4010,9 @@
 		res.freq = bss->freq;
 		res.ssid_len = bss->ssid_len;
 		os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+		wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency "
+			   "from BSS table: %d MHz (SSID %s)", bss->freq,
+			   wpa_ssid_txt(bss->ssid, bss->ssid_len));
 	}
 
 	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
@@ -5261,7 +5265,7 @@
 	u8 *bssid = NULL;
 	struct wpa_ssid *ssid;
 	int persistent;
-	int force_freq = 0, pref_freq = 0;
+	int freq = 0, force_freq = 0, pref_freq = 0;
 	int res;
 
 	wpa_s->p2p_persistent_go_freq = 0;
@@ -5293,6 +5297,7 @@
 		bssid = wpa_s->own_addr;
 		if (go_dev_addr == NULL)
 			go_dev_addr = wpa_s->global->p2p_dev_addr;
+		freq = ssid->frequency;
 	} else {
 		role = P2P_INVITE_ROLE_CLIENT;
 		if (wpa_s->wpa_state < WPA_ASSOCIATED) {
@@ -5304,6 +5309,8 @@
 		if (go_dev_addr == NULL &&
 		    !is_zero_ether_addr(wpa_s->go_dev_addr))
 			go_dev_addr = wpa_s->go_dev_addr;
+		freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+			(int) wpa_s->assoc_freq;
 	}
 	wpa_s->parent->pending_invite_ssid_id = -1;
 
@@ -5315,7 +5322,7 @@
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
-	res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
 	if (res)
 		return res;
 	wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 7eec468..dc98361 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -21,6 +21,7 @@
 #include "hs20_supplicant.h"
 #include "notify.h"
 #include "bss.h"
+#include "gas_query.h"
 #include "scan.h"
 
 
@@ -595,7 +596,7 @@
 	}
 
 #ifdef CONFIG_P2P
-	if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s)) {
+	if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s, 0)) {
 		if (wpa_s->sta_scan_pending &&
 		    wpas_p2p_in_progress(wpa_s) == 2 &&
 		    wpa_s->global->p2p_cb_on_scan_complete) {
@@ -611,6 +612,14 @@
 	}
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_GAS
+	if (gas_query_in_progress(wpa_s->gas)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Delay scan while GAS query is in progress");
+		wpa_supplicant_req_scan(wpa_s, 1, 0);
+		return;
+	}
+#endif /* CONFIG_GAS */
+
 	if (wpa_s->conf->ap_scan == 2)
 		max_ssids = 1;
 	else {
@@ -887,8 +896,10 @@
 		new_int.usec = remaining.usec;
 	}
 
-	eloop_register_timeout(new_int.sec, new_int.usec, wpa_supplicant_scan,
-			       wpa_s, NULL);
+	if (cancelled) {
+		eloop_register_timeout(new_int.sec, new_int.usec,
+				       wpa_supplicant_scan, wpa_s, NULL);
+	}
 	wpa_s->scan_interval = sec;
 }
 
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6727526..8c900c2 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -625,7 +625,7 @@
 		"wps_nfc_dev_pw", "ext_password_backend",
 		"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
 		"sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
-		"ignore_old_scan_res", "freq_list"
+		"ignore_old_scan_res", "freq_list", "external_sim"
 	};
 	int i, num_fields = sizeof(fields) / sizeof(fields[0]);
 
@@ -1270,6 +1270,38 @@
 }
 
 
+static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256], *pos, *end;
+	int i, ret;
+
+	if (argc < 2) {
+		printf("Invalid SIM command: needs two arguments "
+		       "(network id and SIM operation response)\n");
+		return -1;
+	}
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
+			  argv[0], argv[1]);
+	if (ret < 0 || ret >= end - pos) {
+		printf("Too long SIM command.\n");
+		return -1;
+	}
+	pos += ret;
+	for (i = 2; i < argc; i++) {
+		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (ret < 0 || ret >= end - pos) {
+			printf("Too long SIM command.\n");
+			return -1;
+		}
+		pos += ret;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
 				  char *argv[])
 {
@@ -2488,6 +2520,9 @@
 	  cli_cmd_flag_sensitive,
 	  "<network id> <passphrase> = configure private key passphrase\n"
 	  "  for an SSID" },
+	{ "sim", wpa_cli_cmd_sim, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <pin> = report SIM operation result" },
 	{ "bssid", wpa_cli_cmd_bssid, NULL,
 	  cli_cmd_flag_none,
 	  "<network id> <BSSID> = set preferred BSSID for an SSID" },
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f924316..fc3471d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -303,6 +303,7 @@
 		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
 		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
 		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
+	eapol_conf.external_sim = wpa_s->conf->external_sim;
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 #endif /* IEEE8021X_EAPOL */
 }
@@ -1225,6 +1226,9 @@
 #endif /* CONFIG_INTERWORKING */
 		break;
 	case 4: /* Bits 32-39 */
+#ifdef CONFIG_INTERWORKING
+		*pos |= 0x01; /* Bit 32 - QoS Map */
+#endif /* CONFIG_INTERWORKING */
 		break;
 	case 5: /* Bits 40-47 */
 		break;
@@ -3768,6 +3772,10 @@
 		if (ssid == wpa_s->current_ssid)
 			wpa_s->reassociate = 1;
 		break;
+	case WPA_CTRL_REQ_SIM:
+		os_free(eap->external_sim_resp);
+		eap->external_sim_resp = os_strdup(value);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
 		return -1;
@@ -3958,37 +3966,53 @@
 }
 
 
+static int wpas_conn_in_progress(struct wpa_supplicant *wpa_s)
+{
+	return wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+		wpa_s->wpa_state != WPA_COMPLETED;
+}
+
+
 /**
  * wpas_wpa_is_in_progress - Check whether a connection is in progress
  * @wpa_s: Pointer to wpa_supplicant data
+ * @include_current: Whether to consider specified interface
  *
  * This function is to check if the wpa state is in beginning of the connection
  * during 4-way handshake or group key handshake with WPA on any shared
  * interface.
  */
-int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s)
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current)
 {
 	const char *rn, *rn2;
 	struct wpa_supplicant *ifs;
 
-	if (!wpa_s->driver->get_radio_name)
+	if (!wpa_s->driver->get_radio_name) {
+		if (include_current && wpas_conn_in_progress(wpa_s)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress on interface %s - defer",
+				wpa_s->ifname);
+			return 1;
+		}
+
                 return 0;
+	}
 
 	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
 	if (rn == NULL || rn[0] == '\0')
 		return 0;
 
 	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-		if (ifs == wpa_s || !ifs->driver->get_radio_name)
+		if (!include_current && ifs == wpa_s)
+			continue;
+		if (!ifs->driver->get_radio_name)
 			continue;
 
 		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
 		if (!rn2 || os_strcmp(rn, rn2) != 0)
 			continue;
-		if (ifs->wpa_state >= WPA_AUTHENTICATING &&
-		    ifs->wpa_state != WPA_COMPLETED) {
+		if (wpas_conn_in_progress(ifs)) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress "
-				"on interface %s - defer scan", ifs->ifname);
+				"on interface %s - defer", ifs->ifname);
 			return 1;
 		}
 	}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index d73d371..6414f44 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -399,9 +399,11 @@
 # milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
 #	format
 #
-# domain: Home service provider FQDN
+# domain: Home service provider FQDN(s)
 #	This is used to compare against the Domain Name List to figure out
-#	whether the AP is operated by the Home SP.
+#	whether the AP is operated by the Home SP. Multiple domain entries can
+#	be used to configure alternative FQDNs that will be considered home
+#	networks.
 #
 # roaming_consortium: Roaming Consortium OI
 #	If roaming_consortium_len is non-zero, this field contains the
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index be493cf..d44f0a2 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -823,7 +823,7 @@
 		    size_t ssid_len);
 void wpas_request_connection(struct wpa_supplicant *wpa_s);
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
-int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s);
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current);
 
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 61a42bd..ab6cdca 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -611,6 +611,8 @@
 		return WPA_CTRL_REQ_EAP_OTP;
 	else if (os_strcmp(field, "PASSPHRASE") == 0)
 		return WPA_CTRL_REQ_EAP_PASSPHRASE;
+	else if (os_strcmp(field, "SIM") == 0)
+		return WPA_CTRL_REQ_SIM;
 	return WPA_CTRL_REQ_UNKNOWN;
 }
 
@@ -647,6 +649,9 @@
 		*txt = "Private key passphrase";
 		ret = "PASSPHRASE";
 		break;
+	case WPA_CTRL_REQ_SIM:
+		ret = "SIM";
+		break;
 	default:
 		break;
 	}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index a2b941c..0d75464 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -882,6 +882,8 @@
 	int id;
 	struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
 
+	wpa_s->after_wps = 0;
+
 	prev_current = wpa_s->current_ssid;
 
 	/* Enable the networks disabled during wpas_wps_reassoc */
@@ -1157,6 +1159,8 @@
 		wpas_wps_clear_ap_info(wpa_s);
 	}
 
+	wpa_s->after_wps = 0;
+
 	return 0;
 }
 
@@ -2465,6 +2469,9 @@
 void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
 {
 	struct wps_ap_info *ap;
+
+	wpa_s->after_wps = 0;
+
 	if (!wpa_s->wps_ap_iter)
 		return;
 	ap = wpas_wps_get_ap_info(wpa_s, bssid);