[PATCH v3 15/25] P2P: Encapsulate P2P2 vendor IE with size more than 255 bytes
Shivani Baranwal
quic_shivbara at quicinc.com
Mon Aug 5 02:33:13 PDT 2024
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 at 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 --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,
--
2.7.4
More information about the Hostap
mailing list