diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 1d3b96ac7..a844f4169 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -32,6 +32,7 @@
 #include "dfs.h"
 #include "taxonomy.h"
 #include "ieee802_11_auth.h"
+#include "crypto/sha1.h"
 
 
 #ifdef NEED_AP_MLME
@@ -2011,6 +2012,36 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
 #endif /* NEED_AP_MLME */
 
+	/* If SAE offload is enabled, provide passphrase to lower layer for
+	 * PMK generation
+	 */
+	if ((wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) &&
+	    (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP)) {
+		if (hapd->conf->ssid.wpa_passphrase) {
+			params->sae_passphrase_len =
+				os_strlen(hapd->conf->ssid.wpa_passphrase);
+			if (params->sae_passphrase_len) {
+				os_memcpy(params->sae_passphrase,
+					hapd->conf->ssid.wpa_passphrase,
+					params->sae_passphrase_len);
+			}
+		}
+		if (hapd->conf->sae_pwe) {
+			params->sae_pwe = hapd->conf->sae_pwe;
+		}
+	}
+
+	/* If key mgmt offload is enabled, configure PSK  */
+	if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+	    (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) {
+		if (hapd->conf->ssid.wpa_psk && hapd->conf->ssid.wpa_psk_set) {
+			os_memcpy(params->psk, hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
+		} else if (hapd->conf->ssid.wpa_passphrase) {
+			pbkdf2_sha1(hapd->conf->ssid.wpa_passphrase, hapd->conf->ssid.ssid,
+				hapd->conf->ssid.ssid_len, 4096, params->psk, PMK_LEN);
+		}
+	}
+
 	params->head = (u8 *) head;
 	params->head_len = head_len;
 	params->tail = tail;
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 0516213f4..42419f523 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -2188,6 +2188,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
 	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = NULL;
+
 #ifndef CONFIG_NO_STDOUT_DEBUG
 	int level = MSG_DEBUG;
 
@@ -2482,6 +2484,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 		hostapd_cleanup_cca_params(hapd);
 		break;
 #endif /* CONFIG_IEEE80211AX */
+	case EVENT_PORT_AUTHORIZED:
+		sta = ap_get_sta(hapd, data->port_authorized.sta_addr);
+		ap_sta_set_authorized(hapd, sta, 1);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
 		break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 966030d57..961524b31 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -3573,8 +3573,11 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
 		    sta->auth_alg != WLAN_AUTH_FILS_PK &&
 		    !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
 			wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
-	} else
-		wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+	} else {
+		if (!(hapd->iface->drv_flags2 &
+		    WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK))
+			wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+	}
 
 	if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
 		if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 30a72b126..35b56b9df 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1757,6 +1757,12 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 
 }
 
+bool hostapd_wpa_auth_is_sae_offload_enabled(void *ctx)
+{
+	struct hostapd_data *hapd = ctx;
+
+	return	!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP);
+}
 
 void hostapd_reconfig_wpa(struct hostapd_data *hapd)
 {
diff --git a/src/ap/wpa_auth_glue.h b/src/ap/wpa_auth_glue.h
index 1b13ae7be..7a7cb966b 100644
--- a/src/ap/wpa_auth_glue.h
+++ b/src/ap/wpa_auth_glue.h
@@ -12,5 +12,6 @@
 int hostapd_setup_wpa(struct hostapd_data *hapd);
 void hostapd_reconfig_wpa(struct hostapd_data *hapd);
 void hostapd_deinit_wpa(struct hostapd_data *hapd);
+bool hostapd_wpa_auth_is_sae_offload_enabled(void *ctx);
 
 #endif /* WPA_AUTH_GLUE_H */
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 43ccec9be..3d33ac934 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -17,6 +17,7 @@
 #include "pmksa_cache_auth.h"
 #include "wpa_auth_ie.h"
 #include "wpa_auth_i.h"
+#include "wpa_auth_glue.h"
 
 
 #ifdef CONFIG_RSN_TESTING
@@ -998,8 +999,9 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 	}
 
 #ifdef CONFIG_SAE
-	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid &&
-	    !sm->pmksa) {
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE &&
+	    !(hostapd_wpa_auth_is_sae_offload_enabled(wpa_auth->cb_ctx)) &&
+	    data.num_pmkid && !sm->pmksa) {
 		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
 				 "No PMKSA cache entry found for SAE");
 		return WPA_INVALID_PMKID;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index dbe2ad5e4..96fe56787 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -69,6 +69,8 @@ enum hostapd_chan_width_attr {
 #define HOSTAPD_DFS_REGION_ETSI	2
 #define HOSTAPD_DFS_REGION_JP	3
 
+#define MAX_PASSPHRASE_LEN 63
+
 /**
  * enum reg_change_initiator - Regulatory change initiator
  */
@@ -1785,6 +1787,21 @@ struct wpa_driver_ap_params {
 	 * mld_link_id - Link id for MLD BSS's
 	 */
 	u8 mld_link_id;
+
+	/**
+	 * sae_passphrase - sae passphrase for SAE offload
+	 */
+	u8 sae_passphrase[MAX_PASSPHRASE_LEN];
+
+	/**
+	 * sae_passphrase_len - sae passphrase length for SAE offload
+	 */
+	u8 sae_passphrase_len;
+
+	/**
+	 * psk - PSK passed to driver for 4-way HS offload
+	 */
+	u8 psk[PMK_LEN];
 };
 
 struct wpa_driver_mesh_bss_params {
@@ -2253,6 +2270,12 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA	0x0000000000002000ULL
 /** Driver supports MLO in station/AP mode */
 #define WPA_DRIVER_FLAGS2_MLO			0x0000000000004000ULL
+/** Driver support AP_PSK authentication offload */
+#define WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK	0x0000000000008000ULL
+/** Driver support SAE STA authentication offload */
+#define WPA_DRIVER_FLAGS2_SAE_OFFLOAD		0x0000000000010000ULL
+/** Driver support SAE AP authentication offload */
+#define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP	0x0000000000020000ULL
 	u64 flags2;
 
 #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -6645,6 +6668,7 @@ union wpa_event_data {
 	struct port_authorized {
 		const u8 *td_bitmap;
 		size_t td_bitmap_len;
+		u8 sta_addr[ETH_ALEN];
 	} port_authorized;
 
 	/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 9bd6a58e0..817bc084f 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5109,6 +5109,17 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 			 suites))
 		goto fail;
 
+	if ((params->key_mgmt_suites & WPA_KEY_MGMT_PSK) &&
+	    (drv->capa.flags & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK) &&
+	    (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk)))
+		goto fail;
+
+	if (wpa_key_mgmt_sae(params->key_mgmt_suites) &&
+	    (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP) &&
+	    (nla_put(msg, NL80211_ATTR_SAE_PASSWORD, params->sae_passphrase_len,
+	    params->sae_passphrase)))
+		goto fail;
+
 	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
 	    (!params->pairwise_ciphers ||
 	     params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
@@ -6926,6 +6937,17 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
 			return -1;
 	}
 
+	/* Add SAE passphrase in case of SAE offload */
+	if (wpa_key_mgmt_sae(params->key_mgmt_suite) &&
+	    (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD) &&
+	    params->passphrase) {
+		wpa_hexdump_key(MSG_DEBUG, "  * SAE passphrase",
+			params->passphrase, os_strlen(params->passphrase));
+		if (nla_put(msg, NL80211_ATTR_SAE_PASSWORD,
+		    os_strlen(params->passphrase), params->passphrase))
+			return -1;
+	}
+
 	if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
 		return -1;
 
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 5e6406885..c17957381 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -697,6 +697,18 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
 		capa->flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA;
 		capa->flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP;
 	}
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK))
+		capa->flags2 |= WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_SAE_OFFLOAD_AP))
+		capa->flags2 |= WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_SAE_OFFLOAD))
+		capa->flags2 |= WPA_DRIVER_FLAGS2_SAE_OFFLOAD;
 }
 
 
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 9d39703e0..d1473e8f9 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -3505,7 +3505,14 @@ static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv,
 	}
 
 	addr = nla_data(tb[NL80211_ATTR_MAC]);
-	if (os_memcmp(addr, drv->bssid, ETH_ALEN) != 0) {
+	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+		/* Update STA assoc address */
+		os_memcpy(event.port_authorized.sta_addr, addr, ETH_ALEN);
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Port authorized for STA BSSID "  MACSTR,
+			   MAC2STR(addr));
+	} else if (is_sta_interface(drv->nlmode) &&
+	    os_memcmp(addr, drv->bssid, ETH_ALEN) != 0) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Ignore port authorized event for " MACSTR
 			   " (not the currently connected BSSID " MACSTR ")",
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 69f228919..961411596 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -4269,6 +4269,21 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 	     params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
 		params.req_handshake_offload = 1;
 
+	params.sae_pwe = wpa_s->conf->sae_pwe;
+	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) &&
+	    (wpa_key_mgmt_sae(params.key_mgmt_suite))) {
+		if (ssid->sae_password) {
+			wpa_printf(MSG_DEBUG, "sae enabled join..Using sae_password");
+			params.passphrase = ssid->sae_password;
+		} else if (ssid->passphrase) {
+			wpa_printf(MSG_DEBUG, "sae enabled join..Using passphrase");
+			params.passphrase = ssid->passphrase;
+		} else {
+			wpa_printf(MSG_ERROR, "sae enabled join.."
+				"But neither sae_password nor passphrase set");
+		}
+	}
+
 	if (wpa_s->conf->key_mgmt_offload) {
 		if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
 		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
