Merge "Don't set he_oper_chwidth for 2.4GHz only band"
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 7708bc2..57fc6da 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -994,6 +994,14 @@
 	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
 		acs_adjust_center_freq(iface);
 
+	err = hostapd_select_hw_mode(iface);
+	if (err) {
+		wpa_printf(MSG_ERROR, "ACS: Could not (err: %d) select hw_mode for freq=%d channel=%d",
+			err, iface->freq, iface->conf->channel);
+		err = -1;
+		goto fail;
+	}
+
 	err = 0;
 fail:
 	/*
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 8ceb1df..8ee2033 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -2816,6 +2816,61 @@
 	return config->identity;
 }
 
+static const u8 * strnchr(const u8 *str, size_t len, u8 needle) {
+	const u8 *cur = str;
+
+	if (NULL == str) return NULL;
+	if (0 >= len) return NULL;
+
+	while (cur < str + len) {
+		if (*cur == needle)
+			return cur;
+		cur++;
+	}
+	return NULL;
+}
+
+const u8 * eap_get_config_realm(struct eap_sm *sm, size_t *len) {
+	struct eap_peer_config *config = eap_get_config(sm);
+	const u8 *realm = NULL;
+	size_t realm_len = 0;
+	const u8 *identity = NULL;
+	size_t identity_len = 0;
+
+	if (!config)
+		return NULL;
+
+	/* Look for the realm of the permanent identity */
+	identity = eap_get_config_identity(sm, &identity_len);
+	realm = strnchr(identity, identity_len, '@');
+	if (NULL != realm) {
+		wpa_printf(MSG_DEBUG, "Get the realm from identity.");
+		*len = identity_len - (realm - identity);
+		return realm;
+	}
+
+	/* Look for the realm of the anonymous identity. */
+	realm = strnchr(config->anonymous_identity,
+	    config->anonymous_identity_len, '@');
+	if (NULL != realm) {
+		wpa_printf(MSG_DEBUG, "Get the realm from anonymous identity.");
+		*len = identity_len - (realm - identity);
+		return realm;
+	}
+
+	/* Look for the realm of the real identity. */
+	realm = strnchr(config->imsi_identity,
+	    config->imsi_identity_len, '@');
+	if (NULL != realm) {
+		wpa_printf(MSG_DEBUG, "Get the realm from IMSI identity.");
+		*len = identity_len - (realm - identity);
+		return realm;
+	}
+	wpa_printf(MSG_DEBUG, "No realm information in identities.");
+	*len = 0;
+	return NULL;
+}
+
 
 static int eap_get_ext_password(struct eap_sm *sm,
 				struct eap_peer_config *config)
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 8dac3cb..7f660e6 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -409,33 +409,16 @@
 		size_t identity_len = 0;
 		const u8 *realm = NULL;
 		size_t realm_len = 0;
-		struct eap_peer_config *config = eap_get_config(sm);
 
 		wpa_hexdump_ascii(MSG_DEBUG,
 				  "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
 				  attr->next_pseudonym,
 				  attr->next_pseudonym_len);
 		os_free(data->pseudonym);
-		/* Look for the realm of the permanent identity */
-		identity = eap_get_config_identity(sm, &identity_len);
-		if (identity) {
-			for (realm = identity, realm_len = identity_len;
-			     realm_len > 0; realm_len--, realm++) {
-				if (*realm == '@')
-					break;
-			}
-		}
-		// If no realm from the permanent identity, look for the
-		// realm of the anonymous identity.
-		if (realm_len == 0 && config && config->anonymous_identity
-		    && config->anonymous_identity_len > 0) {
-			for (realm = config->anonymous_identity,
-			    realm_len = config->anonymous_identity_len;
-			    realm_len > 0; realm_len--, realm++) {
-				if (*realm == '@')
-					break;
-			}
-		}
+
+		/* Get realm from identities to decorate pseudonym. */
+		realm = eap_get_config_realm(sm, &realm_len);
+
 		data->pseudonym = os_malloc(attr->next_pseudonym_len +
 					    realm_len);
 		if (data->pseudonym == NULL) {
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index f43891e..652b67e 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -392,6 +392,7 @@
 const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash);
 const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len);
 const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len);
+const u8 * eap_get_config_realm(struct eap_sm *sm, size_t *len);
 void eap_clear_config_otp(struct eap_sm *sm);
 const char * eap_get_config_phase1(struct eap_sm *sm);
 const char * eap_get_config_phase2(struct eap_sm *sm);
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index a555680..71e9108 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -435,33 +435,16 @@
 		size_t identity_len = 0;
 		const u8 *realm = NULL;
 		size_t realm_len = 0;
-		struct eap_peer_config *config = eap_get_config(sm);
 
 		wpa_hexdump_ascii(MSG_DEBUG,
 				  "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
 				  attr->next_pseudonym,
 				  attr->next_pseudonym_len);
 		os_free(data->pseudonym);
-		/* Look for the realm of the permanent identity */
-		identity = eap_get_config_identity(sm, &identity_len);
-		if (identity) {
-			for (realm = identity, realm_len = identity_len;
-			     realm_len > 0; realm_len--, realm++) {
-				if (*realm == '@')
-					break;
-			}
-		}
-		// If no realm from the permanent identity, look for the
-		// realm of the anonymous identity.
-		if (realm_len == 0 && config && config->anonymous_identity
-		    && config->anonymous_identity_len > 0) {
-			for (realm = config->anonymous_identity,
-			    realm_len = config->anonymous_identity_len;
-			    realm_len > 0; realm_len--, realm++) {
-				if (*realm == '@')
-					break;
-			}
-		}
+
+		/* Get realm from identities to decorate pseudonym. */
+		realm = eap_get_config_realm(sm, &realm_len);
+
 		data->pseudonym = os_malloc(attr->next_pseudonym_len +
 					    realm_len);
 		if (data->pseudonym == NULL) {
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 6080eb3..1ec7d5e 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3473,14 +3473,22 @@
 		ft_completed = wpa_fils_is_completed(wpa_s->wpa);
 
 #if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
-	/* For driver based roaming, insert PSK during the initial association */
-	if (is_zero_ether_addr(wpa_s->bssid) &&
-		wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
-		/* In case the driver wants to handle re-assocs, pass it down the PMK. */
-		wpa_dbg(wpa_s, MSG_DEBUG, "Pass the PMK to the driver");
-		wpa_sm_install_pmk(wpa_s->wpa);
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
+		/*
+		 * For driver based roaming, insert PSK during
+		 * the initial association
+		 */
+		if (is_zero_ether_addr(wpa_s->bssid) &&
+			wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+			/*
+			 * In case the driver wants to handle re-assocs,
+			 * pass it down the PMK.
+			 */
+			wpa_dbg(wpa_s, MSG_DEBUG, "Pass the PMK to the driver");
+			wpa_sm_install_pmk(wpa_s->wpa);
+		}
 	}
-#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+#endif
 
 	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
 	if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
@@ -3601,14 +3609,23 @@
 		eapol_sm_notify_eap_success(wpa_s->eapol, true);
 	} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
 		   wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
-		/*
-		 * We are done; the driver will take care of RSN 4-way
-		 * handshake.
-		 */
-		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-		eapol_sm_notify_portValid(wpa_s->eapol, true);
-		eapol_sm_notify_eap_success(wpa_s->eapol, true);
+		if (already_authorized) {
+			/*
+			 * We are done; the driver will take care of RSN 4-way
+			 * handshake.
+			 */
+			wpa_supplicant_cancel_auth_timeout(wpa_s);
+			wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+			eapol_sm_notify_portValid(wpa_s->eapol, true);
+			eapol_sm_notify_eap_success(wpa_s->eapol, true);
+		} else {
+			/* Update port, WPA_COMPLETED state from
+			 * EVENT_PORT_AUTHORIZED context when driver is done
+			 * with 4way handshake.
+			 */
+			wpa_msg(wpa_s, MSG_INFO, "ASSOC INFO: wait for driver port "
+				"authorized indication");
+		}
 	} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
 		   wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
 		/*
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 8a0fe8d..90af6eb 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -286,7 +286,7 @@
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	int res, pmk_len;
-	u8 pmk[PMK_LEN];
+	u8 pmk[PMK_LEN_MAX];
 
 	wpa_printf(MSG_DEBUG, "EAPOL authentication completed - result=%s",
 		   result_str(result));
@@ -336,7 +336,11 @@
 	wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
 		   "handshake");
 
-	pmk_len = PMK_LEN;
+	if (wpa_key_mgmt_sha384(wpa_s->key_mgmt))
+		pmk_len = PMK_LEN_SUITE_B_192;
+	else
+		pmk_len = PMK_LEN;
+
 	if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) {
 #ifdef CONFIG_IEEE80211R
 		u8 buf[2 * PMK_LEN];
@@ -351,7 +355,7 @@
 		res = -1;
 #endif /* CONFIG_IEEE80211R */
 	} else {
-		res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
+		res = eapol_sm_get_key(eapol, pmk, pmk_len);
 		if (res) {
 			/*
 			 * EAP-LEAP is an exception from other EAP methods: it