diff mbox series

[v3,16/25] P2P: Add support for GO negotiation wrapped in PASN auth frame

Message ID 1722850403-8852-17-git-send-email-quic_shivbara@quicinc.com
State Deferred
Headers show
Series Add support for P2P2 | expand

Commit Message

Shivani Baranwal Aug. 5, 2024, 9:33 a.m. UTC
Add P2P2 support for GO negotiation wrapped in PASN authentication
frames as a action wrapper attribute.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
---
 src/ap/ieee802_11.c               |  16 +-
 src/common/ieee802_11_common.c    |   4 +
 src/common/ieee802_11_common.h    |   2 +
 src/common/ieee802_11_defs.h      |   2 +
 src/p2p/p2p.c                     | 808 +++++++++++++++++++++++++++++++++++++-
 src/p2p/p2p.h                     |  85 ++++
 src/p2p/p2p_go_neg.c              |   4 +-
 src/p2p/p2p_i.h                   |  27 ++
 src/p2p/p2p_parse.c               |  20 +
 src/p2p/p2p_pd.c                  |   6 +
 src/pasn/pasn_common.h            |   7 +
 src/pasn/pasn_initiator.c         |  50 ++-
 src/pasn/pasn_responder.c         |  20 +-
 wpa_supplicant/events.c           |  56 ++-
 wpa_supplicant/p2p_supplicant.c   | 161 +++++++-
 wpa_supplicant/p2p_supplicant.h   |  11 +-
 wpa_supplicant/pasn_supplicant.c  |   5 +
 wpa_supplicant/wpa_supplicant_i.h |   5 +
 18 files changed, 1260 insertions(+), 29 deletions(-)
diff mbox series

Patch

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 38fcba5..3c5a8dd 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2487,6 +2487,10 @@  static void pasn_fils_auth_resp(struct hostapd_data *hapd,
 	fils->erp_resp = erp_resp;
 	ret = handle_auth_pasn_resp(sta->pasn, hapd->own_addr, sta->addr, NULL,
 				    WLAN_STATUS_SUCCESS);
+	if (sta->pasn->frame) {
+		wpabuf_free(sta->pasn->frame);
+		sta->pasn->frame = NULL;
+	}
 	fils->erp_resp = NULL;
 
 	if (ret) {
@@ -2800,6 +2804,8 @@  static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
 			     const struct ieee80211_mgmt *mgmt, size_t len,
 			     u16 trans_seq, u16 status)
 {
+	int ret;
+
 	if (hapd->conf->wpa != WPA_PROTO_RSN) {
 		wpa_printf(MSG_INFO, "PASN: RSN is not configured");
 		return;
@@ -2831,9 +2837,15 @@  static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
 		hapd_initialize_pasn(hapd, sta);
 
 		hapd_pasn_update_params(hapd, sta, mgmt, len);
-		if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
-				       sta->addr, mgmt, len) < 0)
+		ret = handle_auth_pasn_1(sta->pasn, hapd->own_addr, sta->addr,
+					 mgmt, len);
+		if (sta->pasn->frame) {
+			wpabuf_free(sta->pasn->frame);
+			sta->pasn->frame = NULL;
+		}
+		if (ret < 0)
 			ap_free_sta(hapd, sta);
+
 	} else if (trans_seq == 3) {
 		if (!sta->pasn) {
 			wpa_printf(MSG_DEBUG,
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 2d4540b..b16564d 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -413,6 +413,10 @@  static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
 		elems->mbssid_known_bss = pos;
 		elems->mbssid_known_bss_len = elen;
 		break;
+	case WLAN_EID_EXT_PASN_ENCRYPTED_ELEMENT:
+		elems->pasn_encrypted_ie = pos;
+		elems->pasn_encrypted_ie_len = elen;
+		break;
 	default:
 		if (show_errors) {
 			wpa_printf(MSG_MSGDUMP,
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index e4321b5..7ca99f3 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -66,6 +66,7 @@  struct ieee802_11_elems {
 	const u8 *vendor_vht;
 	const u8 *p2p;
 	const u8 *p2p2_ie;
+	const u8 *pasn_encrypted_ie;
 	const u8 *wfd;
 	const u8 *link_id;
 	const u8 *interworking;
@@ -141,6 +142,7 @@  struct ieee802_11_elems {
 	u8 vendor_vht_len;
 	u8 p2p_len;
 	u8 p2p2_ie_len;
+	u8 pasn_encrypted_ie_len;
 	u8 wfd_len;
 	u8 interworking_len;
 	u8 qos_map_set_len;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 0e88797..db1033a 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -524,6 +524,7 @@ 
 #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
 #define WLAN_EID_EXT_QOS_CHARACTERISTICS 113
 #define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
+#define WLAN_EID_EXT_PASN_ENCRYPTED_ELEMENT 140
 
 /* Extended Capabilities field */
 #define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -616,6 +617,7 @@ 
 #define WLAN_RSNX_CAPAB_SECURE_RTT 9
 #define WLAN_RSNX_CAPAB_URNM_MFPR_X20 10
 #define WLAN_RSNX_CAPAB_URNM_MFPR 15
+#define WLAN_RSNX_CAPAB_KEK 18
 #define WLAN_RSNX_CAPAB_SSID_PROTECTION 21
 
 /* Multiple BSSID element subelements */
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 01490e2..6e2a97c 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -15,10 +15,14 @@ 
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
 #include "crypto/sha256.h"
+#include "crypto/sha384.h"
 #include "crypto/crypto.h"
 #include "wps/wps_i.h"
 #include "p2p_i.h"
 #include "p2p.h"
+#include "common/sae.h"
+#include "pasn/pasn_common.h"
+#include "crypto/aes_wrap.h"
 
 
 static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx);
@@ -242,6 +246,11 @@  void p2p_go_neg_failed(struct p2p_data *p2p, int status)
 	peer->go_neg_conf = NULL;
 	p2p->go_neg_peer = NULL;
 
+#ifdef CONFIG_PASN
+	if (peer->p2p2 && peer->pasn)
+		wpa_pasn_reset(peer->pasn);
+#endif /* CONFIG_PASN */
+
 	os_memset(&res, 0, sizeof(res));
 	res.status = status;
 	os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
@@ -959,6 +968,14 @@  static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
 		dev->bootstrap_params = NULL;
 	}
 
+#ifdef CONFIG_PASN
+	if (dev->pasn) {
+		wpa_pasn_reset(dev->pasn);
+		pasn_data_deinit(dev->pasn);
+		dev->pasn = NULL;
+	}
+#endif /* CONFIG_PASN */
+
 	wpabuf_free(dev->info.wfd_subelems);
 	wpabuf_free(dev->info.vendor_elems);
 	wpabuf_free(dev->go_neg_conf);
@@ -1861,8 +1878,13 @@  void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
 
 	os_memset(&res, 0, sizeof(res));
 	res.role_go = go;
+
+	if (is_zero_ether_addr(peer->interface_addr))
+		os_memcpy(peer->interface_addr, peer->intended_addr, ETH_ALEN);
+
 	os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
-	os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
+	os_memcpy(res.peer_interface_addr, peer->interface_addr, ETH_ALEN);
+
 	res.wps_method = peer->wps_method;
 	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
 		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
@@ -1911,6 +1933,11 @@  void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
 	wpabuf_free(peer->go_neg_conf);
 	peer->go_neg_conf = NULL;
 
+#ifdef CONFIG_PASN
+	if (peer->p2p2 && peer->pasn)
+		wpa_pasn_reset(peer->pasn);
+#endif /* CONFIG_PASN */
+
 	p2p_set_state(p2p, P2P_PROVISIONING);
 	p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
 }
@@ -3012,7 +3039,18 @@  int p2p_pairing_info_init(struct p2p_data *p2p)
 	os_memcpy(pairing_info->dev_ik.dik_data,
 		  p2p->cfg->pairing_config.dik_data,
 		  p2p->cfg->pairing_config.dik_len);
+
+	if (!p2p->cfg->dev_password_len) {
+		p2p->cfg->dev_password_len = 10;
+		p2p_random(p2p->cfg->dev_password, p2p->cfg->dev_password_len);
+		p2p->cfg->dev_password[p2p->cfg->dev_password_len] = '\0';
+	}
+
 	p2p->pairing_info = pairing_info;
+#ifdef CONFIG_PASN
+	p2p->initiator_pmksa = pasn_initiator_pmksa_cache_init();
+	p2p->responder_pmksa = pasn_responder_pmksa_cache_init();
+#endif /* CONFIG_PASN */
 
 	return 0;
 }
@@ -3086,6 +3124,10 @@  struct p2p_data * p2p_init(const struct p2p_config *cfg)
 
 void p2p_pairing_info_deinit(struct p2p_data *p2p)
 {
+#ifdef CONFIG_PASN
+	pasn_initiator_pmksa_cache_deinit(p2p->initiator_pmksa);
+	pasn_responder_pmksa_cache_deinit(p2p->responder_pmksa);
+#endif /* CONFIG_PASN */
 	os_free(p2p->pairing_info);
 }
 
@@ -4975,8 +5017,11 @@  int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
 			   u8 *iface_addr)
 {
 	struct p2p_device *dev = p2p_get_device(p2p, dev_addr);
-	if (dev == NULL || is_zero_ether_addr(dev->interface_addr))
+	if (dev == NULL || is_zero_ether_addr(dev->interface_addr)) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to get interface addr from dev addr "
+			   MACSTR, MAC2STR(dev_addr));
 		return -1;
+	}
 	os_memcpy(iface_addr, dev->interface_addr, ETH_ALEN);
 	return 0;
 }
@@ -4986,8 +5031,11 @@  int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr,
 			   u8 *dev_addr)
 {
 	struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr);
-	if (dev == NULL)
+	if (!dev) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to get device addr from iface addr "
+			   MACSTR, MAC2STR(iface_addr));
 		return -1;
+	}
 	os_memcpy(dev_addr, dev->info.p2p_device_addr, ETH_ALEN);
 	return 0;
 }
@@ -5862,3 +5910,757 @@  void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
 
 	p2p_parse_free(&msg);
 }
+
+#ifdef CONFIG_PASN
+int p2p_prepare_pasn_extra_ie(struct p2p_data *p2p, struct wpabuf *extra_ies,
+			      struct wpabuf *frame)
+{
+	struct wpabuf *buf, *buf2;
+
+	buf = wpabuf_alloc(1500);
+	if (!buf) {
+		p2p_dbg(p2p, "Mem alloc failed for buf");
+		return -1;
+	}
+
+	/* P2P Capability Extension attribute */
+	p2p_buf_add_pcea(buf, p2p);
+
+	if (frame) {
+		p2p_dbg(p2p, "P2P: Added Action frame wrapper");
+		wpabuf_put_u8(buf, P2P_ATTR_ACTION_FRAME_WRAPPER);
+		wpabuf_put_le16(buf, wpabuf_len(frame));
+		wpabuf_put_buf(buf, frame);
+	}
+
+	buf2 = p2p_encaps_p2p_vendor_ie(p2p, buf, P2P2_IE_VENDOR_TYPE);
+	wpabuf_free(buf);
+
+	wpabuf_put_buf(extra_ies, buf2);
+	wpabuf_free(buf2);
+
+	return 0;
+}
+
+struct wpabuf *p2p_pairing_generate_rsnxe(int akmp)
+{
+	u32 capab;
+	size_t flen = 0;
+	struct wpabuf *buf;
+
+	capab = BIT(WLAN_RSNX_CAPAB_KEK);
+
+	if (akmp == WPA_KEY_MGMT_SAE)
+		capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+	while (capab >> flen * 8)
+		flen++;
+
+	buf = wpabuf_alloc(2 + flen);
+	if (!buf) {
+		wpa_printf(MSG_ERROR, "Memory allocation failed");
+		return NULL;
+	}
+
+	if (wpabuf_tailroom(buf) < 2 + flen) {
+		wpa_printf(MSG_ERROR, "wpabuf tail room small");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+	wpa_printf(MSG_DEBUG, "RSNXE capabilities: %04x", capab);
+	wpabuf_put_u8(buf, WLAN_EID_RSNX);
+	wpabuf_put_u8(buf, flen);
+	while (flen--) {
+		wpabuf_put_u8(buf, (capab & 0xff));
+		capab = capab >> 8;
+	}
+	return buf;
+}
+
+/* sae password id to derive pt */
+#define P2P_PAIRING_SSID "516F9A020000"
+
+void p2p_pairing_set_password(struct pasn_data *pasn, const char *passphrase,
+			      u32 len)
+{
+	const u8 *pairing_ssid;
+	size_t pairing_ssid_len;
+
+	if (!passphrase) {
+		wpa_printf(MSG_ERROR, "p2p pairing password NULL");
+		return;
+	}
+
+	pairing_ssid = (const u8 *)(P2P_PAIRING_SSID);
+	pairing_ssid_len = strlen(P2P_PAIRING_SSID);
+	pasn->pt = sae_derive_pt(pasn->pasn_groups, pairing_ssid,
+				 pairing_ssid_len, (const u8 *)passphrase, len,
+				 NULL);
+	/* Set passpharse for Pairing Responder to validate PASN auth1 frame*/
+	pasn->password = passphrase;
+}
+
+void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev,
+			 const u8 *addr, int freq, bool verify)
+{
+	struct pasn_data *pasn;
+	struct wpabuf *rsnxe;
+
+	if (!p2p || !dev)
+		return;
+
+	if (dev->pasn)
+		wpa_pasn_reset(dev->pasn);
+	else
+		dev->pasn = pasn_data_init();
+
+	pasn = dev->pasn;
+
+	os_memcpy(pasn->own_addr, p2p->cfg->dev_addr, ETH_ALEN);
+	os_memcpy(pasn->peer_addr, addr, ETH_ALEN);
+
+	if (dev->role == P2P_ROLE_PAIRING_INITIATOR)
+		memcpy(pasn->bssid, pasn->peer_addr, ETH_ALEN);
+	else
+		memcpy(pasn->bssid, pasn->own_addr, ETH_ALEN);
+
+	pasn->noauth = 1;
+
+	if ((p2p->cfg->pairing_config.pasn_type & 0xc) &&
+	    (dev->info.pairing_config.pasn_type & 0xc)) {
+		pasn->group = 20;
+		pasn->cipher = WPA_CIPHER_GCMP_256;
+		pasn->kek_len = WPA_KEK_256;
+		pasn->pasn_groups = p2p->cfg->pairing_config.pasn_groups;
+	} else {
+		pasn->group = 19;
+		pasn->cipher = WPA_CIPHER_CCMP;
+		pasn->kek_len = WPA_KEK_128;
+	}
+
+	if (dev->password_len) {
+		pasn->akmp = WPA_KEY_MGMT_SAE;
+		p2p_pairing_set_password(pasn, dev->password,
+					 dev->password_len);
+		pasn->rsnxe_capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+	} else if (verify) {
+		pasn->akmp = WPA_KEY_MGMT_SAE;
+	} else {
+		pasn->akmp = WPA_KEY_MGMT_PASN;
+	}
+
+	pasn->rsn_pairwise = pasn->cipher;
+	pasn->wpa_key_mgmt = pasn->akmp;
+
+	rsnxe = p2p_pairing_generate_rsnxe(pasn->akmp);
+	if (rsnxe) {
+		pasn->rsnxe_ie = os_zalloc(wpabuf_len(rsnxe));
+		if (!pasn->rsnxe_ie) {
+			p2p_dbg(p2p, "Mem alloc failed for pasn rsnxe ie");
+			wpabuf_free(rsnxe);
+			return;
+		}
+		os_memcpy((u8 *)pasn->rsnxe_ie, wpabuf_head_u8(rsnxe),
+			  wpabuf_len(rsnxe));
+		pasn->rsnxe_ie_len = wpabuf_len(rsnxe);
+		wpabuf_free(rsnxe);
+	}
+
+	if (dev->role == P2P_ROLE_PAIRING_INITIATOR)
+		pasn->pmksa = p2p->initiator_pmksa;
+	else
+		pasn->pmksa = p2p->responder_pmksa;
+
+	pasn->cb_ctx = p2p->cfg->cb_ctx;
+	pasn->send_mgmt = p2p->cfg->pasn_send_mgmt;
+	pasn->update_extra_ies = p2p->cfg->pasn_update_extra_ies;
+	pasn->parse_encrypted_data = p2p->cfg->pasn_parse_encrypted_data;
+
+	pasn->freq = freq;
+}
+
+
+int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq)
+{
+	struct pasn_data *pasn;
+	struct p2p_device *dev;
+	struct wpabuf *extra_ies, *req;
+	int ret = 0;
+
+	if (!addr) {
+		p2p_dbg(p2p, "peer address NULL");
+		return -1;
+	}
+
+	dev = p2p_get_device(p2p, addr);
+	if (!dev) {
+		p2p_dbg(p2p, "Peer not known");
+		return -1;
+	}
+
+	dev->role = P2P_ROLE_PAIRING_INITIATOR;
+	p2p_pasn_initialize(p2p, dev, addr, freq, false);
+	pasn = dev->pasn;
+
+	pasn_initiator_pmksa_cache_remove(pasn->pmksa, (u8 *)addr);
+
+	/* FIXME:  Added to resolve listen freq issue resulting in GO Neg no
+	 * common channel failure
+	 */
+	p2p->cfg->reg_class = p2p->op_reg_class;
+	p2p->cfg->channel = p2p->op_channel;
+
+	req = p2p_build_go_neg_req(p2p, dev);
+	if (!req)
+		return -1;
+
+	p2p->go_neg_peer = dev;
+	dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
+
+	extra_ies = wpabuf_alloc(1500);
+	if (!extra_ies) {
+		wpabuf_free(req);
+		p2p_dbg(p2p, "Mem alloc failed for extra ies");
+		return -1;
+	}
+
+	if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req)) {
+		p2p_dbg(p2p, "prepare pasn extra ies failed");
+		ret = -1;
+		goto out;
+	}
+
+	pasn->extra_ies = os_zalloc(wpabuf_len(extra_ies));
+	if (!pasn->extra_ies) {
+		p2p_dbg(p2p, "Mem alloc failed for pasn extra ies");
+		ret = -1;
+		goto out;
+	}
+
+	os_memcpy((u8 *)pasn->extra_ies, wpabuf_head_u8(extra_ies),
+		  wpabuf_len(extra_ies));
+	pasn->extra_ies_len = wpabuf_len(extra_ies);
+
+	/* Start PASN Auth */
+	if (wpas_pasn_start(pasn, pasn->own_addr, pasn->peer_addr, pasn->bssid,
+			    pasn->akmp, pasn->cipher, pasn->group, pasn->freq,
+			    NULL, 0, NULL, 0, NULL)) {
+		p2p_dbg(p2p, "p2p pasn start failed");
+		ret = -1;
+	}
+out:
+	if (pasn->extra_ies) {
+		os_free((u8 *)pasn->extra_ies);
+		pasn->extra_ies = NULL;
+		pasn->extra_ies_len = 0;
+	}
+	wpabuf_free(req);
+	wpabuf_free(extra_ies);
+	return ret;
+}
+
+
+int p2p_pasn_handle_action_wrapper(struct p2p_data *p2p,
+				   struct p2p_device *dev,
+				   const struct ieee80211_mgmt *mgmt,
+				   size_t len, int freq, int trans_seq)
+{
+	const u8 *ies;
+	size_t ies_len;
+	size_t data_len = 0;
+	const u8 *data = NULL;
+	struct p2p_message msg;
+
+	ies = mgmt->u.auth.variable;
+	ies_len = len - offsetof(struct ieee80211_mgmt, u.auth.variable);
+
+	os_memset(&msg, 0, sizeof(msg));
+	if (p2p_parse_ies(ies, ies_len, &msg)) {
+		p2p_dbg(p2p, "Failed to parse P2P IE from auth frame");
+		p2p_parse_free(&msg);
+		return -1;
+	}
+
+	if (msg.action_frame_wrapper && msg.action_frame_wrapper_len) {
+		data = msg.action_frame_wrapper;
+		data_len = msg.action_frame_wrapper_len;
+		if (data[0] == WLAN_ACTION_PUBLIC &&
+		    data[1] == WLAN_PA_VENDOR_SPECIFIC) {
+			data += 2;
+			data_len -= 2;
+			if (data_len < 4 ||
+			    WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE) {
+				p2p_parse_free(&msg);
+				return -1;
+			}
+			data += 4;
+			data_len -= 4;
+		} else {
+			p2p_dbg(p2p, "Invalid category in action frame wrapper in Auth %d",
+				trans_seq);
+			p2p_parse_free(&msg);
+			return -1;
+		}
+	}
+
+	if (trans_seq == 1) {
+		if (data && data[0] == P2P_INVITATION_REQ) {
+			p2p_process_invitation_req(p2p, mgmt->sa, data + 1,
+						   data_len - 1, freq);
+			if (!p2p->invitation_resp)
+				p2p_dbg(p2p, "No Invitation Response found");
+
+			dev->role = P2P_ROLE_PAIRING_RESPONDER;
+			p2p_pasn_initialize(p2p, dev, mgmt->sa, freq, true);
+			dev->pasn->action_frame_wrapper = p2p->invitation_resp;
+		} else if (data && data[0] == P2P_GO_NEG_REQ) {
+			p2p_process_go_neg_req(p2p, mgmt->sa, data + 1,
+					       data_len - 1, freq, true);
+			if (!p2p->go_neg_resp)
+				p2p_dbg(p2p, "No GO Neg Response found");
+			dev->pasn->action_frame_wrapper = p2p->go_neg_resp;
+		} else {
+			p2p_dbg(p2p, "Invalid action frame wrapper in Auth1");
+		}
+	} else if (trans_seq == 2) {
+		if (data && data[0] == P2P_INVITATION_RESP) {
+			p2p_process_invitation_resp(p2p, mgmt->sa, data + 1,
+						    data_len - 1);
+			dev->pasn->action_frame_wrapper = NULL;
+		} else if (data && data[0] == P2P_GO_NEG_RESP) {
+			p2p_process_go_neg_resp(p2p, mgmt->sa, data + 1,
+						data_len - 1, freq, true);
+			if (!p2p->go_neg_conf)
+				p2p_dbg(p2p, "No GO Neg confirm found");
+			dev->pasn->action_frame_wrapper = p2p->go_neg_conf;
+			/* FIXME: If go neg resp is with failure status,
+			 how go_neg_failed is indicated to host */
+		} else {
+			p2p_dbg(p2p, "Invalid action frame wrapper in Auth2");
+		}
+	} else if (trans_seq == 3) {
+		if (data && data[0] == P2P_GO_NEG_CONF) {
+			p2p_handle_go_neg_conf(p2p, mgmt->sa, data + 1,
+					       data_len - 1, true);
+		} else {
+			p2p_invitation_resp_cb(p2p, P2P_SEND_ACTION_SUCCESS);
+		}
+	}
+	p2p_parse_free(&msg);
+	return 0;
+}
+
+
+static void p2p_pasn_add_encrypted_element(struct p2p_data *p2p,
+					   struct p2p_device *dev,
+					   struct wpabuf *buf)
+{
+	int ret;
+	struct pasn_data *pasn;
+	struct wpabuf *p2p2_ie;
+	u8 *len, *dika_len, *p2p2_ie_len;
+	u8 *pos, *key_data, *encrypted_data;
+	u16 key_data_len, pad_len = 0;
+
+	if (!p2p || !dev || !dev->pasn)
+		return;
+
+	pasn = dev->pasn;
+
+	if (dev->req_bootstrap_method != P2P_PBMA_OPPORTUNISTIC &&
+	    !p2p->pairing_info->enable_pairing_cache)
+		return;
+
+	p2p2_ie = wpabuf_alloc(100);
+	if (!p2p2_ie) {
+		p2p_dbg(p2p, "Mem alloc failed for p2p2 IE");
+		return;
+	}
+
+	p2p2_ie_len = p2p_buf_add_p2p2_ie_hdr(p2p2_ie);
+
+	if (p2p->pairing_info->enable_pairing_cache) {
+		wpabuf_put_u8(p2p2_ie, P2P_ATTR_DEVICE_IDENTITY_KEY);
+		dika_len = wpabuf_put(p2p2_ie, 2);
+
+		wpabuf_put_u8(p2p2_ie, DIRA_CIPHER_VERSION_128);
+		wpabuf_put_data(p2p2_ie, p2p->pairing_info->dev_ik.dik_data,
+				p2p->pairing_info->dev_ik.dik_len);
+		wpabuf_put_be32(p2p2_ie, p2p->pairing_info->dev_ik.expiration);
+
+		WPA_PUT_LE16(dika_len,
+			     (u8 *)wpabuf_put(p2p2_ie, 0) - dika_len - 2);
+	}
+
+	if (dev->req_bootstrap_method == P2P_PBMA_OPPORTUNISTIC &&
+	    p2p->cfg->dev_password_len) {
+		wpabuf_put_u8(p2p2_ie, P2P_ATTR_PASSWORD);
+		wpabuf_put_le16(p2p2_ie, p2p->cfg->dev_password_len);
+		wpabuf_put_data(p2p2_ie, p2p->cfg->dev_password,
+				p2p->cfg->dev_password_len);
+	}
+
+	p2p_buf_update_p2p2_ie_hdr(p2p2_ie, p2p2_ie_len);
+
+	key_data = (u8 *)wpabuf_head(p2p2_ie);
+	key_data_len = wpabuf_len(p2p2_ie);
+
+	pad_len = key_data_len % 8;
+
+	if (pad_len) {
+		pad_len = 8 - pad_len;
+		pos = key_data + key_data_len;
+		*pos++ = 0xdd;
+	}
+	key_data_len += pad_len + 8;
+
+	encrypted_data = os_malloc(key_data_len);
+	if (!encrypted_data) {
+		p2p_dbg(p2p, "P2P PASN: Mem alloc failed for encrypted data");
+		wpabuf_free(p2p2_ie);
+		return;
+	}
+	ret = aes_wrap(pasn->ptk.kek, pasn->ptk.kek_len,
+		       (key_data_len - 8) / 8, key_data, encrypted_data);
+	if (ret) {
+		p2p_dbg(p2p, "P2P PASN: AES upwrap failed, ret=%d", ret);
+		goto out;
+	}
+
+	wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+	len = wpabuf_put(buf, 1);
+
+	wpabuf_put_u8(buf, WLAN_EID_EXT_PASN_ENCRYPTED_ELEMENT);
+
+	wpabuf_put_data(buf, encrypted_data, key_data_len);
+	*len = (u8 *)wpabuf_put(buf, 0) - len - 1;
+
+out:
+	os_free(encrypted_data);
+	wpabuf_free(p2p2_ie);
+}
+
+
+int p2p_pasn_update_extra_ies(struct p2p_data *p2p, const u8 *peer_addr)
+{
+	int ret = -1;
+	struct p2p_device *dev;
+	struct pasn_data *pasn;
+	struct wpabuf *extra_ies;
+
+	if (!p2p)
+		return -1;
+
+	dev = p2p_get_device(p2p, (u8 *)peer_addr);
+	if (!dev || !dev->pasn) {
+		p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR,
+			MAC2STR(peer_addr));
+		return -1;
+	}
+	pasn = dev->pasn;
+
+	extra_ies = wpabuf_alloc(1500);
+	if (!extra_ies) {
+		p2p_dbg(p2p, "Mem alloc failed for extra ies");
+		goto out;
+	}
+
+	if (p2p_prepare_pasn_extra_ie(p2p, extra_ies,
+				      pasn->action_frame_wrapper)) {
+		p2p_dbg(p2p, "prepare pasn extra ies failed");
+		goto out;
+	}
+
+	p2p_pasn_add_encrypted_element(p2p, dev, extra_ies);
+
+	pasn->extra_ies = os_zalloc(wpabuf_len(extra_ies));
+	if (!pasn->extra_ies) {
+		p2p_dbg(p2p, "Mem alloc failed for pasn extra ies");
+		goto out;
+	}
+
+	os_memcpy((u8 *)pasn->extra_ies, wpabuf_head_u8(extra_ies),
+		  wpabuf_len(extra_ies));
+	pasn->extra_ies_len = wpabuf_len(extra_ies);
+	ret = 0;
+
+out:
+	wpabuf_free(extra_ies);
+	wpabuf_free(pasn->action_frame_wrapper);
+	pasn->action_frame_wrapper = NULL;
+
+	return ret;
+}
+
+
+int p2p_pasn_parse_encrypted_data(struct p2p_data *p2p, const u8 *data,
+				  size_t len)
+{
+	int ret = -1;
+	u8 attr_id;
+	u8 *buf, *pos;
+	u16 rem_len, attr_len;
+	struct p2p_device *dev;
+	struct pasn_data *pasn;
+	struct ieee802_11_elems elems;
+	const struct ieee80211_mgmt *mgmt =
+		(const struct ieee80211_mgmt *) data;
+
+	if (!p2p)
+		return -1;
+
+	dev = p2p_get_device(p2p, (u8 *)mgmt->sa);
+	if (!dev || !dev->pasn) {
+		p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR,
+			MAC2STR(mgmt->sa));
+		return -1;
+	}
+
+	if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+				   len - offsetof(struct ieee80211_mgmt,
+						  u.auth.variable),
+				   &elems, 0) == ParseFailed) {
+		p2p_dbg(p2p, "P2P PASN: Failed parsing Authentication frame");
+		return -1;
+	}
+
+	if (!elems.pasn_encrypted_ie || !elems.pasn_encrypted_ie_len) {
+		p2p_dbg(p2p, "P2P PASN: No encrypted IEs");
+		return 0;
+	}
+
+	pasn = dev->pasn;
+	rem_len = elems.pasn_encrypted_ie_len;
+
+	buf = os_zalloc(rem_len);
+	if (!buf) {
+		p2p_dbg(p2p, "Mem alloc failed for buf");
+		return -1;
+	}
+
+	ret = aes_unwrap(pasn->ptk.kek, pasn->ptk.kek_len, (rem_len - 8) / 8,
+			 elems.pasn_encrypted_ie, buf);
+	if (ret) {
+		p2p_dbg(p2p, "P2P PASN: AES unwrap failed, ret=%d", ret);
+		goto done;
+	}
+
+	pos = buf;
+	if (pos[0] != WLAN_EID_VENDOR_SPECIFIC ||
+	    WPA_GET_BE32(&pos[2]) != P2P2_IE_VENDOR_TYPE) {
+		p2p_dbg(p2p, "P2P PASN: P2P2 IE not present");
+		goto done;
+	}
+
+	pos += 6;
+	rem_len -= 6;
+
+	while (rem_len > 2) {
+		attr_id = *pos++;
+		attr_len = WPA_GET_LE16(pos);
+
+		pos += 2;
+		rem_len -= 3;
+		switch (attr_id) {
+		case P2P_ATTR_DEVICE_IDENTITY_KEY:
+			if (rem_len < 13) {
+				p2p_dbg(p2p, "P2P PASN: Invalid rem len %d", rem_len);
+				goto done;
+			}
+			dev->info.dik_cipher_version = *pos++;
+			rem_len--;
+			if (dev->info.dik_cipher_version == 0) {
+				memcpy(dev->info.dik_data, pos, 16);
+				dev->info.dik_len = 16;
+				pos += 16;
+				rem_len -= 16;
+			} else {
+				p2p_dbg(p2p, "P2P PASN: Invalid cipher");
+				goto done;
+			}
+			dev->info.dik_lifetime = WPA_GET_BE32(pos);
+			pos += 4;
+			rem_len -= 4;
+			break;
+		case P2P_ATTR_PASSWORD:
+			if (rem_len < 1) {
+				p2p_dbg(p2p, "P2P PASN: Invalid rem len %d", rem_len);
+				goto done;
+			}
+			dev->info.password_len = attr_len;
+			memset(dev->info.password, 0,
+			       sizeof(dev->info.password));
+			memcpy(dev->info.password, pos, attr_len);
+			break;
+		default:
+			p2p_dbg(p2p, "Invalid Attr ID: %d", attr_id);
+			break;
+		}
+	}
+	ret = 0;
+done:
+	os_free(buf);
+	return ret;
+}
+
+int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
+			    size_t data_len, u8 acked)
+{
+	int ret = 0;
+	struct p2p_device *dev;
+	struct pasn_data *pasn;
+	const struct ieee80211_mgmt *mgmt =
+		(const struct ieee80211_mgmt *) data;
+
+	if (!p2p)
+		return -1;
+
+	dev = p2p_get_device(p2p, (u8 *)mgmt->da);
+	if (!dev || !dev->pasn) {
+		p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR,
+			MAC2STR(mgmt->da));
+		return -1;
+	}
+
+	pasn = dev->pasn;
+
+	ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked);
+	if (ret != 1 && acked == 0 && pasn->frame) {
+		return pasn->send_mgmt(pasn->cb_ctx, wpabuf_head(pasn->frame),
+				       wpabuf_len(pasn->frame), 0, pasn->freq,
+				       1000);
+	} else if (pasn->frame) {
+		wpabuf_free(pasn->frame);
+		pasn->frame = NULL;
+	}
+
+	if (ret != 1)
+		return ret;
+
+	if (dev == p2p->go_neg_peer)
+		p2p_go_complete(p2p, dev);
+
+	return 0;
+}
+
+int p2p_handle_pasn_auth(struct p2p_data *p2p, struct p2p_device *dev,
+			 const struct ieee80211_mgmt *mgmt, size_t len,
+			 int freq)
+{
+	struct pasn_data *pasn;
+	u16 auth_alg, auth_transaction, status_code;
+
+	if (!p2p || !dev || !dev->pasn)
+		return -1;
+
+	if (os_memcmp(mgmt->da, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
+		p2p_dbg(p2p, "P2P PASN Responder: Not our frame");
+		return -1;
+	}
+
+	pasn = dev->pasn;
+	auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+	status_code = le_to_host16(mgmt->u.auth.status_code);
+
+	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+
+	if (status_code != WLAN_STATUS_SUCCESS &&
+	    status_code != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+		p2p_dbg(p2p, "P2P PASN: Authentication rejected - status=%u",
+			status_code);
+		return -1;
+	}
+
+	if (auth_alg != WLAN_AUTH_PASN || auth_transaction == 2) {
+		p2p_dbg(p2p, "P2P PASN Responder: Not PASN frame "
+			" or Unexpected auth frame, auth_alg = %d",
+			auth_alg);
+		return -1;
+	}
+	if (auth_transaction == 1) {
+		if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq,
+						   auth_transaction)) {
+			p2p_dbg(p2p, "P2P PASN Responder: Handle Auth1 action wrapper failed");
+			return -1;
+		}
+		if (handle_auth_pasn_1(pasn, p2p->cfg->dev_addr, mgmt->sa, mgmt,
+				       len) < 0) {
+			p2p_dbg(p2p, "P2P PASN Responder: Handle Auth1 failed");
+			return -1;
+		}
+	} else if (auth_transaction == 3) {
+		if (handle_auth_pasn_3(pasn, p2p->cfg->dev_addr, mgmt->sa, mgmt,
+				       len) < 0) {
+			p2p_dbg(p2p, "P2P PASN Responder: Handle PASN Auth3 failed");
+			return -1;
+		}
+		if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq,
+						   auth_transaction)) {
+			p2p_dbg(p2p, "P2P PASN Responder: Handle Auth3 action wrapper failed");
+			memset(dev->info.dik_data, 0,
+			       sizeof(dev->info.dik_data));
+			memset(dev->info.password, 0,
+			       sizeof(dev->info.password));
+			dev->info.password_len = 0;
+			return -1;
+		}
+		forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
+	}
+	return 0;
+}
+
+
+int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt,
+		     size_t len, int freq)
+{
+	int ret = 0;
+	u8 auth_transaction;
+	struct p2p_device *dev;
+	struct pasn_data *pasn;
+	struct wpa_pasn_params_data pasn_data;
+
+	dev = p2p_get_device(p2p, (u8 *)mgmt->sa);
+	if (!dev) {
+		p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR,
+			MAC2STR(mgmt->sa));
+		return -1;
+	}
+
+	if (!dev->pasn) {
+		p2p_dbg(p2p, "P2P PASN: uninitialized");
+		return -1;
+	}
+
+	pasn = dev->pasn;
+
+	if (pasn->frame) {
+		wpabuf_free(pasn->frame);
+		pasn->frame = NULL;
+	}
+
+	pasn_register_callbacks(pasn, p2p->cfg->cb_ctx,
+				p2p->cfg->pasn_send_mgmt, NULL);
+	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+
+	if (dev->role == P2P_ROLE_PAIRING_INITIATOR && auth_transaction == 2) {
+		if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq,
+						   auth_transaction)) {
+			p2p_dbg(p2p, "P2P PASN Initiator: Handle Auth2 action wrapper failed");
+			return -1;
+		}
+		ret = wpa_pasn_auth_rx(pasn, (const u8 *)mgmt, len, &pasn_data);
+		forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
+
+		if (ret < 0) {
+			p2p_dbg(p2p, "P2P PASN: wpa_pasn_auth_rx failed");
+			dev->role = P2P_ROLE_IDLE;
+		}
+
+	} else {
+		ret = p2p_handle_pasn_auth(p2p, dev, mgmt, len, freq);
+	}
+	return ret;
+}
+#endif
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index c9bc12f..1b1c19f 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -372,6 +372,11 @@  struct p2p_pairing_config {
 
 	/* length of DevIK */
 	size_t dik_len;
+
+	/**
+	 * The set of supported PASN groups
+	 */
+	int pasn_groups[4];
 };
 
 
@@ -479,6 +484,36 @@  struct p2p_peer_info {
 	 * p2p_pairing_config - P2P Pairing configuration
 	 */
 	struct p2p_pairing_config pairing_config;
+
+	/**
+	 * cipher version for Device Identity key generation
+	 */
+	u8 dik_cipher_version;
+
+	/**
+	 * Device Identity key which is unique for a device
+	 */
+	u8 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN];
+
+	/**
+	 * Device Identity key length
+	 */
+	u16 dik_len;
+
+	/**
+	 * Device Identity key lifetime
+	 */
+	u32 dik_lifetime;
+
+	/**
+	 * password used during group formation post opportunistic pasn auth
+	 */
+	char password[100];
+
+	/**
+	 * password length. Non zero if valid
+	 */
+	u16 password_len;
 };
 
 enum p2p_prov_disc_status {
@@ -658,6 +693,16 @@  struct p2p_config {
 	unsigned int passphrase_len;
 
 	/**
+	 * password used during group formation post opportunistic pasn auth
+	 */
+	char dev_password[100];
+
+	/**
+	 * password length. Non zero if valid
+	 */
+	u16 dev_password_len;
+
+	/**
 	 * p2p_pairing_config - P2P Pairing configuration
 	 */
 	struct p2p_pairing_config pairing_config;
@@ -1269,6 +1314,38 @@  struct p2p_config {
 	 */
 	void (*bootstrap_completed)(void *ctx, const u8 *addr, int status,
 				    int freq);
+
+	/**
+	 * pasn_send_mgmt - Function handler to transmit a Management frame
+	 * @ctx: Callback context from cb_ctx
+	 * @data : Frame to transmit
+	 * @data_len: Length of frame to transmit
+	 * @noack : No ack flag
+	 * @freq: Frequency in MHz for the channel on which to transmit
+	 * @wait: How many milliseconds to wait for a response frame
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*pasn_send_mgmt)(void *ctx, const u8 *data, size_t data_len,
+			      int noack, unsigned int freq, unsigned int wait);
+
+	/**
+	 * pasn_update_extra_ies - Function handler to update protocol specific
+	 *	IEs in pasn auth frames
+	 * @ctx: Callback context from cb_ctx
+	 * @peer_addr : peer mac address
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*pasn_update_extra_ies)(void *ctx, const u8 *peer_addr);
+
+	/**
+	 * pasn_parse_encrypted_data - Function handler to parse encrypted data
+	 *	with KEK received in pasn auth frames
+	 * @ctx: Callback context from cb_ctx
+	 * @data : data to be decrypted
+	 * @len: length of encrypted data
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*pasn_parse_encrypted_data)(void *ctx, const u8 *data, size_t len);
 };
 
 
@@ -2571,4 +2648,12 @@  int p2p_channel_to_freq(int op_class, int channel);
 struct wpabuf * p2p_usd_elems(struct p2p_data *p2p);
 void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
 			   const u8 *peer_addr, unsigned int freq);
+int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq);
+int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt,
+		     size_t len, int freq);
+int p2p_pasn_update_extra_ies(struct p2p_data *p2p, const u8 *peer_addr);
+int p2p_pasn_parse_encrypted_data(struct p2p_data *p2p, const u8 *data,
+				  size_t len);
+int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
+			    size_t data_len, u8 acked);
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 5798018..1f6923d 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -135,8 +135,8 @@  static const char * p2p_wps_method_str(enum p2p_wps_method wps_method)
 }
 
 
-static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
-					    struct p2p_device *peer)
+struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
+				     struct p2p_device *peer)
 {
 	u8 group_capab;
 	size_t extra = 0;
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index d7a5dc1..e0d2ee0 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -37,6 +37,13 @@  enum p2p_go_state {
 };
 
 
+/* Enumeration for P2P device current role */
+enum p2p_role {
+	P2P_ROLE_IDLE = 0,
+	P2P_ROLE_PAIRING_INITIATOR,
+	P2P_ROLE_PAIRING_RESPONDER,
+};
+
 /**
  * struct bootstrap_params - P2P Device bootstrap request params
  */
@@ -188,6 +195,12 @@  struct p2p_device {
 	 * password length. Non zero if valid
 	 */
 	u16 password_len;
+
+	/* pasn data structure */
+	struct pasn_data *pasn;
+
+	/* device role */
+	enum p2p_role role;
 };
 
 struct p2p_sd_query {
@@ -630,6 +643,10 @@  struct p2p_data {
 	bool allow_6ghz;
 
 	struct p2p_pairing_info *pairing_info;
+	/*p2p pairing initiator pmksa cache list */
+	struct rsn_pmksa_cache *initiator_pmksa;
+	/* p2p pairing responder pmksa cache list */
+	struct rsn_pmksa_cache *responder_pmksa;
 	/**
 	 * go_neg_resp - GO Negotiation Response frame
 	 */
@@ -761,6 +778,12 @@  struct p2p_message {
 
 	const u8 *pbma_info;
 	size_t pbma_info_len;
+
+	const u8 *action_frame_wrapper;
+	size_t action_frame_wrapper_len;
+
+	const u8 *dira;
+	size_t dira_len;
 };
 
 
@@ -919,6 +942,8 @@  void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
 int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev);
 
 /* p2p_go_neg.c */
+struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
+				     struct p2p_device *peer);
 int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
 			    struct p2p_device *dev,
 			    const u8 *channel_list, size_t channel_list_len);
@@ -1021,6 +1046,8 @@  void p2p_pref_channel_filter(const struct p2p_channels *a,
 			     struct p2p_channels *res, bool go);
 
 void p2p_sd_query_cb(struct p2p_data *p2p, int success);
+void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev,
+			 const u8 *addr, int freq, bool verify);
 
 void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
 PRINTF_FORMAT(2, 3);
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index a70e180..de2a43f 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -437,6 +437,26 @@  static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
 		msg->pbma_info_len = len;
 		wpa_printf(MSG_DEBUG, "P2P: * PBMA (length=%u)", len);
 		break;
+	case P2P_ATTR_ACTION_FRAME_WRAPPER:
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "P2P: Too short Action frame (length %d)",
+				   len);
+			return -1;
+		}
+		msg->action_frame_wrapper = data;
+		msg->action_frame_wrapper_len = len;
+		wpa_printf(MSG_DEBUG, "P2P: * Action frame wrapper (length=%u)", len);
+		break;
+	case P2P_ATTR_DEVICE_IDENTITY_RESOLUTION:
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "P2P: Too short DIRA (length %d)",
+				   len);
+			return -1;
+		}
+		msg->dira = data;
+		msg->dira_len = len;
+		wpa_printf(MSG_DEBUG, "P2P: * DIRA (length=%u)", len);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
 			   "(length %d)", id, len);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 56022ff..f1856d2 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -824,6 +824,12 @@  static void p2p_process_prov_disc_bootstrap_req(struct p2p_data *p2p,
 
 	wpa_printf(MSG_ERROR, "Bootstrap received %d", bootstrap);
 
+	if (status == P2P_SC_SUCCESS) {
+		dev->role = P2P_ROLE_PAIRING_RESPONDER;
+#ifdef CONFIG_PASN
+		p2p_pasn_initialize(p2p, dev, sa, rx_freq, false);
+#endif /* CONFIG_PASN */
+	}
 out:
 	/*
 	 * Send PD Bootstrapping Response for the PD Request
diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h
index e3ff746..8eb3bce 100644
--- a/src/pasn/pasn_common.h
+++ b/src/pasn/pasn_common.h
@@ -55,6 +55,7 @@  struct pasn_data {
 	int rsn_pairwise;
 	u16 rsnxe_capab;
 	const u8 *rsnxe_ie;
+	size_t rsnxe_ie_len;
 	bool custom_pmkid_valid;
 	u8 custom_pmkid[PMKID_LEN];
 
@@ -130,6 +131,8 @@  struct pasn_data {
 	struct os_reltime last_comeback_key_update;
 	u16 comeback_idx;
 	u16 *comeback_pending_idx;
+	struct wpabuf *action_frame_wrapper;
+	struct wpabuf *frame;
 
 	/**
 	 * send_mgmt - Function handler to transmit a Management frame
@@ -151,6 +154,10 @@  struct pasn_data {
 	 */
 	int (*validate_custom_pmkid)(void *ctx, const u8 *addr,
 				     const u8 *pmkid);
+
+	int (*update_extra_ies)(void *ctx, const u8 *peer_addr);
+
+	int (*parse_encrypted_data)(void *ctx, const u8 *data, size_t len);
 };
 
 /* Initiator */
diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c
index dbcc91a..9d97895 100644
--- a/src/pasn/pasn_initiator.c
+++ b/src/pasn/pasn_initiator.c
@@ -646,7 +646,10 @@  static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn,
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
 
-	wpa_pasn_add_rsnxe(buf, pasn->rsnxe_capab);
+	if (pasn->rsnxe_ie)
+		wpabuf_put_data(buf, pasn->rsnxe_ie, pasn->rsnxe_ie_len);
+	else
+		wpa_pasn_add_rsnxe(buf, pasn->rsnxe_capab);
 
 	wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
 
@@ -675,11 +678,13 @@  fail:
 }
 
 
-static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn)
+static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn,
+					      const u8 *mgmt, size_t len)
 {
 	struct wpabuf *buf, *wrapped_data_buf = NULL;
 	u8 mic[WPA_PASN_MAX_MIC_LEN];
-	u8 mic_len, data_len;
+	u8 mic_len;
+	size_t data_len;
 	const u8 *data;
 	u8 *ptr;
 	u8 wrapped_data;
@@ -713,6 +718,11 @@  static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn)
 	wpabuf_free(wrapped_data_buf);
 	wrapped_data_buf = NULL;
 
+	if (pasn->update_extra_ies && pasn->cb_ctx)
+		pasn->update_extra_ies(pasn->cb_ctx, pasn->peer_addr);
+
+	wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
+
 	/* Add the MIC */
 	mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
 	wpabuf_put_u8(buf, WLAN_EID_MIC);
@@ -806,13 +816,25 @@  void wpa_pasn_reset(struct pasn_data *pasn)
 	pasn->derive_kdk = false;
 	pasn->rsn_ie = NULL;
 	pasn->rsn_ie_len = 0;
-	pasn->rsnxe_ie = NULL;
 	pasn->custom_pmkid_valid = false;
 
+	if (pasn->rsnxe_ie) {
+		os_free((u8 *)pasn->rsnxe_ie);
+		pasn->rsnxe_ie = NULL;
+		pasn->rsnxe_ie_len = 0;
+	}
 	if (pasn->extra_ies) {
 		os_free((u8 *) pasn->extra_ies);
 		pasn->extra_ies = NULL;
 	}
+	if (pasn->action_frame_wrapper) {
+		wpabuf_free(pasn->action_frame_wrapper);
+		pasn->action_frame_wrapper = NULL;
+	}
+	if (pasn->frame) {
+		wpabuf_free(pasn->frame);
+		pasn->frame = NULL;
+	}
 }
 
 
@@ -982,17 +1004,21 @@  static int wpas_pasn_send_auth_1(struct pasn_data *pasn, const u8 *own_addr,
 		wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
 		goto fail;
 	}
+	if (pasn->frame) {
+		wpabuf_free(pasn->frame);
+		pasn->frame = NULL;
+	}
 
 	ret = pasn->send_mgmt(pasn->cb_ctx,
 			      wpabuf_head(frame), wpabuf_len(frame), 0,
 			      pasn->freq, 1000);
 
-	wpabuf_free(frame);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed sending 1st auth frame");
+		wpabuf_free(frame);
 		goto fail;
 	}
-
+	pasn->frame = frame;
 	return 0;
 
 fail:
@@ -1382,21 +1408,29 @@  int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
 
 	wpa_printf(MSG_DEBUG, "PASN: Success verifying Authentication frame");
 
-	frame = wpas_pasn_build_auth_3(pasn);
+	if (pasn->parse_encrypted_data && pasn->cb_ctx)
+		pasn->parse_encrypted_data(pasn->cb_ctx, data, len);
+
+	frame = wpas_pasn_build_auth_3(pasn, data, len);
 	if (!frame) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed building 3rd auth frame");
 		goto fail;
 	}
+	if (pasn->frame) {
+		wpabuf_free(pasn->frame);
+		pasn->frame = NULL;
+	}
 
 	ret = pasn->send_mgmt(pasn->cb_ctx,
 			      wpabuf_head(frame), wpabuf_len(frame), 0,
 			      pasn->freq, 100);
-	wpabuf_free(frame);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed sending 3st auth frame");
+		wpabuf_free(frame);
 		goto fail;
 	}
 
+	pasn->frame = frame;
 	wpa_printf(MSG_DEBUG, "PASN: Success sending last frame. Store PTK");
 
 	pasn->status = WLAN_STATUS_SUCCESS;
diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c
index c75ba87..e5216a0 100644
--- a/src/pasn/pasn_responder.c
+++ b/src/pasn/pasn_responder.c
@@ -473,7 +473,7 @@  static void handle_auth_pasn_comeback(struct pasn_data *pasn,
 		   "PASN: comeback: STA=" MACSTR, MAC2STR(peer_addr));
 
 	ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
-			      wpabuf_len(buf), 0, 0, 0);
+			      wpabuf_len(buf), 0, pasn->freq, 0);
 	if (ret)
 		wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
 
@@ -561,6 +561,9 @@  int handle_auth_pasn_resp(struct pasn_data *pasn, const u8 *own_addr,
 	if (rsnxe_ie)
 		wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
 
+	if (pasn->update_extra_ies && pasn->cb_ctx)
+		pasn->update_extra_ies(pasn->cb_ctx, peer_addr);
+
 	wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
 
 	/* Add the mic */
@@ -636,14 +639,20 @@  done:
 	wpa_printf(MSG_DEBUG,
 		   "PASN: Building frame 2: success; resp STA=" MACSTR,
 		   MAC2STR(peer_addr));
+	if (pasn->frame) {
+		wpabuf_free(pasn->frame);
+		pasn->frame = NULL;
+	}
 
 	ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
-			      wpabuf_len(buf), 0, 0, 0);
-	if (ret)
+			      wpabuf_len(buf), 0, pasn->freq, 0);
+	if (ret) {
 		wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
+		goto fail;
+	}
 
 	wpabuf_free(rsn_buf);
-	wpabuf_free(buf);
+	pasn->frame = buf;
 	return ret;
 fail:
 	wpabuf_free(wrapped_data_buf);
@@ -1079,6 +1088,9 @@  int handle_auth_pasn_3(struct pasn_data *pasn, const u8 *own_addr,
 		wpabuf_free(wrapped_data);
 	}
 
+	if (pasn->parse_encrypted_data && pasn->cb_ctx)
+		pasn->parse_encrypted_data(pasn->cb_ctx, (const u8 *) mgmt, len);
+
 	wpa_printf(MSG_INFO,
 		   "PASN: Success handling transaction == 3. Store PTK");
 	return 0;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 46e7cf1..1c7992e 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -6093,6 +6093,37 @@  static void wpas_link_reconfig(struct wpa_supplicant *wpa_s)
 }
 
 
+#ifdef CONFIG_PASN
+int wpas_pasn_auth(struct wpa_supplicant *wpa_s,
+		   const struct ieee80211_mgmt *mgmt, size_t len, int freq)
+{
+	int ret = 0;
+	struct ieee802_11_elems elems;
+
+	if (len < 24) {
+		wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
+		return -2;
+	}
+
+	if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+				   len - offsetof(struct ieee80211_mgmt,
+						  u.auth.variable),
+				   &elems, 1) == ParseFailed) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Failed parsing Authentication frame");
+		return -2;
+	}
+
+	if (!elems.p2p2_ie || !elems.p2p2_ie_len)
+		ret = wpas_pasn_auth_rx(wpa_s, mgmt, len);
+	else
+		ret = wpas_p2p_pasn_auth_rx(wpa_s, mgmt, len, freq);
+
+	return ret;
+}
+#endif /* CONFIG_PASN */
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -6323,11 +6354,22 @@  void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #endif /* CONFIG_WNM */
 #ifdef CONFIG_PASN
 		if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
-		    data->tx_status.stype == WLAN_FC_STYPE_AUTH &&
-		    wpas_pasn_auth_tx_status(wpa_s, data->tx_status.data,
-					     data->tx_status.data_len,
-					     data->tx_status.ack) == 0)
-			break;
+		    data->tx_status.stype == WLAN_FC_STYPE_AUTH) {
+			if (!wpa_s->pasn_auth_work &&
+			    wpa_s->p2p_pasn_auth_work) {
+				if (wpas_p2p_pasn_auth_tx_status(wpa_s,
+						data->tx_status.data,
+						data->tx_status.data_len,
+						data->tx_status.ack) == 0)
+					break;
+			} else {
+				if (wpas_pasn_auth_tx_status(wpa_s,
+						data->tx_status.data,
+						data->tx_status.data_len,
+						data->tx_status.ack) == 0)
+					break;
+			}
+		}
 #endif /* CONFIG_PASN */
 #ifdef CONFIG_AP
 		if (wpa_s->ap_iface == NULL) {
@@ -6599,8 +6641,8 @@  void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			}
 #ifdef CONFIG_PASN
 			if (stype == WLAN_FC_STYPE_AUTH &&
-			    wpas_pasn_auth_rx(wpa_s, mgmt,
-					      data->rx_mgmt.frame_len) != -2)
+			    wpas_pasn_auth(wpa_s, mgmt, data->rx_mgmt.frame_len,
+					   data->rx_mgmt.freq) != -2)
 				break;
 #endif /* CONFIG_PASN */
 
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 6e7cf8f..0cffb99 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -40,6 +40,7 @@ 
 #include "crypto/random.h"
 
 
+
 /*
  * How many times to try to scan to find the GO before giving up on join
  * request.
@@ -165,7 +166,10 @@  wpas_p2p_consider_moving_gos(struct wpa_supplicant *wpa_s,
 static void wpas_p2p_reconsider_moving_go(void *eloop_ctx, void *timeout_ctx);
 static int wpas_p2p_disallowed_freq(struct wpa_global *global,
 				    unsigned int freq);
-
+#ifdef CONFIG_PASN
+static int wpas_p2p_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+				       const u8 *peer_addr, int freq);
+#endif /* CONFIG_PASN */
 
 static int wpas_get_6ghz_he_chwidth_capab(struct hostapd_hw_modes *mode)
 {
@@ -1717,6 +1721,29 @@  static void wpas_send_action_done(void *ctx)
 	offchannel_send_action_done(wpa_s);
 }
 
+#ifdef CONFIG_PASN
+struct wpa_p2p_pasn_auth_work {
+	u8 peer_addr[ETH_ALEN];
+	bool verify;
+	int freq;
+};
+
+
+static void wpas_p2p_pasn_free_auth_work(struct wpa_p2p_pasn_auth_work *awork)
+{
+	os_free(awork);
+}
+
+
+static void wpas_p2p_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
+{
+	wpa_printf(MSG_DEBUG, "P2P PASN: Cancel p2p-pasn-start-auth work");
+
+	/* Remove pending/started work */
+	radio_remove_works(wpa_s, "p2p-pasn-start-auth", 0);
+}
+#endif /* CONFIG_PASN */
+
 
 static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
 				    struct p2p_go_neg_results *params)
@@ -2392,6 +2419,12 @@  static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
 					     void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
+#ifdef CONFIG_PASN
+	if (wpa_s->p2p_pasn_auth_work) {
+		wpas_p2p_pasn_cancel_auth_work(wpa_s);
+		wpa_s->p2p_pasn_auth_work = NULL;
+	}
+#endif /* CONFIG_PASN */
 	wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
 	wpas_p2p_group_formation_failed(wpa_s, 0);
 }
@@ -2456,6 +2489,12 @@  static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 		wpa_s->off_channel_freq = 0;
 		wpa_s->roc_waiting_drv_freq = 0;
 	}
+#ifdef CONFIG_PASN
+	if (wpa_s->p2p_pasn_auth_work) {
+		wpas_p2p_pasn_cancel_auth_work(wpa_s);
+		wpa_s->p2p_pasn_auth_work = NULL;
+	}
+#endif /* CONFIG_PASN */
 
 	if (res->status) {
 		wpa_msg_global(wpa_s, MSG_INFO,
@@ -4888,8 +4927,109 @@  static void wpas_bootstrap_completed(void *ctx, const u8 *addr, int status,
 
 	if (status)
 		return;
+#ifdef CONFIG_PASN
+	wpas_p2p_initiate_pasn_auth(wpa_s, addr, freq);
+#endif /* CONFIG_PASN */
+}
+
+#ifdef CONFIG_PASN
+static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
+{
+	struct wpa_supplicant *wpa_s = work->wpa_s;
+	struct wpa_p2p_pasn_auth_work *awork = work->ctx;
+	struct p2p_data *p2p = wpa_s->global->p2p;
+	const u8 *peer_addr = NULL;
+
+	if (deinit) {
+		if (!work->started) {
+			eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+					     wpa_s->p2pdev, NULL);
+		}
+		os_free(awork);
+		return;
+	}
+
+	if (!is_zero_ether_addr(awork->peer_addr))
+		peer_addr = awork->peer_addr;
+	if (p2p_initiate_pasn_auth(p2p, peer_addr, awork->freq)) {
+		wpa_printf(MSG_DEBUG,
+			   "P2P PASN: Failed to start PASN authentication");
+		goto fail;
+	}
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+			     wpa_s->p2pdev, NULL);
+	eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+			       wpas_p2p_group_formation_timeout,
+			       wpa_s->p2pdev, NULL);
+	wpa_s->p2p_pasn_auth_work = work;
+	return;
+fail:
+	wpas_p2p_pasn_free_auth_work(awork);
+	work->ctx = NULL;
+	radio_work_done(work);
 }
 
+static int wpas_p2p_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+				       const u8 *peer_addr, int freq)
+{
+	struct wpa_p2p_pasn_auth_work *awork;
+
+	wpas_p2p_pasn_cancel_auth_work(wpa_s);
+	wpa_s->p2p_pasn_auth_work = NULL;
+
+	awork = os_zalloc(sizeof(*awork));
+	if (!awork)
+		return -1;
+
+	awork->freq = freq;
+	os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN);
+
+	if (radio_add_work(wpa_s, freq, "p2p-pasn-start-auth", 1,
+			   wpas_p2p_pasn_auth_start_cb, awork) < 0) {
+		wpas_p2p_pasn_free_auth_work(awork);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P PASN: Auth work successfully added");
+	return 0;
+}
+
+static int wpas_p2p_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
+				   int noack, unsigned int freq,
+				   unsigned int wait)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait);
+}
+
+
+static int wpas_p2p_pasn_update_extra_ies(void *ctx, const u8 *peer_addr)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct p2p_data *p2p = wpa_s->global->p2p;
+
+	return p2p_pasn_update_extra_ies(p2p, peer_addr);
+}
+
+
+static int wpas_p2p_pasn_parse_encrypted_data(void *ctx, const u8 *data,
+					      size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct p2p_data *p2p = wpa_s->global->p2p;
+
+	return p2p_pasn_parse_encrypted_data(p2p, data, len);
+}
+
+int wpas_p2p_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data,
+				 size_t data_len, u8 acked)
+{
+	struct p2p_data *p2p = wpa_s->global->p2p;
+
+	return p2p_pasn_auth_tx_status(p2p, data, data_len, acked);
+}
+#endif
 
 int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
 {
@@ -5013,7 +5153,11 @@  int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
 	p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback;
 	p2p.bootstrap_req_rx = wpas_bootstrap_req_rx;
 	p2p.bootstrap_completed = wpas_bootstrap_completed;
-
+#ifdef CONFIG_PASN
+	p2p.pasn_send_mgmt = wpas_p2p_pasn_send_mlme;
+	p2p.pasn_update_extra_ies = wpas_p2p_pasn_update_extra_ies;
+	p2p.pasn_parse_encrypted_data = wpas_p2p_pasn_parse_encrypted_data;
+#endif /* CONFIG_PASN */
 	os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
 	os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
 	p2p.dev_name = wpa_s->conf->device_name;
@@ -10383,3 +10527,16 @@  void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
 		return;
 	p2p_process_usd_elems(p2p, buf, buf_len, peer_addr, freq);
 }
+
+#ifdef CONFIG_PASN
+int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+			  const struct ieee80211_mgmt *mgmt, size_t len,
+			  int freq)
+{
+	struct p2p_data *p2p = wpa_s->global->p2p;
+
+	if (wpa_s->global->p2p_disabled || !p2p)
+		return -2;
+	return p2p_pasn_auth_rx(p2p, mgmt, len, freq);
+}
+#endif /* CONFIG_PASN */
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index a2cb78d..5612d83 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -227,7 +227,9 @@  int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
 int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
 int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s);
 struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s);
-
+int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+			  const struct ieee80211_mgmt *mgmt, size_t len,
+			  int freq);
 #else /* CONFIG_P2P */
 
 static inline int
@@ -358,6 +360,13 @@  static inline struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s)
 	return NULL;
 }
 
+static inline int
+wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+		      const struct ieee80211_mgmt *mgmt, size_t len, int freq)
+{
+	return 0;
+}
+
 #endif /* CONFIG_P2P */
 
 #endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index 89edad4..f4a3bb2 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -806,6 +806,11 @@  int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 	if (!wpa_s->pasn_auth_work)
 		return -2;
 
+	if (pasn->frame) {
+		wpabuf_free(pasn->frame);
+		pasn->frame = NULL;
+	}
+
 	pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
 	ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data);
 	if (ret == 0) {
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 35f541f..51da6ff 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1593,6 +1593,9 @@  struct wpa_supplicant {
 	struct wpa_radio_work *pasn_auth_work;
 	unsigned int pasn_count;
 	struct pasn_auth *pasn_params;
+#ifdef CONFIG_P2P
+	struct wpa_radio_work *p2p_pasn_auth_work;
+#endif /* CONFIG_P2P */
 #endif /* CONFIG_PASN */
 
 	bool is_6ghz_enabled;
@@ -2028,5 +2031,7 @@  int wpas_get_owe_trans_network(const u8 *owe_ie, const u8 **bssid,
 void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
 				u16 buf_len, const u8 *peer_addr,
 				unsigned int freq);
+int wpas_p2p_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data,
+				 size_t data_len, u8 acked);
 
 #endif /* WPA_SUPPLICANT_I_H */