@@ -1785,6 +1785,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)
@@ -1816,6 +1831,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 {
@@ -955,6 +955,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);
@@ -1600,7 +1605,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;
@@ -1684,6 +1690,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) {
@@ -1702,7 +1714,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;
@@ -1736,6 +1749,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);
@@ -1928,7 +1947,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);
@@ -3437,7 +3456,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 "
@@ -663,6 +663,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
*/
@@ -1210,6 +1217,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);
};
@@ -1393,6 +1413,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,
@@ -1400,7 +1424,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)
@@ -1428,7 +1453,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)
@@ -784,9 +784,6 @@ void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie,
{
u8 *len;
- if (!bootstrap)
- return;
-
/* P2P Pairing and Bootstrapping methods */
wpabuf_put_u8(buf, P2P_ATTR_PAIRING_AND_BOOTSTRAPPING);
/* Length to be filled */
@@ -798,6 +795,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 */
@@ -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,
@@ -41,6 +41,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)
*/
@@ -155,6 +177,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 {
@@ -887,7 +925,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);
@@ -14,6 +14,7 @@
#include "wps/wps_defs.h"
#include "p2p_i.h"
#include "p2p.h"
+#include "crypto/random.h"
/*
@@ -180,6 +181,61 @@ 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;
+
+ 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 +304,39 @@ 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;
+
+ 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,
@@ -597,6 +686,160 @@ 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 + 1, len - 1,
+ 0)) {
+ p2p_dbg(p2p, "Provision Discovery Request add device failed "
+ MACSTR, MAC2STR(sa));
+ goto out;
+ }
+
+ dev = p2p_get_device(p2p, sa);
+ if (!dev) {
+ p2p_dbg(p2p,
+ "Provision Discovery device not found "
+ MACSTR, MAC2STR(sa));
+ goto out;
+ }
+ }
+ dev->p2p2 = true;
+
+ // FIXME: 6ghz capab is present in PCEA for P2P2
+ 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)
@@ -1239,7 +1482,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);
}
@@ -1342,6 +1591,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)
@@ -1632,14 +1963,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);
}
@@ -1673,7 +2009,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;
@@ -1703,7 +2039,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;
@@ -1742,13 +2082,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) {
@@ -1756,12 +2105,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
@@ -1770,8 +2119,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;
}
@@ -6362,6 +6362,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;
@@ -6374,7 +6378,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;
@@ -6408,6 +6414,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) {
@@ -6463,6 +6470,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, ' ');
@@ -6478,11 +6487,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;
@@ -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];
@@ -4822,6 +4822,38 @@ 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;
+
+ 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)
{
@@ -4942,6 +4974,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);
@@ -5193,7 +5226,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;
@@ -5211,7 +5245,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);
}
@@ -5220,7 +5254,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;
@@ -5230,7 +5265,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);
}
@@ -5414,7 +5449,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;
}
@@ -5959,6 +5996,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
@@ -5970,7 +6011,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;
@@ -6020,6 +6062,8 @@ 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->p2p2 = p2p2;
+ wpa_s->p2p_bootstrap = bootstrap;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -6105,14 +6149,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;
@@ -8740,7 +8785,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;
}
@@ -9278,7 +9324,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);
}
@@ -9357,7 +9404,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);
}
@@ -9374,7 +9422,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;
@@ -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,
@@ -1111,6 +1111,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;
@@ -1165,6 +1166,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;
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@quicinc.com>