diff mbox series

[v3,19/25] p2p: Add support for Invitation using pairing verification

Message ID 1722850403-8852-20-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
Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
---
 src/p2p/p2p.c                               | 124 +++++++++++++++++++-
 src/p2p/p2p.h                               |  18 ++-
 src/p2p/p2p_i.h                             |  16 ++-
 src/p2p/p2p_invitation.c                    | 100 ++++++++++++++--
 wpa_supplicant/ctrl_iface.c                 |  12 +-
 wpa_supplicant/dbus/dbus_new_handlers_p2p.c |   8 +-
 wpa_supplicant/p2p_supplicant.c             | 175 +++++++++++++++++++++++++---
 wpa_supplicant/p2p_supplicant.h             |   6 +-
 8 files changed, 415 insertions(+), 44 deletions(-)
diff mbox series

Patch

diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 8f3d76e..702c90a 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -3996,7 +3996,7 @@  void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
 		p2p_invitation_req_cb(p2p, success);
 		break;
 	case P2P_PENDING_INVITATION_RESPONSE:
-		p2p_invitation_resp_cb(p2p, success);
+		p2p_invitation_resp_cb(p2p, dst, success);
 		break;
 	case P2P_PENDING_DEV_DISC_REQUEST:
 		p2p_dev_disc_req_cb(p2p, success);
@@ -4296,7 +4296,7 @@  static void p2p_timeout_invite_listen(struct p2p_data *p2p)
 				p2p->cfg->invitation_result(
 					p2p->cfg->cb_ctx, -1, NULL, NULL,
 					p2p->invite_peer->info.p2p_device_addr,
-					0, 0);
+					0, 0, NULL, NULL, 0);
 		}
 		p2p_set_state(p2p, P2P_IDLE);
 	}
@@ -6206,6 +6206,117 @@  void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev,
 	pasn->freq = freq;
 }
 
+int get_listen_freq(struct p2p_data *p2p, const u8 *peer_addr)
+{
+	int freq;
+	struct p2p_device *dev;
+
+	if (!peer_addr) {
+		p2p_dbg(p2p, "peer address NULL");
+		return -1;
+	}
+
+	dev = p2p_get_device(p2p, peer_addr);
+	if (!dev) {
+		p2p_dbg(p2p, "Peer not known");
+		return -1;
+	}
+
+	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+	if (freq <= 0)
+		freq = dev->oob_go_neg_freq;
+	if (freq <= 0) {
+		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+			MACSTR, MAC2STR(dev->info.p2p_device_addr));
+		return -1;
+	}
+	return freq;
+}
+
+int p2p_initiate_pasn_verify(struct p2p_data *p2p, const u8 *peer_addr,
+			     int freq, enum p2p_invite_role role,
+			     const u8 *bssid, const u8 *ssid, size_t ssid_len,
+			     unsigned int force_freq, const u8 *go_dev_addr,
+			     unsigned int pref_freq)
+{
+	struct pasn_data *pasn;
+	struct p2p_device *dev;
+	struct wpabuf *extra_ies, *req;
+	int ret = 0;
+
+	if (!peer_addr) {
+		p2p_dbg(p2p, "peer address NULL");
+		return -1;
+	}
+
+	dev = p2p_get_device(p2p, peer_addr);
+	if (!dev) {
+		p2p_dbg(p2p, "Peer not known");
+		return -1;
+	}
+
+	if (p2p_invite(p2p, peer_addr, role, bssid, ssid, ssid_len, force_freq,
+		       go_dev_addr, 1, pref_freq, -1, 1)) {
+		p2p_dbg(p2p, "p2p_invite failed");
+		return -1;
+	}
+
+	dev->role = P2P_ROLE_PAIRING_INITIATOR;
+	p2p_pasn_initialize(p2p, dev, peer_addr, freq, true);
+	pasn = dev->pasn;
+
+	req = p2p_build_invitation_req(p2p, dev, go_dev_addr, -1);
+	if (!req)
+		return -1;
+
+	p2p_set_state(p2p, P2P_INVITE);
+	p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST;
+	p2p->invite_peer = dev;
+	dev->invitation_reqs++;
+
+	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 Verify */
+	if (wpa_pasn_verify(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 verify failed");
+		ret = -1;
+	} else {
+		dev->flags |= P2P_DEV_WAIT_INV_REQ_ACK;
+	}
+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_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq)
 {
@@ -6370,7 +6481,8 @@  int p2p_pasn_handle_action_wrapper(struct p2p_data *p2p,
 			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_invitation_resp_cb(p2p, mgmt->sa,
+					       P2P_SEND_ACTION_SUCCESS);
 		}
 	}
 	p2p_parse_free(&msg);
@@ -6631,7 +6743,7 @@  done:
 }
 
 int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
-			    size_t data_len, u8 acked)
+			    size_t data_len, u8 acked, bool verify)
 {
 	int ret = 0;
 	struct p2p_device *dev;
@@ -6664,7 +6776,9 @@  int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
 	if (ret != 1)
 		return ret;
 
-	if (dev == p2p->go_neg_peer)
+	if (verify && dev == p2p->invite_peer)
+		p2p_start_invitation_connect(p2p, dev);
+	else if (dev == p2p->go_neg_peer)
 		p2p_go_complete(p2p, dev);
 
 	return 0;
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 65e2e0d..4759947 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1127,7 +1127,8 @@  struct p2p_config {
 	void (*invitation_received)(void *ctx, const u8 *sa, const u8 *bssid,
 				    const u8 *ssid, size_t ssid_len,
 				    const u8 *go_dev_addr, u8 status,
-				    int op_freq);
+				    int op_freq, u8 *pmkid, u8 *pmk,
+				    size_t pmk_len);
 
 	/**
 	 * invitation_result - Callback on Invitation result
@@ -1148,7 +1149,8 @@  struct p2p_config {
 	 */
 	void (*invitation_result)(void *ctx, int status, const u8 *bssid,
 				  const struct p2p_channels *channels,
-				  const u8 *addr, int freq, int peer_oper_freq);
+				  const u8 *addr, int freq, int peer_oper_freq,
+				  u8 *pmkid, u8 *pmk, size_t pmk_len);
 
 	/**
 	 * go_connected - Check whether we are connected to a GO
@@ -1693,12 +1695,14 @@  enum p2p_invite_role {
  *	force_freq == 0)
  * @dev_pw_id: Device Password ID from OOB Device Password (NFC) static handover
  *	case or -1 if not used
+ * @p2p2: Operating in p2p2 mode
  * Returns: 0 on success, -1 on failure
  */
 int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
 	       const u8 *bssid, const u8 *ssid, size_t ssid_len,
 	       unsigned int force_freq, const u8 *go_dev_addr,
-	       int persistent_group, unsigned int pref_freq, int dev_pw_id);
+	       int persistent_group, unsigned int pref_freq, int dev_pw_id,
+	       bool p2p2);
 
 /**
  * p2p_presence_req - Request GO presence
@@ -2675,12 +2679,18 @@  void p2p_set_comeback_after(struct p2p_data *p2p, int comeback_after);
 void p2p_set_reg_info(struct p2p_data *p2p, u8 val);
 void p2p_set_twt_power_mgmt(struct p2p_data *p2p, int val);
 
+int get_listen_freq(struct p2p_data *p2p, const u8 *peer_addr);
 int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq);
+int p2p_initiate_pasn_verify(struct p2p_data *p2p, const u8 *peer_addr,
+			     int freq, enum p2p_invite_role role,
+			     const u8 *bssid, const u8 *ssid, size_t ssid_len,
+			     unsigned int force_freq, const u8 *go_dev_addr,
+			     unsigned int pref_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);
+			    size_t data_len, u8 acked, bool verify);
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 440ed1f..7ff2c97 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -201,6 +201,16 @@  struct p2p_device {
 
 	/* device role */
 	enum p2p_role role;
+
+	/**
+	 * Invitation params for P2P2
+	 */
+	u8 inv_reject;
+	u8 inv_status;
+	int inv_freq;
+	int inv_peer_oper_freq;
+	u8 inv_bssid[ETH_ALEN];
+	struct p2p_channels *inv_channels;
 };
 
 struct p2p_sd_query {
@@ -979,6 +989,9 @@  void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
 		      struct p2p_device *dev);
 
 /* p2p_invitation.c */
+struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
+					 struct p2p_device *peer,
+					 const u8 *go_dev_addr, int dev_pw_id);
 void p2p_handle_invitation_req(struct p2p_data *p2p, const u8 *sa,
 			       const u8 *data, size_t len, int rx_freq);
 void p2p_handle_invitation_resp(struct p2p_data *p2p, const u8 *sa,
@@ -990,7 +1003,8 @@  void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
 int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
 		    const u8 *go_dev_addr, int dev_pw_id);
 void p2p_invitation_req_cb(struct p2p_data *p2p, int success);
-void p2p_invitation_resp_cb(struct p2p_data *p2p, int success);
+void p2p_invitation_resp_cb(struct p2p_data *p2p, const u8 *dst, int success);
+void p2p_start_invitation_connect(struct p2p_data *p2p, struct p2p_device *dev);
 
 /* p2p_dev_disc.c */
 void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 8ade838..19785d4 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -13,12 +13,15 @@ 
 #include "common/wpa_ctrl.h"
 #include "p2p_i.h"
 #include "p2p.h"
+#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "common/sae.h"
+#include "pasn/pasn_common.h"
 
 
-static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
-						struct p2p_device *peer,
-						const u8 *go_dev_addr,
-						int dev_pw_id)
+struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
+					 struct p2p_device *peer,
+					 const u8 *go_dev_addr, int dev_pw_id)
 {
 	struct wpabuf *buf;
 	u8 *len;
@@ -100,7 +103,7 @@  static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
 		wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
 
-	if (dev_pw_id >= 0) {
+	if (dev_pw_id >= 0 && !peer->p2p2) {
 		/* WSC IE in Invitation Request for NFC static handover */
 		p2p_build_wps_ie(p2p, buf, dev_pw_id, 0);
 	}
@@ -120,6 +123,7 @@  static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
 	u8 *len;
 	size_t extra = 0;
 
+	p2p_dbg(p2p, "Building Invitation Response ");
 #ifdef CONFIG_WIFI_DISPLAY
 	struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
 	if (wfd_ie && group_bssid) {
@@ -453,6 +457,7 @@  void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
 	struct p2p_device *dev;
 	struct p2p_message msg;
 	struct p2p_channels intersection, *channels = NULL;
+	struct p2p_channels *p2p2_channels = NULL;
 
 	p2p_dbg(p2p, "Received Invitation Response from " MACSTR,
 		MAC2STR(sa));
@@ -532,14 +537,17 @@  void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
 #endif /* CONFIG_P2P_STRICT */
 		/* Try to survive without peer channel list */
 		channels = &p2p->channels;
+		p2p2_channels = channels;
 	} else if (!msg.channel_list) {
 		/* Non-success cases are not required to include Channel List */
 		channels = &p2p->channels;
+		p2p2_channels = channels;
 	} else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
 					   msg.channel_list,
 					   msg.channel_list_len) < 0) {
 		p2p_dbg(p2p, "No common channels found");
 		p2p_parse_free(&msg);
+		dev->inv_reject = 1;
 		return;
 	} else {
 		p2p_channels_intersect(&p2p->channels, &dev->channels,
@@ -547,6 +555,7 @@  void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
 		channels = &intersection;
 	}
 
+
 	if (p2p->cfg->invitation_result) {
 		int peer_oper_freq = 0;
 		int freq = p2p_channel_to_freq(p2p->op_reg_class,
@@ -568,18 +577,70 @@  void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
 		 */
 		p2p_check_pref_chan(p2p, 0, dev, &msg);
 
+		if (dev->p2p2) {
+			dev->inv_freq = freq;
+			dev->inv_status = *msg.status;
+			dev->inv_channels = p2p2_channels;
+			dev->inv_peer_oper_freq = peer_oper_freq;
+			if (msg.group_bssid)
+				os_memcpy(dev->inv_bssid, msg.group_bssid, ETH_ALEN);
+			goto out;
+		}
+
 		p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
 					    msg.group_bssid, channels, sa,
-					    freq, peer_oper_freq);
+					    freq, peer_oper_freq, NULL, NULL,
+					    0);
 	}
 
+	p2p_clear_timeout(p2p);
+	p2p_set_state(p2p, P2P_IDLE);
+	p2p->invite_peer = NULL;
+
+out:
 	p2p_parse_free(&msg);
+}
+
+
+#ifdef CONFIG_PASN
+void p2p_start_invitation_connect(struct p2p_data *p2p, struct p2p_device *dev)
+{
+	size_t pmk_len = 0;
+	u8 pmkid[PMKID_LEN];
+	u8 pmk[PMK_LEN_MAX];
+	struct p2p_channels intersection;
+
+	if (!p2p || !dev || dev->inv_reject || !dev->pasn)
+		return;
+
+	if (!dev->inv_channels) {
+		p2p_channels_intersect(&p2p->channels, &dev->channels,
+				       &intersection);
+		dev->inv_channels = &intersection;
+	}
+
+	pasn_initiator_pmksa_cache_get(dev->pasn->pmksa, dev->pasn->peer_addr,
+				       pmkid, pmk, &pmk_len);
+
+	wpa_pasn_reset(dev->pasn);
+	p2p_dbg(p2p, "P2P Invitation connect: msg status %d", dev->inv_status);
+	if (p2p->cfg->invitation_result)
+		p2p->cfg->invitation_result(p2p->cfg->cb_ctx, dev->inv_status,
+					    dev->inv_bssid, dev->inv_channels,
+					    dev->info.p2p_device_addr,
+					    dev->inv_freq,
+					    dev->inv_peer_oper_freq, pmkid,
+					    pmk, pmk_len);
+
+	/* Reset pmk and pmkid from RAM */
+	memset(pmkid, 0, sizeof(pmkid));
+	memset(pmk, 0, sizeof(pmk));
 
 	p2p_clear_timeout(p2p);
 	p2p_set_state(p2p, P2P_IDLE);
 	p2p->invite_peer = NULL;
 }
-
+#endif /* CONFIG_PASN */
 
 int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
 		    const u8 *go_dev_addr, int dev_pw_id)
@@ -649,8 +710,19 @@  void p2p_invitation_req_cb(struct p2p_data *p2p, int success)
 }
 
 
-void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
+void p2p_invitation_resp_cb(struct p2p_data *p2p, const u8 *peer, int success)
 {
+	size_t pmk_len = 0;
+	u8 pmkid[PMKID_LEN];
+	u8 pmk[PMK_LEN_MAX];
+	struct p2p_device *dev;
+
+	dev = p2p_get_device(p2p, peer);
+	if (dev && dev->pasn)
+		pasn_responder_pmksa_cache_get(dev->pasn->pmksa,
+					       dev->pasn->peer_addr, pmkid,
+					       pmk, &pmk_len);
+
 	p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success);
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 
@@ -664,15 +736,20 @@  void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
 					      p2p->inv_ssid, p2p->inv_ssid_len,
 					      p2p->inv_go_dev_addr,
 					      p2p->inv_status,
-					      p2p->inv_op_freq);
+					      p2p->inv_op_freq, pmkid, pmk,
+					      pmk_len);
 	}
+	/* Reset pmk and pmkid from RAM */
+	memset(pmkid, 0, sizeof(pmkid));
+	memset(pmk, 0, sizeof(pmk));
 }
 
 
 int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
 	       const u8 *bssid, const u8 *ssid, size_t ssid_len,
 	       unsigned int force_freq, const u8 *go_dev_addr,
-	       int persistent_group, unsigned int pref_freq, int dev_pw_id)
+	       int persistent_group, unsigned int pref_freq, int dev_pw_id,
+	       bool p2p2)
 {
 	struct p2p_device *dev;
 
@@ -740,5 +817,8 @@  int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
 	os_memcpy(p2p->inv_ssid, ssid, ssid_len);
 	p2p->inv_ssid_len = ssid_len;
 	p2p->inv_persistent = persistent_group;
+	if (p2p2)
+		return 0;
+
 	return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id);
 }
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index d976914..daa8bef 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -7073,6 +7073,7 @@  static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
 	int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
 	int edmg;
 	bool allow_6ghz;
+	bool p2p2;
 
 	id = atoi(cmd);
 	pos = os_strstr(cmd, " peer=");
@@ -7129,9 +7130,11 @@  static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
 	if (allow_6ghz && chwidth == 40)
 		max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
 
+	p2p2 = os_strstr(cmd, "p2p2") != NULL;
+
 	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
 			       max_oper_chwidth, pref_freq, he, edmg,
-			       allow_6ghz);
+			       allow_6ghz, p2p2);
 }
 
 
@@ -7186,6 +7189,9 @@  static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
 					 int he, int edmg, bool allow_6ghz,
 					 const u8 *go_bssid)
 {
+	size_t pmk_len = 0;
+	u8 pmkid[PMKID_LEN];
+	u8 pmk[PMK_LEN_MAX];
 	struct wpa_ssid *ssid;
 
 	ssid = wpa_config_get_network(wpa_s->conf, id);
@@ -7196,11 +7202,13 @@  static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
 		return -1;
 	}
 
+	/* FIXME Fetch pmk, pmkid from p2p_supplicant.conf */
 	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, freq,
 					     vht_center_freq2, ht40, vht,
 					     vht_chwidth, he, edmg,
 					     NULL, 0, 0, allow_6ghz, 0,
-					     go_bssid);
+					     go_bssid, NULL, pmkid, pmk,
+					     pmk_len);
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 65bd478..aad4c5b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -367,6 +367,9 @@  DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
 	int he = wpa_s->conf->p2p_go_he;
 	int edmg = wpa_s->conf->p2p_go_edmg;
 	int max_oper_chwidth, chwidth = 0, freq2 = 0;
+	size_t pmk_len = 0;
+	u8 pmkid[PMKID_LEN];
+	u8 pmk[PMK_LEN_MAX];
 
 	dbus_message_iter_init(message, &iter);
 
@@ -477,7 +480,8 @@  DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
 						  freq2, ht40, vht,
 						  max_oper_chwidth, he, edmg,
 						  NULL, 0, 0, allow_6ghz,
-						  retry_limit, go_bssid)) {
+						  retry_limit, go_bssid, NULL, pmkid,
+						  pmk, pmk_len)) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
@@ -866,7 +870,7 @@  DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
 			goto err;
 
 		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
-				    0, 0, 0, false) < 0) {
+				    0, 0, 0, false, 0) < 0) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 71aaeba..0befcdd 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -39,7 +39,8 @@ 
 #include "wifi_display.h"
 #include "crypto/random.h"
 
-
+#include "ap/ieee802_11.h"
+#include "ap/wpa_auth.h"
 
 /*
  * How many times to try to scan to find the GO before giving up on join
@@ -1736,13 +1737,22 @@  static void wpas_send_action_done(void *ctx)
 #ifdef CONFIG_PASN
 struct wpa_p2p_pasn_auth_work {
 	u8 peer_addr[ETH_ALEN];
-	bool verify;
 	int freq;
+	bool verify;
+	int force_freq;
+	int pref_freq;
+	enum p2p_invite_role role;
+	u8 *ssid;
+	size_t ssid_len;
+	u8 bssid[ETH_ALEN];
+	u8 go_dev_addr[ETH_ALEN];
 };
 
 
 static void wpas_p2p_pasn_free_auth_work(struct wpa_p2p_pasn_auth_work *awork)
 {
+	if (awork->ssid)
+		os_free(awork->ssid);
 	os_free(awork);
 }
 
@@ -3522,7 +3532,8 @@  accept_inv:
 static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
 				     const u8 *ssid, size_t ssid_len,
 				     const u8 *go_dev_addr, u8 status,
-				     int op_freq)
+				     int op_freq, u8 *pmkid, u8 *pmk,
+				     size_t pmk_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *s;
@@ -3562,7 +3573,7 @@  static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
 				wpa_s->conf->p2p_go_edmg, NULL,
 				go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
 				1, is_p2p_allow_6ghz(wpa_s->global->p2p), 0,
-				NULL);
+				bssid, sa, pmkid, pmk, pmk_len);
 		} else if (bssid) {
 			wpa_s->user_initiated_pd = 0;
 			wpa_msg_global(wpa_s, MSG_INFO,
@@ -3680,12 +3691,20 @@  static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
 static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
 				   const struct p2p_channels *channels,
 				   const u8 *peer, int neg_freq,
-				   int peer_oper_freq)
+				   int peer_oper_freq, u8 *pmkid, u8 *pmk,
+				   size_t pmk_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *ssid;
 	int freq;
 
+#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 (bssid) {
 		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
 			       "status=%d " MACSTR,
@@ -3793,7 +3812,7 @@  static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
 				      P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
 				      0, 1,
 				      is_p2p_allow_6ghz(wpa_s->global->p2p), 0,
-				      NULL);
+				      bssid, peer, pmkid, pmk, pmk_len);
 }
 
 
@@ -4859,7 +4878,8 @@  static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
 					persistent_go->mode ==
 					WPAS_MODE_P2P_GO ?
 					P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
-					0, 0, false, 0, NULL);
+					0, 0, false, 0, NULL, NULL, NULL, NULL,
+					0);
 			} else if (response_done) {
 				wpas_p2p_group_add(wpa_s, 1, freq,
 						   0, 0, 0, 0, 0, 0, false);
@@ -4982,7 +5002,8 @@  static int wpas_prov_disc_resp_cb(void *ctx)
 			NULL,
 			persistent_go->mode == WPAS_MODE_P2P_GO ?
 			P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0,
-			is_p2p_allow_6ghz(wpa_s->global->p2p), 0, NULL);
+			is_p2p_allow_6ghz(wpa_s->global->p2p), 0, NULL, NULL,
+			NULL, NULL, 0);
 	} else {
 		wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0,
 				   is_p2p_allow_6ghz(wpa_s->global->p2p));
@@ -5075,10 +5096,13 @@  static void wpas_bootstrap_completed(void *ctx, const u8 *addr, int status,
 #ifdef CONFIG_PASN
 static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 {
+	int ret = 0;
 	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;
+	const u8 *bssid = NULL;
+	const u8 *go_dev_addr = NULL;
 
 	if (deinit) {
 		if (!work->started) {
@@ -5091,7 +5115,22 @@  static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 
 	if (!is_zero_ether_addr(awork->peer_addr))
 		peer_addr = awork->peer_addr;
-	if (p2p_initiate_pasn_auth(p2p, peer_addr, awork->freq)) {
+	if (!is_zero_ether_addr(awork->bssid))
+		bssid = awork->bssid;
+	if (!is_zero_ether_addr(awork->go_dev_addr))
+		go_dev_addr = awork->go_dev_addr;
+
+
+	if (awork->verify)
+		ret = p2p_initiate_pasn_verify(p2p, peer_addr, awork->freq,
+					       awork->role, bssid, awork->ssid,
+					       awork->ssid_len,
+					       awork->force_freq, go_dev_addr,
+					       awork->pref_freq);
+	else
+		ret = p2p_initiate_pasn_auth(p2p, peer_addr, awork->freq);
+
+	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "P2P PASN: Failed to start PASN authentication");
 		goto fail;
@@ -5109,6 +5148,59 @@  fail:
 	radio_work_done(work);
 }
 
+static int wpas_p2p_initiate_pasn_verify(struct wpa_supplicant *wpa_s,
+					 const u8 *peer,
+					 enum p2p_invite_role role,
+					 const u8 *bssid, const u8 *ssid,
+					 size_t ssid_len,
+					 unsigned int force_freq,
+					 const u8 *go_dev_addr,
+					 unsigned int pref_freq)
+{
+	int freq;
+	struct wpa_p2p_pasn_auth_work *awork;
+
+	wpas_p2p_pasn_cancel_auth_work(wpa_s);
+	wpa_s->p2p_pasn_auth_work = NULL;
+
+	freq = get_listen_freq(wpa_s->global->p2p, peer);
+	if (freq == -1)
+		return -1;
+
+	awork = os_zalloc(sizeof(*awork));
+	if (!awork)
+		return -1;
+
+	awork->verify = 1;
+	awork->role = role;
+	awork->freq = freq;
+	awork->force_freq = force_freq;
+	awork->pref_freq = pref_freq;
+	os_memcpy(awork->peer_addr, peer, ETH_ALEN);
+	if (go_dev_addr)
+		os_memcpy(awork->go_dev_addr, go_dev_addr, ETH_ALEN);
+	if (bssid)
+		os_memcpy(awork->bssid, bssid, ETH_ALEN);
+	if (ssid_len) {
+		awork->ssid = os_zalloc(ssid_len);
+		if (!awork->ssid) {
+			os_free(awork);
+			return -1;
+		}
+		memcpy(awork->ssid, ssid, ssid_len);
+		awork->ssid_len = ssid_len;
+	}
+
+	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_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
 				       const u8 *peer_addr, int freq)
 {
@@ -5166,8 +5258,12 @@  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;
+	struct wpa_p2p_pasn_auth_work *awork;
 
-	return p2p_pasn_auth_tx_status(p2p, data, data_len, acked);
+	awork = wpa_s->p2p_pasn_auth_work->ctx;
+
+	return p2p_pasn_auth_tx_status(p2p, data, data_len, acked,
+				       awork->verify);
 }
 #endif
 
@@ -6897,6 +6993,7 @@  static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 	params->max_oper_chwidth = max_oper_chwidth;
 	params->vht_center_freq2 = vht_center_freq2;
 	params->edmg = edmg;
+	params->p2p2 = wpa_s->p2p2;
 
 	freqs = os_calloc(wpa_s->num_multichan_concurrent,
 			  sizeof(struct wpa_used_freq_data));
@@ -7339,7 +7436,8 @@  int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
 				 struct wpa_ssid *params, int addr_allocated,
 				 int freq, int force_scan, int retry_limit,
-				 const u8 *go_bssid)
+				 const u8 *go_bssid, bool p2p2, u8 *pmkid,
+				 u8 *pmk, size_t pmk_len)
 {
 	struct wpa_ssid *ssid;
 	int other_iface_found = 0;
@@ -7397,6 +7495,20 @@  static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
 		os_memcpy(ssid->bssid, go_bssid, ETH_ALEN);
 	}
 
+	if (p2p2) {
+		ssid->key_mgmt = WPA_KEY_MGMT_SAE;
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->sae_password = "12345678";
+		wpa_s->conf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+		ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+		ssid->disabled = 0;
+
+		if (pmk && pmk_len && pmkid)
+			wpa_sm_set_pmk(wpa_s->wpa, pmk, pmk_len, pmkid,
+				       ssid->bssid);
+		wpa_s->current_ssid = ssid;
+	}
+
 	wpa_s->show_group_started = 1;
 	wpa_s->p2p_in_invitation = 1;
 	wpa_s->p2p_retry_limit = retry_limit;
@@ -7444,7 +7556,8 @@  int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 				  const struct p2p_channels *channels,
 				  int connection_timeout, int force_scan,
 				  bool allow_6ghz, int retry_limit,
-				  const u8 *go_bssid)
+				  const u8 *go_bssid, const u8 *dev_addr,
+				  u8 *pmkid, u8 *pmk, size_t pmk_len)
 {
 	struct p2p_go_neg_results params;
 	int go = 0, freq;
@@ -7513,7 +7626,8 @@  int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 		}
 
 		return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq,
-					     force_scan, retry_limit, go_bssid);
+					     force_scan, retry_limit, go_bssid,
+					     wpa_s->p2p2, pmkid, pmk, pmk_len);
 	} else {
 		return -1;
 	}
@@ -7540,6 +7654,15 @@  int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 	params.ssid_len = ssid->ssid_len;
 	params.persistent_group = 1;
 
+	if (wpa_s->p2p2 && pmk_len && pmk && pmkid) {
+		memcpy(params.peer_device_addr, dev_addr, ETH_ALEN);
+		memcpy(params.pmkid, pmkid, PMKID_LEN);
+		memcpy(params.pmk, pmk, pmk_len);
+		params.pmk_len = pmk_len;
+		params.akmp = WPA_KEY_MGMT_SAE;
+		params.p2p2 = true;
+	}
+
 	wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 1);
 	if (wpa_s == NULL)
 		return -1;
@@ -8077,7 +8200,7 @@  int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
 		    int vht_center_freq2, int ht40, int vht, int max_chwidth,
-		    int pref_freq, int he, int edmg, bool allow_6ghz)
+		    int pref_freq, int he, int edmg, bool allow_6ghz, bool p2p2)
 {
 	enum p2p_invite_role role;
 	u8 *bssid = NULL;
@@ -8103,6 +8226,7 @@  int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 	wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
 	wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
 	wpa_s->p2p_go_edmg = !!edmg;
+	wpa_s->p2p2 = p2p2;
 	if (ssid->mode == WPAS_MODE_P2P_GO) {
 		role = P2P_INVITE_ROLE_GO;
 		if (peer_addr == NULL) {
@@ -8125,7 +8249,8 @@  int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 			bssid = wpa_s->own_addr;
 	} else {
 		role = P2P_INVITE_ROLE_CLIENT;
-		peer_addr = ssid->bssid;
+		if (!wpa_s->p2p2)
+			peer_addr = ssid->bssid;
 	}
 	wpa_s->pending_invite_ssid_id = ssid->id;
 
@@ -8156,9 +8281,23 @@  int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 	 */
 	wpas_p2p_stop_find_oper(wpa_s);
 
+#ifdef CONFIG_PASN
+	if (p2p2) {
+		if (wpas_p2p_initiate_pasn_verify(wpa_s, peer_addr, role, bssid,
+						  ssid->ssid, ssid->ssid_len,
+						  force_freq, go_dev_addr,
+						  pref_freq) < 0) {
+			if (wpa_s->create_p2p_iface)
+				wpas_p2p_remove_pending_group_interface(wpa_s);
+			return -1;
+		}
+		return 0;
+	}
+#endif /* CONFIG_PASN */
+
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
 			  ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
-			  1, pref_freq, -1);
+			  1, pref_freq, -1, 0);
 }
 
 
@@ -8242,7 +8381,7 @@  int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
 
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
 			  ssid->ssid, ssid->ssid_len, force_freq,
-			  go_dev_addr, persistent, pref_freq, -1);
+			  go_dev_addr, persistent, pref_freq, -1, 0);
 }
 
 
@@ -9743,7 +9882,7 @@  static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
 			  P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr,
 			  ssid->ssid, ssid->ssid_len, ssid->frequency,
 			  wpa_s->global->p2p_dev_addr, persistent, 0,
-			  wpa_s->p2pdev->p2p_oob_dev_pw_id);
+			  wpa_s->p2pdev->p2p_oob_dev_pw_id, 0);
 }
 
 
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 5612d83..61d4281 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -54,7 +54,8 @@  int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 				  const struct p2p_channels *channels,
 				  int connection_timeout, int force_scan,
 				  bool allow_6ghz, int retry_limit,
-				  const u8 *go_bssid);
+				  const u8 *go_bssid, const u8 *dev_addr,
+				  u8 *pmkid, u8 *pmk, size_t pmk_len);
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
 				       struct wpa_ssid *ssid);
 enum wpas_p2p_prov_disc_use {
@@ -122,7 +123,8 @@  int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
 		    int vht_center_freq2, int ht40, int vht, int max_chwidth,
-		    int pref_freq, int he, int edmg, bool allow_6ghz);
+		    int pref_freq, int he, int edmg, bool allow_6ghz,
+		    bool p2p2);
 int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
 			  const u8 *peer_addr, const u8 *go_dev_addr,
 			  bool allow_6ghz);