mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-25 17:59:25 +01:00
p2p: Add the Provision Discovery frame sequence
When connecting to an existing group, use the Provision Discovery Request/Response frame exchange before calling p2p_start_client_provision().
This commit is contained in:
parent
fdf2b8a94c
commit
ce4b1e1fcb
135
src/p2p.c
135
src/p2p.c
@ -411,6 +411,15 @@ static const struct frame_xchg_prefix p2p_frame_go_neg_confirm = {
|
||||
.len = 7,
|
||||
};
|
||||
|
||||
static const struct frame_xchg_prefix p2p_frame_pd_resp = {
|
||||
/* Management -> Public Action -> P2P -> Provision Discovery Response */
|
||||
.data = (uint8_t []) {
|
||||
0x04, 0x09, 0x50, 0x6f, 0x9a, 0x09,
|
||||
P2P_ACTION_PROVISION_DISCOVERY_RESP
|
||||
},
|
||||
.len = 7,
|
||||
};
|
||||
|
||||
static void p2p_scan_destroy(void *user_data)
|
||||
{
|
||||
struct p2p_device *dev = user_data;
|
||||
@ -1032,9 +1041,133 @@ static void p2p_start_go_negotiation(struct p2p_device *dev)
|
||||
p2p_go_negotiation_resp_cb, NULL);
|
||||
}
|
||||
|
||||
static bool p2p_provision_disc_resp_cb(const struct mmpdu_header *mpdu,
|
||||
const void *body, size_t body_len,
|
||||
int rssi, struct p2p_device *dev)
|
||||
{
|
||||
struct p2p_provision_discovery_resp info;
|
||||
int r;
|
||||
|
||||
l_debug("");
|
||||
|
||||
if (!dev->conn_peer)
|
||||
return true;
|
||||
|
||||
if (body_len < 8) {
|
||||
l_error("Provision Discovery Response frame too short");
|
||||
p2p_connect_failed(dev);
|
||||
return true;
|
||||
}
|
||||
|
||||
r = p2p_parse_provision_disc_resp(body + 7, body_len - 7, &info);
|
||||
if (r < 0) {
|
||||
l_error("Provision Discovery Response parse error %s (%i)",
|
||||
strerror(-r), -r);
|
||||
p2p_connect_failed(dev);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (info.dialog_token != 2) {
|
||||
l_error("Provision Discovery Response dialog token doesn't "
|
||||
"match");
|
||||
p2p_connect_failed(dev);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (info.wsc_config_method != dev->conn_config_method) {
|
||||
l_error("Provision Discovery Response WSC device password ID "
|
||||
"wrong");
|
||||
p2p_connect_failed(dev);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're not joining an existing group, continue with Group
|
||||
* Formation now.
|
||||
*/
|
||||
if (!dev->conn_peer->group) {
|
||||
p2p_start_go_negotiation(dev);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Indended P2P Interface address is optional, we don't have the
|
||||
* BSSID of the group here.
|
||||
*
|
||||
* We might want to make sure that Group Formation is false but the
|
||||
* Capability attribute is also optional.
|
||||
*/
|
||||
dev->go_oper_freq = dev->conn_peer->bss->frequency;
|
||||
memset(dev->go_interface_addr, 0, 6);
|
||||
memcpy(dev->go_group_id.device_addr, dev->conn_peer->device_addr, 6);
|
||||
l_strlcpy(dev->go_group_id.ssid,
|
||||
(const char *) dev->conn_peer->bss->ssid,
|
||||
dev->conn_peer->bss->ssid_len + 1);
|
||||
|
||||
/* Ready to start WSC */
|
||||
p2p_start_client_provision(dev);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void p2p_provision_disc_req_done(int error, void *user_data)
|
||||
{
|
||||
struct p2p_device *dev = user_data;
|
||||
|
||||
if (error)
|
||||
l_error("Sending the Provision Discovery Req failed: %s (%i)",
|
||||
strerror(-error), -error);
|
||||
else
|
||||
l_error("No Provision Discovery Response after Request ACKed");
|
||||
|
||||
p2p_connect_failed(dev);
|
||||
}
|
||||
|
||||
static void p2p_start_provision_discovery(struct p2p_device *dev)
|
||||
{
|
||||
/* TODO: start Provision Discovery */
|
||||
struct p2p_provision_discovery_req info = { .status = -1 };
|
||||
uint8_t *req_body;
|
||||
size_t req_len;
|
||||
struct iovec iov[16];
|
||||
int iov_len = 0;
|
||||
|
||||
/* This frame is pretty simple when P2Ps isn't supported */
|
||||
info.dialog_token = 2;
|
||||
info.capability = dev->capability;
|
||||
info.device_info = dev->device_info;
|
||||
|
||||
if (dev->conn_peer->group) {
|
||||
memcpy(info.group_id.device_addr, dev->conn_peer->bss->addr, 6);
|
||||
memcpy(info.group_id.ssid, dev->conn_peer->bss->ssid,
|
||||
dev->conn_peer->bss->ssid_len);
|
||||
}
|
||||
|
||||
info.wsc_config_method = dev->conn_config_method;
|
||||
|
||||
req_body = p2p_build_provision_disc_req(&info, &req_len);
|
||||
p2p_clear_provision_disc_req(&info);
|
||||
|
||||
if (!req_body) {
|
||||
p2p_connect_failed(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
iov[iov_len].iov_base = req_body;
|
||||
iov[iov_len].iov_len = req_len;
|
||||
iov_len++;
|
||||
|
||||
/* WFD and other service IEs go here */
|
||||
|
||||
iov[iov_len].iov_base = NULL;
|
||||
|
||||
/*
|
||||
* Section 3.2.3: "The Provision Discovery Request frame shall be
|
||||
* sent to the P2P Device Address of the P2P Group Owner"
|
||||
*/
|
||||
p2p_peer_frame_xchg(dev->conn_peer, iov, dev->conn_peer->device_addr,
|
||||
200, 600, 8, false, FRAME_GROUP_CONNECT,
|
||||
p2p_provision_disc_req_done,
|
||||
&p2p_frame_pd_resp, p2p_provision_disc_resp_cb,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static bool p2p_peer_get_info(struct p2p_peer *peer,
|
||||
|
Loading…
Reference in New Issue
Block a user