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@xxxxxxxxxxx> --- 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap