Cumulative patch from commit e15dcf6d1bc2725388555523effca75b1ffab735

e15dcf6 nl8021: Avoid potential memory leak on error path
17d32eb Allow re-write of ip_addr* configurations to conf file.
bcce934 dbus: Restrict DeviceName size to 32 characters in setter
7c70fe2 Sort options and reduce printf calls in wpa_supplicant usage text
6b418ce Fix wpa_supplicant build with IEEE8021X_EAPOL=y and CONFIG_NO_WPA=y
03269d5 AP: Print interface name in more STA events
9e8fde2 AP: Fix Deauth/Disassoc TX status timeout handling
269f9d5 EAP peer: Use ifdef PCSC_FUNCS to get rid of compiler warnings
c6e0b4b FST: Get rid of gcc extensions in structure/array initialization
2e3a41a hs20-osu-client: Fix check for osu_nai being available
ac2053b OpenSSL: Clean up openssl_digest_vector() to use a single implementation
5c9a337 OpenSSL: Clean up crypto_hash_*() to use a single implementation
587b045 LibreSSL: Fix build with LibreSSL
0daa9f6 EAP-TTLS peer: Fix success after fragmented final Phase 2 message
1eb87ae OpenSSL: Use EVP_CIPHER_CTX_new() to work with OpenSSL 1.1.0
3fb3bea OpenSSL: Update session_secret callback to match OpenSSL 1.1.0 API
814f43c EAP server: Simplify EAP method registration call
49a26bb EAP peer: Simplify EAP method registration call
7ce5603 EAP-WSC peer: Remove unused state values
449a316 bsd: Optimize socket use
4653ceb nl80211: Report disassociated STA / lost peer for the correct BSS
38af042 Drop OpenSSL 0.9.8 patches to add EAP-FAST support

Change-Id: Ib88c54b382c322d6151ed77e08f83329f918e3e8
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 0315f7b..35793c8 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2229,7 +2229,7 @@
 		fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
 			"SSID: %s<br>\n",
 			last->bssid, last->osu_ssid);
-		if (last->osu_nai)
+		if (last->osu_nai[0])
 			fprintf(f, "NAI: %s<br>\n", last->osu_nai);
 		fprintf(f, "URL: %s<br>\n"
 			"methods:%s%s<br>\n"
diff --git a/src/ap/ap_mlme.c b/src/ap/ap_mlme.c
index 13604ed..e7308a0 100644
--- a/src/ap/ap_mlme.c
+++ b/src/ap/ap_mlme.c
@@ -59,6 +59,7 @@
 		       MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
 	if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
 		mlme_deletekeys_request(hapd, sta);
+	ap_sta_clear_disconnect_timeouts(hapd, sta);
 }
 
 
@@ -106,6 +107,7 @@
 		       MAC2STR(sta->addr));
 	if (sta->auth_alg != WLAN_AUTH_FT)
 		mlme_deletekeys_request(hapd, sta);
+	ap_sta_clear_disconnect_timeouts(hapd, sta);
 }
 
 
@@ -130,6 +132,7 @@
 		       MAC2STR(sta->addr));
 	if (sta->auth_alg != WLAN_AUTH_FT)
 		mlme_deletekeys_request(hapd, sta);
+	ap_sta_clear_disconnect_timeouts(hapd, sta);
 }
 
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index b10b454..2aa4f8c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -2634,6 +2634,7 @@
 	}
 
 	hostapd_prune_associations(hapd, sta->addr);
+	ap_sta_clear_disconnect_timeouts(hapd, sta);
 
 	/* IEEE 802.11F (IAPP) */
 	if (hapd->conf->ieee802_11f)
@@ -2667,9 +2668,10 @@
 		wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
 
 	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
-		wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
-			   "for " MACSTR " (%d seconds - ap_max_inactivity)",
-			   __func__, MAC2STR(sta->addr),
+		wpa_printf(MSG_DEBUG,
+			   "%s: %s: reschedule ap_handle_timer timeout for "
+			   MACSTR " (%d seconds - ap_max_inactivity)",
+			   hapd->conf->iface, __func__, MAC2STR(sta->addr),
 			   hapd->conf->ap_max_inactivity);
 		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
 		eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 68fff4c..8bba73c 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -249,8 +249,7 @@
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
 	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
 	eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
-	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
-	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	ap_sta_clear_disconnect_timeouts(hapd, sta);
 	sae_clear_retransmit_timer(hapd, sta);
 
 	ieee802_1x_free_station(hapd, sta);
@@ -359,8 +358,8 @@
 	unsigned long next_time = 0;
 	int reason;
 
-	wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
-		   __func__, MAC2STR(sta->addr), sta->flags,
+	wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
+		   hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
 		   sta->timeout_next);
 	if (sta->timeout_next == STA_REMOVE) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -524,6 +523,8 @@
 	struct hostapd_data *hapd = eloop_ctx;
 	struct sta_info *sta = timeout_ctx;
 
+	wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
+		   hapd->conf->iface, MAC2STR(sta->addr));
 	if (!(sta->flags & WLAN_STA_AUTH)) {
 		if (sta->flags & WLAN_STA_GAS) {
 			wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
@@ -582,8 +583,8 @@
 	struct hostapd_data *hapd = eloop_ctx;
 	struct sta_info *sta = timeout_ctx;
 
-	wpa_printf(MSG_DEBUG, "WNM: Session warning time reached for " MACSTR,
-		   MAC2STR(sta->addr));
+	wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for "
+		   MACSTR, hapd->conf->iface, MAC2STR(sta->addr));
 	if (sta->hs20_session_info_url == NULL)
 		return;
 
@@ -657,12 +658,13 @@
 		hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
 	ap_sta_ip6addr_del(hapd, sta);
 
-	wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
-		   MAC2STR(sta->addr));
+	wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver",
+		   hapd->conf->iface, MAC2STR(sta->addr));
 	if (hostapd_drv_sta_remove(hapd, sta->addr) &&
 	    sta->flags & WLAN_STA_ASSOC) {
-		wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
-			   " from kernel driver.", MAC2STR(sta->addr));
+		wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR
+			   " from kernel driver",
+			   hapd->conf->iface, MAC2STR(sta->addr));
 		return -1;
 	}
 	return 0;
@@ -688,6 +690,10 @@
 		if (!sta2)
 			continue;
 
+		wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR
+			   " association from another BSS %s",
+			   hapd->conf->iface, MAC2STR(sta2->addr),
+			   bss->conf->iface);
 		ap_sta_disconnect(bss, sta2, sta2->addr,
 				  WLAN_REASON_PREV_AUTH_NOT_VALID);
 	}
@@ -699,6 +705,8 @@
 	struct hostapd_data *hapd = eloop_ctx;
 	struct sta_info *sta = timeout_ctx;
 
+	wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR,
+		   hapd->conf->iface, MAC2STR(sta->addr));
 	ap_sta_remove(hapd, sta);
 	mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
 }
@@ -738,6 +746,8 @@
 	struct hostapd_data *hapd = eloop_ctx;
 	struct sta_info *sta = timeout_ctx;
 
+	wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR,
+		   hapd->conf->iface, MAC2STR(sta->addr));
 	ap_sta_remove(hapd, sta);
 	mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
 }
@@ -923,6 +933,10 @@
 	unsigned int timeout, sec, usec;
 	u8 *trans_id, *nbuf;
 
+	wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR
+		   " (count=%d)",
+		   hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count);
+
 	if (sta->sa_query_count > 0 &&
 	    ap_check_sa_query_timeout(hapd, sta))
 		return;
@@ -1061,6 +1075,14 @@
 void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *addr, u16 reason)
 {
+	if (sta)
+		wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u",
+			   hapd->conf->iface, __func__, MAC2STR(sta->addr),
+			   reason);
+	else if (addr)
+		wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u",
+			   hapd->conf->iface, __func__, MAC2STR(addr),
+			   reason);
 
 	if (sta == NULL && addr)
 		sta = ap_get_sta(hapd, addr);
@@ -1074,10 +1096,10 @@
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+	wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
 		   "for " MACSTR " (%d seconds - "
 		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
-		   __func__, MAC2STR(sta->addr),
+		   hapd->conf->iface, __func__, MAC2STR(sta->addr),
 		   AP_MAX_INACTIVITY_AFTER_DEAUTH);
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
 	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
@@ -1117,6 +1139,22 @@
 }
 
 
+void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
+				      struct sta_info *sta)
+{
+	if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0)
+		wpa_printf(MSG_DEBUG,
+			   "%s: Removed ap_sta_deauth_cb_timeout timeout for "
+			   MACSTR,
+			   hapd->conf->iface, MAC2STR(sta->addr));
+	if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0)
+		wpa_printf(MSG_DEBUG,
+			   "%s: Removed ap_sta_disassoc_cb_timeout timeout for "
+			   MACSTR,
+			   hapd->conf->iface, MAC2STR(sta->addr));
+}
+
+
 int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
 {
 	int res;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 09deac6..e3b4915 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -236,6 +236,8 @@
 
 void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
+				      struct sta_info *sta);
 
 int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
 
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 73b547d..071a4dc 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -31,6 +31,50 @@
 #include "sha384.h"
 #include "crypto.h"
 
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+/* Compatibility wrappers for older versions. */
+
+static int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx)
+{
+	return EVP_CIPHER_CTX_cleanup(ctx);
+}
+
+
+static HMAC_CTX * HMAC_CTX_new(void)
+{
+	HMAC_CTX *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx)
+		HMAC_CTX_init(ctx);
+	return ctx;
+}
+
+
+static void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+	bin_clear_free(ctx, sizeof(*ctx));
+}
+
+
+static EVP_MD_CTX * EVP_MD_CTX_new(void)
+{
+	EVP_MD_CTX *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx)
+		EVP_MD_CTX_init(ctx);
+	return ctx;
+}
+
+
+static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+	bin_clear_free(ctx, sizeof(*ctx));
+}
+
+#endif /* OpenSSL version < 1.1.0 */
+
 static BIGNUM * get_group5_prime(void)
 {
 #ifdef OPENSSL_IS_BORINGSSL
@@ -65,7 +109,6 @@
 static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
 				 const u8 *addr[], const size_t *len, u8 *mac)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 	EVP_MD_CTX *ctx;
 	size_t i;
 	unsigned int mac_len;
@@ -100,36 +143,6 @@
 	EVP_MD_CTX_free(ctx);
 
 	return 0;
-#else
-	EVP_MD_CTX ctx;
-	size_t i;
-	unsigned int mac_len;
-
-	if (TEST_FAIL())
-		return -1;
-
-	EVP_MD_CTX_init(&ctx);
-	if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
-		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
-		return -1;
-	}
-	for (i = 0; i < num_elem; i++) {
-		if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
-			wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
-				   "failed: %s",
-				   ERR_error_string(ERR_get_error(), NULL));
-			return -1;
-		}
-	}
-	if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
-		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
-		return -1;
-	}
-
-	return 0;
-#endif
 }
 
 
@@ -169,32 +182,34 @@
 #ifdef OPENSSL_NO_RC4
 	return -1;
 #else /* OPENSSL_NO_RC4 */
-	EVP_CIPHER_CTX ctx;
+	EVP_CIPHER_CTX *ctx;
 	int outl;
 	int res = -1;
 	unsigned char skip_buf[16];
 
-	EVP_CIPHER_CTX_init(&ctx);
-	if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
-	    !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
-	    !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
-	    !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
+	ctx = EVP_CIPHER_CTX_new();
+	if (!ctx ||
+	    !EVP_CIPHER_CTX_set_padding(ctx, 0) ||
+	    !EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
+	    !EVP_CIPHER_CTX_set_key_length(ctx, keylen) ||
+	    !EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, 1))
 		goto out;
 
 	while (skip >= sizeof(skip_buf)) {
 		size_t len = skip;
 		if (len > sizeof(skip_buf))
 			len = sizeof(skip_buf);
-		if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
+		if (!EVP_CipherUpdate(ctx, skip_buf, &outl, skip_buf, len))
 			goto out;
 		skip -= len;
 	}
 
-	if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
+	if (EVP_CipherUpdate(ctx, data, &outl, data, data_len))
 		res = 0;
 
 out:
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	if (ctx)
+		EVP_CIPHER_CTX_reset(ctx);
 	return res;
 #endif /* OPENSSL_NO_RC4 */
 }
@@ -246,14 +261,16 @@
 	EVP_CIPHER_CTX *ctx;
 	const EVP_CIPHER *type;
 
+	if (TEST_FAIL())
+		return NULL;
+
 	type = aes_get_evp_cipher(len);
 	if (type == NULL)
 		return NULL;
 
-	ctx = os_malloc(sizeof(*ctx));
+	ctx = EVP_CIPHER_CTX_new();
 	if (ctx == NULL)
 		return NULL;
-	EVP_CIPHER_CTX_init(ctx);
 	if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
 		os_free(ctx);
 		return NULL;
@@ -287,8 +304,8 @@
 		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
 			   "in AES encrypt", len);
 	}
-	EVP_CIPHER_CTX_cleanup(c);
-	bin_clear_free(c, sizeof(*c));
+	EVP_CIPHER_CTX_reset(c);
+	EVP_CIPHER_CTX_free(c);
 }
 
 
@@ -297,16 +314,18 @@
 	EVP_CIPHER_CTX *ctx;
 	const EVP_CIPHER *type;
 
+	if (TEST_FAIL())
+		return NULL;
+
 	type = aes_get_evp_cipher(len);
 	if (type == NULL)
 		return NULL;
 
-	ctx = os_malloc(sizeof(*ctx));
+	ctx = EVP_CIPHER_CTX_new();
 	if (ctx == NULL)
 		return NULL;
-	EVP_CIPHER_CTX_init(ctx);
 	if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
-		os_free(ctx);
+		EVP_CIPHER_CTX_free(ctx);
 		return NULL;
 	}
 	EVP_CIPHER_CTX_set_padding(ctx, 0);
@@ -338,8 +357,8 @@
 		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
 			   "in AES decrypt", len);
 	}
-	EVP_CIPHER_CTX_cleanup(c);
-	bin_clear_free(c, sizeof(*c));
+	EVP_CIPHER_CTX_reset(c);
+	EVP_CIPHER_CTX_free(c);
 }
 
 
@@ -378,57 +397,56 @@
 
 int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
 {
-	EVP_CIPHER_CTX ctx;
+	EVP_CIPHER_CTX *ctx;
 	int clen, len;
 	u8 buf[16];
+	int res = -1;
 
 	if (TEST_FAIL())
 		return -1;
 
-	EVP_CIPHER_CTX_init(&ctx);
-	if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+	ctx = EVP_CIPHER_CTX_new();
+	if (!ctx)
 		return -1;
-	EVP_CIPHER_CTX_set_padding(&ctx, 0);
-
 	clen = data_len;
-	if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 ||
-	    clen != (int) data_len)
-		return -1;
-
 	len = sizeof(buf);
-	if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
-		return -1;
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+	    EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+	    EVP_EncryptUpdate(ctx, data, &clen, data, data_len) == 1 &&
+	    clen == (int) data_len &&
+	    EVP_EncryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+		res = 0;
+	EVP_CIPHER_CTX_reset(ctx);
 
-	return 0;
+	return res;
 }
 
 
 int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
 {
-	EVP_CIPHER_CTX ctx;
+	EVP_CIPHER_CTX *ctx;
 	int plen, len;
 	u8 buf[16];
+	int res = -1;
 
 	if (TEST_FAIL())
 		return -1;
 
-	EVP_CIPHER_CTX_init(&ctx);
-	if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+	ctx = EVP_CIPHER_CTX_new();
+	if (!ctx)
 		return -1;
-	EVP_CIPHER_CTX_set_padding(&ctx, 0);
-
 	plen = data_len;
-	if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 ||
-	    plen != (int) data_len)
-		return -1;
-
 	len = sizeof(buf);
-	if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
-		return -1;
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+	    EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+	    EVP_DecryptUpdate(ctx, data, &plen, data, data_len) == 1 &&
+	    plen == (int) data_len &&
+	    EVP_DecryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+		res = 0;
+	EVP_CIPHER_CTX_reset(ctx);
 
-	return 0;
+	return res;
+
 }
 
 
@@ -471,8 +489,8 @@
 
 
 struct crypto_cipher {
-	EVP_CIPHER_CTX enc;
-	EVP_CIPHER_CTX dec;
+	EVP_CIPHER_CTX *enc;
+	EVP_CIPHER_CTX *dec;
 };
 
 
@@ -533,23 +551,25 @@
 		return NULL;
 	}
 
-	EVP_CIPHER_CTX_init(&ctx->enc);
-	EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
-	if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
-	    !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
-	    !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
-		EVP_CIPHER_CTX_cleanup(&ctx->enc);
+	if (!(ctx->enc = EVP_CIPHER_CTX_new()) ||
+	    !EVP_CIPHER_CTX_set_padding(ctx->enc, 0) ||
+	    !EVP_EncryptInit_ex(ctx->enc, cipher, NULL, NULL, NULL) ||
+	    !EVP_CIPHER_CTX_set_key_length(ctx->enc, key_len) ||
+	    !EVP_EncryptInit_ex(ctx->enc, NULL, NULL, key, iv)) {
+		if (ctx->enc)
+			EVP_CIPHER_CTX_reset(ctx->enc);
 		os_free(ctx);
 		return NULL;
 	}
 
-	EVP_CIPHER_CTX_init(&ctx->dec);
-	EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
-	if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
-	    !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
-	    !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
-		EVP_CIPHER_CTX_cleanup(&ctx->enc);
-		EVP_CIPHER_CTX_cleanup(&ctx->dec);
+	if (!(ctx->dec = EVP_CIPHER_CTX_new()) ||
+	    !EVP_CIPHER_CTX_set_padding(ctx->dec, 0) ||
+	    !EVP_DecryptInit_ex(ctx->dec, cipher, NULL, NULL, NULL) ||
+	    !EVP_CIPHER_CTX_set_key_length(ctx->dec, key_len) ||
+	    !EVP_DecryptInit_ex(ctx->dec, NULL, NULL, key, iv)) {
+		EVP_CIPHER_CTX_reset(ctx->enc);
+		if (ctx->dec)
+			EVP_CIPHER_CTX_reset(ctx->dec);
 		os_free(ctx);
 		return NULL;
 	}
@@ -562,7 +582,7 @@
 			  u8 *crypt, size_t len)
 {
 	int outl;
-	if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
+	if (!EVP_EncryptUpdate(ctx->enc, crypt, &outl, plain, len))
 		return -1;
 	return 0;
 }
@@ -573,7 +593,7 @@
 {
 	int outl;
 	outl = len;
-	if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
+	if (!EVP_DecryptUpdate(ctx->dec, plain, &outl, crypt, len))
 		return -1;
 	return 0;
 }
@@ -581,8 +601,8 @@
 
 void crypto_cipher_deinit(struct crypto_cipher *ctx)
 {
-	EVP_CIPHER_CTX_cleanup(&ctx->enc);
-	EVP_CIPHER_CTX_cleanup(&ctx->dec);
+	EVP_CIPHER_CTX_reset(ctx->enc);
+	EVP_CIPHER_CTX_reset(ctx->dec);
 	os_free(ctx);
 }
 
@@ -718,11 +738,7 @@
 
 
 struct crypto_hash {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 	HMAC_CTX *ctx;
-#else
-	HMAC_CTX ctx;
-#endif
 };
 
 
@@ -757,7 +773,6 @@
 	ctx = os_zalloc(sizeof(*ctx));
 	if (ctx == NULL)
 		return NULL;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 	ctx->ctx = HMAC_CTX_new();
 	if (!ctx->ctx) {
 		os_free(ctx);
@@ -769,14 +784,6 @@
 		bin_clear_free(ctx, sizeof(*ctx));
 		return NULL;
 	}
-#else
-	HMAC_CTX_init(&ctx->ctx);
-
-	if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
-		bin_clear_free(ctx, sizeof(*ctx));
-		return NULL;
-	}
-#endif
 
 	return ctx;
 }
@@ -786,11 +793,7 @@
 {
 	if (ctx == NULL)
 		return;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 	HMAC_Update(ctx->ctx, data, len);
-#else
-	HMAC_Update(&ctx->ctx, data, len);
-#endif
 }
 
 
@@ -803,21 +806,14 @@
 		return -2;
 
 	if (mac == NULL || len == NULL) {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 		HMAC_CTX_free(ctx->ctx);
-#endif
 		bin_clear_free(ctx, sizeof(*ctx));
 		return 0;
 	}
 
 	mdlen = *len;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 	res = HMAC_Final(ctx->ctx, mac, &mdlen);
 	HMAC_CTX_free(ctx->ctx);
-#else
-	res = HMAC_Final(&ctx->ctx, mac, &mdlen);
-	HMAC_CTX_cleanup(&ctx->ctx);
-#endif
 	bin_clear_free(ctx, sizeof(*ctx));
 
 	if (res == 1) {
@@ -834,7 +830,6 @@
 			       const u8 *addr[], const size_t *len, u8 *mac,
 			       unsigned int mdlen)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 	HMAC_CTX *ctx;
 	size_t i;
 	int res;
@@ -857,26 +852,6 @@
 	HMAC_CTX_free(ctx);
 
 	return res == 1 ? 0 : -1;
-#else
-	HMAC_CTX ctx;
-	size_t i;
-	int res;
-
-	if (TEST_FAIL())
-		return -1;
-
-	HMAC_CTX_init(&ctx);
-	if (HMAC_Init_ex(&ctx, key, key_len, type, NULL) != 1)
-		return -1;
-
-	for (i = 0; i < num_elem; i++)
-		HMAC_Update(&ctx, addr[i], len[i]);
-
-	res = HMAC_Final(&ctx, mac, &mdlen);
-	HMAC_CTX_cleanup(&ctx);
-
-	return res == 1 ? 0 : -1;
-#endif
 }
 
 
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 22d6dc4..b16b519 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -4049,7 +4049,7 @@
  * commented out unless explicitly needed for EAP-FAST in order to be able to
  * build this file with unmodified openssl. */
 
-#ifdef OPENSSL_IS_BORINGSSL
+#if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
 static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
 			   STACK_OF(SSL_CIPHER) *peer_ciphers,
 			   const SSL_CIPHER **cipher, void *arg)
@@ -4157,7 +4157,7 @@
 
 int tls_get_library_version(char *buf, size_t buf_len)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
 	return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
 			   OPENSSL_VERSION_TEXT,
 			   OpenSSL_version(OPENSSL_VERSION));
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index bab1f03..780c19b 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -47,12 +47,20 @@
 
 #include "l2_packet/l2_packet.h"
 
+struct bsd_driver_global {
+	int		sock;			/* socket for 802.11 ioctls */
+	int		route;			/* routing socket for events */
+	char		*event_buf;
+	size_t		event_buf_len;
+	struct dl_list	ifaces;			/* list of interfaces */
+};
+
 struct bsd_driver_data {
+	struct dl_list	list;
+	struct bsd_driver_global *global;
 	struct hostapd_data *hapd;	/* back pointer */
 
-	int	sock;			/* open socket for 802.11 ioctls */
 	struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
-	int	route;			/* routing socket for events */
 	char	ifname[IFNAMSIZ+1];	/* interface name */
 	unsigned int ifindex;		/* interface index */
 	void	*ctx;
@@ -62,12 +70,23 @@
 	int	prev_privacy;	/* privacy state to restore on deinit */
 	int	prev_wpa;	/* wpa state to restore on deinit */
 	enum ieee80211_opmode opmode;	/* operation mode */
-	char	*event_buf;
-	size_t	event_buf_len;
 };
 
 /* Generic functions for hostapd and wpa_supplicant */
 
+static struct bsd_driver_data *
+bsd_get_drvindex(void *priv, unsigned int ifindex)
+{
+	struct bsd_driver_global *global = priv;
+	struct bsd_driver_data *drv;
+
+	dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+		if (drv->ifindex == ifindex)
+			return drv;
+	}
+	return NULL;
+}
+
 static int
 bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
 {
@@ -81,7 +100,7 @@
 	ireq.i_data = (void *) arg;
 	ireq.i_len = arg_len;
 
-	if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
+	if (ioctl(drv->global->sock, SIOCS80211, &ireq) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, "
 			   "arg_len=%u]: %s", op, val, arg_len,
 			   strerror(errno));
@@ -102,7 +121,7 @@
 	ireq->i_len = arg_len;
 	ireq->i_data = arg;
 
-	if (ioctl(drv->sock, SIOCG80211, ireq) < 0) {
+	if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
 			   "arg_len=%u]: %s", op, arg_len, strerror(errno));
 		return -1;
@@ -143,7 +162,7 @@
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 	ifr.ifr_data = (void *)&nwid;
-	if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
+	if (ioctl(drv->global->sock, SIOCG80211NWID, &ifr) < 0 ||
 	    nwid.i_len > IEEE80211_NWID_LEN)
 		return -1;
 	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
@@ -166,7 +185,7 @@
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 	ifr.ifr_data = (void *)&nwid;
-	return ioctl(drv->sock, SIOCS80211NWID, &ifr);
+	return ioctl(drv->global->sock, SIOCS80211NWID, &ifr);
 #else
 	return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
 #endif
@@ -181,7 +200,7 @@
 	os_memset(&ifmr, 0, sizeof(ifmr));
 	os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
 
-	if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) {
+	if (ioctl(drv->global->sock, SIOCGIFMEDIA, &ifmr) < 0) {
 		wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__,
 			   strerror(errno));
 		return -1;
@@ -200,7 +219,7 @@
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 	ifr.ifr_media = media;
 
-	if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) {
+	if (ioctl(drv->global->sock, SIOCSIFMEDIA, &ifr) < 0) {
 		wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__,
 			   strerror(errno));
 		return -1;
@@ -263,7 +282,7 @@
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 
-	if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
+	if (ioctl(drv->global->sock, SIOCGIFFLAGS, &ifr) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
 			   strerror(errno));
 		return -1;
@@ -279,7 +298,7 @@
 		ifr.ifr_flags &= ~IFF_UP;
 	}
 
-	if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
+	if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
 			   strerror(errno));
 		return -1;
@@ -576,7 +595,7 @@
 	os_memset(&creq, 0, sizeof(creq));
 	os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name));
 	creq.i_channel = (u_int16_t)channel;
-	return ioctl(drv->sock, SIOCS80211CHANNEL, &creq);
+	return ioctl(drv->global->sock, SIOCS80211CHANNEL, &creq);
 #else /* SIOCS80211CHANNEL */
 	return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
 #endif /* SIOCS80211CHANNEL */
@@ -730,7 +749,8 @@
 static void
 bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 {
-	struct bsd_driver_data *drv = ctx;
+	struct bsd_driver_global *global = sock_ctx;
+	struct bsd_driver_data *drv;
 	struct if_announcemsghdr *ifan;
 	struct rt_msghdr *rtm;
 	struct ieee80211_michael_event *mic;
@@ -739,7 +759,7 @@
 	int n;
 	union wpa_event_data data;
 
-	n = read(sock, drv->event_buf, drv->event_buf_len);
+	n = read(sock, global->event_buf, global->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
 			wpa_printf(MSG_ERROR, "%s read() failed: %s",
@@ -747,15 +767,18 @@
 		return;
 	}
 
-	rtm = (struct rt_msghdr *) drv->event_buf;
+	rtm = (struct rt_msghdr *) global->event_buf;
 	if (rtm->rtm_version != RTM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
 			   rtm->rtm_version);
 		return;
 	}
-	ifan = (struct if_announcemsghdr *) rtm;
+	drv = bsd_get_drvindex(global, rtm->rtm_index);
+	if (drv == NULL)
+		return;
 	switch (rtm->rtm_type) {
 	case RTM_IEEE80211:
+		ifan = (struct if_announcemsghdr *) rtm;
 		switch (ifan->ifan_what) {
 		case RTM_IEEE80211_ASSOC:
 		case RTM_IEEE80211_REASSOC:
@@ -811,21 +834,15 @@
 		return NULL;
 	}
 
-	drv->event_buf_len = rtbuf_len();
-
-	drv->event_buf = os_malloc(drv->event_buf_len);
-	if (drv->event_buf == NULL) {
-		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+	drv->ifindex = if_nametoindex(params->ifname);
+	if (drv->ifindex == 0) {
+		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
+			   __func__, params->ifname);
 		goto bad;
 	}
 
 	drv->hapd = hapd;
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0) {
-		wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
-			   strerror(errno));
-		goto bad;
-	}
+	drv->global = params->global_priv;
 	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
 
 	drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
@@ -839,28 +856,18 @@
 	if (bsd_ctrl_iface(drv, 0) < 0)
 		goto bad;
 
-	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
-	if (drv->route < 0) {
-		wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s",
-			   strerror(errno));
-		goto bad;
-	}
-	eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv,
-				 NULL);
-
 	if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
 		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
 			   __func__);
 		goto bad;
 	}
 
+	dl_list_add(&drv->global->ifaces, &drv->list);
+
 	return drv;
 bad:
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
-	if (drv->sock >= 0)
-		close(drv->sock);
-	os_free(drv->event_buf);
 	os_free(drv);
 	return NULL;
 }
@@ -871,16 +878,9 @@
 {
 	struct bsd_driver_data *drv = priv;
 
-	if (drv->route >= 0) {
-		eloop_unregister_read_sock(drv->route);
-		close(drv->route);
-	}
 	bsd_ctrl_iface(drv, 0);
-	if (drv->sock >= 0)
-		close(drv->sock);
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
-	os_free(drv->event_buf);
 	os_free(drv);
 }
 
@@ -932,7 +932,7 @@
 	struct ieee80211_bssid bs;
 
 	os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
-	if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0)
+	if (ioctl(drv->global->sock, SIOCG80211BSSID, &bs) < 0)
 		return -1;
 	os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
 	return 0;
@@ -1186,9 +1186,9 @@
 static void
 wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 {
-	struct bsd_driver_data *drv = sock_ctx;
+	struct bsd_driver_global *global = sock_ctx;
+	struct bsd_driver_data *drv;
 	struct if_announcemsghdr *ifan;
-	struct if_msghdr *ifm;
 	struct rt_msghdr *rtm;
 	union wpa_event_data event;
 	struct ieee80211_michael_event *mic;
@@ -1196,7 +1196,7 @@
 	struct ieee80211_join_event *join;
 	int n;
 
-	n = read(sock, drv->event_buf, drv->event_buf_len);
+	n = read(sock, global->event_buf, global->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
 			wpa_printf(MSG_ERROR, "%s read() failed: %s",
@@ -1204,18 +1204,20 @@
 		return;
 	}
 
-	rtm = (struct rt_msghdr *) drv->event_buf;
+	rtm = (struct rt_msghdr *) global->event_buf;
 	if (rtm->rtm_version != RTM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
 			   rtm->rtm_version);
 		return;
 	}
+	drv = bsd_get_drvindex(global, rtm->rtm_index);
+	if (drv == NULL)
+		return;
+	ctx = drv->ctx;
 	os_memset(&event, 0, sizeof(event));
 	switch (rtm->rtm_type) {
 	case RTM_IFANNOUNCE:
 		ifan = (struct if_announcemsghdr *) rtm;
-		if (ifan->ifan_index != drv->ifindex)
-			break;
 		os_strlcpy(event.interface_status.ifname, drv->ifname,
 			   sizeof(event.interface_status.ifname));
 		switch (ifan->ifan_what) {
@@ -1232,8 +1234,6 @@
 		break;
 	case RTM_IEEE80211:
 		ifan = (struct if_announcemsghdr *) rtm;
-		if (ifan->ifan_index != drv->ifindex)
-			break;
 		switch (ifan->ifan_what) {
 		case RTM_IEEE80211_ASSOC:
 		case RTM_IEEE80211_REASSOC:
@@ -1281,9 +1281,6 @@
 		}
 		break;
 	case RTM_IFINFO:
-		ifm = (struct if_msghdr *) rtm;
-		if (ifm->ifm_index != drv->ifindex)
-			break;
 		if ((rtm->rtm_flags & RTF_UP) == 0) {
 			os_strlcpy(event.interface_status.ifname, drv->ifname,
 				   sizeof(event.interface_status.ifname));
@@ -1477,7 +1474,7 @@
 	(void) memset(&ifmr, 0, sizeof(ifmr));
 	(void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
 
-	if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+	if (ioctl(drv->global->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
 		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
 			if (ifmr.ifm_current & IFM_FLAG0)
 				return IEEE80211_M_AHDEMO;
@@ -1497,7 +1494,7 @@
 }
 
 static void *
-wpa_driver_bsd_init(void *ctx, const char *ifname)
+wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
 {
 #define	GETPARAM(drv, param, v) \
 	(((v) = get80211param(drv, param)) != -1)
@@ -1507,14 +1504,6 @@
 	if (drv == NULL)
 		return NULL;
 
-	drv->event_buf_len = rtbuf_len();
-
-	drv->event_buf = os_malloc(drv->event_buf_len);
-	if (drv->event_buf == NULL) {
-		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
-		goto fail1;
-	}
-
 	/*
 	 * NB: We require the interface name be mappable to an index.
 	 *     This implies we do not support having wpa_supplicant
@@ -1525,25 +1514,17 @@
 	if (drv->ifindex == 0) {
 		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
 			   __func__, ifname);
-		goto fail1;
+		goto fail;
 	}
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0)
-		goto fail1;
+
+	drv->ctx = ctx;
+	drv->global = priv;
 
 	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
 	/* Down interface during setup. */
 	if (bsd_ctrl_iface(drv, 0) < 0)
 		goto fail;
 
-	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
-	if (drv->route < 0)
-		goto fail;
-	eloop_register_read_sock(drv->route,
-		wpa_driver_bsd_event_receive, ctx, drv);
-
-	drv->ctx = ctx;
-
 	if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
 		wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
 			__func__, strerror(errno));
@@ -1564,12 +1545,10 @@
 		goto fail;
 
 	drv->opmode = get80211opmode(drv);
+	dl_list_add(&drv->global->ifaces, &drv->list);
 
 	return drv;
 fail:
-	close(drv->sock);
-fail1:
-	os_free(drv->event_buf);
 	os_free(drv);
 	return NULL;
 #undef GETPARAM
@@ -1581,21 +1560,19 @@
 	struct bsd_driver_data *drv = priv;
 
 	wpa_driver_bsd_set_wpa(drv, 0);
-	eloop_unregister_read_sock(drv->route);
 
 	/* NB: mark interface down */
 	bsd_ctrl_iface(drv, 0);
 
 	wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
+
 	if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
 		wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
 			__func__);
 
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
-	(void) close(drv->route);		/* ioctl socket */
-	(void) close(drv->sock);		/* event socket */
-	os_free(drv->event_buf);
+	dl_list_del(&drv->list);
 	os_free(drv);
 }
 
@@ -1609,10 +1586,73 @@
 }
 #endif /* HOSTAPD */
 
+static void *
+bsd_global_init(void)
+{
+	struct bsd_driver_global *global;
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+
+	dl_list_init(&global->ifaces);
+
+	global->sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (global->sock < 0) {
+		wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
+		goto fail1;
+	}
+
+	global->route = socket(PF_ROUTE, SOCK_RAW, 0);
+	if (global->route < 0) {
+		wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s",
+			   strerror(errno));
+		goto fail;
+	}
+
+	global->event_buf_len = rtbuf_len();
+	global->event_buf = os_malloc(global->event_buf_len);
+	if (global->event_buf == NULL) {
+		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+		goto fail;
+	}
+
+#ifdef HOSTAPD
+	eloop_register_read_sock(global->route, bsd_wireless_event_receive,
+				 NULL, global);
+
+#else /* HOSTAPD */
+	eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive,
+				 NULL, global);
+#endif /* HOSTAPD */
+
+	return global;
+
+fail:
+	close(global->sock);
+fail1:
+	os_free(global);
+	return NULL;
+}
+
+static void
+bsd_global_deinit(void *priv)
+{
+	struct bsd_driver_global *global = priv;
+
+	eloop_unregister_read_sock(global->route);
+	(void) close(global->route);
+	(void) close(global->sock);
+	os_free(global);
+}
+
 
 const struct wpa_driver_ops wpa_driver_bsd_ops = {
 	.name			= "bsd",
 	.desc			= "BSD 802.11 support",
+	.global_init		= bsd_global_init,
+	.global_deinit		= bsd_global_deinit,
 #ifdef HOSTAPD
 	.hapd_init		= bsd_init,
 	.hapd_deinit		= bsd_deinit,
@@ -1625,7 +1665,7 @@
 	.sta_set_flags		= bsd_set_sta_authorized,
 	.commit			= bsd_commit,
 #else /* HOSTAPD */
-	.init			= wpa_driver_bsd_init,
+	.init2			= wpa_driver_bsd_init,
 	.deinit			= wpa_driver_bsd_deinit,
 	.get_bssid		= wpa_driver_bsd_get_bssid,
 	.get_ssid		= wpa_driver_bsd_get_ssid,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index cdd1504..4cb92d0 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4549,8 +4549,9 @@
 			goto fail;
 	}
 
-	if (nl80211_ht_vht_overrides(msg, params) < 0)
-		return -1;
+	ret = nl80211_ht_vht_overrides(msg, params);
+	if (ret < 0)
+		goto fail;
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index d5b5a87..2b2086c 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -1181,6 +1181,7 @@
 
 
 static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+				      struct i802_bss *bss,
 				      struct nlattr **tb)
 {
 	u8 *addr;
@@ -1193,7 +1194,7 @@
 		   MAC2STR(addr));
 
 	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
-		drv_event_disassoc(drv->ctx, addr);
+		drv_event_disassoc(bss->ctx, addr);
 		return;
 	}
 
@@ -1202,7 +1203,7 @@
 
 	os_memset(&data, 0, sizeof(data));
 	os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
-	wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
+	wpa_supplicant_event(bss->ctx, EVENT_IBSS_PEER_LOST, &data);
 }
 
 
@@ -2155,7 +2156,7 @@
 		nl80211_new_station_event(drv, bss, tb);
 		break;
 	case NL80211_CMD_DEL_STATION:
-		nl80211_del_station_event(drv, tb);
+		nl80211_del_station_event(drv, bss, tb);
 		break;
 	case NL80211_CMD_SET_REKEY_OFFLOAD:
 		nl80211_rekey_offload_event(drv, tb);
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index dc9e8cc..0bac62d 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -1492,7 +1492,6 @@
 int eap_peer_aka_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
@@ -1511,10 +1510,7 @@
 	eap->get_identity = eap_aka_get_identity;
 	eap->get_emsk = eap_aka_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
 
 
@@ -1522,7 +1518,6 @@
 int eap_peer_aka_prime_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
@@ -1542,10 +1537,6 @@
 	eap->get_identity = eap_aka_get_identity;
 	eap->get_emsk = eap_aka_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-
-	return ret;
+	return eap_peer_method_register(eap);
 }
 #endif /* EAP_AKA_PRIME */
diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c
index 1fd4970..f899f65 100644
--- a/src/eap_peer/eap_eke.c
+++ b/src/eap_peer/eap_eke.c
@@ -771,7 +771,6 @@
 int eap_peer_eke_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
@@ -786,8 +785,5 @@
 	eap->get_emsk = eap_eke_get_emsk;
 	eap->getSessionId = eap_eke_get_session_id;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 57390ae..8bd1bdb 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -1800,7 +1800,6 @@
 int eap_peer_fast_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
@@ -1821,8 +1820,5 @@
 #endif
 	eap->get_emsk = eap_fast_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c
index 902b4ba..177cbcc 100644
--- a/src/eap_peer/eap_gpsk.c
+++ b/src/eap_peer/eap_gpsk.c
@@ -771,7 +771,6 @@
 int eap_peer_gpsk_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
@@ -786,8 +785,5 @@
 	eap->get_emsk = eap_gpsk_get_emsk;
 	eap->getSessionId = eap_gpsk_get_session_id;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_gtc.c b/src/eap_peer/eap_gtc.c
index 9f3cfbd..a519a78 100644
--- a/src/eap_peer/eap_gtc.c
+++ b/src/eap_peer/eap_gtc.c
@@ -127,7 +127,6 @@
 int eap_peer_gtc_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
@@ -138,8 +137,5 @@
 	eap->deinit = eap_gtc_deinit;
 	eap->process = eap_gtc_process;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c
index b5ef71b..390f0ec 100644
--- a/src/eap_peer/eap_ikev2.c
+++ b/src/eap_peer/eap_ikev2.c
@@ -513,7 +513,6 @@
 int eap_peer_ikev2_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
@@ -529,8 +528,5 @@
 	eap->get_emsk = eap_ikev2_get_emsk;
 	eap->getSessionId = eap_ikev2_get_session_id;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_leap.c b/src/eap_peer/eap_leap.c
index e0f8bcf..ff6fa4a 100644
--- a/src/eap_peer/eap_leap.c
+++ b/src/eap_peer/eap_leap.c
@@ -393,7 +393,6 @@
 int eap_peer_leap_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP");
@@ -406,8 +405,5 @@
 	eap->isKeyAvailable = eap_leap_isKeyAvailable;
 	eap->getKey = eap_leap_getKey;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_md5.c b/src/eap_peer/eap_md5.c
index d06befa..efae8de 100644
--- a/src/eap_peer/eap_md5.c
+++ b/src/eap_peer/eap_md5.c
@@ -102,7 +102,6 @@
 int eap_peer_md5_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
@@ -113,8 +112,5 @@
 	eap->deinit = eap_md5_deinit;
 	eap->process = eap_md5_process;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c
index 1bdd81e..9747954 100644
--- a/src/eap_peer/eap_methods.c
+++ b/src/eap_peer/eap_methods.c
@@ -18,6 +18,8 @@
 
 static struct eap_method *eap_methods = NULL;
 
+static void eap_peer_method_free(struct eap_method *method);
+
 
 /**
  * eap_peer_get_eap_method - Get EAP method based on type number
@@ -295,7 +297,7 @@
  * eap_peer_method_free - Free EAP peer method structure
  * @method: Method structure allocated with eap_peer_method_alloc()
  */
-void eap_peer_method_free(struct eap_method *method)
+static void eap_peer_method_free(struct eap_method *method)
 {
 	os_free(method);
 }
@@ -303,26 +305,31 @@
 
 /**
  * eap_peer_method_register - Register an EAP peer method
- * @method: EAP method to register
+ * @method: EAP method to register from eap_peer_method_alloc()
  * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
  * has already been registered
  *
  * Each EAP peer method needs to call this function to register itself as a
- * supported EAP method.
+ * supported EAP method. The caller must not free the allocated method data
+ * regardless of the return value.
  */
 int eap_peer_method_register(struct eap_method *method)
 {
 	struct eap_method *m, *last = NULL;
 
 	if (method == NULL || method->name == NULL ||
-	    method->version != EAP_PEER_METHOD_INTERFACE_VERSION)
+	    method->version != EAP_PEER_METHOD_INTERFACE_VERSION) {
+		eap_peer_method_free(method);
 		return -1;
+	}
 
 	for (m = eap_methods; m; m = m->next) {
 		if ((m->vendor == method->vendor &&
 		     m->method == method->method) ||
-		    os_strcmp(m->name, method->name) == 0)
+		    os_strcmp(m->name, method->name) == 0) {
+			eap_peer_method_free(method);
 			return -2;
+		}
 		last = m;
 	}
 
diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h
index e35c919..b96b211 100644
--- a/src/eap_peer/eap_methods.h
+++ b/src/eap_peer/eap_methods.h
@@ -16,7 +16,6 @@
 
 struct eap_method * eap_peer_method_alloc(int version, int vendor,
 					  EapType method, const char *name);
-void eap_peer_method_free(struct eap_method *method);
 int eap_peer_method_register(struct eap_method *method);
 
 
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index 6acf1e8..ce2227d 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -880,7 +880,6 @@
 int eap_peer_mschapv2_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
@@ -894,8 +893,5 @@
 	eap->isKeyAvailable = eap_mschapv2_isKeyAvailable;
 	eap->getKey = eap_mschapv2_getKey;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_otp.c b/src/eap_peer/eap_otp.c
index 9ac744a..0ab4c79 100644
--- a/src/eap_peer/eap_otp.c
+++ b/src/eap_peer/eap_otp.c
@@ -83,7 +83,6 @@
 int eap_peer_otp_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_OTP, "OTP");
@@ -94,8 +93,5 @@
 	eap->deinit = eap_otp_deinit;
 	eap->process = eap_otp_process;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_pax.c b/src/eap_peer/eap_pax.c
index 2b87a64..5f0b7fb 100644
--- a/src/eap_peer/eap_pax.c
+++ b/src/eap_peer/eap_pax.c
@@ -535,7 +535,6 @@
 int eap_peer_pax_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
@@ -550,8 +549,5 @@
 	eap->get_emsk = eap_pax_get_emsk;
 	eap->getSessionId = eap_pax_get_session_id;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index bf420cc..45ba381 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -1281,7 +1281,6 @@
 int eap_peer_peap_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
@@ -1299,8 +1298,5 @@
 	eap->init_for_reauth = eap_peap_init_for_reauth;
 	eap->getSessionId = eap_peap_get_session_id;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_psk.c b/src/eap_peer/eap_psk.c
index f012663..ac18c15 100644
--- a/src/eap_peer/eap_psk.c
+++ b/src/eap_peer/eap_psk.c
@@ -480,7 +480,6 @@
 int eap_peer_psk_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
@@ -495,8 +494,5 @@
 	eap->getSessionId = eap_psk_get_session_id;
 	eap->get_emsk = eap_psk_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 892b590..1c8e88f 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -1054,7 +1054,6 @@
 int eap_peer_pwd_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
@@ -1069,8 +1068,5 @@
 	eap->getSessionId = eap_pwd_get_session_id;
 	eap->get_emsk = eap_pwd_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_sake.c b/src/eap_peer/eap_sake.c
index c4f9843..80f4667 100644
--- a/src/eap_peer/eap_sake.c
+++ b/src/eap_peer/eap_sake.c
@@ -494,7 +494,6 @@
 int eap_peer_sake_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
@@ -509,8 +508,5 @@
 	eap->getSessionId = eap_sake_get_session_id;
 	eap->get_emsk = eap_sake_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index cbf7461..b97c95d 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -249,6 +249,7 @@
 			return eap_sim_ext_sim_req(sm, data);
 	}
 
+#ifdef PCSC_FUNCS
 	if (conf->pcsc) {
 		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
 				   data->sres[0], data->kc[0]) ||
@@ -263,6 +264,7 @@
 		}
 		return 0;
 	}
+#endif /* PCSC_FUNCS */
 
 #ifdef CONFIG_SIM_SIMULATOR
 	if (conf->password) {
@@ -1235,7 +1237,6 @@
 int eap_peer_sim_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
@@ -1254,8 +1255,5 @@
 	eap->get_identity = eap_sim_get_identity;
 	eap->get_emsk = eap_sim_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index ba8e74b..ca2354f 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -390,7 +390,6 @@
 int eap_peer_tls_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
@@ -409,10 +408,7 @@
 	eap->init_for_reauth = eap_tls_init_for_reauth;
 	eap->get_emsk = eap_tls_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
 
 
@@ -420,7 +416,6 @@
 int eap_peer_unauth_tls_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_UNAUTH_TLS,
@@ -439,10 +434,7 @@
 	eap->init_for_reauth = eap_tls_init_for_reauth;
 	eap->get_emsk = eap_tls_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
 #endif /* EAP_UNAUTH_TLS */
 
@@ -451,7 +443,6 @@
 int eap_peer_wfa_unauth_tls_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_WFA_NEW,
@@ -471,9 +462,6 @@
 	eap->init_for_reauth = eap_tls_init_for_reauth;
 	eap->get_emsk = eap_tls_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
 #endif /* CONFIG_HS20 */
diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c
index e4294bb..726221e 100644
--- a/src/eap_peer/eap_tnc.c
+++ b/src/eap_peer/eap_tnc.c
@@ -410,7 +410,6 @@
 int eap_peer_tnc_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
@@ -421,8 +420,5 @@
 	eap->deinit = eap_tnc_deinit;
 	eap->process = eap_tnc_process;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index a4b2697..92f94dc 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -35,6 +35,7 @@
 	void *phase2_priv;
 	int phase2_success;
 	int phase2_start;
+	EapDecision decision_succ;
 
 	enum phase2_types {
 		EAP_TTLS_PHASE2_EAP,
@@ -1547,6 +1548,7 @@
 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
 				   "completed successfully");
 			data->phase2_success = 1;
+			data->decision_succ = ret->decision;
 #ifdef EAP_TNC
 			if (!data->ready_for_tnc && !data->tnc_started) {
 				/*
@@ -1564,6 +1566,18 @@
 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
 				   "completed successfully (MAY_CONT)");
 			data->phase2_success = 1;
+			data->decision_succ = ret->decision;
+	} else if (data->decision_succ != DECISION_FAIL &&
+		   data->phase2_success &&
+		   !data->ssl.tls_out) {
+		/*
+		 * This is needed to cover the case where the final Phase 2
+		 * message gets fragmented since fragmentation clears
+		 * decision back to FAIL.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "EAP-TTLS: Restore success decision after fragmented frame sent completely");
+		ret->decision = data->decision_succ;
 	}
 }
 
@@ -1638,6 +1652,7 @@
 	data->pending_phase2_req = NULL;
 	wpabuf_free(data->pending_resp);
 	data->pending_resp = NULL;
+	data->decision_succ = DECISION_FAIL;
 #ifdef EAP_TNC
 	data->ready_for_tnc = 0;
 	data->tnc_started = 0;
@@ -1776,7 +1791,6 @@
 int eap_peer_ttls_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
@@ -1795,8 +1809,5 @@
 	eap->init_for_reauth = eap_ttls_init_for_reauth;
 	eap->get_emsk = eap_ttls_get_emsk;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_vendor_test.c b/src/eap_peer/eap_vendor_test.c
index b61057e..16e3c39 100644
--- a/src/eap_peer/eap_vendor_test.c
+++ b/src/eap_peer/eap_vendor_test.c
@@ -169,7 +169,6 @@
 int eap_peer_vendor_test_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_ID, EAP_VENDOR_TYPE,
@@ -183,8 +182,5 @@
 	eap->isKeyAvailable = eap_vendor_test_isKeyAvailable;
 	eap->getKey = eap_vendor_test_getKey;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 7ac99c7..d140c88 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -17,7 +17,7 @@
 
 
 struct eap_wsc_data {
-	enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
+	enum { WAIT_START, MESG, WAIT_FRAG_ACK, FAIL } state;
 	int registrar;
 	struct wpabuf *in_buf;
 	struct wpabuf *out_buf;
@@ -36,12 +36,8 @@
 		return "WAIT_START";
 	case MESG:
 		return "MESG";
-	case FRAG_ACK:
-		return "FRAG_ACK";
 	case WAIT_FRAG_ACK:
 		return "WAIT_FRAG_ACK";
-	case DONE:
-		return "DONE";
 	case FAIL:
 		return "FAIL";
 	default:
@@ -579,7 +575,6 @@
 int eap_peer_wsc_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
@@ -591,8 +586,5 @@
 	eap->deinit = eap_wsc_deinit;
 	eap->process = eap_wsc_process;
 
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
+	return eap_peer_method_register(eap);
 }
diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h
index 0baa327..3bf1495 100644
--- a/src/eap_server/eap_methods.h
+++ b/src/eap_server/eap_methods.h
@@ -15,7 +15,6 @@
 						    EapType method);
 struct eap_method * eap_server_method_alloc(int version, int vendor,
 					    EapType method, const char *name);
-void eap_server_method_free(struct eap_method *method);
 int eap_server_method_register(struct eap_method *method);
 
 EapType eap_server_get_type(const char *name, int *vendor);
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index db9b6aa..a8bb5ea 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -1319,7 +1319,6 @@
 int eap_server_aka_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
@@ -1337,10 +1336,7 @@
 	eap->get_emsk = eap_aka_get_emsk;
 	eap->getSessionId = eap_aka_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
 
 
@@ -1348,7 +1344,6 @@
 int eap_server_aka_prime_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
@@ -1367,10 +1362,6 @@
 	eap->get_emsk = eap_aka_get_emsk;
 	eap->getSessionId = eap_aka_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-
-	return ret;
+	return eap_server_method_register(eap);
 }
 #endif /* EAP_SERVER_AKA_PRIME */
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
index ba82be9..1eba8f5 100644
--- a/src/eap_server/eap_server_eke.c
+++ b/src/eap_server/eap_server_eke.c
@@ -792,7 +792,6 @@
 int eap_server_eke_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
@@ -810,8 +809,5 @@
 	eap->get_emsk = eap_eke_get_emsk;
 	eap->getSessionId = eap_eke_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 2e03f88..6993159 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -1620,7 +1620,6 @@
 int eap_server_fast_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
@@ -1638,8 +1637,5 @@
 	eap->isSuccess = eap_fast_isSuccess;
 	eap->getSessionId = eap_fast_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index 50f15c3..94e74ec 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -631,7 +631,6 @@
 int eap_server_gpsk_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
@@ -649,8 +648,5 @@
 	eap->get_emsk = eap_gpsk_get_emsk;
 	eap->getSessionId = eap_gpsk_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_gtc.c b/src/eap_server/eap_server_gtc.c
index 98ac3c6..193a851 100644
--- a/src/eap_server/eap_server_gtc.c
+++ b/src/eap_server/eap_server_gtc.c
@@ -202,7 +202,6 @@
 int eap_server_gtc_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
@@ -217,8 +216,5 @@
 	eap->isDone = eap_gtc_isDone;
 	eap->isSuccess = eap_gtc_isSuccess;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_identity.c b/src/eap_server/eap_server_identity.c
index 4501533..1b1db53 100644
--- a/src/eap_server/eap_server_identity.c
+++ b/src/eap_server/eap_server_identity.c
@@ -157,7 +157,6 @@
 int eap_server_identity_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
@@ -174,8 +173,5 @@
 	eap->isDone = eap_identity_isDone;
 	eap->isSuccess = eap_identity_isSuccess;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 16e6276..3a249d1 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -550,7 +550,6 @@
 int eap_server_ikev2_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
@@ -569,8 +568,5 @@
 	eap->get_emsk = eap_ikev2_get_emsk;
 	eap->getSessionId = eap_ikev2_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_md5.c b/src/eap_server/eap_server_md5.c
index 71e8d59..cf5ceb1 100644
--- a/src/eap_server/eap_server_md5.c
+++ b/src/eap_server/eap_server_md5.c
@@ -153,7 +153,6 @@
 int eap_server_md5_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
@@ -168,8 +167,5 @@
 	eap->isDone = eap_md5_isDone;
 	eap->isSuccess = eap_md5_isSuccess;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 9e9dc93..79ed344 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -87,7 +87,7 @@
  * eap_server_method_free - Free EAP server method structure
  * @method: Method structure allocated with eap_server_method_alloc()
  */
-void eap_server_method_free(struct eap_method *method)
+static void eap_server_method_free(struct eap_method *method)
 {
 	os_free(method);
 }
@@ -95,26 +95,31 @@
 
 /**
  * eap_server_method_register - Register an EAP server method
- * @method: EAP method to register
+ * @method: EAP method to register from eap_server_method_alloc()
  * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
  * has already been registered
  *
  * Each EAP server method needs to call this function to register itself as a
- * supported EAP method.
+ * supported EAP method. The caller must not free the allocated method data
+ * regardless of the return value.
  */
 int eap_server_method_register(struct eap_method *method)
 {
 	struct eap_method *m, *last = NULL;
 
 	if (method == NULL || method->name == NULL ||
-	    method->version != EAP_SERVER_METHOD_INTERFACE_VERSION)
+	    method->version != EAP_SERVER_METHOD_INTERFACE_VERSION) {
+		eap_server_method_free(method);
 		return -1;
+	}
 
 	for (m = eap_methods; m; m = m->next) {
 		if ((m->vendor == method->vendor &&
 		     m->method == method->method) ||
-		    os_strcmp(m->name, method->name) == 0)
+		    os_strcmp(m->name, method->name) == 0) {
+			eap_server_method_free(method);
 			return -2;
+		}
 		last = m;
 	}
 
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 98d74e0..460cd9c 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -571,7 +571,6 @@
 int eap_server_mschapv2_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
@@ -588,8 +587,5 @@
 	eap->getKey = eap_mschapv2_getKey;
 	eap->isSuccess = eap_mschapv2_isSuccess;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_pax.c b/src/eap_server/eap_server_pax.c
index 0e6b4a0..782b8c3 100644
--- a/src/eap_server/eap_server_pax.c
+++ b/src/eap_server/eap_server_pax.c
@@ -565,7 +565,6 @@
 int eap_server_pax_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
@@ -583,8 +582,5 @@
 	eap->get_emsk = eap_pax_get_emsk;
 	eap->getSessionId = eap_pax_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index d424862..18d31b5 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -1363,7 +1363,6 @@
 int eap_server_peap_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
@@ -1380,8 +1379,5 @@
 	eap->isSuccess = eap_peap_isSuccess;
 	eap->getSessionId = eap_peap_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index 12b5d25..857d421 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -510,7 +510,6 @@
 int eap_server_psk_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
@@ -528,8 +527,5 @@
 	eap->get_emsk = eap_psk_get_emsk;
 	eap->getSessionId = eap_psk_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 9f787ab..36ac555 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -1094,7 +1094,6 @@
 int eap_server_pwd_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 	struct timeval tp;
 	struct timezone tz;
 	u32 sr;
@@ -1121,9 +1120,6 @@
 	eap->isSuccess = eap_pwd_is_success;
 	eap->getSessionId = eap_pwd_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
 
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index de70777..84d0e0b 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -520,7 +520,6 @@
 int eap_server_sake_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
@@ -538,8 +537,5 @@
 	eap->get_emsk = eap_sake_get_emsk;
 	eap->getSessionId = eap_sake_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index ddfb71c..3a6ed79 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -846,7 +846,6 @@
 int eap_server_sim_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
@@ -864,8 +863,5 @@
 	eap->get_emsk = eap_sim_get_emsk;
 	eap->getSessionId = eap_sim_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index bd18a4b..7249858 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -375,7 +375,6 @@
 int eap_server_tls_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
@@ -393,10 +392,7 @@
 	eap->get_emsk = eap_tls_get_emsk;
 	eap->getSessionId = eap_tls_get_session_id;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
 
 
@@ -404,7 +400,6 @@
 int eap_server_unauth_tls_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_UNAUTH_TLS,
@@ -423,10 +418,7 @@
 	eap->isSuccess = eap_tls_isSuccess;
 	eap->get_emsk = eap_tls_get_emsk;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
 #endif /* EAP_SERVER_UNAUTH_TLS */
 
@@ -435,7 +427,6 @@
 int eap_server_wfa_unauth_tls_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_WFA_NEW,
@@ -454,9 +445,6 @@
 	eap->isSuccess = eap_tls_isSuccess;
 	eap->get_emsk = eap_tls_get_emsk;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
 #endif /* CONFIG_HS20 */
diff --git a/src/eap_server/eap_server_tnc.c b/src/eap_server/eap_server_tnc.c
index 21bd26f..b568558 100644
--- a/src/eap_server/eap_server_tnc.c
+++ b/src/eap_server/eap_server_tnc.c
@@ -554,7 +554,6 @@
 int eap_server_tnc_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
@@ -569,8 +568,5 @@
 	eap->isDone = eap_tnc_isDone;
 	eap->isSuccess = eap_tnc_isSuccess;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 53ffa1e..a53633f 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -1335,7 +1335,6 @@
 int eap_server_ttls_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
@@ -1353,8 +1352,5 @@
 	eap->getSessionId = eap_ttls_get_session_id;
 	eap->get_emsk = eap_ttls_get_emsk;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_vendor_test.c b/src/eap_server/eap_server_vendor_test.c
index 30f600d..9639977 100644
--- a/src/eap_server/eap_server_vendor_test.c
+++ b/src/eap_server/eap_server_vendor_test.c
@@ -168,7 +168,6 @@
 int eap_server_vendor_test_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_ID, EAP_VENDOR_TYPE,
@@ -185,8 +184,5 @@
 	eap->getKey = eap_vendor_test_getKey;
 	eap->isSuccess = eap_vendor_test_isSuccess;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c
index 9d9c28d..7d9d285 100644
--- a/src/eap_server/eap_server_wsc.c
+++ b/src/eap_server/eap_server_wsc.c
@@ -488,7 +488,6 @@
 int eap_server_wsc_register(void)
 {
 	struct eap_method *eap;
-	int ret;
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
@@ -505,8 +504,5 @@
 	eap->isSuccess = eap_wsc_isSuccess;
 	eap->getTimeout = eap_wsc_getTimeout;
 
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
+	return eap_server_method_register(eap);
 }
diff --git a/src/fst/fst_ctrl_aux.c b/src/fst/fst_ctrl_aux.c
index dc7b2a7..b632827 100644
--- a/src/fst/fst_ctrl_aux.c
+++ b/src/fst/fst_ctrl_aux.c
@@ -14,27 +14,28 @@
 
 
 static const char *session_event_names[] = {
-	[EVENT_FST_ESTABLISHED] FST_PVAL_EVT_TYPE_ESTABLISHED,
-	[EVENT_FST_SETUP] FST_PVAL_EVT_TYPE_SETUP,
-	[EVENT_FST_SESSION_STATE_CHANGED] FST_PVAL_EVT_TYPE_SESSION_STATE,
+	[EVENT_FST_ESTABLISHED] = FST_PVAL_EVT_TYPE_ESTABLISHED,
+	[EVENT_FST_SETUP] = FST_PVAL_EVT_TYPE_SETUP,
+	[EVENT_FST_SESSION_STATE_CHANGED] = FST_PVAL_EVT_TYPE_SESSION_STATE,
 };
 
 static const char *reason_names[] = {
-	[REASON_TEARDOWN] FST_CS_PVAL_REASON_TEARDOWN,
-	[REASON_SETUP] FST_CS_PVAL_REASON_SETUP,
-	[REASON_SWITCH] FST_CS_PVAL_REASON_SWITCH,
-	[REASON_STT] FST_CS_PVAL_REASON_STT,
-	[REASON_REJECT] FST_CS_PVAL_REASON_REJECT,
-	[REASON_ERROR_PARAMS] FST_CS_PVAL_REASON_ERROR_PARAMS,
-	[REASON_RESET] FST_CS_PVAL_REASON_RESET,
-	[REASON_DETACH_IFACE] FST_CS_PVAL_REASON_DETACH_IFACE,
+	[REASON_TEARDOWN] = FST_CS_PVAL_REASON_TEARDOWN,
+	[REASON_SETUP] = FST_CS_PVAL_REASON_SETUP,
+	[REASON_SWITCH] = FST_CS_PVAL_REASON_SWITCH,
+	[REASON_STT] = FST_CS_PVAL_REASON_STT,
+	[REASON_REJECT] = FST_CS_PVAL_REASON_REJECT,
+	[REASON_ERROR_PARAMS] = FST_CS_PVAL_REASON_ERROR_PARAMS,
+	[REASON_RESET] = FST_CS_PVAL_REASON_RESET,
+	[REASON_DETACH_IFACE] = FST_CS_PVAL_REASON_DETACH_IFACE,
 };
 
 static const char *session_state_names[] = {
-	[FST_SESSION_STATE_INITIAL] FST_CS_PVAL_STATE_INITIAL,
-	[FST_SESSION_STATE_SETUP_COMPLETION] FST_CS_PVAL_STATE_SETUP_COMPLETION,
-	[FST_SESSION_STATE_TRANSITION_DONE] FST_CS_PVAL_STATE_TRANSITION_DONE,
-	[FST_SESSION_STATE_TRANSITION_CONFIRMED]
+	[FST_SESSION_STATE_INITIAL] = FST_CS_PVAL_STATE_INITIAL,
+	[FST_SESSION_STATE_SETUP_COMPLETION] =
+	FST_CS_PVAL_STATE_SETUP_COMPLETION,
+	[FST_SESSION_STATE_TRANSITION_DONE] = FST_CS_PVAL_STATE_TRANSITION_DONE,
+	[FST_SESSION_STATE_TRANSITION_CONFIRMED] =
 	FST_CS_PVAL_STATE_TRANSITION_CONFIRMED,
 };
 
diff --git a/src/fst/fst_ctrl_iface.c b/src/fst/fst_ctrl_iface.c
index 98ece9f..7820e58 100644
--- a/src/fst/fst_ctrl_iface.c
+++ b/src/fst/fst_ctrl_iface.c
@@ -648,9 +648,9 @@
 static const char * band_freq(enum mb_band_id band)
 {
 	static const char *band_names[] = {
-		[MB_BAND_ID_WIFI_2_4GHZ] "2.4GHZ",
-		[MB_BAND_ID_WIFI_5GHZ] "5GHZ",
-		[MB_BAND_ID_WIFI_60GHZ] "60GHZ",
+		[MB_BAND_ID_WIFI_2_4GHZ] = "2.4GHZ",
+		[MB_BAND_ID_WIFI_5GHZ] = "5GHZ",
+		[MB_BAND_ID_WIFI_60GHZ] = "60GHZ",
 	};
 
 	return fst_get_str_name(band, band_names, ARRAY_SIZE(band_names));
diff --git a/src/fst/fst_session.c b/src/fst/fst_session.c
index 9e4dada..11f3b63 100644
--- a/src/fst/fst_session.c
+++ b/src/fst/fst_session.c
@@ -525,7 +525,9 @@
 	enum hostapd_hw_mode hw_mode;
 	u8 channel;
 	union fst_session_state_switch_extra evext = {
-		.to_initial = {0},
+		.to_initial = {
+			.reject_code = 0,
+		},
 	};
 
 	if (iface != s->data.old_iface) {
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index b221e12..1afeaa2 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -15,7 +15,7 @@
 #include "wpa_i.h"
 #include "pmksa_cache.h"
 
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
 static const int pmksa_cache_max_entries = 32;
 
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index 7ec09ea..d559430 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -44,7 +44,7 @@
 	PMKSA_EXPIRE,
 };
 
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
 struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index c6534af..55a4a74 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -18,7 +18,7 @@
 #include "wpa_i.h"
 
 
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
 #define PMKID_CANDIDATE_PRIO_SCAN 1000
 
@@ -538,4 +538,4 @@
 	return sm->preauth_eapol != NULL;
 }
 
-#endif /* IEEE8021X_EAPOL */
+#endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
diff --git a/src/rsn_supp/preauth.h b/src/rsn_supp/preauth.h
index 277f066..8caf3ee 100644
--- a/src/rsn_supp/preauth.h
+++ b/src/rsn_supp/preauth.h
@@ -11,7 +11,7 @@
 
 struct wpa_scan_results;
 
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
 void pmksa_candidate_free(struct wpa_sm *sm);
 int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
@@ -27,7 +27,7 @@
 			   int verbose);
 int rsn_preauth_in_progress(struct wpa_sm *sm);
 
-#else /* IEEE8021X_EAPOL */
+#else /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
 
 static inline void pmksa_candidate_free(struct wpa_sm *sm)
 {
@@ -74,6 +74,6 @@
 	return 0;
 }
 
-#endif /* IEEE8021X_EAPOL */
+#endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
 
 #endif /* PREAUTH_H */
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 6ea113e..c9ba8b7 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1140,6 +1140,22 @@
 	if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE)
 		fprintf(f, "p2p_go_freq_change_policy=%u\n",
 			config->p2p_go_freq_change_policy);
+	if (WPA_GET_BE32(config->ip_addr_go))
+		fprintf(f, "ip_addr_go=%u.%u.%u.%u\n",
+			config->ip_addr_go[0], config->ip_addr_go[1],
+			config->ip_addr_go[2], config->ip_addr_go[3]);
+	if (WPA_GET_BE32(config->ip_addr_mask))
+		fprintf(f, "ip_addr_mask=%u.%u.%u.%u\n",
+			config->ip_addr_mask[0], config->ip_addr_mask[1],
+			config->ip_addr_mask[2], config->ip_addr_mask[3]);
+	if (WPA_GET_BE32(config->ip_addr_start))
+		fprintf(f, "ip_addr_start=%u.%u.%u.%u\n",
+			config->ip_addr_start[0], config->ip_addr_start[1],
+			config->ip_addr_start[2], config->ip_addr_start[3]);
+	if (WPA_GET_BE32(config->ip_addr_end))
+		fprintf(f, "ip_addr_end=%u.%u.%u.%u\n",
+			config->ip_addr_end[0], config->ip_addr_end[1],
+			config->ip_addr_end[2], config->ip_addr_end[3]);
 #endif /* CONFIG_P2P */
 	if (config->country[0] && config->country[1]) {
 		fprintf(f, "country=%c%c\n",
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index e2f0afc..73b9e20 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -945,7 +945,8 @@
 		if (os_strcmp(entry.key, "DeviceName") == 0) {
 			char *devname;
 
-			if (entry.type != DBUS_TYPE_STRING)
+			if (entry.type != DBUS_TYPE_STRING ||
+			    os_strlen(entry.str_value) > WPS_DEV_NAME_MAX_LEN)
 				goto error;
 
 			devname = os_strdup(entry.str_value);
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index d5d47e1..3ab80a5 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -65,41 +65,41 @@
 	       "  -B = run daemon in the background\n"
 	       "  -c = Configuration file\n"
 	       "  -C = ctrl_interface parameter (only used if -c is not)\n"
-	       "  -i = interface name\n"
-	       "  -I = additional configuration file\n"
 	       "  -d = increase debugging verbosity (-dd even more)\n"
 	       "  -D = driver name (can be multiple drivers: nl80211,wext)\n"
-	       "  -e = entropy file\n");
+	       "  -e = entropy file\n"
 #ifdef CONFIG_DEBUG_FILE
-	printf("  -f = log output to debug file instead of stdout\n");
+	       "  -f = log output to debug file instead of stdout\n"
 #endif /* CONFIG_DEBUG_FILE */
-	printf("  -g = global ctrl_interface\n"
+	       "  -g = global ctrl_interface\n"
 	       "  -G = global ctrl_interface group\n"
-	       "  -K = include keys (passwords, etc.) in debug output\n");
-#ifdef CONFIG_DEBUG_SYSLOG
-	printf("  -s = log output to syslog instead of stdout\n");
-#endif /* CONFIG_DEBUG_SYSLOG */
-#ifdef CONFIG_DEBUG_LINUX_TRACING
-	printf("  -T = record to Linux tracing in addition to logging\n");
-	printf("       (records all messages regardless of debug verbosity)\n");
-#endif /* CONFIG_DEBUG_LINUX_TRACING */
-	printf("  -t = include timestamp in debug messages\n"
 	       "  -h = show this help text\n"
+	       "  -i = interface name\n"
+	       "  -I = additional configuration file\n"
+	       "  -K = include keys (passwords, etc.) in debug output\n"
 	       "  -L = show license (BSD)\n"
+#ifdef CONFIG_P2P
+	       "  -m = Configuration file for the P2P Device interface\n"
+#endif /* CONFIG_P2P */
+	       "  -N = start describing new interface\n"
 	       "  -o = override driver parameter for new interfaces\n"
 	       "  -O = override ctrl_interface parameter for new interfaces\n"
 	       "  -p = driver parameters\n"
 	       "  -P = PID file\n"
-	       "  -q = decrease debugging verbosity (-qq even less)\n");
+	       "  -q = decrease debugging verbosity (-qq even less)\n"
+#ifdef CONFIG_DEBUG_SYSLOG
+	       "  -s = log output to syslog instead of stdout\n"
+#endif /* CONFIG_DEBUG_SYSLOG */
+	       "  -t = include timestamp in debug messages\n"
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	       "  -T = record to Linux tracing in addition to logging\n"
+	       "       (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 #ifdef CONFIG_DBUS
-	printf("  -u = enable DBus control interface\n");
+	       "  -u = enable DBus control interface\n"
 #endif /* CONFIG_DBUS */
-	printf("  -v = show version\n"
-	       "  -W = wait for a control interface monitor before starting\n"
-#ifdef CONFIG_P2P
-	       "  -m = Configuration file for the P2P Device interface\n"
-#endif /* CONFIG_P2P */
-	       "  -N = start describing new interface\n");
+	       "  -v = show version\n"
+	       "  -W = wait for a control interface monitor before starting\n");
 
 	printf("example:\n"
 	       "  wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",