Cumulative patch from commit 801e117376e13d5b3c50f1627b93a949529fdf99

801e117 Fix validation of RSN EAPOL-Key version for GCMP with PMF
3d4d234 FT: Fix GTK rekeying after FT protocol
d3d0483 nl80211: Work around error case prints for nl_recvmsgs on Android
8a387a2 P2P NFC: Fix use of freed memory
df48efc Fix external radio work stopping to not read freed memory
13c3303 SAE: Fix memory leak in random number generation
d92bdf9 hostapd: Make sure hapd->drv_priv gets cleared on driver deinit
438e133 hostapd: Use helper function to avoid duplicate deinit calls
ac1a224 hostapd: Clean up if interface setup fails
81c4fca hostapd: Reset hapd->interface_add properly
3fbd036 hostapd: Prevent double interface disabling from segfaulting
ea39367 nl80211: Fix wpa_driver_nl80211_if_add() failure paths
b77aeae Interworking: Re-trigger scan if no connect attempt is done
b523973 RADIUS client: Trigger failover more quickly if socket is not valid
09844c0 RADIUS client: Do not flush pending messages if server did not change
5d67bf1 hostapd: Fix configuration of multiple RADIUS servers with SET
70d4084 RADIUS client: Fix socket close/re-open on server change
d045cc8 RADIUS client: Fix crash issue in radius_client_timer()
c1fb75a RADIUS client: Handle ENETUNREACH similarly to other failure cases
9ed4076 RADIUS client: Do not try to send message without socket
cc0b7cb hostapd_cli: Fix segmentation fault with interface command
114153b P2P: Debug print channel lists for invitation processing
4eb3b76 OpenSSL: Fix OCSP certificate debug print to use wpa_printf
f6fb192 HS 2.0R2: Fix subscr_remediation_method for RADIUS server
74879f3 Remove extra newline from a debug print

Change-Id: I82d4f00501fabb8b325e4461178b45e7b2c0178e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index caf51a9..be40398 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3238,7 +3238,7 @@
 	fclose(f);
 
 	for (i = 0; i < conf->num_bss; i++)
-		hostapd_set_security_params(conf->bss[i]);
+		hostapd_set_security_params(conf->bss[i], 1);
 
 	if (hostapd_config_check(conf, 1))
 		errors++;
@@ -3270,7 +3270,7 @@
 	}
 
 	for (i = 0; i < conf->num_bss; i++)
-		hostapd_set_security_params(conf->bss[i]);
+		hostapd_set_security_params(conf->bss[i], 0);
 
 	if (hostapd_config_check(conf, 0)) {
 		wpa_printf(MSG_ERROR, "Configuration check failed");
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index c488b4f..1c4a84c 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -842,8 +842,8 @@
 	}
 
 	hostapd_cli_close_connection();
-	free(ctrl_ifname);
-	ctrl_ifname = strdup(argv[0]);
+	os_free(ctrl_ifname);
+	ctrl_ifname = os_strdup(argv[0]);
 
 	if (hostapd_cli_open_connection(ctrl_ifname)) {
 		printf("Connected to interface '%s.\n", ctrl_ifname);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 9680817..7535b1b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -859,7 +859,8 @@
 }
 
 
-void hostapd_set_security_params(struct hostapd_bss_config *bss)
+void hostapd_set_security_params(struct hostapd_bss_config *bss,
+				 int full_config)
 {
 	if (bss->individual_wep_key_len == 0) {
 		/* individual keys are not use; can use key idx0 for
@@ -872,8 +873,10 @@
 	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
 						    bss->rsn_pairwise);
 
-	bss->radius->auth_server = bss->radius->auth_servers;
-	bss->radius->acct_server = bss->radius->acct_servers;
+	if (full_config) {
+		bss->radius->auth_server = bss->radius->auth_servers;
+		bss->radius->acct_server = bss->radius->acct_servers;
+	}
 
 	if (bss->wpa && bss->ieee802_1x) {
 		bss->ssid.security_policy = SECURITY_WPA;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index dfbe626..905aec3 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -621,6 +621,7 @@
 struct hostapd_radius_attr *
 hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
 int hostapd_config_check(struct hostapd_config *conf, int full_config);
-void hostapd_set_security_params(struct hostapd_bss_config *bss);
+void hostapd_set_security_params(struct hostapd_bss_config *bss,
+				 int full_config);
 
 #endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index b7e118c..ed73301 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -277,10 +277,21 @@
 
 	authsrv_deinit(hapd);
 
-	if (hapd->interface_added &&
-	    hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
-		wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
-			   hapd->conf->iface);
+	if (hapd->interface_added) {
+		hapd->interface_added = 0;
+		if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
+			wpa_printf(MSG_WARNING,
+				   "Failed to remove BSS interface %s",
+				   hapd->conf->iface);
+			hapd->interface_added = 1;
+		} else {
+			/*
+			 * Since this was a dynamically added interface, the
+			 * driver wrapper may have removed its internal instance
+			 * and hapd->drv_priv is not valid anymore.
+			 */
+			hapd->drv_priv = NULL;
+		}
 	}
 
 	os_free(hapd->probereq_cb);
@@ -433,6 +444,14 @@
 }
 
 
+static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
+{
+	hostapd_free_stas(hapd);
+	hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+	hostapd_clear_wep(hapd);
+}
+
+
 /**
  * hostapd_validate_bssid_configuration - Validate BSSID configuration
  * @iface: Pointer to interface data
@@ -1226,8 +1245,14 @@
 		hapd = iface->bss[j];
 		if (j)
 			os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
-		if (hostapd_setup_bss(hapd, j == 0))
+		if (hostapd_setup_bss(hapd, j == 0)) {
+			do {
+				hapd = iface->bss[j];
+				hostapd_bss_deinit_no_free(hapd);
+				hostapd_free_hapd_data(hapd);
+			} while (j-- > 0);
 			goto fail;
+		}
 		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
 			prev_addr = hapd->own_addr;
 	}
@@ -1346,9 +1371,7 @@
 {
 	wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
 		   hapd->conf->iface);
-	hostapd_free_stas(hapd);
-	hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
-	hostapd_clear_wep(hapd);
+	hostapd_bss_deinit_no_free(hapd);
 	hostapd_cleanup(hapd);
 }
 
@@ -1601,8 +1624,10 @@
 	hostapd_interface_deinit(iface);
 	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
 		   __func__, driver, drv_priv);
-	if (driver && driver->hapd_deinit && drv_priv)
+	if (driver && driver->hapd_deinit && drv_priv) {
 		driver->hapd_deinit(drv_priv);
+		iface->bss[0]->drv_priv = NULL;
+	}
 	hostapd_interface_free(iface);
 }
 
@@ -1630,6 +1655,8 @@
 
 int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
 {
+	size_t j;
+
 	if (hapd_iface->bss[0]->drv_priv != NULL) {
 		wpa_printf(MSG_ERROR, "Interface %s already enabled",
 			   hapd_iface->conf->bss[0]->iface);
@@ -1639,6 +1666,8 @@
 	wpa_printf(MSG_DEBUG, "Enable interface %s",
 		   hapd_iface->conf->bss[0]->iface);
 
+	for (j = 0; j < hapd_iface->num_bss; j++)
+		hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
 	if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
 		wpa_printf(MSG_INFO, "Invalid configuration - cannot enable");
 		return -1;
@@ -1667,7 +1696,7 @@
 	wpa_printf(MSG_DEBUG, "Reload interface %s",
 		   hapd_iface->conf->bss[0]->iface);
 	for (j = 0; j < hapd_iface->num_bss; j++)
-		hostapd_set_security_params(hapd_iface->conf->bss[j]);
+		hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
 	if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
 		wpa_printf(MSG_ERROR, "Updated configuration is invalid");
 		return -1;
@@ -1688,6 +1717,13 @@
 
 	if (hapd_iface == NULL)
 		return -1;
+
+	if (hapd_iface->bss[0]->drv_priv == NULL) {
+		wpa_printf(MSG_INFO, "Interface %s already disabled",
+			   hapd_iface->conf->bss[0]->iface);
+		return -1;
+	}
+
 	wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
 	driver = hapd_iface->bss[0]->driver;
 	drv_priv = hapd_iface->bss[0]->drv_priv;
@@ -1699,9 +1735,7 @@
 	/* same as hostapd_interface_deinit without deinitializing ctrl-iface */
 	for (j = 0; j < hapd_iface->num_bss; j++) {
 		struct hostapd_data *hapd = hapd_iface->bss[j];
-		hostapd_free_stas(hapd);
-		hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
-		hostapd_clear_wep(hapd);
+		hostapd_bss_deinit_no_free(hapd);
 		hostapd_free_hapd_data(hapd);
 	}
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index d212610..a9cd6f6 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -565,6 +565,8 @@
 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
 				"FT authentication already completed - do not "
 				"start 4-way handshake");
+		/* Go to PTKINITDONE state to allow GTK rekeying */
+		sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
 		return 0;
 	}
 #endif /* CONFIG_IEEE80211R */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 7701596..a80bbb7 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -898,6 +898,7 @@
 	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
 
 	sm->pairwise = pairwise;
+	sm->PTK_valid = TRUE;
 	wpa_ft_install_ptk(sm);
 
 	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
new file mode 100644
index 0000000..56b1122
--- /dev/null
+++ b/src/common/common_module_tests.c
@@ -0,0 +1,172 @@
+/*
+ * common module tests
+ * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "ieee802_11_common.h"
+#include "wpa_common.h"
+
+
+struct ieee802_11_parse_test_data {
+	u8 *data;
+	size_t len;
+	ParseRes result;
+	int count;
+};
+
+static const struct ieee802_11_parse_test_data parse_tests[] = {
+	{ (u8 *) "", 0, ParseOK, 0 },
+	{ (u8 *) " ", 1, ParseFailed, 0 },
+	{ (u8 *) "\xff\x00", 2, ParseUnknown, 1 },
+	{ (u8 *) "\xff\x01", 2, ParseFailed, 0 },
+	{ (u8 *) "\xdd\x03\x01\x02\x03", 5, ParseUnknown, 1 },
+	{ (u8 *) "\xdd\x04\x01\x02\x03\x04", 6, ParseUnknown, 1 },
+	{ (u8 *) "\xdd\x04\x00\x50\xf2\x02", 6, ParseUnknown, 1 },
+	{ (u8 *) "\xdd\x05\x00\x50\xf2\x02\x02", 7, ParseOK, 1 },
+	{ (u8 *) "\xdd\x05\x00\x50\xf2\x02\xff", 7, ParseUnknown, 1 },
+	{ (u8 *) "\xdd\x04\x00\x50\xf2\xff", 6, ParseUnknown, 1 },
+	{ (u8 *) "\xdd\x04\x50\x6f\x9a\xff", 6, ParseUnknown, 1 },
+	{ (u8 *) "\xdd\x04\x00\x90\x4c\x33", 6, ParseOK, 1 },
+	{ (u8 *) "\xdd\x04\x00\x90\x4c\xff\xdd\x04\x00\x90\x4c\x33", 12,
+	  ParseUnknown, 2 },
+	{ (u8 *) "\x10\x01\x00\x21\x00", 5, ParseOK, 2 },
+	{ (u8 *) "\x24\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\x38\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\x54\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\x5a\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\x65\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\x65\x12\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11",
+	  20, ParseOK, 1 },
+	{ (u8 *) "\x6e\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\xc7\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\xc7\x01\x00", 3, ParseOK, 1 },
+	{ NULL, 0, ParseOK, 0 }
+};
+
+static int ieee802_11_parse_tests(void)
+{
+	int i, ret = 0;
+
+	wpa_printf(MSG_INFO, "ieee802_11_parse tests");
+
+	for (i = 0; parse_tests[i].data; i++) {
+		const struct ieee802_11_parse_test_data *test;
+		struct ieee802_11_elems elems;
+		ParseRes res;
+
+		test = &parse_tests[i];
+		res = ieee802_11_parse_elems(test->data, test->len, &elems, 1);
+		if (res != test->result ||
+		    ieee802_11_ie_count(test->data, test->len) != test->count) {
+			wpa_printf(MSG_ERROR, "ieee802_11_parse test %d failed",
+				   i);
+			ret = -1;
+		}
+	}
+
+	if (ieee802_11_vendor_ie_concat((const u8 *) "\x00\x01", 2, 0) != NULL)
+	{
+		wpa_printf(MSG_ERROR,
+			   "ieee802_11_vendor_ie_concat test failed");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+struct rsn_ie_parse_test_data {
+	u8 *data;
+	size_t len;
+	int result;
+};
+
+static const struct rsn_ie_parse_test_data rsn_parse_tests[] = {
+	{ (u8 *) "", 0, -1 },
+	{ (u8 *) "\x30\x00", 2, -1 },
+	{ (u8 *) "\x30\x02\x01\x00", 4, 0 },
+	{ (u8 *) "\x30\x02\x00\x00", 4, -2 },
+	{ (u8 *) "\x30\x02\x02\x00", 4, -2 },
+	{ (u8 *) "\x30\x02\x00\x01", 4, -2 },
+	{ (u8 *) "\x30\x02\x00\x00\x00", 5, -2 },
+	{ (u8 *) "\x30\x03\x01\x00\x00", 5, -3 },
+	{ (u8 *) "\x30\x06\x01\x00\x00\x00\x00\x00", 8, -1 },
+	{ (u8 *) "\x30\x06\x01\x00\x00\x0f\xac\x04", 8, 0 },
+	{ (u8 *) "\x30\x07\x01\x00\x00\x0f\xac\x04\x00", 9, -5 },
+	{ (u8 *) "\x30\x08\x01\x00\x00\x0f\xac\x04\x00\x00", 10, -4 },
+	{ (u8 *) "\x30\x08\x01\x00\x00\x0f\xac\x04\x00\x01", 10, -4 },
+	{ (u8 *) "\x30\x0c\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04",
+	  14, 0 },
+	{ (u8 *) "\x30\x0c\x01\x00\x00\x0f\xac\x04\x00\x01\x00\x0f\xac\x04",
+	  14, -4 },
+	{ (u8 *) "\x30\x0c\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x06",
+	  14, -1 },
+	{ (u8 *) "\x30\x10\x01\x00\x00\x0f\xac\x04\x02\x00\x00\x0f\xac\x04\x00\x0f\xac\x08",
+	  18, 0 },
+	{ (u8 *) "\x30\x0d\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x00",
+	  15, -7 },
+	{ (u8 *) "\x30\x0e\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x00\x00",
+	  16, -6 },
+	{ (u8 *) "\x30\x0e\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x00\x01",
+	  16, -6 },
+	{ (u8 *) "\x30\x12\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01",
+	  20, 0 },
+	{ (u8 *) "\x30\x16\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x02\x00\x00\x0f\xac\x01\x00\x0f\xac\x02",
+	  24, 0 },
+	{ (u8 *) "\x30\x13\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00",
+	  21, 0 },
+	{ (u8 *) "\x30\x14\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00",
+	  22, 0 },
+	{ (u8 *) "\x30\x16\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x00",
+	  24, 0 },
+	{ (u8 *) "\x30\x16\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x01",
+	  24, -9 },
+	{ (u8 *) "\x30\x1a\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x00\x00\x00\x00\x00",
+	  28, -10 },
+	{ (u8 *) "\x30\x1a\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x00\x00\x0f\xac\x06",
+	  28, 0 },
+	{ (u8 *) "\x30\x1c\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x00\x00\x0f\xac\x06\x01\x02",
+	  30, 0 },
+	{ NULL, 0, 0 }
+};
+
+static int rsn_ie_parse_tests(void)
+{
+	int i, ret = 0;
+
+	wpa_printf(MSG_INFO, "rsn_ie_parse tests");
+
+	for (i = 0; rsn_parse_tests[i].data; i++) {
+		const struct rsn_ie_parse_test_data *test;
+		struct wpa_ie_data data;
+
+		test = &rsn_parse_tests[i];
+		if (wpa_parse_wpa_ie_rsn(test->data, test->len, &data) !=
+		    test->result) {
+			wpa_printf(MSG_ERROR, "rsn_ie_parse test %d failed", i);
+			ret = -1;
+		}
+	}
+
+	return ret;
+}
+
+
+int common_module_tests(void)
+{
+	int ret = 0;
+
+	wpa_printf(MSG_INFO, "common module tests");
+
+	if (ieee802_11_parse_tests() < 0 ||
+	    rsn_ie_parse_tests() < 0)
+		ret = -1;
+
+	return ret;
+}
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index cdee6bc..faa6a39 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -116,7 +116,7 @@
 		default:
 			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
 				   "information element ignored "
-				   "(type=%d len=%lu)\n",
+				   "(type=%d len=%lu)",
 				   pos[3], (unsigned long) elen);
 			return -1;
 		}
diff --git a/src/common/sae.c b/src/common/sae.c
index 674cb65..c1b488e 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -134,8 +134,10 @@
 			return NULL;
 		if (crypto_bignum_is_zero(bn) ||
 		    crypto_bignum_is_one(bn) ||
-		    crypto_bignum_cmp(bn, sae->tmp->order) >= 0)
+		    crypto_bignum_cmp(bn, sae->tmp->order) >= 0) {
+			crypto_bignum_deinit(bn, 0);
 			continue;
+		}
 		break;
 	}
 
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 58a07cf..d2d6600 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2968,6 +2968,41 @@
 }
 
 
+static void debug_print_cert(X509 *cert, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	BIO *out;
+	size_t rlen;
+	char *txt;
+	int res;
+
+	if (wpa_debug_level > MSG_DEBUG)
+		return;
+
+	out = BIO_new(BIO_s_mem());
+	if (!out)
+		return;
+
+	X509_print(out, cert);
+	rlen = BIO_ctrl_pending(out);
+	txt = os_malloc(rlen + 1);
+	if (!txt) {
+		BIO_free(out);
+		return;
+	}
+
+	res = BIO_read(out, txt, rlen);
+	if (res > 0) {
+		txt[res] = '\0';
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
+	}
+	os_free(txt);
+
+	BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
 static int ocsp_resp_cb(SSL *s, void *arg)
 {
 	struct tls_connection *conn = arg;
@@ -3011,8 +3046,7 @@
 
 	store = SSL_CTX_get_cert_store(s->ctx);
 	if (conn->peer_issuer) {
-		wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer");
-		X509_print_fp(stdout, conn->peer_issuer);
+		debug_print_cert(conn->peer_issuer, "Add OCSP issuer");
 
 		if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
 			tls_show_errors(MSG_INFO, __func__,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 9f7d0f5..7568653 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -652,7 +652,7 @@
 
 	while (err > 0) {
 		int res = nl_recvmsgs(nl_handle, cb);
-		if (res) {
+		if (res < 0) {
 			wpa_printf(MSG_INFO,
 				   "nl80211: %s->nl_recvmsgs failed: %d",
 				   __func__, res);
@@ -910,7 +910,7 @@
 	wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
 
 	res = nl_recvmsgs(handle, w->nl_cb);
-	if (res) {
+	if (res < 0) {
 		wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
 			   __func__, res);
 	}
@@ -3276,7 +3276,7 @@
 	wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
 
 	res = nl_recvmsgs(handle, cb);
-	if (res) {
+	if (res < 0) {
 		wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
 			   __func__, res);
 	}
@@ -10107,19 +10107,22 @@
 
 		if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
 				       new_addr) < 0) {
-			nl80211_remove_iface(drv, ifidx);
+			if (added)
+				nl80211_remove_iface(drv, ifidx);
 			return -1;
 		}
 		if (nl80211_addr_in_use(drv->global, new_addr)) {
 			wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
 				   "for P2P group interface");
 			if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
-				nl80211_remove_iface(drv, ifidx);
+				if (added)
+					nl80211_remove_iface(drv, ifidx);
 				return -1;
 			}
 			if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
 					       new_addr) < 0) {
-				nl80211_remove_iface(drv, ifidx);
+				if (added)
+					nl80211_remove_iface(drv, ifidx);
 				return -1;
 			}
 		}
@@ -10148,7 +10151,8 @@
 
 		if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
 		{
-			nl80211_remove_iface(drv, ifidx);
+			if (added)
+				nl80211_remove_iface(drv, ifidx);
 			os_free(new_bss);
 			return -1;
 		}
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 1a19041..1875ca4 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -4638,10 +4638,9 @@
 			  params->go_ssid_len);
 	}
 
-	p2p_parse_free(&msg);
-
 	if (dev->flags & P2P_DEV_USER_REJECTED) {
 		p2p_dbg(p2p, "Do not report rejected device");
+		p2p_parse_free(&msg);
 		return 0;
 	}
 
@@ -4650,6 +4649,7 @@
 				    !(dev->flags & P2P_DEV_REPORTED_ONCE));
 		dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
 	}
+	p2p_parse_free(&msg);
 
 	if (role == P2P_GO_IN_A_GROUP && p2p->num_groups > 0)
 		params->next_step = BOTH_GO;
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index cb77aee..a36898e 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -227,8 +227,11 @@
 		goto fail;
 	}
 
+	p2p_channels_dump(p2p, "own channels", &p2p->cfg->channels);
+	p2p_channels_dump(p2p, "peer channels", &dev->channels);
 	p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
 			       &intersection);
+	p2p_channels_dump(p2p, "intersection", &intersection);
 
 	if (p2p->cfg->invitation_process) {
 		status = p2p->cfg->invitation_process(
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 7625996..10056a6 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -295,26 +295,34 @@
 }
 
 
-static void radius_client_handle_send_error(struct radius_client_data *radius,
-					    int s, RadiusType msg_type)
+/*
+ * Returns >0 if message queue was flushed (i.e., the message that triggered
+ * the error is not available anymore)
+ */
+static int radius_client_handle_send_error(struct radius_client_data *radius,
+					   int s, RadiusType msg_type)
 {
 #ifndef CONFIG_NATIVE_WINDOWS
 	int _errno = errno;
 	wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno));
 	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
-	    _errno == EBADF) {
+	    _errno == EBADF || _errno == ENETUNREACH) {
 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 			       HOSTAPD_LEVEL_INFO,
 			       "Send failed - maybe interface status changed -"
 			       " try to connect again");
-		eloop_unregister_read_sock(s);
-		close(s);
-		if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
+		if (msg_type == RADIUS_ACCT ||
+		    msg_type == RADIUS_ACCT_INTERIM) {
 			radius_client_init_acct(radius);
-		else
+			return 0;
+		} else {
 			radius_client_init_auth(radius);
+			return 1;
+		}
 	}
 #endif /* CONFIG_NATIVE_WINDOWS */
+
+	return 0;
 }
 
 
@@ -353,8 +361,11 @@
 
 	os_get_reltime(&entry->last_attempt);
 	buf = radius_msg_get_buf(entry->msg);
-	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0)
-		radius_client_handle_send_error(radius, s, entry->msg_type);
+	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+		if (radius_client_handle_send_error(radius, s, entry->msg_type)
+		    > 0)
+			return 0;
+	}
 
 	entry->next_try = now + entry->next_wait;
 	entry->next_wait *= 2;
@@ -378,6 +389,8 @@
 	struct radius_msg_list *entry, *prev, *tmp;
 	int auth_failover = 0, acct_failover = 0;
 	char abuf[50];
+	size_t prev_num_msgs;
+	int s;
 
 	entry = radius->msgs;
 	if (!entry)
@@ -388,6 +401,7 @@
 
 	prev = NULL;
 	while (entry) {
+		prev_num_msgs = radius->num_msgs;
 		if (now.sec >= entry->next_try &&
 		    radius_client_retransmit(radius, entry, now.sec)) {
 			if (prev)
@@ -402,7 +416,18 @@
 			continue;
 		}
 
-		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
+		if (prev_num_msgs != radius->num_msgs) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS: Message removed from queue - restart from beginning");
+			entry = radius->msgs;
+			prev = NULL;
+			continue;
+		}
+
+		s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
+			radius->acct_sock;
+		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
+		    (s < 0 && entry->attempts > 0)) {
 			if (entry->msg_type == RADIUS_ACCT ||
 			    entry->msg_type == RADIUS_ACCT_INTERIM)
 				acct_failover++;
@@ -633,7 +658,7 @@
 	}
 
 	if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
-		if (conf->acct_server == NULL) {
+		if (conf->acct_server == NULL || radius->acct_sock < 0) {
 			hostapd_logger(radius->ctx, NULL,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
@@ -647,7 +672,7 @@
 		s = radius->acct_sock;
 		conf->acct_server->requests++;
 	} else {
-		if (conf->auth_server == NULL) {
+		if (conf->auth_server == NULL || radius->auth_sock < 0) {
 			hostapd_logger(radius->ctx, NULL,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
@@ -951,9 +976,10 @@
 		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
 		       nserv->port);
 
-	if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
-	    os_memcmp(nserv->shared_secret, oserv->shared_secret,
-		      nserv->shared_secret_len) != 0) {
+	if (oserv && oserv != nserv &&
+	    (nserv->shared_secret_len != oserv->shared_secret_len ||
+	     os_memcmp(nserv->shared_secret, oserv->shared_secret,
+		       nserv->shared_secret_len) != 0)) {
 		/* Pending RADIUS packets used different shared secret, so
 		 * they need to be modified. Update accounting message
 		 * authenticators here. Authentication messages are removed
@@ -971,7 +997,8 @@
 	}
 
 	/* Reset retry counters for the new server */
-	for (entry = radius->msgs; entry; entry = entry->next) {
+	for (entry = radius->msgs; oserv && oserv != nserv && entry;
+	     entry = entry->next) {
 		if ((auth && entry->msg_type != RADIUS_AUTH) ||
 		    (!auth && entry->msg_type != RADIUS_ACCT))
 			continue;
@@ -1128,11 +1155,51 @@
 }
 
 
+static void radius_close_auth_sockets(struct radius_client_data *radius)
+{
+	radius->auth_sock = -1;
+
+	if (radius->auth_serv_sock >= 0) {
+		eloop_unregister_read_sock(radius->auth_serv_sock);
+		close(radius->auth_serv_sock);
+		radius->auth_serv_sock = -1;
+	}
+#ifdef CONFIG_IPV6
+	if (radius->auth_serv_sock6 >= 0) {
+		eloop_unregister_read_sock(radius->auth_serv_sock6);
+		close(radius->auth_serv_sock6);
+		radius->auth_serv_sock6 = -1;
+	}
+#endif /* CONFIG_IPV6 */
+}
+
+
+static void radius_close_acct_sockets(struct radius_client_data *radius)
+{
+	radius->acct_sock = -1;
+
+	if (radius->acct_serv_sock >= 0) {
+		eloop_unregister_read_sock(radius->acct_serv_sock);
+		close(radius->acct_serv_sock);
+		radius->acct_serv_sock = -1;
+	}
+#ifdef CONFIG_IPV6
+	if (radius->acct_serv_sock6 >= 0) {
+		eloop_unregister_read_sock(radius->acct_serv_sock6);
+		close(radius->acct_serv_sock6);
+		radius->acct_serv_sock6 = -1;
+	}
+#endif /* CONFIG_IPV6 */
+}
+
+
 static int radius_client_init_auth(struct radius_client_data *radius)
 {
 	struct hostapd_radius_servers *conf = radius->conf;
 	int ok = 0;
 
+	radius_close_auth_sockets(radius);
+
 	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (radius->auth_serv_sock < 0)
 		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
@@ -1163,6 +1230,7 @@
 				     radius_client_receive, radius,
 				     (void *) RADIUS_AUTH)) {
 		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
+		radius_close_auth_sockets(radius);
 		return -1;
 	}
 
@@ -1172,6 +1240,7 @@
 				     radius_client_receive, radius,
 				     (void *) RADIUS_AUTH)) {
 		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
+		radius_close_auth_sockets(radius);
 		return -1;
 	}
 #endif /* CONFIG_IPV6 */
@@ -1185,6 +1254,8 @@
 	struct hostapd_radius_servers *conf = radius->conf;
 	int ok = 0;
 
+	radius_close_acct_sockets(radius);
+
 	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (radius->acct_serv_sock < 0)
 		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
@@ -1215,6 +1286,7 @@
 				     radius_client_receive, radius,
 				     (void *) RADIUS_ACCT)) {
 		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
+		radius_close_acct_sockets(radius);
 		return -1;
 	}
 
@@ -1224,6 +1296,7 @@
 				     radius_client_receive, radius,
 				     (void *) RADIUS_ACCT)) {
 		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
+		radius_close_acct_sockets(radius);
 		return -1;
 	}
 #endif /* CONFIG_IPV6 */
@@ -1285,16 +1358,8 @@
 	if (!radius)
 		return;
 
-	if (radius->auth_serv_sock >= 0)
-		eloop_unregister_read_sock(radius->auth_serv_sock);
-	if (radius->acct_serv_sock >= 0)
-		eloop_unregister_read_sock(radius->acct_serv_sock);
-#ifdef CONFIG_IPV6
-	if (radius->auth_serv_sock6 >= 0)
-		eloop_unregister_read_sock(radius->auth_serv_sock6);
-	if (radius->acct_serv_sock6 >= 0)
-		eloop_unregister_read_sock(radius->acct_serv_sock6);
-#endif /* CONFIG_IPV6 */
+	radius_close_auth_sockets(radius);
+	radius_close_acct_sockets(radius);
 
 	eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
 
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index bd358ae..78c9961 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -1730,6 +1730,7 @@
 		data->subscr_remediation_url =
 			os_strdup(conf->subscr_remediation_url);
 	}
+	data->subscr_remediation_method = conf->subscr_remediation_method;
 
 #ifdef CONFIG_SQLITE
 	if (conf->sqlite_file) {
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index d45f5dc..ba2a8c8 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1734,9 +1734,8 @@
 				"version for non-CCMP group keys");
 		} else
 			goto out;
-	}
-	if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
-	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+	} else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+		   ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: GCMP is used, but EAPOL-Key "
 			"descriptor version (%d) is not 2", ver);
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index c0913e0..817a69d 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -97,15 +97,6 @@
 OBJS_p += ../src/utils/os_$(CONFIG_OS).o
 OBJS_c += ../src/utils/os_$(CONFIG_OS).o
 
-ifdef CONFIG_MODULE_TESTS
-CFLAGS += -DCONFIG_MODULE_TESTS
-OBJS += wpas_module_tests.o
-OBJS += ../src/utils/utils_module_tests.o
-ifdef CONFIG_WPS
-OBJS += ../src/wps/wps_module_tests.o
-endif
-endif
-
 ifdef CONFIG_WPA_TRACE
 CFLAGS += -DWPA_TRACE
 OBJS += ../src/utils/trace.o
@@ -1500,6 +1491,16 @@
 CFLAGS += -DCONFIG_OFFCHANNEL
 endif
 
+ifdef CONFIG_MODULE_TESTS
+CFLAGS += -DCONFIG_MODULE_TESTS
+OBJS += wpas_module_tests.o
+OBJS += ../src/utils/utils_module_tests.o
+OBJS += ../src/common/common_module_tests.o
+ifdef CONFIG_WPS
+OBJS += ../src/wps/wps_module_tests.o
+endif
+endif
+
 OBJS += ../src/drivers/driver_common.o
 OBJS_priv += ../src/drivers/driver_common.o
 
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 88a4cd9..53e23ff 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5808,8 +5808,8 @@
 		"Timing out external radio work %u (%s)",
 		ework->id, work->type);
 	wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
-	os_free(ework);
 	radio_work_done(work);
+	os_free(ework);
 }
 
 
@@ -5951,8 +5951,8 @@
 		if (work->started)
 			eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
 					     work, NULL);
-		os_free(ework);
 		radio_work_done(work);
+		os_free(ework);
 	}
 }
 
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index a8ecb8c..6d1539c 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -2397,9 +2397,10 @@
 		if (interworking_find_network_match(wpa_s)) {
 			wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
 				   "match for enabled network configurations");
-			if (wpa_s->auto_select)
+			if (wpa_s->auto_select) {
 				interworking_reconnect(wpa_s);
-			return;
+				return;
+			}
 		}
 
 		if (wpa_s->auto_network_select) {
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
index 38493d4..e4c83b5 100644
--- a/wpa_supplicant/wpas_module_tests.c
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -92,5 +92,11 @@
 			ret = -1;
 	}
 
+	{
+		int common_module_tests(void);
+		if (common_module_tests() < 0)
+			ret = -1;
+	}
+
 	return ret;
 }