Cumulative patch from commit 2b6623ab134fff6d96114f5fe329a2f87d5e893a

2b6623a hostapd: Do not terminate process on dynamic interface add failure
217cf49 P2P: Add more debug prints for frequency selection
4dd3f86 P2P: Fix bug in GO frequency selection
9804873 wpa_supplicant: Fix bug in get_shared_radio_freqs
3342c26 wpa_supplicant: Fix updating GO beacons on WFD subelements change
72c12c1 EAPOL: Fix static analyzer warnings for pac_opaque_encr_key
3139270 bgscan: Add global bgscan configuration
efc58df eap_proxy: Re-read IMSI from proxy in Interworking functionality

Change-Id: I006abd3b52fbbd1a7b97059364c72ab0386d5f63
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/README b/README
index 805c6cf..bf0bd83 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 These programs are licensed under the BSD license (the one with
diff --git a/hostapd/main.c b/hostapd/main.c
index bc61db1..4e9fe40 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -693,6 +693,7 @@
 	 * In such case, the interface will be enabled from eloop context within
 	 * hostapd_global_run().
 	 */
+	interfaces.terminate_on_error = interfaces.count;
 	for (i = 0; i < interfaces.count; i++) {
 		if (hostapd_driver_init(interfaces.iface[i]) ||
 		    hostapd_setup_interface(interfaces.iface[i]))
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 5d51c77..52be311 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1082,7 +1082,8 @@
 	if (err) {
 		wpa_printf(MSG_ERROR, "Interface initialization failed");
 		hostapd_set_state(iface, HAPD_IFACE_DISABLED);
-		eloop_terminate();
+		if (iface->interfaces && iface->interfaces->terminate_on_error)
+			eloop_terminate();
 		return -1;
 	}
 
@@ -1187,6 +1188,8 @@
 
 	wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
 		   iface->bss[0]->conf->iface);
+	if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
+		iface->interfaces->terminate_on_error--;
 
 	return 0;
 }
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 05bcb62..adb3728 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -45,6 +45,8 @@
 	gid_t ctrl_iface_group;
 	struct hostapd_iface **iface;
 	struct hostapd_dynamic_iface **dynamic_iface;
+
+	size_t terminate_on_error;
 };
 
 enum hostapd_chan_status {
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 013d781..a257781 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -1062,6 +1062,10 @@
 	}
 	if (src->pac_opaque_encr_key) {
 		dst->pac_opaque_encr_key = os_malloc(16);
+		if (dst->pac_opaque_encr_key == NULL) {
+			os_free(dst->eap_req_id_text);
+			return -1;
+		}
 		os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
 			  16);
 	} else
@@ -1070,6 +1074,7 @@
 		dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
 		if (dst->eap_fast_a_id == NULL) {
 			os_free(dst->eap_req_id_text);
+			os_free(dst->pac_opaque_encr_key);
 			return -1;
 		}
 		os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
@@ -1081,6 +1086,7 @@
 		dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
 		if (dst->eap_fast_a_id_info == NULL) {
 			os_free(dst->eap_req_id_text);
+			os_free(dst->pac_opaque_encr_key);
 			os_free(dst->eap_fast_a_id);
 			return -1;
 		}
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 9730282..b09fbac 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -4298,7 +4298,7 @@
 
 	for (g = 0; g < p2p->num_groups; g++) {
 		group = p2p->groups[g];
-		p2p_group_update_ies(group);
+		p2p_group_force_beacon_update_ies(group);
 	}
 }
 
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 15e7622..92b5583 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -980,3 +980,10 @@
 	return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
 			 group->cfg->ssid_len) == 0;
 }
+
+
+void p2p_group_force_beacon_update_ies(struct p2p_group *group)
+{
+	group->beacon_update = 1;
+	p2p_group_update_ies(group);
+}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index e5d52aa..e4ec6de 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -616,6 +616,7 @@
 int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
 				size_t group_id_len);
 void p2p_group_update_ies(struct p2p_group *group);
+void p2p_group_force_beacon_update_ies(struct p2p_group *group);
 struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g);
 
 
diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
index 9a9bd52..f74cdbf 100644
--- a/wpa_supplicant/bgscan.c
+++ b/wpa_supplicant/bgscan.c
@@ -31,9 +31,9 @@
 };
 
 
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+		const char *name)
 {
-	const char *name = ssid->bgscan;
 	const char *params;
 	size_t nlen;
 	int i;
@@ -41,7 +41,7 @@
 
 	bgscan_deinit(wpa_s);
 	if (name == NULL)
-		return 0;
+		return -1;
 
 	params = os_strchr(name, ':');
 	if (params == NULL) {
diff --git a/wpa_supplicant/bgscan.h b/wpa_supplicant/bgscan.h
index e9d15fc..9131e4e 100644
--- a/wpa_supplicant/bgscan.h
+++ b/wpa_supplicant/bgscan.h
@@ -29,7 +29,8 @@
 
 #ifdef CONFIG_BGSCAN
 
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+		const char *name);
 void bgscan_deinit(struct wpa_supplicant *wpa_s);
 int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
 		       struct wpa_scan_results *scan_res);
@@ -41,7 +42,7 @@
 #else /* CONFIG_BGSCAN */
 
 static inline int bgscan_init(struct wpa_supplicant *wpa_s,
-			      struct wpa_ssid *ssid)
+			      struct wpa_ssid *ssid, const char name)
 {
 	return 0;
 }
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 08d2ecd..19bcece 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2848,6 +2848,24 @@
 }
 
 
+static int wpa_config_process_bgscan(const struct global_parse_data *data,
+				     struct wpa_config *config, int line,
+				     const char *pos)
+{
+	size_t len;
+	char *tmp;
+
+	tmp = wpa_config_parse_string(pos, &len);
+	if (tmp == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: failed to parse %s",
+			   line, data->name);
+		return -1;
+	}
+
+	return wpa_global_config_parse_str(data, config, line, tmp);
+}
+
+
 static int wpa_global_config_parse_bin(const struct global_parse_data *data,
 				       struct wpa_config *config, int line,
 				       const char *pos)
@@ -3209,6 +3227,7 @@
 #endif /* CONFIG_CTRL_IFACE */
 	{ INT_RANGE(eapol_version, 1, 2), 0 },
 	{ INT(ap_scan), 0 },
+	{ FUNC(bgscan), 0 },
 	{ INT(disable_scan_offload), 0 },
 	{ INT(fast_reauth), 0 },
 	{ STR(opensc_engine_path), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 8cbeb62..55a2d62 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -329,6 +329,18 @@
 	int ap_scan;
 
 	/**
+	 * bgscan - Background scan and roaming parameters or %NULL if none
+	 *
+	 * This is an optional set of parameters for background scanning and
+	 * roaming within a network (ESS). For more detailed information see
+	 * ssid block documentation.
+	 *
+	 * The variable defines default bgscan behavior for all BSS station
+	 * networks except for those which have their own bgscan configuration.
+	 */
+	 char *bgscan;
+
+	/**
 	 * disable_scan_offload - Disable automatic offloading of scan requests
 	 *
 	 * By default, %wpa_supplicant tries to offload scanning if the driver
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 067b3bd..8667221 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -18,6 +18,7 @@
 #include "eap_common/eap_defs.h"
 #include "eap_peer/eap.h"
 #include "eap_peer/eap_methods.h"
+#include "eapol_supp/eapol_supp_sm.h"
 #include "wpa_supplicant_i.h"
 #include "config.h"
 #include "config_ssid.h"
@@ -1383,6 +1384,23 @@
 	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
 		return NULL;
 
+#ifdef CONFIG_EAP_PROXY
+	if (!wpa_s->imsi[0]) {
+		size_t len;
+		wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy");
+		wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
+							     wpa_s->imsi,
+							     &len);
+		if (wpa_s->mnc_len > 0) {
+			wpa_s->imsi[len] = '\0';
+			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+				   wpa_s->imsi, wpa_s->mnc_len);
+		} else {
+			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+		}
+	}
+#endif /* CONFIG_EAP_PROXY */
+
 	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
 		char *sep;
 		const char *imsi;
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 4f34b75..a8e003c 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -134,7 +134,7 @@
 static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s)
 {
 	int *freqs;
-	int num;
+	int num, unused;
 
 	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
 	if (!freqs)
@@ -144,7 +144,9 @@
 				     wpa_s->num_multichan_concurrent);
 	os_free(freqs);
 
-	return wpa_s->num_multichan_concurrent - num;
+	unused = wpa_s->num_multichan_concurrent - num;
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: num_unused_channels: %d", unused);
+	return unused;
 }
 
 
@@ -174,6 +176,8 @@
 
 	os_free(freqs);
 
+	dump_freq_array(wpa_s, "valid for P2P", p2p_freqs, j);
+
 	return j;
 }
 
@@ -4667,7 +4671,7 @@
 		}
 
 		if (i == num) {
-			if (num == wpa_s->num_multichan_concurrent) {
+			if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
 				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
 				os_free(freqs);
 				return -1;
@@ -4682,7 +4686,7 @@
 		}
 
 		if (i == num) {
-			if (num == wpa_s->num_multichan_concurrent) {
+			if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
 				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
 				os_free(freqs);
 				return -1;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 1d7fabf..6f21998 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -272,9 +272,8 @@
 	ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
 	if (ret)
 		wpa_supplicant_notify_scanning(wpa_s, 0);
-	else {
+	else
 		wpa_s->sched_scanning = 1;
-	}
 
 	return ret;
 }
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 41ae8f1..27cbd44 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -570,14 +570,22 @@
 
 static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
 {
+	const char *name;
+
+	if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan)
+		name = wpa_s->current_ssid->bgscan;
+	else
+		name = wpa_s->conf->bgscan;
+	if (name == NULL)
+		return;
 	if (wpas_driver_bss_selection(wpa_s))
 		return;
 	if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
 		return;
 
 	bgscan_deinit(wpa_s);
-	if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
-		if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+	if (wpa_s->current_ssid) {
+		if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
 				"bgscan");
 			/*
@@ -4022,6 +4030,18 @@
 }
 
 
+void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
+		     int *freq_array, unsigned int len)
+{
+	unsigned int i;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
+		len, title);
+	for (i = 0; i < len; i++)
+		wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d", i, freq_array[i]);
+}
+
+
 /*
  * Find the operating frequencies of any of the virtual interfaces that
  * are using the same radio as the current interface.
@@ -4035,6 +4055,8 @@
 	int freq;
 	unsigned int idx = 0, i;
 
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"Determining shared radio frequencies (max len %u)", len);
 	os_memset(freq_array, 0, sizeof(int) * len);
 
 	/* First add the frequency of the local interface */
@@ -4052,14 +4074,18 @@
 		if (freq > 0 && idx < len &&
 		    (idx == 0 || freq_array[0] != freq))
 			freq_array[idx++] = freq;
+		dump_freq_array(wpa_s, "No get_radio_name", freq_array, idx);
 		return idx;
 	}
 
 	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
-	if (rn == NULL || rn[0] == '\0')
+	if (rn == NULL || rn[0] == '\0') {
+		dump_freq_array(wpa_s, "get_radio_name failed",
+				freq_array, idx);
 		return idx;
+	}
 
-	for (ifs = wpa_s->global->ifaces, idx = 0; ifs && idx < len;
+	for (ifs = wpa_s->global->ifaces; ifs && idx < len;
 	     ifs = ifs->next) {
 		if (wpa_s == ifs || !ifs->driver->get_radio_name)
 			continue;
@@ -4087,5 +4113,7 @@
 		if (i == idx)
 			freq_array[idx++] = freq;
 	}
+
+	dump_freq_array(wpa_s, "completed iteration", freq_array, idx);
 	return idx;
 }
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 11be8dd..0ecfaa6 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -550,6 +550,10 @@
 # <long interval>[:<database file name>]"
 # bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan"
 #
+# This option can also be set outside of all network blocks for the bgscan
+# parameter to apply for all the networks that have no specific bgscan
+# parameter.
+#
 # proto: list of accepted protocols
 # WPA = WPA/IEEE 802.11i/D3.0
 # RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index da536cb..eed1053 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -863,6 +863,8 @@
 
 int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
 
+void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
+		     int *freq_array, unsigned int len);
 int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 			   int *freq_array, unsigned int len);