diff mbox series

[v3,18/25] Add p2p2 support for group formation on successful negotiation

Message ID 1722850403-8852-19-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 support for Group formation and connection between p2p go and
p2p client on successful go negotiation.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
---
 src/ap/ap_drv_ops.c             |  23 +++++
 src/ap/ap_drv_ops.h             |   5 ++
 src/ap/ieee802_11.c             |  15 ++++
 src/ap/ieee802_11.h             |   2 +
 src/ap/wpa_auth_ie.c            |  17 ++++
 src/p2p/p2p.c                   |  59 +++++++++++--
 src/p2p/p2p.h                   |  22 ++++-
 src/p2p/p2p_group.c             |  50 ++++++++++-
 src/p2p/p2p_i.h                 |   2 +
 wpa_supplicant/p2p_supplicant.c | 180 +++++++++++++++++++++++++++++++++++-----
 10 files changed, 346 insertions(+), 29 deletions(-)
diff mbox series

Patch

diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index c473491..e22efeb 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -1250,3 +1250,26 @@  int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
 	return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, &params);
 }
 #endif /* CONFIG_PASN */
+
+int hostapd_drv_add_pmkid(struct hostapd_data *hapd,
+			  struct wpa_pmkid_params *params)
+{
+	if (!hapd->driver || !hapd->driver->add_pmkid || !hapd->drv_priv)
+		return 0;
+	return hapd->driver->add_pmkid(hapd->drv_priv, params);
+}
+
+int hostapd_drv_remove_pmkid(struct hostapd_data *hapd,
+			     struct wpa_pmkid_params *params)
+{
+	if (!hapd->driver || !hapd->driver->remove_pmkid || !hapd->drv_priv)
+		return 0;
+	return hapd->driver->remove_pmkid(hapd->drv_priv, params);
+}
+
+int hostapd_drv_flush_pmkid(struct hostapd_data *hapd)
+{
+	if (!hapd->driver || !hapd->driver->flush_pmkid || !hapd->drv_priv)
+		return 0;
+	return hapd->driver->flush_pmkid(hapd->drv_priv);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index d7e79c8..de7c4af 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -148,6 +148,11 @@  int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
 				       u32 cipher, u8 key_len, const u8 *key,
 				       u8 ltf_keyseed_len,
 				       const u8 *ltf_keyseed, u32 action);
+int hostapd_drv_add_pmkid(struct hostapd_data *hapd,
+			  struct wpa_pmkid_params *params);
+int hostapd_drv_remove_pmkid(struct hostapd_data *hapd,
+			     struct wpa_pmkid_params *params);
+int hostapd_drv_flush_pmkid(struct hostapd_data *hapd);
 
 
 #include "drivers/driver.h"
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 3c5a8dd..5973056 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -8295,4 +8295,19 @@  u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
 	return eid;
 }
 
+
+int hostapd_add_pmkid(struct hostapd_data *hapd, const u8 *bssid, const u8 *pmk,
+		      size_t pmk_len, const u8 *pmkid, int akmp)
+{
+	struct wpa_pmkid_params params;
+
+	os_memset(&params, 0, sizeof(params));
+	params.bssid = bssid;
+	params.pmkid = pmkid;
+	params.pmk = pmk;
+	params.pmk_len = pmk_len;
+
+	return hostapd_drv_add_pmkid(hapd, &params);
+}
+
 #endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index dd4995f..b1a3edf 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -263,5 +263,7 @@  int hostapd_process_assoc_ml_info(struct hostapd_data *hapd,
 				  const u8 *ies, size_t ies_len,
 				  bool reassoc, int tx_link_status,
 				  bool offload);
+int hostapd_add_pmkid(struct hostapd_data *hapd, const u8 *bssid, const u8 *pmk,
+		      size_t pmk_len, const u8 *pmkid, int akmp);
 
 #endif /* IEEE802_11_H */
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 43d9c1d..bd1bd64 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -499,6 +499,9 @@  static u32 rsnxe_capab(struct wpa_auth_config *conf, int key_mgmt)
 #endif /* CONFIG_SAE_PK */
 	}
 
+	// FIXME: Should not set it by default
+	capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
 	if (conf->secure_ltf)
 		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
 	if (conf->secure_rtt)
@@ -1251,6 +1254,20 @@  wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 			pmkid = sm->pmksa->pmkid;
 			break;
 		}
+
+		if (!is_zero_ether_addr(sm->p2p_dev_addr)) {
+			wpa_hexdump(MSG_DEBUG, "RSN IE: P2P DEV PMKID",
+				    &data.pmkid[i * PMKID_LEN], PMKID_LEN);
+			sm->pmksa =
+			pmksa_cache_auth_get(wpa_auth->pmksa,
+					     sm->p2p_dev_addr,
+					     &data.pmkid[i * PMKID_LEN]);
+			if (sm->pmksa) {
+				pmkid = sm->pmksa->pmkid;
+				break;
+			}
+		}
+
 	}
 	for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
 		     i < data.num_pmkid; i++) {
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index ab3ccc1..8f3d76e 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -253,6 +253,7 @@  void p2p_go_neg_failed(struct p2p_data *p2p, int status)
 
 	os_memset(&res, 0, sizeof(res));
 	res.status = status;
+	res.p2p2 = peer->p2p2;
 	os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
 	os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
 	p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
@@ -1072,7 +1073,8 @@  static void p2p_search(struct p2p_data *p2p)
 
 	res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
 				 p2p->num_req_dev_types, p2p->req_dev_types,
-				 p2p->find_dev_id, pw_id, p2p->include_6ghz);
+				 p2p->find_dev_id, pw_id, p2p->include_6ghz,
+				 false);
 	if (res < 0) {
 		p2p_dbg(p2p, "Scan request schedule failed");
 		p2p_continue_find(p2p);
@@ -1299,7 +1301,7 @@  int p2p_find(struct p2p_data *p2p, unsigned int timeout,
 						 p2p->num_req_dev_types,
 						 p2p->req_dev_types, dev_id,
 						 DEV_PW_DEFAULT,
-						 p2p->include_6ghz);
+						 p2p->include_6ghz, false);
 			break;
 		}
 		/* fall through */
@@ -1307,13 +1309,15 @@  int p2p_find(struct p2p_data *p2p, unsigned int timeout,
 		res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
 					 p2p->num_req_dev_types,
 					 p2p->req_dev_types, dev_id,
-					 DEV_PW_DEFAULT, p2p->include_6ghz);
+					 DEV_PW_DEFAULT, p2p->include_6ghz,
+					 false);
 		break;
 	case P2P_FIND_ONLY_SOCIAL:
 		res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,
 					 p2p->num_req_dev_types,
 					 p2p->req_dev_types, dev_id,
-					 DEV_PW_DEFAULT, p2p->include_6ghz);
+					 DEV_PW_DEFAULT, p2p->include_6ghz,
+					 false);
 		break;
 	default:
 		return -1;
@@ -1861,6 +1865,16 @@  int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params)
 	}
 	p2p->ssid_set = 0;
 
+	params->cipher = WPA_CIPHER_CCMP;
+	if (p2p->cfg->pairing_config.pasn_type & 0xc)
+		params->cipher |= WPA_CIPHER_GCMP_256;
+
+	if (params->p2p2) {
+		params->password_len = p2p->cfg->dev_password_len;
+		memcpy(params->password, p2p->cfg->dev_password,
+		       p2p->cfg->dev_password_len);
+	}
+
 	p2p_random(params->passphrase, p2p->cfg->passphrase_len);
 	params->passphrase[p2p->cfg->passphrase_len] = '\0';
 	return 0;
@@ -1934,8 +1948,43 @@  void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
 	peer->go_neg_conf = NULL;
 
 #ifdef CONFIG_PASN
-	if (peer->p2p2 && peer->pasn)
+	if (peer->p2p2 && peer->pasn) {
+		res.p2p2 = peer->p2p2;
+		res.akmp = peer->pasn->akmp;
+		res.cipher = peer->pasn->cipher;
+
+		if (res.akmp == WPA_KEY_MGMT_PASN) {
+			if (go) {
+				res.password_len = p2p->cfg->dev_password_len;
+				memcpy(res.password, p2p->cfg->dev_password,
+				       res.password_len);
+			} else {
+				if (!peer->info.password_len) {
+					p2p_dbg(p2p, "Password Invalid for P2P2 group formation");
+					return;
+				}
+				res.password_len = peer->info.password_len;
+				memcpy(res.password, peer->info.password,
+				       res.password_len);
+			}
+		} else if (res.akmp == WPA_KEY_MGMT_SAE) {
+			res.password_len = peer->password_len;
+			memcpy(res.password, peer->password, res.password_len);
+			if (peer->role == P2P_ROLE_PAIRING_INITIATOR) {
+				pasn_initiator_pmksa_cache_get(peer->pasn->pmksa,
+						peer->pasn->peer_addr,
+						res.pmkid, res.pmk,
+						&res.pmk_len);
+			} else {
+				pasn_responder_pmksa_cache_get(peer->pasn->pmksa,
+						peer->pasn->peer_addr,
+						res.pmkid, res.pmk,
+						&res.pmk_len);
+			}
+		}
+
 		wpa_pasn_reset(peer->pasn);
+	}
 #endif /* CONFIG_PASN */
 
 	p2p_set_state(p2p, P2P_PROVISIONING);
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index db2052f..65e2e0d 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -11,6 +11,7 @@ 
 
 #include "common/ieee802_11_defs.h"
 #include "wps/wps.h"
+#include "common/wpa_common.h"
 
 #define DEVICE_IDENTITY_KEY_MAX_LEN 64
 #define DEVICE_IDENTITY_KEY_LEN 16
@@ -181,6 +182,22 @@  struct p2p_go_neg_results {
 	 * peer_config_timeout - Peer configuration timeout (in 10 msec units)
 	 */
 	unsigned int peer_config_timeout;
+
+	bool p2p2;
+
+	int akmp;
+
+	int cipher;
+
+	u8 pmkid[PMKID_LEN];
+
+	u8 pmk[PMK_LEN_MAX];
+
+	size_t pmk_len;
+
+	char password[100];
+
+	size_t password_len;
 };
 
 struct p2ps_provision {
@@ -779,7 +796,7 @@  struct p2p_config {
 	int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq,
 			unsigned int num_req_dev_types,
 			const u8 *req_dev_types, const u8 *dev_id, u16 pw_id,
-			bool include_6ghz);
+			bool include_6ghz, bool p2p2);
 
 	/**
 	 * send_probe_resp - Transmit a Probe Response frame
@@ -1993,6 +2010,7 @@  struct p2p_group_config {
  * p2p_group_init - Initialize P2P group
  * @p2p: P2P module context from p2p_init()
  * @config: P2P group configuration (will be freed by p2p_group_deinit())
+ * @p2p2: parameter to indicate that the group formed using p2p2
  * Returns: Pointer to private data or %NULL on failure
  *
  * This function is used to initialize per-group P2P module context. Currently,
@@ -2000,7 +2018,7 @@  struct p2p_group_config {
  * create an instance of this per-group information.
  */
 struct p2p_group * p2p_group_init(struct p2p_data *p2p,
-				  struct p2p_group_config *config);
+				  struct p2p_group_config *config, bool p2p2);
 
 /**
  * p2p_group_deinit - Deinitialize P2P group
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index c036f92..4822c28 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -40,11 +40,12 @@  struct p2p_group {
 	int beacon_update;
 	struct wpabuf *noa;
 	struct wpabuf *wfd_ie;
+	bool p2p2;
 };
 
 
 struct p2p_group * p2p_group_init(struct p2p_data *p2p,
-				  struct p2p_group_config *config)
+				  struct p2p_group_config *config, bool p2p2)
 {
 	struct p2p_group *group, **groups;
 
@@ -62,6 +63,7 @@  struct p2p_group * p2p_group_init(struct p2p_data *p2p,
 	p2p->groups = groups;
 
 	group->p2p = p2p;
+	group->p2p2 = p2p2;
 	group->cfg = config;
 	group->group_formation = 1;
 	group->beacon_update = 1;
@@ -205,11 +207,28 @@  static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems)
 }
 
 
+struct wpabuf * p2p_group_build_p2p2_ie(struct p2p_data *p2p,
+					struct wpabuf *p2p2_ie, int freq)
+{
+	u8 *len;
+
+	wpabuf_put_u8(p2p2_ie, WLAN_EID_VENDOR_SPECIFIC);
+	len = wpabuf_put(p2p2_ie, 1);
+	wpabuf_put_be32(p2p2_ie, P2P2_IE_VENDOR_TYPE);
+	wpa_printf(MSG_DEBUG, "P2P: * P2P2 IE header");
+	p2p_buf_add_pcea(p2p2_ie, p2p);
+	*len = (u8 *)wpabuf_put(p2p2_ie, 0) - len - 1;
+
+	return p2p2_ie;
+}
+
+
 static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
 {
 	struct wpabuf *ie;
 	u8 *len;
 	size_t extra = 0;
+	struct wpabuf *p2p2_ie;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (group->p2p->wfd_ie_beacon)
@@ -220,7 +239,7 @@  static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
 	    group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO])
 		extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]);
 
-	ie = wpabuf_alloc(257 + extra);
+	ie = wpabuf_alloc(500 + extra);
 	if (ie == NULL)
 		return NULL;
 
@@ -240,6 +259,15 @@  static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
 	p2p_group_add_noa(ie, group->noa);
 	p2p_buf_update_ie_hdr(ie, len);
 
+	if (group->p2p2) {
+		p2p2_ie = wpabuf_alloc(255);
+		if (!p2p2_ie)
+			return NULL;
+
+		p2p_group_build_p2p2_ie(group->p2p, p2p2_ie, group->cfg->freq);
+		ie = wpabuf_concat(p2p2_ie, ie);
+	}
+
 	return ie;
 }
 
@@ -443,6 +471,7 @@  void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf)
 static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
 {
 	struct wpabuf *p2p_subelems, *ie;
+	struct wpabuf *p2p2_ie;
 
 	p2p_subelems = wpabuf_alloc(500);
 	if (p2p_subelems == NULL)
@@ -474,7 +503,14 @@  static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
 		ie = wpabuf_concat(wfd, ie);
 	}
 #endif /* CONFIG_WIFI_DISPLAY */
+	if (group->p2p2) {
+		p2p2_ie = wpabuf_alloc(255);
+		if (!p2p2_ie)
+			return NULL;
 
+		p2p_group_build_p2p2_ie(group->p2p, p2p2_ie, group->cfg->freq);
+		ie = wpabuf_concat(p2p2_ie, ie);
+	}
 	return ie;
 }
 
@@ -648,6 +684,7 @@  struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
 	struct wpabuf *resp;
 	u8 *rlen;
 	size_t extra = 0;
+	struct wpabuf *p2p2_ie;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (group->wfd_ie)
@@ -683,6 +720,15 @@  struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
 		p2p_buf_add_status(resp, status);
 	p2p_buf_update_ie_hdr(resp, rlen);
 
+	if (group->p2p2) {
+		p2p2_ie = wpabuf_alloc(255);
+		if (!p2p2_ie)
+			return NULL;
+
+		p2p_group_build_p2p2_ie(group->p2p, p2p2_ie, group->cfg->freq);
+		resp = wpabuf_concat(p2p2_ie, resp);
+	}
+
 	return resp;
 }
 
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index e0d2ee0..440ed1f 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -926,6 +926,8 @@  void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
 				   unsigned int size);
 struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p,
 					struct wpabuf *subelems, u32 ie_type);
+struct wpabuf * p2p_group_build_p2p2_ie(struct p2p_data *p2p,
+					struct wpabuf *p2p2_ie, int freq);
 
 /* p2p_sd.c */
 struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 0cffb99..71aaeba 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -426,11 +426,11 @@  static int wpas_p2p_search_social_channel(struct wpa_supplicant *wpa_s,
 static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
 			 unsigned int num_req_dev_types,
 			 const u8 *req_dev_types, const u8 *dev_id, u16 pw_id,
-			 bool include_6ghz)
+			 bool include_6ghz, bool p2p2)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_driver_scan_params *params = NULL;
-	struct wpabuf *wps_ie, *ies;
+	struct wpabuf *wps_ie = NULL, *ies;
 	unsigned int num_channels = 0;
 	int social_channels_freq[] = { 2412, 2437, 2462, 60480 };
 	size_t ielen;
@@ -459,11 +459,16 @@  static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
 	params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
 
 	wpa_s->wps->dev.p2p = 1;
-	wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
-					wpa_s->wps->uuid, WPS_REQ_ENROLLEE,
-					num_req_dev_types, req_dev_types);
-	if (wps_ie == NULL)
-		goto fail;
+
+	if (!p2p2) {
+		wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
+						wpa_s->wps->uuid,
+						WPS_REQ_ENROLLEE,
+						num_req_dev_types,
+						req_dev_types);
+		if (wps_ie == NULL)
+			goto fail;
+	}
 
 	/*
 	 * In case 6 GHz channels are requested as part of the P2P scan, only
@@ -514,13 +519,20 @@  static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
 	}
 
 	ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
-	ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
-	if (ies == NULL) {
+
+	if (wps_ie)
+		ielen += wpabuf_len(wps_ie);
+
+	ies = wpabuf_alloc(ielen);
+	if (!ies) {
 		wpabuf_free(wps_ie);
 		goto fail;
 	}
-	wpabuf_put_buf(ies, wps_ie);
-	wpabuf_free(wps_ie);
+
+	if (wps_ie) {
+		wpabuf_put_buf(ies, wps_ie);
+		wpabuf_free(wps_ie);
+	}
 
 	bands = wpas_get_bands(wpa_s, params->freqs);
 	p2p_scan_ie(wpa_s->global->p2p, ies, dev_id, bands);
@@ -1757,6 +1769,80 @@  static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
 	return 0;
 }
 
+static void wpas_start_gc(struct wpa_supplicant *wpa_s,
+			  struct p2p_go_neg_results *res)
+{
+	struct wpa_ssid *ssid;
+
+	if (!res->ssid_len) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: SSID info not present");
+		return;
+	}
+
+	wpa_s->group_formation_reported = 0;
+	wpa_printf(MSG_DEBUG, "P2P: Start connect for peer " MACSTR
+		   " dev_addr " MACSTR,
+		   MAC2STR(res->peer_interface_addr),
+		   MAC2STR(res->peer_device_addr));
+	wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start connect for SSID",
+			  res->ssid, res->ssid_len);
+	wpa_supplicant_ap_deinit(wpa_s);
+	wpas_copy_go_neg_results(wpa_s, res);
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not add network for Client");
+		return;
+	}
+	os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
+	wpa_config_set_network_defaults(ssid);
+	ssid->temporary = 1;
+	ssid->p2p_group = 1;
+
+	ssid->ssid = os_zalloc(res->ssid_len);
+	if (!ssid->ssid)
+		return;
+
+	ssid->ssid_len = res->ssid_len;
+	os_memcpy(ssid->ssid, res->ssid, ssid->ssid_len);
+
+	memcpy(ssid->bssid, res->peer_interface_addr, ETH_ALEN);
+
+	if (res->akmp == WPA_KEY_MGMT_PASN) {
+		ssid->auth_alg = WPA_AUTH_ALG_SAE;
+		ssid->sae_password = os_strdup(res->password);
+	} else if (res->akmp == WPA_KEY_MGMT_SAE) {
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->sae_password = os_strdup(res->password);
+		wpa_sm_set_pmk(wpa_s->wpa, res->pmk, res->pmk_len,
+			       res->pmkid, res->peer_interface_addr);
+	}
+
+	if (res->psk_set) {
+		os_memcpy(ssid->psk, res->psk, 32);
+		ssid->psk_set = 1;
+	}
+	ssid->proto = WPA_PROTO_RSN;
+	ssid->key_mgmt = WPA_KEY_MGMT_SAE;
+	ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+	ssid->group_cipher = WPA_CIPHER_CCMP;
+	if (res->cipher) {
+		ssid->pairwise_cipher |= res->cipher;
+	}
+	ssid->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+	wpa_s->conf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+	ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+	ssid->disabled = 0;
+	wpa_s->show_group_started = 1;
+	wpa_s->p2p_in_invitation = 1;
+	wpa_s->p2p_go_group_formation_completed = 0;
+	wpa_s->global->p2p_group_formation = wpa_s;
+
+	wpa_s->current_ssid = ssid;
+	wpa_supplicant_update_scan_results(wpa_s, res->peer_interface_addr);
+	wpa_supplicant_select_network(wpa_s, ssid);
+}
+
 
 static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
 				    struct p2p_go_neg_results *res)
@@ -1892,6 +1978,9 @@  static void p2p_go_configured(void *ctx, void *data)
 	struct wpa_supplicant *wpa_s = ctx;
 	struct p2p_go_neg_results *params = data;
 	struct wpa_ssid *ssid;
+	struct sta_info sta;
+	struct sae_data *sae;
+	struct hostapd_data *hapd;
 
 	wpa_s->ap_configured_cb = NULL;
 	wpa_s->ap_configured_cb_ctx = NULL;
@@ -1901,6 +1990,26 @@  static void p2p_go_configured(void *ctx, void *data)
 			   "P2P: p2p_go_configured() called with wpa_s->go_params == NULL");
 		return;
 	}
+	if (wpa_s->ap_iface && params->p2p2 &&
+	    params->akmp == WPA_KEY_MGMT_SAE) {
+		hapd = wpa_s->ap_iface->bss[0];
+		memset(&sta, 0, sizeof(struct sta_info));
+		memcpy(sta.addr, params->peer_device_addr, ETH_ALEN);
+		sae = os_zalloc(sizeof(struct sae_data));
+		if (sae) {
+			sta.sae = sae;
+			memcpy(sta.sae->pmkid, params->pmkid, PMKID_LEN);
+			wpa_auth_pmksa_add_sae(hapd->wpa_auth,
+					       params->peer_device_addr,
+					       params->pmk, params->pmk_len,
+					       params->pmkid, WPA_KEY_MGMT_SAE);
+			hostapd_add_pmkid(hapd, params->peer_device_addr,
+					  params->pmk, params->pmk_len,
+					  params->pmkid, WPA_KEY_MGMT_SAE);
+			memset(&sta, 0, sizeof(struct sta_info));
+			os_free(sae);
+		}
+	}
 
 	p2p_go_save_group_common_freqs(wpa_s, params);
 	p2p_go_dump_common_freqs(wpa_s);
@@ -1967,13 +2076,21 @@  static void p2p_go_configured(void *ctx, void *data)
 		return;
 	}
 
-	wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning");
 	if (wpa_supplicant_ap_mac_addr_filter(wpa_s,
 					      params->peer_interface_addr)) {
 		wpa_printf(MSG_DEBUG, "P2P: Failed to setup MAC address "
 			   "filtering");
 		return;
 	}
+
+	if (params->p2p2) {
+		wpas_group_formation_completed(wpa_s, 1, 0);
+		wpa_printf(MSG_DEBUG, "P2P2: Group formation completed, "
+			   "First connection in progress");
+		goto out;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning");
 	if (params->wps_method == WPS_PBC) {
 		wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
 					  params->peer_device_addr);
@@ -1994,6 +2111,7 @@  static void p2p_go_configured(void *ctx, void *data)
 	} else if (wpa_s->p2p_pin[0])
 		wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
 					  wpa_s->p2p_pin, NULL, 0, 0);
+out:
 	os_free(wpa_s->go_params);
 	wpa_s->go_params = NULL;
 }
@@ -2076,9 +2194,9 @@  int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
-			      struct p2p_go_neg_results *params,
-			      int group_formation)
+static void wpas_start_go(struct wpa_supplicant *wpa_s,
+			  struct p2p_go_neg_results *params,
+			  int group_formation, bool p2p2)
 {
 	struct wpa_ssid *ssid;
 
@@ -2173,6 +2291,21 @@  static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
 		wpa_config_update_psk(ssid);
 	ssid->ap_max_inactivity = wpa_s->p2pdev->conf->p2p_go_max_inactivity;
 
+	if (p2p2) {
+		if (params->akmp == WPA_KEY_MGMT_SAE)
+			ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		else
+			ssid->auth_alg |= WPA_AUTH_ALG_SAE;
+
+		ssid->key_mgmt = WPA_KEY_MGMT_SAE;
+		ssid->sae_password = os_strdup(params->password);
+		ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+		wpa_s->conf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+		if (params->cipher) {
+			ssid->pairwise_cipher |= params->cipher;
+		}
+	}
+
 	wpa_s->ap_configured_cb = p2p_go_configured;
 	wpa_s->ap_configured_cb_ctx = wpa_s;
 	wpa_s->ap_configured_cb_data = wpa_s->go_params;
@@ -2387,6 +2520,7 @@  wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go)
 	wpa_s->global->pending_group_iface_for_p2ps = 0;
 
 	wpas_p2p_clone_config(group_wpa_s, wpa_s);
+	group_wpa_s->p2p2 = wpa_s->p2p2;
 
 	if (wpa_s->conf->p2p_interface_random_mac_addr) {
 		if (wpa_drv_set_mac_addr(group_wpa_s,
@@ -2569,12 +2703,18 @@  static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 		os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
 			  sizeof(group_wpa_s->p2p_pin));
 		group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
+		group_wpa_s->p2p2 = res->p2p2;
+		group_wpa_s->p2p_bootstrap = wpa_s->p2p_bootstrap;
 	}
+
 	if (res->role_go) {
-		wpas_start_wps_go(group_wpa_s, res, 1);
+		wpas_start_go(group_wpa_s, res, 1, res->p2p2);
 	} else {
 		os_get_reltime(&group_wpa_s->scan_min_time);
-		wpas_start_wps_enrollee(group_wpa_s, res);
+		if (res->p2p2)
+			wpas_start_gc(group_wpa_s, res);
+		else
+			wpas_start_wps_enrollee(group_wpa_s, res);
 	}
 
 	wpa_s->global->p2p_long_listen = 0;
@@ -7190,7 +7330,7 @@  int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 		return -1;
 	if (freq > 0)
 		wpa_s->p2p_go_no_pri_sec_switch = 1;
-	wpas_start_wps_go(wpa_s, &params, 0);
+	wpas_start_go(wpa_s, &params, 0, wpa_s->p2p2);
 
 	return 0;
 }
@@ -7407,7 +7547,7 @@  int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 	p2p_channels_to_freqs(channels, params.freq_list, P2P_MAX_CHANNELS);
 
 	wpa_s->p2p_first_connection_timeout = connection_timeout;
-	wpas_start_wps_go(wpa_s, &params, 0);
+	wpas_start_go(wpa_s, &params, 0, wpa_s->p2p2);
 
 	return 0;
 }
@@ -7489,7 +7629,7 @@  struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
 	cfg->ip_addr_alloc = WPA_GET_BE32(wpa_s->p2pdev->conf->ip_addr_start)
 		!= 0;
 
-	group = p2p_group_init(wpa_s->global->p2p, cfg);
+	group = p2p_group_init(wpa_s->global->p2p, cfg, wpa_s->p2p2);
 	if (group == NULL)
 		os_free(cfg);
 	if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)