diff mbox series

[v3,15/25] P2P: Encapsulate P2P2 vendor IE with size more than 255 bytes

Message ID 1722850403-8852-16-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 to encapsulate vendor IE exceeding 255 bytes in go
negotiation frames and action wrapper IE of pasn auth frames for p2p2.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
---
 src/p2p/p2p_build.c  |  35 +++++++++++++
 src/p2p/p2p_go_neg.c | 137 +++++++++++++++++++++++++++++----------------------
 src/p2p/p2p_i.h      |   2 +
 3 files changed, 115 insertions(+), 59 deletions(-)
diff mbox series

Patch

diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 182af37..f505ad9 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -1022,3 +1022,38 @@  int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
 
 	return 0;
 }
+
+
+struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p,
+					struct wpabuf *subelems, u32 ie_type)
+{
+	struct wpabuf *ie;
+	const u8 *pos, *end;
+	size_t len;
+
+	if (!subelems)
+		return NULL;
+
+	len = wpabuf_len(subelems) + 1000;
+
+	ie = wpabuf_alloc(len);
+	if (!ie)
+		return NULL;
+
+	pos = wpabuf_head(subelems);
+	end = pos + wpabuf_len(subelems);
+
+	while (end > pos) {
+		size_t frag_len = end - pos;
+
+		if (frag_len > 251)
+			frag_len = 251;
+		wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+		wpabuf_put_u8(ie, 4 + frag_len);
+		wpabuf_put_be32(ie, ie_type);
+		wpabuf_put_data(ie, pos, frag_len);
+		pos += frag_len;
+	}
+
+	return ie;
+}
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 58ea89c..5798018 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -138,12 +138,11 @@  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 *buf;
-	u8 *len;
 	u8 group_capab;
 	size_t extra = 0;
 	u16 pw_id;
 	bool is_6ghz_capab;
+	struct wpabuf *buf, *buf2, *p2p_ie;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
@@ -153,13 +152,16 @@  static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
 		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
 
-	buf = wpabuf_alloc(1000 + extra);
-	if (buf == NULL)
+	buf2 = wpabuf_alloc(1000 + extra);
+	if (!buf2)
 		return NULL;
 
-	p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token);
+	p2p_buf_add_public_action_hdr(buf2, P2P_GO_NEG_REQ, peer->dialog_token);
+
+	p2p_ie = wpabuf_alloc(500);
+	if (!p2p_ie)
+		return NULL;
 
-	len = p2p_buf_add_ie_hdr(buf);
 	group_capab = 0;
 	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
 		group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
@@ -170,17 +172,17 @@  static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
 		group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
 	if (p2p->cfg->p2p_intra_bss)
 		group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
-	p2p_buf_add_capability(buf, p2p->dev_capab &
+	p2p_buf_add_capability(p2p_ie, p2p->dev_capab &
 			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
 			       group_capab);
-	p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker);
-	p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
-	p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
+	p2p_buf_add_go_intent(p2p_ie, (p2p->go_intent << 1) | peer->tie_breaker);
+	p2p_buf_add_config_timeout(p2p_ie, p2p->go_timeout, p2p->client_timeout);
+	p2p_buf_add_listen_channel(p2p_ie, p2p->cfg->country, p2p->cfg->reg_class,
 				   p2p->cfg->channel);
 	if (p2p->ext_listen_interval)
-		p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
+		p2p_buf_add_ext_listen_timing(p2p_ie, p2p->ext_listen_period,
 					      p2p->ext_listen_interval);
-	p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+	p2p_buf_add_intended_addr(p2p_ie, p2p->intended_addr);
 	is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
 		p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
 	if (p2p->num_pref_freq) {
@@ -191,37 +193,41 @@  static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
 					p2p->num_pref_freq, &pref_chanlist, go);
 		p2p_channels_dump(p2p, "channel list after filtering",
 				  &pref_chanlist);
-		p2p_buf_add_channel_list(buf, p2p->cfg->country,
+		p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country,
 					 &pref_chanlist, is_6ghz_capab);
 	} else {
-		p2p_buf_add_channel_list(buf, p2p->cfg->country,
+		p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country,
 					 &p2p->channels, is_6ghz_capab);
 	}
-	p2p_buf_add_device_info(buf, p2p, peer);
-	p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+	p2p_buf_add_device_info(p2p_ie, p2p, peer);
+	p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country,
 				      p2p->op_reg_class, p2p->op_channel);
-	p2p_buf_update_ie_hdr(buf, len);
 
-	p2p_buf_add_pref_channel_list(buf, p2p->pref_freq_list,
+	buf = p2p_encaps_p2p_vendor_ie(p2p, p2p_ie, P2P_IE_VENDOR_TYPE);
+	wpabuf_free(p2p_ie);
+
+	p2p_buf_add_pref_channel_list(buf2, p2p->pref_freq_list,
 				      p2p->num_pref_freq);
 
 	/* WPS IE with Device Password ID attribute */
 	pw_id = p2p_wps_method_pw_id(peer->wps_method);
 	if (peer->oob_pw_id)
 		pw_id = peer->oob_pw_id;
-	if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+	if (peer && !peer->p2p2 && p2p_build_wps_ie(p2p, buf2, pw_id, 0) < 0) {
 		p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
+		wpabuf_free(buf2);
 		wpabuf_free(buf);
 		return NULL;
 	}
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
-		wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+		wpabuf_put_buf(buf2, p2p->wfd_ie_go_neg);
 #endif /* CONFIG_WIFI_DISPLAY */
 
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
-		wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+		wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+	buf = wpabuf_concat(buf2, buf);
 
 	return buf;
 }
@@ -292,13 +298,12 @@  static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
 					     u8 dialog_token, u8 status,
 					     u8 tie_breaker)
 {
-	struct wpabuf *buf;
-	u8 *len;
 	u8 group_capab;
 	size_t extra = 0;
 	u16 pw_id;
 	bool is_6ghz_capab;
 	struct p2p_channels pref_chanlist;
+	struct wpabuf *buf, *buf2, *p2p_ie;
 
 	p2p_dbg(p2p, "Building GO Negotiation Response");
 
@@ -310,14 +315,17 @@  static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
 		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
 
-	buf = wpabuf_alloc(1000 + extra);
-	if (buf == NULL)
+	buf2 = wpabuf_alloc(1000 + extra);
+	if (!buf2)
 		return NULL;
 
-	p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_RESP, dialog_token);
+	p2p_buf_add_public_action_hdr(buf2, P2P_GO_NEG_RESP, dialog_token);
 
-	len = p2p_buf_add_ie_hdr(buf);
-	p2p_buf_add_status(buf, status);
+	p2p_ie = wpabuf_alloc(500);
+	if (!p2p_ie)
+		return NULL;
+
+	p2p_buf_add_status(p2p_ie, status);
 	group_capab = 0;
 	if (peer && peer->go_state == LOCAL_GO) {
 		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
@@ -331,24 +339,25 @@  static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
 		if (p2p->cfg->p2p_intra_bss)
 			group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
 	}
-	p2p_buf_add_capability(buf, p2p->dev_capab &
+	p2p_buf_add_capability(p2p_ie, p2p->dev_capab &
 			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
 			       group_capab);
-	p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
-	p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
+	p2p_buf_add_go_intent(p2p_ie, (p2p->go_intent << 1) | tie_breaker);
+	p2p_buf_add_config_timeout(p2p_ie, p2p->go_timeout, p2p->client_timeout);
 	if (p2p->override_pref_op_class) {
 		p2p_dbg(p2p, "Override operating channel preference");
-		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+		p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country,
 					      p2p->override_pref_op_class,
 					      p2p->override_pref_channel);
 	} else if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
 		p2p_dbg(p2p, "Omit Operating Channel attribute");
 	} else {
-		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+		p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country,
 					      p2p->op_reg_class,
 					      p2p->op_channel);
 	}
-	p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+	p2p_buf_add_intended_addr(p2p_ie, p2p->intended_addr);
+
 	if (p2p->num_pref_freq) {
 		bool go = (peer && peer->go_state == LOCAL_GO) ||
 			p2p->go_intent == 15;
@@ -362,12 +371,12 @@  static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
 				  p2p->allow_6ghz);
 	}
 	if (status || peer == NULL) {
-		p2p_buf_add_channel_list(buf, p2p->cfg->country,
+		p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country,
 					 &pref_chanlist, false);
 	} else if (peer->go_state == REMOTE_GO) {
 		is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
 			p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
-		p2p_buf_add_channel_list(buf, p2p->cfg->country,
+		p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country,
 					 &pref_chanlist, is_6ghz_capab);
 	} else {
 		struct p2p_channels res;
@@ -376,33 +385,37 @@  static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
 			p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
 		p2p_channels_intersect(&pref_chanlist, &peer->channels,
 				       &res);
-		p2p_buf_add_channel_list(buf, p2p->cfg->country, &res,
-				       is_6ghz_capab);
+		p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &res,
+					 is_6ghz_capab);
 	}
-	p2p_buf_add_device_info(buf, p2p, peer);
+	p2p_buf_add_device_info(p2p_ie, p2p, peer);
 	if (peer && peer->go_state == LOCAL_GO) {
-		p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
+		p2p_buf_add_group_id(p2p_ie, p2p->cfg->dev_addr, p2p->ssid,
 				     p2p->ssid_len);
 	}
-	p2p_buf_update_ie_hdr(buf, len);
+
+	buf = p2p_encaps_p2p_vendor_ie(p2p, p2p_ie, P2P_IE_VENDOR_TYPE);
+	wpabuf_free(p2p_ie);
 
 	/* WPS IE with Device Password ID attribute */
 	pw_id = p2p_wps_method_pw_id(peer ? peer->wps_method : WPS_NOT_READY);
 	if (peer && peer->oob_pw_id)
 		pw_id = peer->oob_pw_id;
-	if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+	if (peer && !peer->p2p2 && p2p_build_wps_ie(p2p, buf2, pw_id, 0) < 0) {
 		p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
+		wpabuf_free(buf2);
 		wpabuf_free(buf);
 		return NULL;
 	}
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
-		wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+		wpabuf_put_buf(buf2, p2p->wfd_ie_go_neg);
 #endif /* CONFIG_WIFI_DISPLAY */
 
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
-		wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
+		wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
+	buf = wpabuf_concat(buf2, buf);
 
 	return buf;
 }
@@ -1163,12 +1176,11 @@  static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
 					     u8 dialog_token, u8 status,
 					     const u8 *resp_chan, int go)
 {
-	struct wpabuf *buf;
-	u8 *len;
 	struct p2p_channels res;
 	u8 group_capab;
 	size_t extra = 0;
 	bool is_6ghz_capab;
+	struct wpabuf *buf, *buf2, *p2p_ie;
 
 	p2p_dbg(p2p, "Building GO Negotiation Confirm");
 
@@ -1180,14 +1192,17 @@  static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
 		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
 
-	buf = wpabuf_alloc(1000 + extra);
-	if (buf == NULL)
+	buf2 = wpabuf_alloc(1000 + extra);
+	if (!buf2)
 		return NULL;
 
-	p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_CONF, dialog_token);
+	p2p_buf_add_public_action_hdr(buf2, P2P_GO_NEG_CONF, dialog_token);
+
+	p2p_ie = wpabuf_alloc(500);
+	if (!p2p_ie)
+		return NULL;
 
-	len = p2p_buf_add_ie_hdr(buf);
-	p2p_buf_add_status(buf, status);
+	p2p_buf_add_status(p2p_ie, status);
 	group_capab = 0;
 	if (peer->go_state == LOCAL_GO) {
 		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
@@ -1201,33 +1216,37 @@  static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
 		if (p2p->cfg->p2p_intra_bss)
 			group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
 	}
-	p2p_buf_add_capability(buf, p2p->dev_capab &
+	p2p_buf_add_capability(p2p_ie, p2p->dev_capab &
 			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
 			       group_capab);
 	if (go || resp_chan == NULL)
-		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+		p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country,
 					      p2p->op_reg_class,
 					      p2p->op_channel);
 	else
-		p2p_buf_add_operating_channel(buf, (const char *) resp_chan,
+		p2p_buf_add_operating_channel(p2p_ie, (const char *) resp_chan,
 					      resp_chan[3], resp_chan[4]);
 	p2p_channels_intersect(&p2p->channels, &peer->channels, &res);
 	is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
 		p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
-	p2p_buf_add_channel_list(buf, p2p->cfg->country, &res, is_6ghz_capab);
+	p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &res, is_6ghz_capab);
 	if (go) {
-		p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
+		p2p_buf_add_group_id(p2p_ie, p2p->cfg->dev_addr, p2p->ssid,
 				     p2p->ssid_len);
 	}
-	p2p_buf_update_ie_hdr(buf, len);
+
+	buf = p2p_encaps_p2p_vendor_ie(p2p, p2p_ie, P2P_IE_VENDOR_TYPE);
+	wpabuf_free(p2p_ie);
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
-		wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+		wpabuf_put_buf(buf2, p2p->wfd_ie_go_neg);
 #endif /* CONFIG_WIFI_DISPLAY */
 
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
-		wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+		wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+
+	buf = wpabuf_concat(buf2, buf);
 
 	return buf;
 }
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index c3dfcea..d7a5dc1 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -901,6 +901,8 @@  int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
 void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
 				   const struct weighted_pcl *pref_freq_list,
 				   unsigned int size);
+struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p,
+					struct wpabuf *subelems, u32 ie_type);
 
 /* p2p_sd.c */
 struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,