P2P2: Add bootstrapping support with PD frames
Add support for P2P2 bootstrapping with comeback mechanism using Provision Discovery frames. Extend the control interface command P2P_CONNECT to allow P2P2 bootstrapping handshake. Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
This commit is contained in:
parent
6aa9ad8f8f
commit
59299a8a7d
10 changed files with 562 additions and 31 deletions
|
@ -954,6 +954,7 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
|
||||||
dev->info.wps_vendor_ext[i] = NULL;
|
dev->info.wps_vendor_ext[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
os_free(dev->bootstrap_params);
|
||||||
wpabuf_free(dev->info.wfd_subelems);
|
wpabuf_free(dev->info.wfd_subelems);
|
||||||
wpabuf_free(dev->info.vendor_elems);
|
wpabuf_free(dev->info.vendor_elems);
|
||||||
wpabuf_free(dev->go_neg_conf);
|
wpabuf_free(dev->go_neg_conf);
|
||||||
|
@ -1599,7 +1600,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
int go_intent, const u8 *own_interface_addr,
|
int go_intent, const u8 *own_interface_addr,
|
||||||
unsigned int force_freq, int persistent_group,
|
unsigned int force_freq, int persistent_group,
|
||||||
const u8 *force_ssid, size_t force_ssid_len,
|
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;
|
struct p2p_device *dev;
|
||||||
|
|
||||||
|
@ -1683,6 +1685,10 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
|
|
||||||
dev->wps_method = wps_method;
|
dev->wps_method = wps_method;
|
||||||
dev->oob_pw_id = oob_pw_id;
|
dev->oob_pw_id = oob_pw_id;
|
||||||
|
dev->p2p2 = p2p2;
|
||||||
|
dev->req_bootstrap_method = bootstrap;
|
||||||
|
if (password && os_strlen(password) < sizeof(dev->password))
|
||||||
|
os_strlcpy(dev->password, password, sizeof(dev->password));
|
||||||
dev->status = P2P_SC_SUCCESS;
|
dev->status = P2P_SC_SUCCESS;
|
||||||
|
|
||||||
if (p2p->p2p_scan_running) {
|
if (p2p->p2p_scan_running) {
|
||||||
|
@ -1701,7 +1707,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
int go_intent, const u8 *own_interface_addr,
|
int go_intent, const u8 *own_interface_addr,
|
||||||
unsigned int force_freq, int persistent_group,
|
unsigned int force_freq, int persistent_group,
|
||||||
const u8 *force_ssid, size_t force_ssid_len,
|
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;
|
struct p2p_device *dev;
|
||||||
|
|
||||||
|
@ -1735,6 +1742,10 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
dev->flags &= ~P2P_DEV_USER_REJECTED;
|
dev->flags &= ~P2P_DEV_USER_REJECTED;
|
||||||
dev->go_neg_req_sent = 0;
|
dev->go_neg_req_sent = 0;
|
||||||
dev->go_state = UNKNOWN_GO;
|
dev->go_state = UNKNOWN_GO;
|
||||||
|
dev->req_bootstrap_method = bootstrap;
|
||||||
|
|
||||||
|
if (password && os_strlen(password) < sizeof(dev->password))
|
||||||
|
os_strlcpy(dev->password, password, sizeof(dev->password));
|
||||||
p2p_set_dev_persistent(dev, persistent_group);
|
p2p_set_dev_persistent(dev, persistent_group);
|
||||||
p2p->go_intent = go_intent;
|
p2p->go_intent = go_intent;
|
||||||
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
|
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
|
||||||
|
@ -1927,7 +1938,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);
|
p2p_handle_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
|
||||||
break;
|
break;
|
||||||
case P2P_PROV_DISC_RESP:
|
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;
|
break;
|
||||||
case P2P_DEV_DISC_REQ:
|
case P2P_DEV_DISC_REQ:
|
||||||
p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
|
p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
|
||||||
|
@ -3061,6 +3072,9 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
|
||||||
p2p->go_timeout = 100;
|
p2p->go_timeout = 100;
|
||||||
p2p->client_timeout = 20;
|
p2p->client_timeout = 20;
|
||||||
p2p->num_p2p_sd_queries = 0;
|
p2p->num_p2p_sd_queries = 0;
|
||||||
|
/* Default comeback after one second */
|
||||||
|
if (!p2p->cfg->comeback_after)
|
||||||
|
p2p->cfg->comeback_after = 977; /* TUs */
|
||||||
p2p_pairing_info_init(p2p);
|
p2p_pairing_info_init(p2p);
|
||||||
|
|
||||||
p2p_dbg(p2p, "initialized");
|
p2p_dbg(p2p, "initialized");
|
||||||
|
@ -3439,7 +3453,7 @@ static void p2p_retry_pd(struct p2p_data *p2p)
|
||||||
if (!ether_addr_equal(p2p->pending_pd_devaddr,
|
if (!ether_addr_equal(p2p->pending_pd_devaddr,
|
||||||
dev->info.p2p_device_addr))
|
dev->info.p2p_device_addr))
|
||||||
continue;
|
continue;
|
||||||
if (!dev->req_config_methods)
|
if (!dev->req_config_methods && !dev->req_bootstrap_method)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
p2p_dbg(p2p, "Send pending Provision Discovery Request to "
|
p2p_dbg(p2p, "Send pending Provision Discovery Request to "
|
||||||
|
@ -5868,6 +5882,7 @@ void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev->p2p2 = true;
|
||||||
/* Reset info from old IEs */
|
/* Reset info from old IEs */
|
||||||
dev->info.reg_info = 0;
|
dev->info.reg_info = 0;
|
||||||
os_memset(&dev->info.pairing_config, 0,
|
os_memset(&dev->info.pairing_config, 0,
|
||||||
|
|
|
@ -678,6 +678,13 @@ struct p2p_config {
|
||||||
*/
|
*/
|
||||||
bool twt_power_mgmt;
|
bool twt_power_mgmt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* comeback_after - Bootstrap request unauthorized for peer
|
||||||
|
*
|
||||||
|
* Ask to come back after this many TUs.
|
||||||
|
*/
|
||||||
|
u16 comeback_after;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cb_ctx - Context to use with callback functions
|
* cb_ctx - Context to use with callback functions
|
||||||
*/
|
*/
|
||||||
|
@ -1225,6 +1232,19 @@ struct p2p_config {
|
||||||
int (*get_pref_freq_list)(void *ctx, int go,
|
int (*get_pref_freq_list)(void *ctx, int go,
|
||||||
unsigned int *len,
|
unsigned int *len,
|
||||||
struct weighted_pcl *freq_list);
|
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 is to be sent
|
||||||
|
* @comeback_after: Time in TUs 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1408,6 +1428,10 @@ void p2p_stop_listen(struct p2p_data *p2p);
|
||||||
* formation
|
* formation
|
||||||
* @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
|
* @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
|
||||||
* force_freq == 0)
|
* 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
|
* Returns: 0 on success, -1 on failure
|
||||||
*/
|
*/
|
||||||
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
|
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
|
@ -1415,7 +1439,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
int go_intent, const u8 *own_interface_addr,
|
int go_intent, const u8 *own_interface_addr,
|
||||||
unsigned int force_freq, int persistent_group,
|
unsigned int force_freq, int persistent_group,
|
||||||
const u8 *force_ssid, size_t force_ssid_len,
|
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)
|
* p2p_authorize - Authorize P2P group formation (GO negotiation)
|
||||||
|
@ -1433,6 +1458,9 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
* @force_ssid_len: Length of $force_ssid buffer
|
* @force_ssid_len: Length of $force_ssid buffer
|
||||||
* @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
|
* @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
|
||||||
* force_freq == 0)
|
* force_freq == 0)
|
||||||
|
* @oob_pw_id: OOB password identifier
|
||||||
|
* @bootstrap: Bootstrapping method requested for P2P2 provision discovery
|
||||||
|
* @password: P2P2 pairing password or %NULL for opportunistic method
|
||||||
* Returns: 0 on success, -1 on failure
|
* Returns: 0 on success, -1 on failure
|
||||||
*
|
*
|
||||||
* This is like p2p_connect(), but the actual group negotiation is not
|
* This is like p2p_connect(), but the actual group negotiation is not
|
||||||
|
@ -1443,7 +1471,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
int go_intent, const u8 *own_interface_addr,
|
int go_intent, const u8 *own_interface_addr,
|
||||||
unsigned int force_freq, int persistent_group,
|
unsigned int force_freq, int persistent_group,
|
||||||
const u8 *force_ssid, size_t force_ssid_len,
|
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)
|
* p2p_reject - Reject peer device (explicitly block connection attempts)
|
||||||
|
|
|
@ -244,6 +244,8 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
|
||||||
config_method = WPS_CONFIG_PUSHBUTTON;
|
config_method = WPS_CONFIG_PUSHBUTTON;
|
||||||
else if (dev->wps_method == WPS_P2PS)
|
else if (dev->wps_method == WPS_P2PS)
|
||||||
config_method = WPS_CONFIG_P2PS;
|
config_method = WPS_CONFIG_P2PS;
|
||||||
|
else if (dev->p2p2 && dev->req_bootstrap_method)
|
||||||
|
config_method = WPS_NOT_READY;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
|
return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
|
||||||
|
|
|
@ -36,6 +36,26 @@ enum p2p_go_state {
|
||||||
REMOTE_GO
|
REMOTE_GO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bootstrap_params - P2P Device bootstrap request parameters
|
||||||
|
*/
|
||||||
|
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)
|
* struct p2p_device - P2P Device data (internal to P2P module)
|
||||||
*/
|
*/
|
||||||
|
@ -150,6 +170,18 @@ struct p2p_device {
|
||||||
|
|
||||||
int sd_pending_bcast_queries;
|
int sd_pending_bcast_queries;
|
||||||
bool support_6ghz;
|
bool support_6ghz;
|
||||||
|
|
||||||
|
/* Supports P2P2 */
|
||||||
|
bool p2p2;
|
||||||
|
|
||||||
|
/* Requested bootstrap method */
|
||||||
|
u16 req_bootstrap_method;
|
||||||
|
|
||||||
|
/* Bootstrap parameters received from peer */
|
||||||
|
struct p2p_bootstrap_params *bootstrap_params;
|
||||||
|
|
||||||
|
/* Password for P2P2 GO negotiation */
|
||||||
|
char password[100];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct p2p_sd_query {
|
struct p2p_sd_query {
|
||||||
|
@ -876,7 +908,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,
|
void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||||
const u8 *data, size_t len, int rx_freq);
|
const u8 *data, size_t len, int rx_freq);
|
||||||
void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
|
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 p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
|
||||||
int join, int force_freq);
|
int join, int force_freq);
|
||||||
void p2p_reset_pending_pd(struct p2p_data *p2p);
|
void p2p_reset_pending_pd(struct p2p_data *p2p);
|
||||||
|
|
383
src/p2p/p2p_pd.c
383
src/p2p/p2p_pd.c
|
@ -181,6 +181,64 @@ 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)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p2p_dbg(p2p, "P2P2: Building bootstrapping PD Request");
|
||||||
|
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_ie_hdr(buf, len);
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "P2P2: Added PCEA and PBMA in PD Request");
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
|
static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
|
||||||
struct p2p_device *dev,
|
struct p2p_device *dev,
|
||||||
int join)
|
int join)
|
||||||
|
@ -249,6 +307,42 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
u8 *len;
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(1000);
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p2p_dbg(p2p, "P2P2: Building boostrapping PD Response");
|
||||||
|
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);
|
||||||
|
|
||||||
|
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_ie_hdr(buf, len);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
|
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
|
||||||
struct p2p_device *dev,
|
struct p2p_device *dev,
|
||||||
u8 dialog_token,
|
u8 dialog_token,
|
||||||
|
@ -614,6 +708,171 @@ 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++;
|
||||||
|
if (msg->pbma_info_len < 1 + cookie_len) {
|
||||||
|
p2p_dbg(p2p, "Truncated PBMA");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cookie = pos;
|
||||||
|
|
||||||
|
if (!dev->bootstrap_params ||
|
||||||
|
dev->bootstrap_params->cookie_len != cookie_len ||
|
||||||
|
os_memcmp(cookie, dev->bootstrap_params->cookie,
|
||||||
|
cookie_len) != 0) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (os_get_random(dev->bootstrap_params->cookie,
|
||||||
|
dev->bootstrap_params->cookie_len) <
|
||||||
|
0) {
|
||||||
|
os_free(dev->bootstrap_params);
|
||||||
|
dev->bootstrap_params = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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 operating 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,
|
static void p2p_process_prov_disc_req(struct p2p_data *p2p,
|
||||||
struct p2p_message *msg, const u8 *sa,
|
struct p2p_message *msg, const u8 *sa,
|
||||||
const u8 *data, size_t len, int rx_freq)
|
const u8 *data, size_t len, int rx_freq)
|
||||||
|
@ -1257,7 +1516,13 @@ void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||||
if (p2p_parse(data, len, &msg))
|
if (p2p_parse(data, len, &msg))
|
||||||
return;
|
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);
|
p2p_parse_free(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1360,6 +1625,91 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 information 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;
|
||||||
|
if (msg->pbma_info_len < 2 + 1)
|
||||||
|
return;
|
||||||
|
comeback_after = WPA_GET_LE16(pos);
|
||||||
|
pos += 2;
|
||||||
|
cookie_len = *pos++;
|
||||||
|
if (msg->pbma_info_len < 2 + 1 + cookie_len) {
|
||||||
|
p2p_dbg(p2p, "Truncated PBMA");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cookie = pos;
|
||||||
|
|
||||||
|
dev->bootstrap_params =
|
||||||
|
os_zalloc(sizeof(struct p2p_bootstrap_params));
|
||||||
|
if (!dev->bootstrap_params)
|
||||||
|
return;
|
||||||
|
dev->bootstrap_params->cookie_len = cookie_len;
|
||||||
|
os_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,
|
static void p2p_process_prov_disc_resp(struct p2p_data *p2p,
|
||||||
struct p2p_message *msg, const u8 *sa,
|
struct p2p_message *msg, const u8 *sa,
|
||||||
const u8 *data, size_t len)
|
const u8 *data, size_t len)
|
||||||
|
@ -1650,14 +2000,19 @@ out:
|
||||||
|
|
||||||
|
|
||||||
void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
|
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;
|
struct p2p_message msg;
|
||||||
|
|
||||||
if (p2p_parse(data, len, &msg))
|
if (p2p_parse(data, len, &msg))
|
||||||
return;
|
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);
|
p2p_parse_free(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1691,7 +2046,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
|
||||||
/* TODO: use device discoverability request through GO */
|
/* 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->status == P2P_SC_SUCCESS_DEFERRED) {
|
||||||
if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY)
|
if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY)
|
||||||
dev->req_config_methods = WPS_CONFIG_KEYPAD;
|
dev->req_config_methods = WPS_CONFIG_KEYPAD;
|
||||||
|
@ -1721,7 +2076,11 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
|
||||||
return -1;
|
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)
|
if (req == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -1760,13 +2119,22 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
return -1;
|
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
|
p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
|
||||||
" (config methods 0x%x)",
|
" (config methods 0x%x)",
|
||||||
MAC2STR(peer_addr), config_methods);
|
MAC2STR(peer_addr), config_methods);
|
||||||
|
|
||||||
if (config_methods == 0 && !p2ps_prov) {
|
if (config_methods == 0 && !p2ps_prov) {
|
||||||
os_free(p2ps_prov);
|
os_free(p2ps_prov);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
dev->req_config_methods = config_methods;
|
||||||
|
|
||||||
if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED &&
|
if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED &&
|
||||||
p2p->p2ps_prov) {
|
p2p->p2ps_prov) {
|
||||||
|
@ -1774,12 +2142,12 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
p2ps_prov->method = p2p->p2ps_prov->method;
|
p2ps_prov->method = p2p->p2ps_prov->method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
/* Reset provisioning info */
|
/* Reset provisioning info */
|
||||||
dev->wps_prov_info = 0;
|
dev->wps_prov_info = 0;
|
||||||
p2ps_prov_free(p2p);
|
p2ps_prov_free(p2p);
|
||||||
p2p->p2ps_prov = p2ps_prov;
|
p2p->p2ps_prov = p2ps_prov;
|
||||||
|
|
||||||
dev->req_config_methods = config_methods;
|
|
||||||
if (join)
|
if (join)
|
||||||
dev->flags |= P2P_DEV_PD_FOR_JOIN;
|
dev->flags |= P2P_DEV_PD_FOR_JOIN;
|
||||||
else
|
else
|
||||||
|
@ -1788,8 +2156,7 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
|
||||||
if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
|
if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
|
||||||
p2p->state != P2P_LISTEN_ONLY) {
|
p2p->state != P2P_LISTEN_ONLY) {
|
||||||
p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
|
p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
|
||||||
MACSTR " (config methods 0x%x)",
|
MACSTR, MAC2STR(peer_addr));
|
||||||
MAC2STR(peer_addr), config_methods);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6376,6 +6376,10 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
|
||||||
size_t group_ssid_len = 0;
|
size_t group_ssid_len = 0;
|
||||||
int he;
|
int he;
|
||||||
bool allow_6ghz;
|
bool allow_6ghz;
|
||||||
|
bool p2p2;
|
||||||
|
u16 bootstrap = 0;
|
||||||
|
const char *password = NULL;
|
||||||
|
char *token, *context = NULL;
|
||||||
|
|
||||||
if (!wpa_s->global->p2p_init_wpa_s)
|
if (!wpa_s->global->p2p_init_wpa_s)
|
||||||
return -1;
|
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]
|
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
|
||||||
* [persistent|persistent=<network id>]
|
* [persistent|persistent=<network id>]
|
||||||
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
|
* [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))
|
if (hwaddr_aton(cmd, addr))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -6422,6 +6428,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
|
||||||
vht;
|
vht;
|
||||||
he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
|
he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
|
||||||
edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
|
edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
|
||||||
|
p2p2 = os_strstr(pos, " p2p2") != NULL;
|
||||||
|
|
||||||
pos2 = os_strstr(pos, " go_intent=");
|
pos2 = os_strstr(pos, " go_intent=");
|
||||||
if (pos2) {
|
if (pos2) {
|
||||||
|
@ -6477,6 +6484,8 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
|
||||||
wps_method = WPS_PBC;
|
wps_method = WPS_PBC;
|
||||||
} else if (os_strstr(pos, "p2ps") != NULL) {
|
} else if (os_strstr(pos, "p2ps") != NULL) {
|
||||||
wps_method = WPS_P2PS;
|
wps_method = WPS_P2PS;
|
||||||
|
} else if (p2p2) {
|
||||||
|
wps_method = WPS_NOT_READY;
|
||||||
} else {
|
} else {
|
||||||
pin = pos;
|
pin = pos;
|
||||||
pos = os_strchr(pin, ' ');
|
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,
|
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
|
||||||
persistent_group, automatic, join,
|
persistent_group, automatic, join,
|
||||||
auth, go_intent, freq, freq2, persistent_id,
|
auth, go_intent, freq, freq2, persistent_id,
|
||||||
pd, ht40, vht, max_oper_chwidth, he, edmg,
|
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) {
|
if (new_pin == -2) {
|
||||||
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
|
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
|
||||||
return 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,
|
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
|
||||||
persistent_group, 0, join, authorize_only,
|
persistent_group, 0, join, authorize_only,
|
||||||
go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0,
|
go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0,
|
||||||
NULL, 0, false);
|
NULL, 0, false, 0, 0, NULL);
|
||||||
|
|
||||||
if (new_pin >= 0) {
|
if (new_pin >= 0) {
|
||||||
char npin[9];
|
char npin[9];
|
||||||
|
|
|
@ -4823,6 +4823,42 @@ static int wpas_p2p_get_pref_freq_list(void *ctx, int go,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 Request");
|
||||||
|
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;
|
||||||
|
os_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)
|
int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
|
||||||
{
|
{
|
||||||
u8 addr[ETH_ALEN] = {0};
|
u8 addr[ETH_ALEN] = {0};
|
||||||
|
@ -4942,6 +4978,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
|
||||||
p2p.p2ps_group_capability = p2ps_group_capability;
|
p2p.p2ps_group_capability = p2ps_group_capability;
|
||||||
p2p.get_pref_freq_list = wpas_p2p_get_pref_freq_list;
|
p2p.get_pref_freq_list = wpas_p2p_get_pref_freq_list;
|
||||||
p2p.p2p_6ghz_disable = wpa_s->conf->p2p_6ghz_disable;
|
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(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);
|
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
|
||||||
|
@ -5139,6 +5176,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
|
||||||
wpa_s->p2p_send_action_work = NULL;
|
wpa_s->p2p_send_action_work = NULL;
|
||||||
}
|
}
|
||||||
eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL);
|
eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL);
|
||||||
|
eloop_cancel_timeout(wpas_p2p_send_bootstrap_comeback, wpa_s, NULL);
|
||||||
|
|
||||||
wpabuf_free(wpa_s->p2p_oob_dev_pw);
|
wpabuf_free(wpa_s->p2p_oob_dev_pw);
|
||||||
wpa_s->p2p_oob_dev_pw = NULL;
|
wpa_s->p2p_oob_dev_pw = NULL;
|
||||||
|
@ -5221,7 +5259,8 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
|
||||||
enum p2p_wps_method wps_method,
|
enum p2p_wps_method wps_method,
|
||||||
int go_intent, const u8 *own_interface_addr,
|
int go_intent, const u8 *own_interface_addr,
|
||||||
unsigned int force_freq, int persistent_group,
|
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)
|
if (persistent_group && wpa_s->conf->persistent_reconnect)
|
||||||
persistent_group = 2;
|
persistent_group = 2;
|
||||||
|
@ -5239,7 +5278,7 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
|
||||||
ssid ? ssid->ssid_len : 0,
|
ssid ? ssid->ssid_len : 0,
|
||||||
wpa_s->p2p_pd_before_go_neg, pref_freq,
|
wpa_s->p2p_pd_before_go_neg, pref_freq,
|
||||||
wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
|
wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
|
||||||
0);
|
0, p2p2, bootstrap, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5248,7 +5287,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
|
||||||
enum p2p_wps_method wps_method,
|
enum p2p_wps_method wps_method,
|
||||||
int go_intent, const u8 *own_interface_addr,
|
int go_intent, const u8 *own_interface_addr,
|
||||||
unsigned int force_freq, int persistent_group,
|
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)
|
if (persistent_group && wpa_s->conf->persistent_reconnect)
|
||||||
persistent_group = 2;
|
persistent_group = 2;
|
||||||
|
@ -5258,7 +5298,7 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
|
||||||
persistent_group, ssid ? ssid->ssid : NULL,
|
persistent_group, ssid ? ssid->ssid : NULL,
|
||||||
ssid ? ssid->ssid_len : 0, pref_freq,
|
ssid ? ssid->ssid_len : 0, pref_freq,
|
||||||
wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
|
wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
|
||||||
0);
|
0, bootstrap, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5442,7 +5482,9 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
|
||||||
wpa_s->p2p_go_he,
|
wpa_s->p2p_go_he,
|
||||||
wpa_s->p2p_go_edmg,
|
wpa_s->p2p_go_edmg,
|
||||||
NULL, 0,
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5936,6 +5978,9 @@ static bool is_p2p_6ghz_supported(struct wpa_supplicant *wpa_s,
|
||||||
HOSTAPD_MODE_IEEE80211A, true))
|
HOSTAPD_MODE_IEEE80211A, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (wpa_s->p2p2)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (!p2p_wfd_enabled(wpa_s->global->p2p))
|
if (!p2p_wfd_enabled(wpa_s->global->p2p))
|
||||||
return false;
|
return false;
|
||||||
if (peer_addr && !p2p_peer_wfd_enabled(wpa_s->global->p2p, peer_addr))
|
if (peer_addr && !p2p_peer_wfd_enabled(wpa_s->global->p2p, peer_addr))
|
||||||
|
@ -5987,6 +6032,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: Specific Group SSID for join or %NULL if not set
|
||||||
* @group_ssid_len: Length of @group_ssid in octets
|
* @group_ssid_len: Length of @group_ssid in octets
|
||||||
* @allow_6ghz: Allow P2P connection on 6 GHz channels
|
* @allow_6ghz: Allow P2P connection on 6 GHz channels
|
||||||
|
* @p2p2: Whether device is 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
|
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
|
||||||
* failure, -2 on failure due to channel not currently available,
|
* failure, -2 on failure due to channel not currently available,
|
||||||
* -3 if forced channel is not supported
|
* -3 if forced channel is not supported
|
||||||
|
@ -5998,7 +6047,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
|
||||||
int persistent_id, int pd, int ht40, int vht,
|
int persistent_id, int pd, int ht40, int vht,
|
||||||
unsigned int vht_chwidth, int he, int edmg,
|
unsigned int vht_chwidth, int he, int edmg,
|
||||||
const u8 *group_ssid, size_t group_ssid_len,
|
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 force_freq = 0, pref_freq = 0;
|
||||||
int ret = 0, res;
|
int ret = 0, res;
|
||||||
|
@ -6018,6 +6068,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wpa_s->p2p2 = p2p2;
|
||||||
|
|
||||||
if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq))
|
if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq))
|
||||||
return -2;
|
return -2;
|
||||||
|
|
||||||
|
@ -6048,6 +6100,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_max_oper_chwidth = vht_chwidth;
|
||||||
wpa_s->p2p_go_he = !!he;
|
wpa_s->p2p_go_he = !!he;
|
||||||
wpa_s->p2p_go_edmg = !!edmg;
|
wpa_s->p2p_go_edmg = !!edmg;
|
||||||
|
wpa_s->p2p_bootstrap = bootstrap;
|
||||||
|
|
||||||
if (pin)
|
if (pin)
|
||||||
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
|
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
|
||||||
|
@ -6133,14 +6186,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,
|
if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
|
||||||
go_intent, if_addr,
|
go_intent, if_addr,
|
||||||
force_freq, persistent_group, ssid,
|
force_freq, persistent_group, ssid,
|
||||||
pref_freq) < 0)
|
pref_freq, bootstrap, password) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
|
if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
|
||||||
go_intent, if_addr, force_freq,
|
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)
|
if (wpa_s->create_p2p_iface)
|
||||||
wpas_p2p_remove_pending_group_interface(wpa_s);
|
wpas_p2p_remove_pending_group_interface(wpa_s);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -8768,7 +8822,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_max_oper_chwidth,
|
||||||
wpa_s->p2p_go_he,
|
wpa_s->p2p_go_he,
|
||||||
wpa_s->p2p_go_edmg,
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9306,7 +9361,8 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
|
||||||
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
|
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
|
||||||
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
|
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
|
||||||
params->go_ssid_len ? params->go_ssid : NULL,
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9385,7 +9441,8 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
|
||||||
forced_freq, wpa_s->p2p_go_vht_center_freq2,
|
forced_freq, wpa_s->p2p_go_vht_center_freq2,
|
||||||
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
|
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
|
||||||
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
|
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
|
||||||
NULL, 0, false);
|
NULL, 0, false, wpa_s->p2p2,
|
||||||
|
wpa_s->p2p_bootstrap, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9402,7 +9459,8 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
|
||||||
forced_freq, wpa_s->p2p_go_vht_center_freq2,
|
forced_freq, wpa_s->p2p_go_vht_center_freq2,
|
||||||
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
|
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
|
||||||
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
|
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)
|
if (res)
|
||||||
return 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,
|
int persistent_id, int pd, int ht40, int vht,
|
||||||
unsigned int vht_chwidth, int he, int edmg,
|
unsigned int vht_chwidth, int he, int edmg,
|
||||||
const u8 *group_ssid, size_t group_ssid_len,
|
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 wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
|
||||||
int freq, struct wpa_ssid *ssid);
|
int freq, struct wpa_ssid *ssid);
|
||||||
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
|
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
|
||||||
|
|
|
@ -1113,6 +1113,7 @@ struct wpa_supplicant {
|
||||||
int pending_pd_before_join;
|
int pending_pd_before_join;
|
||||||
u8 pending_join_iface_addr[ETH_ALEN];
|
u8 pending_join_iface_addr[ETH_ALEN];
|
||||||
u8 pending_join_dev_addr[ETH_ALEN];
|
u8 pending_join_dev_addr[ETH_ALEN];
|
||||||
|
u8 p2p_bootstrap_dev_addr[ETH_ALEN];
|
||||||
int pending_join_wps_method;
|
int pending_join_wps_method;
|
||||||
u8 p2p_join_ssid[SSID_MAX_LEN];
|
u8 p2p_join_ssid[SSID_MAX_LEN];
|
||||||
size_t p2p_join_ssid_len;
|
size_t p2p_join_ssid_len;
|
||||||
|
@ -1167,6 +1168,8 @@ struct wpa_supplicant {
|
||||||
unsigned int p2ps_method_config_any:1;
|
unsigned int p2ps_method_config_any:1;
|
||||||
unsigned int p2p_cli_probe:1;
|
unsigned int p2p_cli_probe:1;
|
||||||
unsigned int p2p_go_allow_dfs:1;
|
unsigned int p2p_go_allow_dfs:1;
|
||||||
|
unsigned int p2p2:1;
|
||||||
|
u16 p2p_bootstrap;
|
||||||
enum hostapd_hw_mode p2p_go_acs_band;
|
enum hostapd_hw_mode p2p_go_acs_band;
|
||||||
int p2p_persistent_go_freq;
|
int p2p_persistent_go_freq;
|
||||||
int p2p_persistent_id;
|
int p2p_persistent_id;
|
||||||
|
|
Loading…
Reference in a new issue