Add support for p2p2 bootstrapping with comeback mechanism using provision discovery frames. Add control iface to extend p2p_connect to allow p2p2 bootstrapping handshake. Signed-off-by: Shivani Baranwal <quic_shivbara@xxxxxxxxxxx> --- src/common/ieee802_11_defs.h | 16 ++ src/p2p/p2p.c | 31 ++- src/p2p/p2p.h | 30 ++- src/p2p/p2p_build.c | 1 + src/p2p/p2p_go_neg.c | 2 + src/p2p/p2p_i.h | 40 ++- src/p2p/p2p_pd.c | 370 +++++++++++++++++++++++++++- wpa_supplicant/ctrl_iface.c | 28 ++- wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 2 +- wpa_supplicant/p2p_supplicant.c | 79 +++++- wpa_supplicant/p2p_supplicant.h | 3 +- wpa_supplicant/wpa_supplicant_i.h | 3 + 12 files changed, 574 insertions(+), 31 deletions(-) diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 8791318..0e88797 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1793,6 +1793,21 @@ enum p2p_attr_id { #define P2P_PCEA_PASN_TYPE BIT(11) #define P2P_PCEA_TWT_POWER_MGMT BIT(12) + +/* P2P Pairing Bootstrapping Method attribute - Bootstrapping Method */ +#define P2P_PBMA_OPPORTUNISTIC BIT(0) +#define P2P_PBMA_PIN_CODE_DISPLAY BIT(1) +#define P2P_PBMA_PASSPHRASE_DISPLAY BIT(2) +#define P2P_PBMA_QR_DISPLAY BIT(3) +#define P2P_PBMA_NFC_TAG BIT(4) +#define P2P_PBMA_PIN_CODE_KEYPAD BIT(5) +#define P2P_PBMA_PASSPHRASE_KEYPAD BIT(6) +#define P2P_PBMA_QR_SCAN BIT(7) +#define P2P_PBMA_NFC_READER BIT(8) +#define P2P_PBMA_SERVICE_MANAGED BIT(14) +#define P2P_PBMA_HANDSHAKE_SHIP BIT(15) + + /* P2PS Coordination Protocol Transport Bitmap */ #define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0) #define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1) @@ -1824,6 +1839,7 @@ enum p2p_status_code { P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10, P2P_SC_FAIL_REJECTED_BY_USER = 11, P2P_SC_SUCCESS_DEFERRED = 12, + P2P_SC_COMEBACK = 13, }; enum p2p_role_indication { diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index ba2708d..a66f0c4 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -954,6 +954,11 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev) dev->info.wps_vendor_ext[i] = NULL; } + if (dev->bootstrap_params) { + os_free(dev->bootstrap_params); + dev->bootstrap_params = NULL; + } + wpabuf_free(dev->info.wfd_subelems); wpabuf_free(dev->info.vendor_elems); wpabuf_free(dev->go_neg_conf); @@ -1599,7 +1604,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, const u8 *force_ssid, size_t force_ssid_len, - int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id) + int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id, + bool p2p2, u16 bootstrap, const char *password) { struct p2p_device *dev; @@ -1683,6 +1689,12 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, dev->wps_method = wps_method; dev->oob_pw_id = oob_pw_id; + dev->p2p2 = p2p2; + dev->req_bootstrap_method = bootstrap; + if (password) { + strcpy(dev->password, password); + dev->password_len = strlen(password); + } dev->status = P2P_SC_SUCCESS; if (p2p->p2p_scan_running) { @@ -1701,7 +1713,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, const u8 *force_ssid, size_t force_ssid_len, - unsigned int pref_freq, u16 oob_pw_id) + unsigned int pref_freq, u16 oob_pw_id, u16 bootstrap, + const char *password) { struct p2p_device *dev; @@ -1735,6 +1748,12 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, dev->flags &= ~P2P_DEV_USER_REJECTED; dev->go_neg_req_sent = 0; dev->go_state = UNKNOWN_GO; + dev->req_bootstrap_method = bootstrap; + + if (password) { + strcpy(dev->password, password); + dev->password_len = strlen(password); + } p2p_set_dev_persistent(dev, persistent_group); p2p->go_intent = go_intent; os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); @@ -1927,7 +1946,7 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa, p2p_handle_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_PROV_DISC_RESP: - p2p_handle_prov_disc_resp(p2p, sa, data + 1, len - 1); + p2p_handle_prov_disc_resp(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_DEV_DISC_REQ: p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq); @@ -3054,6 +3073,9 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) p2p->go_timeout = 100; p2p->client_timeout = 20; p2p->num_p2p_sd_queries = 0; + /*Default comeback after 1 sec */ + if (!p2p->cfg->comeback_after) + p2p->cfg->comeback_after = 1024; p2p_pairing_info_init(p2p); p2p_dbg(p2p, "initialized"); @@ -3436,7 +3458,7 @@ static void p2p_retry_pd(struct p2p_data *p2p) if (!ether_addr_equal(p2p->pending_pd_devaddr, dev->info.p2p_device_addr)) continue; - if (!dev->req_config_methods) + if (!dev->req_config_methods && !dev->req_bootstrap_method) continue; p2p_dbg(p2p, "Send pending Provision Discovery Request to " @@ -5800,6 +5822,7 @@ void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len, return; } + dev->p2p2 = true; /* Reset info from old IEs */ dev->info.reg_info = 0; memset(&dev->info.pairing_config, 0, sizeof(struct p2p_pairing_config)); diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index a092887..5e7d1b7 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -678,6 +678,13 @@ struct p2p_config { bool twt_power_mgmt; /** + * comeback_after - Bootstrap request unauthorised for peer, + * ask to comeback after given time in ms + */ + u16 comeback_after; + + + /** * cb_ctx - Context to use with callback functions */ void *cb_ctx; @@ -1224,6 +1231,19 @@ struct p2p_config { int (*get_pref_freq_list)(void *ctx, int go, unsigned int *len, struct weighted_pcl *freq_list); + + /** + * register_bootstrap_comeback - register timeout to initiate bootstrap + * comeback request + * @ctx: Callback context from cb_ctx + * @addr: p2p device address to which comeback request to be sent + * @comeback_after: time in ms after which comeback request is sent + * + * This function can be used to send comeback request after given + * timeout. + */ + void (*register_bootstrap_comeback)(void *ctx, const u8 *addr, + u16 comeback_after); }; @@ -1407,6 +1427,10 @@ void p2p_stop_listen(struct p2p_data *p2p); * formation * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if * force_freq == 0) + * @oob_pw_id: oob password identifier + * @p2p2: Device supports p2p2 features + * @bootstrap: Bootstrapping method requested for p2p2 provision discovery + * @password: p2p2 pairing password or NULL for opportunistic method * Returns: 0 on success, -1 on failure */ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, @@ -1414,7 +1438,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, const u8 *force_ssid, size_t force_ssid_len, - int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id); + int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id, + bool p2p2, u16 bootstrap, const char *password); /** * p2p_authorize - Authorize P2P group formation (GO negotiation) @@ -1442,7 +1467,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, const u8 *force_ssid, size_t force_ssid_len, - unsigned int pref_freq, u16 oob_pw_id); + unsigned int pref_freq, u16 oob_pw_id, u16 bootstrap, + const char *password); /** * p2p_reject - Reject peer device (explicitly block connection attempts) diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index 347e8a1..182af37 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -796,6 +796,7 @@ void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie, wpabuf_put_u8(buf, cookie_len); wpabuf_put_data(buf, cookie, cookie_len); } + wpabuf_put_le16(buf, bootstrap); /* Update attribute length */ diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 30901b3..04e5139 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -244,6 +244,8 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev) config_method = WPS_CONFIG_PUSHBUTTON; else if (dev->wps_method == WPS_P2PS) config_method = WPS_CONFIG_P2PS; + else if (dev->p2p2 && dev->req_bootstrap_method) + config_method = WPS_NOT_READY; else return -1; return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr, diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 2118052..ef2bb9d 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -36,6 +36,28 @@ enum p2p_go_state { REMOTE_GO }; + +/** + * struct bootstrap_params - P2P Device bootstrap request params + */ + +struct p2p_bootstrap_params { + /* bootstrap method */ + u16 bootstrap_method; + + /* status code */ + enum p2p_status_code status; + + /* cookie for comeback */ + u8 cookie[50]; + + /* cookie length */ + size_t cookie_len; + + /* Comeback time in TUs after which receiver is requested to retry */ + int comeback_after; +}; + /** * struct p2p_device - P2P Device data (internal to P2P module) */ @@ -150,6 +172,22 @@ struct p2p_device { int sd_pending_bcast_queries; bool support_6ghz; + + /* support p2p2 */ + bool p2p2; + + /* requested bootstrap method */ + u16 req_bootstrap_method; + + /* bootstrap params received from peer */ + struct p2p_bootstrap_params *bootstrap_params; + + /* password for p2p2 go negotiation */ + char password[100]; + /** + * password length. Non zero if valid + */ + u16 password_len; }; struct p2p_sd_query { @@ -880,7 +918,7 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq); void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len); + const u8 *data, size_t len, int rx_freq); int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, int join, int force_freq); void p2p_reset_pending_pd(struct p2p_data *p2p); diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index b91b6c3..c0b7411 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -14,6 +14,7 @@ #include "wps/wps_defs.h" #include "p2p_i.h" #include "p2p.h" +#include "crypto/random.h" /* @@ -180,6 +181,62 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev, } } +static struct wpabuf * p2p_build_prov_disc_bootstrap_req(struct p2p_data *p2p, + struct p2p_device *dev) +{ + struct wpabuf *buf; + u8 *len; + size_t cookie_len = 0; + const u8 *cookie = NULL; + u8 dialog_token = dev->dialog_token; + u8 group_capab; + + buf = wpabuf_alloc(1000); + if (buf == NULL) + return NULL; + + wpa_printf(MSG_DEBUG, "P2P2: Building bootstrapping PD req"); + p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token); + + len = p2p_buf_add_ie_hdr(buf); + + group_capab = 0; + + if (p2p->num_groups) { + group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; + if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) && + (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) && + p2p->cross_connect) + 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_DEV_CAPAB_CLIENT_DISCOVERABILITY, + group_capab); + p2p_buf_add_device_info(buf, p2p, NULL); + + if (dev->bootstrap_params) { + cookie = dev->bootstrap_params->cookie; + cookie_len = dev->bootstrap_params->cookie_len; + + if (dev->bootstrap_params->status == P2P_SC_COMEBACK) + p2p_buf_add_status(buf, dev->bootstrap_params->status); + } + + p2p_buf_update_ie_hdr(buf, len); + + len = p2p_buf_add_p2p2_ie_hdr(buf); + + p2p_buf_add_pcea(buf, p2p); + p2p_buf_add_pbma(buf, dev->req_bootstrap_method, cookie, cookie_len, 0); + + p2p_buf_update_p2p2_ie_hdr(buf, len); + + wpa_printf(MSG_DEBUG, "P2P2: Added PCEA and PBMA in PD req"); + return buf; +} static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, @@ -248,6 +305,40 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, return buf; } +static struct wpabuf * p2p_build_prov_disc_bootstrap_resp(struct p2p_data *p2p, + struct p2p_device *dev, + u8 dialog_token, + enum p2p_status_code status) +{ + struct wpabuf *buf; + u8 *cookie = NULL; + size_t cookie_len = 0; + int comeback_after = 0; + + buf = wpabuf_alloc(1000); + if (!buf) + return NULL; + + wpa_printf(MSG_DEBUG, "P2P2: Building boostrapping PD rsp"); + if (status == P2P_SC_COMEBACK && dev->bootstrap_params) { + cookie = dev->bootstrap_params->cookie; + cookie_len = dev->bootstrap_params->cookie_len; + comeback_after = dev->bootstrap_params->comeback_after; + } + + p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token); + + u8 *len = p2p_buf_add_p2p2_ie_hdr(buf); + + p2p_buf_add_status(buf, status); + p2p_buf_add_pcea(buf, p2p); + p2p_buf_add_pbma(buf, dev->req_bootstrap_method, cookie, cookie_len, + comeback_after); + + p2p_buf_update_p2p2_ie_hdr(buf, len); + + return buf; +} static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, struct p2p_device *dev, @@ -600,6 +691,164 @@ void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg, } +static void p2p_process_prov_disc_bootstrap_req(struct p2p_data *p2p, + struct p2p_message *msg, + const u8 *sa, const u8 *data, + size_t len, int rx_freq) +{ + struct p2p_device *dev; + int freq; + struct wpabuf *resp; + u16 bootstrap; + size_t cookie_len = 0; + const u8 *pos, *cookie; + enum p2p_status_code status = P2P_SC_FAIL_INVALID_PARAMS; + + p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR + " with bootstrapping Attribute (freq=%d)", + MAC2STR(sa), rx_freq); + + dev = p2p_get_device(p2p, sa); + if (!dev) { + p2p_dbg(p2p, "Provision Discovery Request from unknown peer " + MACSTR, MAC2STR(sa)); + + if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data, len, 0)) { + p2p_dbg(p2p, "Provision Discovery Request add device failed " + MACSTR, MAC2STR(sa)); + return; + } + + dev = p2p_get_device(p2p, sa); + if (!dev) { + p2p_dbg(p2p, + "Provision Discovery device not found " + MACSTR, MAC2STR(sa)); + return; + } + } + dev->p2p2 = true; + + if (p2p->send_action_in_progress) { + p2p_dbg(p2p, "Dropping retry frame as response tx pending"); + return; + } + + + p2p_update_peer_6ghz_capab(dev, msg); + + if (msg->pcea_info && msg->pcea_info_len >= 2) + p2p_process_pcea(p2p, msg, dev); + + pos = msg->pbma_info; + + if (msg->pbma_info_len > 2 && msg->status && + *msg->status == P2P_SC_COMEBACK) { + /* PBMA comeback request */ + cookie_len = *pos++; + cookie = pos; + + if (!dev->bootstrap_params || + dev->bootstrap_params->cookie_len != cookie_len || + memcmp(cookie, dev->bootstrap_params->cookie, cookie_len)) { + status = P2P_SC_FAIL_REJECTED_BY_USER; + goto out; + } + + bootstrap = dev->bootstrap_params->bootstrap_method; + + if (!dev->req_bootstrap_method) { + status = P2P_SC_COMEBACK; + goto out; + } + } else { + /* PBMA request */ + bootstrap = WPA_GET_LE16(pos); + + if (dev->bootstrap_params) { + os_free(dev->bootstrap_params); + dev->bootstrap_params = NULL; + } + + if (!dev->req_bootstrap_method) { + dev->bootstrap_params = + os_zalloc(sizeof(struct p2p_bootstrap_params)); + if (!dev->bootstrap_params) + return; + dev->bootstrap_params->bootstrap_method = bootstrap; + dev->bootstrap_params->cookie_len = 4; + random_get_bytes(dev->bootstrap_params->cookie, + dev->bootstrap_params->cookie_len); + dev->bootstrap_params->comeback_after = + p2p->cfg->comeback_after; + status = P2P_SC_COMEBACK; + goto out; + } + } + + if (bootstrap == P2P_PBMA_PIN_CODE_DISPLAY && + dev->req_bootstrap_method == P2P_PBMA_PIN_CODE_KEYPAD) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_PIN_CODE_KEYPAD && + dev->req_bootstrap_method == P2P_PBMA_PIN_CODE_DISPLAY) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_PASSPHRASE_DISPLAY && + dev->req_bootstrap_method == P2P_PBMA_PASSPHRASE_KEYPAD) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_PASSPHRASE_KEYPAD && + dev->req_bootstrap_method == P2P_PBMA_PASSPHRASE_DISPLAY) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_NFC_TAG && + dev->req_bootstrap_method == P2P_PBMA_NFC_READER) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_NFC_READER && + dev->req_bootstrap_method == P2P_PBMA_NFC_TAG) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_QR_DISPLAY && + dev->req_bootstrap_method == P2P_PBMA_QR_SCAN) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_QR_SCAN && + dev->req_bootstrap_method == P2P_PBMA_QR_DISPLAY) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_OPPORTUNISTIC && + dev->req_bootstrap_method == P2P_PBMA_OPPORTUNISTIC) + status = P2P_SC_SUCCESS; + else + status = P2P_SC_FAIL_INVALID_PARAMS; + + wpa_printf(MSG_ERROR, "Bootstrap received %d", bootstrap); + +out: + /* + * Send PD Bootstrapping Response for the PD Request + */ + resp = p2p_build_prov_disc_bootstrap_resp(p2p, dev, msg->dialog_token, + status); + if (!resp) + return; + + p2p_dbg(p2p, "Sending Provision Discovery Bootstrap Response"); + if (rx_freq > 0) + freq = rx_freq; + else + freq = p2p_channel_to_freq(p2p->cfg->reg_class, + p2p->cfg->channel); + if (freq < 0) { + p2p_dbg(p2p, "Unknown regulatory class/channel"); + wpabuf_free(resp); + return; + } + p2p->pending_action_state = P2P_PENDING_PD_RESPONSE; + if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, + p2p->cfg->dev_addr, wpabuf_head(resp), + wpabuf_len(resp), 50) < 0) + p2p_dbg(p2p, "Failed to send Action frame"); + else + p2p->send_action_in_progress = 1; + + wpabuf_free(resp); +} + static void p2p_process_prov_disc_req(struct p2p_data *p2p, struct p2p_message *msg, const u8 *sa, const u8 *data, size_t len, int rx_freq) @@ -1241,7 +1490,13 @@ void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa, if (p2p_parse(data, len, &msg)) return; - p2p_process_prov_disc_req(p2p, &msg, sa, data + 1, len - 1, rx_freq); + if (msg.pcea_info && msg.pbma_info) + p2p_process_prov_disc_bootstrap_req(p2p, &msg, sa, data + 1, + len - 1, rx_freq); + else + p2p_process_prov_disc_req(p2p, &msg, sa, data + 1, len - 1, + rx_freq); + p2p_parse_free(&msg); } @@ -1344,6 +1599,88 @@ static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p, } +static void p2p_process_prov_disc_bootstrap_resp(struct p2p_data *p2p, + struct p2p_message *msg, + const u8 *sa, const u8 *data, + size_t len, int rx_freq) +{ + struct p2p_device *dev; + u8 status = P2P_SC_SUCCESS; + size_t cookie_len = 0; + const u8 *pos, *cookie; + u16 comeback_after; + + /* Parse the P2P status present */ + if (msg->status) + status = *msg->status; + + p2p_dbg(p2p, "Received Provision Discovery Bootstrap Response from " MACSTR, + MAC2STR(sa)); + + dev = p2p_get_device(p2p, sa); + if (!dev || !dev->req_bootstrap_method) { + p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR + " with no pending request", MAC2STR(sa)); + return; + } + + p2p_update_peer_6ghz_capab(dev, msg); + + if (dev->dialog_token != msg->dialog_token) { + p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)", + msg->dialog_token, dev->dialog_token); + return; + } + + if (p2p->pending_action_state == P2P_PENDING_PD) { + os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN); + p2p->pending_action_state = P2P_NO_PENDING_ACTION; + } + + if (dev->bootstrap_params) { + os_free(dev->bootstrap_params); + dev->bootstrap_params = NULL; + } + + /* + * If the response is from the peer to whom a user initiated request + * was sent earlier, we reset that state info here. + */ + if (p2p->user_initiated_pd && + ether_addr_equal(p2p->pending_pd_devaddr, sa)) + p2p_reset_pending_pd(p2p); + + if (status == P2P_SC_COMEBACK) { + /* PBMA comeback response */ + pos = msg->pbma_info; + comeback_after = WPA_GET_LE16(pos); + pos += 2; + cookie_len = *pos++; + cookie = pos; + + dev->bootstrap_params = + os_zalloc(sizeof(struct p2p_bootstrap_params)); + if (!dev->bootstrap_params) + return; + dev->bootstrap_params->cookie_len = cookie_len; + memcpy(dev->bootstrap_params->cookie, cookie, cookie_len); + dev->bootstrap_params->comeback_after = comeback_after; + dev->bootstrap_params->bootstrap_method = + dev->req_bootstrap_method; + dev->bootstrap_params->status = status; + + p2p->cfg->register_bootstrap_comeback(p2p->cfg->cb_ctx, sa, + comeback_after); + p2p->cfg->send_action_done(p2p->cfg->cb_ctx); + return; + } + + p2p->cfg->send_action_done(p2p->cfg->cb_ctx); + if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) + dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG; +} + + static void p2p_process_prov_disc_resp(struct p2p_data *p2p, struct p2p_message *msg, const u8 *sa, const u8 *data, size_t len) @@ -1634,14 +1971,19 @@ out: void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len) + const u8 *data, size_t len, int rx_freq) { struct p2p_message msg; if (p2p_parse(data, len, &msg)) return; - p2p_process_prov_disc_resp(p2p, &msg, sa, data + 1, len - 1); + if (msg.pcea_info && msg.pbma_info) + p2p_process_prov_disc_bootstrap_resp(p2p, &msg, sa, data + 1, + len - 1, rx_freq); + else + p2p_process_prov_disc_resp(p2p, &msg, sa, data + 1, len - 1); + p2p_parse_free(&msg); } @@ -1675,7 +2017,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, /* TODO: use device discoverability request through GO */ } - if (p2p->p2ps_prov) { + if (!dev->p2p2 && p2p->p2ps_prov) { if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) { if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY) dev->req_config_methods = WPS_CONFIG_KEYPAD; @@ -1705,7 +2047,11 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, return -1; } - req = p2p_build_prov_disc_req(p2p, dev, join); + if (dev->p2p2) + req = p2p_build_prov_disc_bootstrap_req(p2p, dev); + else + req = p2p_build_prov_disc_req(p2p, dev, join); + if (req == NULL) return -1; @@ -1744,13 +2090,22 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, return -1; } + if (dev->p2p2 && dev->req_bootstrap_method) { + p2p_dbg(p2p, "Provision Discovery Request with " MACSTR + " (bootstrap methods 0x%x)", + MAC2STR(peer_addr), dev->req_bootstrap_method); + goto out; + } + p2p_dbg(p2p, "Provision Discovery Request with " MACSTR " (config methods 0x%x)", MAC2STR(peer_addr), config_methods); + if (config_methods == 0 && !p2ps_prov) { os_free(p2ps_prov); return -1; } + dev->req_config_methods = config_methods; if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { @@ -1758,12 +2113,12 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, p2ps_prov->method = p2p->p2ps_prov->method; } +out: /* Reset provisioning info */ dev->wps_prov_info = 0; p2ps_prov_free(p2p); p2p->p2ps_prov = p2ps_prov; - dev->req_config_methods = config_methods; if (join) dev->flags |= P2P_DEV_PD_FOR_JOIN; else @@ -1772,8 +2127,7 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH && p2p->state != P2P_LISTEN_ONLY) { p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with " - MACSTR " (config methods 0x%x)", - MAC2STR(peer_addr), config_methods); + MACSTR, MAC2STR(peer_addr)); return 0; } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 5588e79..b223b7c 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -6376,6 +6376,10 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, size_t group_ssid_len = 0; int he; bool allow_6ghz; + bool p2p2; + u16 bootstrap = 0; + const char *password = NULL; + char *token, *context = NULL; if (!wpa_s->global->p2p_init_wpa_s) return -1; @@ -6388,7 +6392,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps] * [persistent|persistent=<network id>] * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] - * [ht40] [vht] [he] [edmg] [auto] [ssid=<hexdump>] */ + * [ht40] [vht] [he] [edmg] [auto] [ssid=<hexdump>] + * [p2p2] [bstrapmethod=<value>] [password=<string>] + */ if (hwaddr_aton(cmd, addr)) return -1; @@ -6422,6 +6428,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, vht; he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he; edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg; + p2p2 = os_strstr(pos, "p2p2") != NULL; pos2 = os_strstr(pos, " go_intent="); if (pos2) { @@ -6477,6 +6484,8 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, wps_method = WPS_PBC; } else if (os_strstr(pos, "p2ps") != NULL) { wps_method = WPS_P2PS; + } else if (p2p2) { + wps_method = WPS_NOT_READY; } else { pin = pos; pos = os_strchr(pin, ' '); @@ -6492,11 +6501,26 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, } } + pos2 = os_strstr(pos, "bstrapmethod="); + if (pos2) { + pos2 += 13; + bootstrap = atoi(pos2); + pd = true; + } + + while ((token = str_token(pos, " ", &context))) { + if (os_strncmp(token, "password=", 9) == 0) { + password = token + 9; + continue; + } + } + new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, automatic, join, auth, go_intent, freq, freq2, persistent_id, pd, ht40, vht, max_oper_chwidth, he, edmg, - group_ssid, group_ssid_len, allow_6ghz); + group_ssid, group_ssid_len, allow_6ghz, p2p2, + bootstrap, password); if (new_pin == -2) { os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); return 25; diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 3de6ed8..65bd478 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -706,7 +706,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, 0, join, authorize_only, go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0, - NULL, 0, false); + NULL, 0, false, 0, 0, NULL); if (new_pin >= 0) { char npin[9]; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index d756d28..c524084 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -4823,6 +4823,39 @@ static int wpas_p2p_get_pref_freq_list(void *ctx, int go, WPA_IF_P2P_CLIENT, len, freq_list); } +static void wpas_p2p_send_bootstrap_comeback(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + wpa_printf(MSG_DEBUG, "P2P2: Send Bootstrapping comeback PD req"); + wpas_p2p_connect(wpa_s, wpa_s->p2p_bootstrap_dev_addr, wpa_s->p2p_pin, + wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, + 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq, + wpa_s->p2p_go_vht_center_freq2, + wpa_s->p2p_persistent_id, + wpa_s->p2p_pd_before_go_neg, + wpa_s->p2p_go_ht40, + wpa_s->p2p_go_vht, + wpa_s->p2p_go_max_oper_chwidth, + wpa_s->p2p_go_he, + wpa_s->p2p_go_edmg, + NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p), + wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL); +} + +static void wpas_p2p_register_bootstrap_comeback(void *ctx, const u8 *addr, + u16 comeback_after) +{ + unsigned int timeout_us; + struct wpa_supplicant *wpa_s = ctx; + + timeout_us = comeback_after * 1024; + memcpy(wpa_s->p2p_bootstrap_dev_addr, addr, ETH_ALEN); + + eloop_cancel_timeout(wpas_p2p_send_bootstrap_comeback, wpa_s, NULL); + eloop_register_timeout(0, timeout_us, wpas_p2p_send_bootstrap_comeback, + wpa_s, NULL); +} int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s) { @@ -4943,6 +4976,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.p2ps_group_capability = p2ps_group_capability; p2p.get_pref_freq_list = wpas_p2p_get_pref_freq_list; p2p.p2p_6ghz_disable = wpa_s->conf->p2p_6ghz_disable; + p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback; os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); @@ -5222,7 +5256,8 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, - struct wpa_ssid *ssid, unsigned int pref_freq) + struct wpa_ssid *ssid, unsigned int pref_freq, + bool p2p2, u16 bootstrap, const char *password) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; @@ -5240,7 +5275,7 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, ssid ? ssid->ssid_len : 0, wpa_s->p2p_pd_before_go_neg, pref_freq, wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id : - 0); + 0, p2p2, bootstrap, password); } @@ -5249,7 +5284,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, - struct wpa_ssid *ssid, unsigned int pref_freq) + struct wpa_ssid *ssid, unsigned int pref_freq, + u16 bootstrap, const char *password) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; @@ -5259,7 +5295,7 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, persistent_group, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0, pref_freq, wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id : - 0); + 0, bootstrap, password); } @@ -5443,7 +5479,9 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, NULL, 0, - is_p2p_allow_6ghz(wpa_s->global->p2p)); + is_p2p_allow_6ghz(wpa_s->global->p2p), + wpa_s->p2p2, wpa_s->p2p_bootstrap, + NULL); return; } @@ -5937,6 +5975,9 @@ static bool is_p2p_6ghz_supported(struct wpa_supplicant *wpa_s, HOSTAPD_MODE_IEEE80211A, true)) return false; + if (wpa_s->p2p2) + return true; + if (!p2p_wfd_enabled(wpa_s->global->p2p)) return false; if (peer_addr && !p2p_peer_wfd_enabled(wpa_s->global->p2p, peer_addr)) @@ -5988,6 +6029,10 @@ static int wpas_p2p_check_6ghz(struct wpa_supplicant *wpa_s, * @group_ssid: Specific Group SSID for join or %NULL if not set * @group_ssid_len: Length of @group_ssid in octets * @allow_6ghz: Allow P2P connection on 6 GHz channels + * @p2p2: Device in P2P R2 mode + * @bootstrap: Requested bootstrap method for pairing in p2p2 + * @password: Password for pairing setup or NULL for oppurtunistic method + * in p2p2 * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified * failure, -2 on failure due to channel not currently available, * -3 if forced channel is not supported @@ -5999,7 +6044,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int persistent_id, int pd, int ht40, int vht, unsigned int vht_chwidth, int he, int edmg, const u8 *group_ssid, size_t group_ssid_len, - bool allow_6ghz) + bool allow_6ghz, bool p2p2, u16 bootstrap, + const char *password) { int force_freq = 0, pref_freq = 0; int ret = 0, res; @@ -6019,6 +6065,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return -1; } + wpa_s->p2p2 = p2p2; + if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq)) return -2; @@ -6049,6 +6097,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_go_max_oper_chwidth = vht_chwidth; wpa_s->p2p_go_he = !!he; wpa_s->p2p_go_edmg = !!edmg; + wpa_s->p2p_bootstrap = bootstrap; if (pin) os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin)); @@ -6134,14 +6183,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, force_freq, persistent_group, ssid, - pref_freq) < 0) + pref_freq, bootstrap, password) < 0) return -1; return ret; } if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, force_freq, - persistent_group, ssid, pref_freq) < 0) { + persistent_group, ssid, pref_freq, p2p2, + bootstrap, password) < 0) { if (wpa_s->create_p2p_iface) wpas_p2p_remove_pending_group_interface(wpa_s); return -1; @@ -8769,7 +8819,8 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p)); + NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p), + wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL); return ret; } @@ -9307,7 +9358,8 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, params->go_ssid_len ? params->go_ssid : NULL, - params->go_ssid_len, false); + params->go_ssid_len, false, wpa_s->p2p2, + wpa_s->p2p_bootstrap, NULL); } @@ -9386,7 +9438,8 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s, forced_freq, wpa_s->p2p_go_vht_center_freq2, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0, false); + NULL, 0, false, wpa_s->p2p2, + wpa_s->p2p_bootstrap, NULL); } @@ -9403,7 +9456,9 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s, forced_freq, wpa_s->p2p_go_vht_center_freq2, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0, false); + NULL, 0, false, wpa_s->p2p2, + wpa_s->p2p_bootstrap, NULL); + if (res) return res; diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 441e063..a2cb78d 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -39,7 +39,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int persistent_id, int pd, int ht40, int vht, unsigned int vht_chwidth, int he, int edmg, const u8 *group_ssid, size_t group_ssid_len, - bool allow_6ghz); + bool allow_6ghz, bool p2p2, u16 bootstrap, + const char *password); int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq, struct wpa_ssid *ssid); int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 47a1151..35f541f 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1113,6 +1113,7 @@ struct wpa_supplicant { int pending_pd_before_join; u8 pending_join_iface_addr[ETH_ALEN]; u8 pending_join_dev_addr[ETH_ALEN]; + u8 p2p_bootstrap_dev_addr[ETH_ALEN]; int pending_join_wps_method; u8 p2p_join_ssid[SSID_MAX_LEN]; size_t p2p_join_ssid_len; @@ -1167,6 +1168,8 @@ struct wpa_supplicant { unsigned int p2ps_method_config_any:1; unsigned int p2p_cli_probe:1; unsigned int p2p_go_allow_dfs:1; + unsigned int p2p2:1; + u16 p2p_bootstrap; enum hostapd_hw_mode p2p_go_acs_band; int p2p_persistent_go_freq; int p2p_persistent_id; -- 2.7.4 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap