P2P2: Refactor provision discovery request/response processing

Parse the P2P IEs in functions that handle provision discovery request
and response. Process the frames based on the IEs received in the PD
frames. This makes it easier to extend PD for P2P2 cases.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
This commit is contained in:
Shivani Baranwal 2024-08-05 15:03:06 +05:30 committed by Jouni Malinen
parent b4f9742ee2
commit 6aa9ad8f8f
3 changed files with 193 additions and 185 deletions

View file

@ -1924,10 +1924,10 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
p2p_process_invitation_resp(p2p, sa, data + 1, len - 1); p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
break; break;
case P2P_PROV_DISC_REQ: case P2P_PROV_DISC_REQ:
p2p_process_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_process_prov_disc_resp(p2p, sa, data + 1, len - 1); p2p_handle_prov_disc_resp(p2p, sa, data + 1, len - 1);
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);

View file

@ -873,9 +873,9 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
struct p2p_device *dev, struct p2p_message *msg); struct p2p_device *dev, struct p2p_message *msg);
/* p2p_pd.c */ /* p2p_pd.c */
void p2p_process_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_process_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 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);

View file

@ -614,10 +614,10 @@ void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
} }
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, 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) const u8 *data, size_t len, int rx_freq)
{ {
struct p2p_message msg;
struct p2p_device *dev; struct p2p_device *dev;
int freq; int freq;
enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
@ -638,21 +638,17 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
u8 remote_conncap; u8 remote_conncap;
u16 method; u16 method;
if (p2p_parse(data, len, &msg))
return;
p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
" with config methods 0x%x (freq=%d)", " with config methods 0x%x (freq=%d)",
MAC2STR(sa), msg.wps_config_methods, rx_freq); MAC2STR(sa), msg->wps_config_methods, rx_freq);
group_mac = msg.intended_addr; group_mac = msg->intended_addr;
dev = p2p_get_device(p2p, sa); dev = p2p_get_device(p2p, sa);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
p2p_dbg(p2p, "Provision Discovery Request from unknown peer " p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
MACSTR, MAC2STR(sa)); MACSTR, MAC2STR(sa));
if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1, if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data, len, 0)) {
0)) {
p2p_dbg(p2p, "Provision Discovery Request add device failed " p2p_dbg(p2p, "Provision Discovery Request add device failed "
MACSTR, MAC2STR(sa)); MACSTR, MAC2STR(sa));
goto out; goto out;
@ -665,29 +661,29 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
MACSTR, MAC2STR(sa)); MACSTR, MAC2STR(sa));
goto out; goto out;
} }
} else if (msg.wfd_subelems) { } else if (msg->wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems); wpabuf_free(dev->info.wfd_subelems);
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
} }
p2p_update_peer_6ghz_capab(dev, &msg); p2p_update_peer_6ghz_capab(dev, msg);
if (!msg.adv_id) { if (!msg->adv_id) {
allowed_config_methods |= WPS_CONFIG_PUSHBUTTON; allowed_config_methods |= WPS_CONFIG_PUSHBUTTON;
if (!(msg.wps_config_methods & allowed_config_methods)) { if (!(msg->wps_config_methods & allowed_config_methods)) {
p2p_dbg(p2p, p2p_dbg(p2p,
"Unsupported Config Methods in Provision Discovery Request"); "Unsupported Config Methods in Provision Discovery Request");
goto out; goto out;
} }
/* Legacy (non-P2PS) - Unknown groups allowed for P2PS */ /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
if (msg.group_id) { if (msg->group_id) {
size_t i; size_t i;
for (i = 0; i < p2p->num_groups; i++) { for (i = 0; i < p2p->num_groups; i++) {
if (p2p_group_is_group_id_match( if (p2p_group_is_group_id_match(
p2p->groups[i], p2p->groups[i],
msg.group_id, msg.group_id_len)) msg->group_id, msg->group_id_len))
break; break;
} }
if (i == p2p->num_groups) { if (i == p2p->num_groups) {
@ -703,29 +699,29 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
* Set adv_id here, so in case of an error, a P2PS PD Response * Set adv_id here, so in case of an error, a P2PS PD Response
* will be sent. * will be sent.
*/ */
adv_id = WPA_GET_LE32(msg.adv_id); adv_id = WPA_GET_LE32(msg->adv_id);
if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) { if (p2ps_validate_pd_req(p2p, msg, sa) < 0) {
reject = P2P_SC_FAIL_INVALID_PARAMS; reject = P2P_SC_FAIL_INVALID_PARAMS;
goto out; goto out;
} }
req_fcap = (struct p2ps_feature_capab *) msg.feature_cap; req_fcap = (struct p2ps_feature_capab *) msg->feature_cap;
os_memcpy(session_mac, msg.session_mac, ETH_ALEN); os_memcpy(session_mac, msg->session_mac, ETH_ALEN);
os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN);
session_id = WPA_GET_LE32(msg.session_id); session_id = WPA_GET_LE32(msg->session_id);
if (msg.conn_cap) if (msg->conn_cap)
conncap = *msg.conn_cap; conncap = *msg->conn_cap;
/* /*
* We need to verify a P2PS config methog in an initial PD * We need to verify a P2PS config methog in an initial PD
* request or in a follow-on PD request with the status * request or in a follow-on PD request with the status
* SUCCESS_DEFERRED. * SUCCESS_DEFERRED.
*/ */
if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) && if ((!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) &&
!(msg.wps_config_methods & allowed_config_methods)) { !(msg->wps_config_methods & allowed_config_methods)) {
p2p_dbg(p2p, p2p_dbg(p2p,
"Unsupported Config Methods in Provision Discovery Request"); "Unsupported Config Methods in Provision Discovery Request");
goto out; goto out;
@ -741,18 +737,18 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
P2P_DEV_PD_PEER_KEYPAD | P2P_DEV_PD_PEER_KEYPAD |
P2P_DEV_PD_PEER_P2PS); P2P_DEV_PD_PEER_P2PS);
if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) { if (msg->wps_config_methods & WPS_CONFIG_DISPLAY) {
p2p_dbg(p2p, "Peer " MACSTR p2p_dbg(p2p, "Peer " MACSTR
" requested us to show a PIN on display", MAC2STR(sa)); " requested us to show a PIN on display", MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_KEYPAD; dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
passwd_id = DEV_PW_USER_SPECIFIED; passwd_id = DEV_PW_USER_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
p2p_dbg(p2p, "Peer " MACSTR p2p_dbg(p2p, "Peer " MACSTR
" requested us to write its PIN using keypad", " requested us to write its PIN using keypad",
MAC2STR(sa)); MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_DISPLAY; dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
passwd_id = DEV_PW_REGISTRAR_SPECIFIED; passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) {
p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN", p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
MAC2STR(sa)); MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_P2PS; dev->flags |= P2P_DEV_PD_PEER_P2PS;
@ -763,8 +759,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
if (p2p->cfg->remove_stale_groups) { if (p2p->cfg->remove_stale_groups) {
p2p->cfg->remove_stale_groups( p2p->cfg->remove_stale_groups(
p2p->cfg->cb_ctx, dev->info.p2p_device_addr, p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
msg.persistent_dev, msg->persistent_dev,
msg.persistent_ssid, msg.persistent_ssid_len); msg->persistent_ssid, msg->persistent_ssid_len);
} }
reject = P2P_SC_SUCCESS; reject = P2P_SC_SUCCESS;
@ -773,15 +769,15 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
* End of a legacy P2P PD Request processing, from this point continue * End of a legacy P2P PD Request processing, from this point continue
* with P2PS one. * with P2PS one.
*/ */
if (!msg.adv_id) if (!msg->adv_id)
goto out; goto out;
remote_conncap = conncap; remote_conncap = conncap;
if (!msg.status) { if (!msg->status) {
unsigned int forced_freq, pref_freq; unsigned int forced_freq, pref_freq;
if (!ether_addr_equal(p2p->cfg->dev_addr, msg.adv_mac)) { if (!ether_addr_equal(p2p->cfg->dev_addr, msg->adv_mac)) {
p2p_dbg(p2p, p2p_dbg(p2p,
"P2PS PD adv mac does not match the local one"); "P2PS PD adv mac does not match the local one");
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
@ -818,12 +814,12 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
"Incompatible P2PS feature capability CPT bitmask"); "Incompatible P2PS feature capability CPT bitmask");
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
} else if (p2ps_adv->config_methods && } else if (p2ps_adv->config_methods &&
!(msg.wps_config_methods & !(msg->wps_config_methods &
p2ps_adv->config_methods)) { p2ps_adv->config_methods)) {
p2p_dbg(p2p, p2p_dbg(p2p,
"Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)", "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
p2ps_adv->config_methods, p2ps_adv->config_methods,
msg.wps_config_methods); msg->wps_config_methods);
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
} else if (!p2ps_adv->state) { } else if (!p2ps_adv->state) {
p2p_dbg(p2p, "P2PS state unavailable"); p2p_dbg(p2p, "P2PS state unavailable");
@ -833,24 +829,24 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
} }
if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
p2p_dbg(p2p, "Keypad - always defer"); p2p_dbg(p2p, "Keypad - always defer");
auto_accept = 0; auto_accept = 0;
} }
if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) || if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
msg.persistent_dev) && conncap != P2PS_SETUP_NEW && msg->persistent_dev) && conncap != P2PS_SETUP_NEW &&
msg.channel_list && msg.channel_list_len && msg->channel_list && msg->channel_list_len &&
p2p_peer_channels_check(p2p, &p2p->channels, dev, p2p_peer_channels_check(p2p, &p2p->channels, dev,
msg.channel_list, msg->channel_list,
msg.channel_list_len) < 0) { msg->channel_list_len) < 0) {
p2p_dbg(p2p, p2p_dbg(p2p,
"No common channels - force deferred flow"); "No common channels - force deferred flow");
auto_accept = 0; auto_accept = 0;
} }
if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) || if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) ||
msg.persistent_dev) && msg.operating_channel) { msg->persistent_dev) && msg->operating_channel) {
struct p2p_channels intersect; struct p2p_channels intersect;
/* /*
@ -861,15 +857,15 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
*/ */
if (dev->channels.reg_classes == 0 || if (dev->channels.reg_classes == 0 ||
!p2p_channels_includes(&dev->channels, !p2p_channels_includes(&dev->channels,
msg.operating_channel[3], msg->operating_channel[3],
msg.operating_channel[4])) { msg->operating_channel[4])) {
struct p2p_channels *ch = &dev->channels; struct p2p_channels *ch = &dev->channels;
os_memset(ch, 0, sizeof(*ch)); os_memset(ch, 0, sizeof(*ch));
ch->reg_class[0].reg_class = ch->reg_class[0].reg_class =
msg.operating_channel[3]; msg->operating_channel[3];
ch->reg_class[0].channel[0] = ch->reg_class[0].channel[0] =
msg.operating_channel[4]; msg->operating_channel[4];
ch->reg_class[0].channels = 1; ch->reg_class[0].channels = 1;
ch->reg_classes = 1; ch->reg_classes = 1;
} }
@ -888,7 +884,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
struct p2ps_provision *tmp; struct p2ps_provision *tmp;
if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
msg.wps_config_methods, msg->wps_config_methods,
session_mac, adv_mac) < 0) { session_mac, adv_mac) < 0) {
reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
goto out; goto out;
@ -910,7 +906,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
} }
} }
if (!msg.status && !auto_accept && if (!msg->status && !auto_accept &&
(!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) { (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
struct p2ps_provision *tmp; struct p2ps_provision *tmp;
@ -920,7 +916,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
} }
if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
msg.wps_config_methods, msg->wps_config_methods,
session_mac, adv_mac) < 0) { session_mac, adv_mac) < 0) {
reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
goto out; goto out;
@ -931,26 +927,26 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
} }
/* Not a P2PS Follow-on PD */ /* Not a P2PS Follow-on PD */
if (!msg.status) if (!msg->status)
goto out; goto out;
if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) { if (*msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED) {
reject = *msg.status; reject = *msg->status;
goto out; goto out;
} }
if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov) if (*msg->status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
goto out; goto out;
if (p2p->p2ps_prov->adv_id != adv_id || if (p2p->p2ps_prov->adv_id != adv_id ||
!ether_addr_equal(p2p->p2ps_prov->adv_mac, msg.adv_mac)) { !ether_addr_equal(p2p->p2ps_prov->adv_mac, msg->adv_mac)) {
p2p_dbg(p2p, p2p_dbg(p2p,
"P2PS Follow-on PD with mismatch Advertisement ID/MAC"); "P2PS Follow-on PD with mismatch Advertisement ID/MAC");
goto out; goto out;
} }
if (p2p->p2ps_prov->session_id != session_id || if (p2p->p2ps_prov->session_id != session_id ||
!ether_addr_equal(p2p->p2ps_prov->session_mac, msg.session_mac)) { !ether_addr_equal(p2p->p2ps_prov->session_mac, msg->session_mac)) {
p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC"); p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC");
goto out; goto out;
} }
@ -981,7 +977,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
else if (method & WPS_CONFIG_KEYPAD) else if (method & WPS_CONFIG_KEYPAD)
method = WPS_CONFIG_DISPLAY; method = WPS_CONFIG_DISPLAY;
if (!conncap || !(msg.wps_config_methods & method)) { if (!conncap || !(msg->wps_config_methods & method)) {
/* /*
* Reject this "Deferred Accept* * Reject this "Deferred Accept*
* if incompatible conncap or method * if incompatible conncap or method
@ -992,11 +988,11 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
"Incompatible P2PS feature capability CPT bitmask"); "Incompatible P2PS feature capability CPT bitmask");
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
} else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) || } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
msg.persistent_dev) && conncap != P2PS_SETUP_NEW && msg->persistent_dev) && conncap != P2PS_SETUP_NEW &&
msg.channel_list && msg.channel_list_len && msg->channel_list && msg->channel_list_len &&
p2p_peer_channels_check(p2p, &p2p->channels, dev, p2p_peer_channels_check(p2p, &p2p->channels, dev,
msg.channel_list, msg->channel_list,
msg.channel_list_len) < 0) { msg->channel_list_len) < 0) {
p2p_dbg(p2p, p2p_dbg(p2p,
"No common channels in Follow-On Provision Discovery Request"); "No common channels in Follow-On Provision Discovery Request");
reject = P2P_SC_FAIL_NO_COMMON_CHANNELS; reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
@ -1008,10 +1004,10 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) { if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) {
u8 tmp; u8 tmp;
if (msg.operating_channel) if (msg->operating_channel)
dev->oper_freq = dev->oper_freq =
p2p_channel_to_freq(msg.operating_channel[3], p2p_channel_to_freq(msg->operating_channel[3],
msg.operating_channel[4]); msg->operating_channel[4]);
if ((conncap & P2PS_SETUP_GROUP_OWNER) && if ((conncap & P2PS_SETUP_GROUP_OWNER) &&
p2p_go_select_channel(p2p, dev, &tmp) < 0) p2p_go_select_channel(p2p, dev, &tmp) < 0)
@ -1024,7 +1020,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
out: out:
if (reject == P2P_SC_SUCCESS || if (reject == P2P_SC_SUCCESS ||
reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
config_methods = msg.wps_config_methods; config_methods = msg->wps_config_methods;
else else
config_methods = 0; config_methods = 0;
@ -1032,18 +1028,18 @@ out:
* Send PD Response for an initial PD Request or for follow-on * Send PD Response for an initial PD Request or for follow-on
* PD Request with P2P_SC_SUCCESS_DEFERRED status. * PD Request with P2P_SC_SUCCESS_DEFERRED status.
*/ */
if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) { if (!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) {
resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, resp = p2p_build_prov_disc_resp(p2p, dev, msg->dialog_token,
reject, config_methods, adv_id, reject, config_methods, adv_id,
msg.group_id, msg.group_id_len, msg->group_id,
msg.persistent_ssid, msg->group_id_len,
msg.persistent_ssid_len, msg->persistent_ssid,
msg->persistent_ssid_len,
(const u8 *) &resp_fcap, (const u8 *) &resp_fcap,
sizeof(resp_fcap)); sizeof(resp_fcap));
if (!resp) { if (!resp)
p2p_parse_free(&msg);
return; return;
}
p2p_dbg(p2p, "Sending Provision Discovery Response"); p2p_dbg(p2p, "Sending Provision Discovery Response");
if (rx_freq > 0) if (rx_freq > 0)
freq = rx_freq; freq = rx_freq;
@ -1053,7 +1049,6 @@ out:
if (freq < 0) { if (freq < 0) {
p2p_dbg(p2p, "Unknown regulatory class/channel"); p2p_dbg(p2p, "Unknown regulatory class/channel");
wpabuf_free(resp); wpabuf_free(resp);
p2p_parse_free(&msg);
return; return;
} }
p2p->pending_action_state = P2P_PENDING_PD_RESPONSE; p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
@ -1068,10 +1063,8 @@ out:
wpabuf_free(resp); wpabuf_free(resp);
} }
if (!dev) { if (!dev)
p2p_parse_free(&msg);
return; return;
}
freq = 0; freq = 0;
if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) { if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) {
@ -1083,17 +1076,17 @@ out:
if (!p2p->cfg->p2ps_prov_complete) { if (!p2p->cfg->p2ps_prov_complete) {
/* Don't emit anything */ /* Don't emit anything */
} else if (msg.status && *msg.status != P2P_SC_SUCCESS && } else if (msg->status && *msg->status != P2P_SC_SUCCESS &&
*msg.status != P2P_SC_SUCCESS_DEFERRED) { *msg->status != P2P_SC_SUCCESS_DEFERRED) {
reject = *msg.status; reject = *msg->status;
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
sa, adv_mac, session_mac, sa, adv_mac, session_mac,
NULL, adv_id, session_id, NULL, adv_id, session_id,
0, 0, msg.persistent_ssid, 0, 0, msg->persistent_ssid,
msg.persistent_ssid_len, msg->persistent_ssid_len,
0, 0, NULL, NULL, 0, freq, 0, 0, NULL, NULL, 0, freq,
NULL, 0); NULL, 0);
} else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && } else if (msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED &&
p2p->p2ps_prov) { p2p->p2ps_prov) {
p2p->p2ps_prov->status = reject; p2p->p2ps_prov->status = reject;
p2p->p2ps_prov->conncap = conncap; p2p->p2ps_prov->conncap = conncap;
@ -1103,77 +1096,77 @@ out:
sa, adv_mac, session_mac, sa, adv_mac, session_mac,
NULL, adv_id, NULL, adv_id,
session_id, conncap, 0, session_id, conncap, 0,
msg.persistent_ssid, msg->persistent_ssid,
msg.persistent_ssid_len, 0, msg->persistent_ssid_len,
0, NULL, NULL, 0, freq, 0, 0, NULL, NULL, 0, freq,
NULL, 0); NULL, 0);
else else
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
*msg.status, *msg->status,
sa, adv_mac, session_mac, sa, adv_mac, session_mac,
group_mac, adv_id, group_mac, adv_id,
session_id, conncap, session_id, conncap,
passwd_id, passwd_id,
msg.persistent_ssid, msg->persistent_ssid,
msg.persistent_ssid_len, 0, msg->persistent_ssid_len,
0, NULL, 0, 0, NULL,
(const u8 *) &resp_fcap, (const u8 *) &resp_fcap,
sizeof(resp_fcap), freq, sizeof(resp_fcap), freq,
NULL, 0); NULL, 0);
} else if (msg.status && p2p->p2ps_prov) { } else if (msg->status && p2p->p2ps_prov) {
p2p->p2ps_prov->status = P2P_SC_SUCCESS; p2p->p2ps_prov->status = P2P_SC_SUCCESS;
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa, p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg->status, sa,
adv_mac, session_mac, group_mac, adv_mac, session_mac, group_mac,
adv_id, session_id, conncap, adv_id, session_id, conncap,
passwd_id, passwd_id,
msg.persistent_ssid, msg->persistent_ssid,
msg.persistent_ssid_len, msg->persistent_ssid_len,
0, 0, NULL, 0, 0, NULL,
(const u8 *) &resp_fcap, (const u8 *) &resp_fcap,
sizeof(resp_fcap), freq, NULL, 0); sizeof(resp_fcap), freq, NULL, 0);
} else if (msg.status) { } else if (msg->status) {
} else if (auto_accept && reject == P2P_SC_SUCCESS) { } else if (auto_accept && reject == P2P_SC_SUCCESS) {
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
sa, adv_mac, session_mac, sa, adv_mac, session_mac,
group_mac, adv_id, session_id, group_mac, adv_id, session_id,
conncap, passwd_id, conncap, passwd_id,
msg.persistent_ssid, msg->persistent_ssid,
msg.persistent_ssid_len, msg->persistent_ssid_len,
0, 0, NULL, 0, 0, NULL,
(const u8 *) &resp_fcap, (const u8 *) &resp_fcap,
sizeof(resp_fcap), freq, sizeof(resp_fcap), freq,
msg.group_id ? msg->group_id ?
msg.group_id + ETH_ALEN : NULL, msg->group_id + ETH_ALEN : NULL,
msg.group_id ? msg->group_id ?
msg.group_id_len - ETH_ALEN : 0); msg->group_id_len - ETH_ALEN : 0);
} else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
(!msg.session_info || !msg.session_info_len)) { (!msg->session_info || !msg->session_info_len)) {
p2p->p2ps_prov->method = msg.wps_config_methods; p2p->p2ps_prov->method = msg->wps_config_methods;
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
sa, adv_mac, session_mac, sa, adv_mac, session_mac,
group_mac, adv_id, session_id, group_mac, adv_id, session_id,
conncap, passwd_id, conncap, passwd_id,
msg.persistent_ssid, msg->persistent_ssid,
msg.persistent_ssid_len, msg->persistent_ssid_len,
0, 1, NULL, 0, 1, NULL,
(const u8 *) &resp_fcap, (const u8 *) &resp_fcap,
sizeof(resp_fcap), freq, NULL, 0); sizeof(resp_fcap), freq, NULL, 0);
} else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
size_t buf_len = msg.session_info_len; size_t buf_len = msg->session_info_len;
char *buf = os_malloc(2 * buf_len + 1); char *buf = os_malloc(2 * buf_len + 1);
if (buf) { if (buf) {
p2p->p2ps_prov->method = msg.wps_config_methods; p2p->p2ps_prov->method = msg->wps_config_methods;
utf8_escape((char *) msg.session_info, buf_len, utf8_escape((char *) msg->session_info, buf_len,
buf, 2 * buf_len + 1); buf, 2 * buf_len + 1);
p2p->cfg->p2ps_prov_complete( p2p->cfg->p2ps_prov_complete(
p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa,
adv_mac, session_mac, group_mac, adv_id, adv_mac, session_mac, group_mac, adv_id,
session_id, conncap, passwd_id, session_id, conncap, passwd_id,
msg.persistent_ssid, msg.persistent_ssid_len, msg->persistent_ssid, msg->persistent_ssid_len,
0, 1, buf, 0, 1, buf,
(const u8 *) &resp_fcap, sizeof(resp_fcap), (const u8 *) &resp_fcap, sizeof(resp_fcap),
freq, NULL, 0); freq, NULL, 0);
@ -1201,29 +1194,30 @@ out:
* seeker: KEYPAD, response status: SUCCESS * seeker: KEYPAD, response status: SUCCESS
*/ */
if (p2p->cfg->prov_disc_req && if (p2p->cfg->prov_disc_req &&
((reject == P2P_SC_SUCCESS && !msg.adv_id) || ((reject == P2P_SC_SUCCESS && !msg->adv_id) ||
(!msg.status && (!msg->status &&
(reject == P2P_SC_SUCCESS || (reject == P2P_SC_SUCCESS ||
reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) && reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) &&
passwd_id == DEV_PW_USER_SPECIFIED) || passwd_id == DEV_PW_USER_SPECIFIED) ||
(!msg.status && (!msg->status &&
reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
passwd_id == DEV_PW_REGISTRAR_SPECIFIED) || passwd_id == DEV_PW_REGISTRAR_SPECIFIED) ||
(reject == P2P_SC_SUCCESS && (reject == P2P_SC_SUCCESS &&
msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED &&
passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) { passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) {
const u8 *dev_addr = sa; const u8 *dev_addr = sa;
if (msg.p2p_device_addr) if (msg->p2p_device_addr)
dev_addr = msg.p2p_device_addr; dev_addr = msg->p2p_device_addr;
p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa, p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
msg.wps_config_methods, msg->wps_config_methods,
dev_addr, msg.pri_dev_type, dev_addr, msg->pri_dev_type,
msg.device_name, msg.config_methods, msg->device_name, msg->config_methods,
msg.capability ? msg.capability[0] : 0, msg->capability ? msg->capability[0] :
msg.capability ? msg.capability[1] :
0, 0,
msg.group_id, msg.group_id_len); msg->capability ? msg->capability[1] :
0,
msg->group_id, msg->group_id_len);
} }
if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
@ -1248,10 +1242,22 @@ out:
break; break;
} }
if (msg.intended_addr) if (msg->intended_addr)
os_memcpy(dev->interface_addr, msg.intended_addr, os_memcpy(dev->interface_addr, msg->intended_addr,
ETH_ALEN); ETH_ALEN);
} }
}
void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
struct p2p_message msg;
if (p2p_parse(data, len, &msg))
return;
p2p_process_prov_disc_req(p2p, &msg, sa, data + 1, len - 1, rx_freq);
p2p_parse_free(&msg); p2p_parse_free(&msg);
} }
@ -1354,10 +1360,10 @@ static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p,
} }
void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, static void p2p_process_prov_disc_resp(struct p2p_data *p2p,
struct p2p_message *msg, const u8 *sa,
const u8 *data, size_t len) const u8 *data, size_t len)
{ {
struct p2p_message msg;
struct p2p_device *dev; struct p2p_device *dev;
u16 report_config_methods = 0, req_config_methods; u16 report_config_methods = 0, req_config_methods;
u8 status = P2P_SC_SUCCESS; u8 status = P2P_SC_SUCCESS;
@ -1368,30 +1374,25 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
int passwd_id = DEV_PW_DEFAULT; int passwd_id = DEV_PW_DEFAULT;
int p2ps_seeker; int p2ps_seeker;
if (p2p_parse(data, len, &msg)) if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, msg))
return; return;
if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) {
p2p_parse_free(&msg);
return;
}
/* Parse the P2PS members present */ /* Parse the P2PS members present */
if (msg.status) if (msg->status)
status = *msg.status; status = *msg->status;
group_mac = msg.intended_addr; group_mac = msg->intended_addr;
if (msg.adv_mac) if (msg->adv_mac)
os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN);
else else
os_memset(adv_mac, 0, ETH_ALEN); os_memset(adv_mac, 0, ETH_ALEN);
if (msg.adv_id) if (msg->adv_id)
adv_id = WPA_GET_LE32(msg.adv_id); adv_id = WPA_GET_LE32(msg->adv_id);
if (msg.conn_cap) { if (msg->conn_cap) {
conncap = *msg.conn_cap; conncap = *msg->conn_cap;
/* Switch bits to local relative */ /* Switch bits to local relative */
switch (conncap) { switch (conncap) {
@ -1406,25 +1407,23 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
" with config methods 0x%x", " with config methods 0x%x",
MAC2STR(sa), msg.wps_config_methods); MAC2STR(sa), msg->wps_config_methods);
dev = p2p_get_device(p2p, sa); dev = p2p_get_device(p2p, sa);
if (dev == NULL || !dev->req_config_methods) { if (dev == NULL || !dev->req_config_methods) {
p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
" with no pending request", MAC2STR(sa)); " with no pending request", MAC2STR(sa));
p2p_parse_free(&msg);
return; return;
} else if (msg.wfd_subelems) { } else if (msg->wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems); wpabuf_free(dev->info.wfd_subelems);
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
} }
p2p_update_peer_6ghz_capab(dev, &msg); p2p_update_peer_6ghz_capab(dev, msg);
if (dev->dialog_token != msg.dialog_token) { if (dev->dialog_token != msg->dialog_token) {
p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)", p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token); msg->dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
return; return;
} }
@ -1449,14 +1448,13 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
ether_addr_equal(p2p->pending_pd_devaddr, sa)) ether_addr_equal(p2p->pending_pd_devaddr, sa))
p2p_reset_pending_pd(p2p); p2p_reset_pending_pd(p2p);
if (msg.wps_config_methods != req_config_methods) { if (msg->wps_config_methods != req_config_methods) {
p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x", p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
msg.wps_config_methods, req_config_methods); msg->wps_config_methods, req_config_methods);
if (p2p->cfg->prov_disc_fail) if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
P2P_PROV_DISC_REJECTED, P2P_PROV_DISC_REJECTED,
adv_id, adv_mac, NULL); adv_id, adv_mac, NULL);
p2p_parse_free(&msg);
p2ps_prov_free(p2p); p2ps_prov_free(p2p);
goto out; goto out;
} }
@ -1470,13 +1468,13 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
" accepted to show a PIN on display", MAC2STR(sa)); " accepted to show a PIN on display", MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_DISPLAY; dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
passwd_id = DEV_PW_REGISTRAR_SPECIFIED; passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
p2p_dbg(p2p, "Peer " MACSTR p2p_dbg(p2p, "Peer " MACSTR
" accepted to write our PIN using keypad", " accepted to write our PIN using keypad",
MAC2STR(sa)); MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_KEYPAD; dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
passwd_id = DEV_PW_USER_SPECIFIED; passwd_id = DEV_PW_USER_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) {
p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN", p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN",
MAC2STR(sa)); MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_P2PS; dev->flags |= P2P_DEV_PD_PEER_P2PS;
@ -1495,23 +1493,23 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
* fails the flow would continue, although it would probably * fails the flow would continue, although it would probably
* fail. Same is true for the operating channel. * fail. Same is true for the operating channel.
*/ */
if (msg.channel_list && msg.channel_list_len && if (msg->channel_list && msg->channel_list_len &&
p2p_peer_channels_check(p2p, &p2p->channels, dev, p2p_peer_channels_check(p2p, &p2p->channels, dev,
msg.channel_list, msg->channel_list,
msg.channel_list_len) < 0) msg->channel_list_len) < 0)
p2p_dbg(p2p, "P2PS PD Response - no common channels"); p2p_dbg(p2p, "P2PS PD Response - no common channels");
if (msg.operating_channel) { if (msg->operating_channel) {
if (p2p_channels_includes(&p2p->channels, if (p2p_channels_includes(&p2p->channels,
msg.operating_channel[3], msg->operating_channel[3],
msg.operating_channel[4]) && msg->operating_channel[4]) &&
p2p_channels_includes(&dev->channels, p2p_channels_includes(&dev->channels,
msg.operating_channel[3], msg->operating_channel[3],
msg.operating_channel[4])) { msg->operating_channel[4])) {
dev->oper_freq = dev->oper_freq =
p2p_channel_to_freq( p2p_channel_to_freq(
msg.operating_channel[3], msg->operating_channel[3],
msg.operating_channel[4]); msg->operating_channel[4]);
} else { } else {
p2p_dbg(p2p, p2p_dbg(p2p,
"P2PS PD Response - invalid operating channel"); "P2PS PD Response - invalid operating channel");
@ -1543,11 +1541,12 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
p2p->cfg->cb_ctx, status, sa, adv_mac, p2p->cfg->cb_ctx, status, sa, adv_mac,
p2p->p2ps_prov->session_mac, p2p->p2ps_prov->session_mac,
group_mac, adv_id, p2p->p2ps_prov->session_id, group_mac, adv_id, p2p->p2ps_prov->session_id,
conncap, passwd_id, msg.persistent_ssid, conncap, passwd_id, msg->persistent_ssid,
msg.persistent_ssid_len, 1, 0, NULL, msg->persistent_ssid_len, 1, 0, NULL,
msg.feature_cap, msg.feature_cap_len, freq, msg->feature_cap, msg->feature_cap_len, freq,
msg.group_id ? msg.group_id + ETH_ALEN : NULL, msg->group_id ? msg->group_id + ETH_ALEN : NULL,
msg.group_id ? msg.group_id_len - ETH_ALEN : 0); msg->group_id ? msg->group_id_len - ETH_ALEN :
0);
} }
p2ps_prov_free(p2p); p2ps_prov_free(p2p);
} else if (status != P2P_SC_SUCCESS && } else if (status != P2P_SC_SUCCESS &&
@ -1569,16 +1568,15 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
NULL, NULL, 0); NULL, NULL, 0);
} }
if (msg.session_info && msg.session_info_len) { if (msg->session_info && msg->session_info_len) {
size_t info_len = msg.session_info_len; size_t info_len = msg->session_info_len;
char *deferred_sess_resp = os_malloc(2 * info_len + 1); char *deferred_sess_resp = os_malloc(2 * info_len + 1);
if (!deferred_sess_resp) { if (!deferred_sess_resp) {
p2p_parse_free(&msg);
p2ps_prov_free(p2p); p2ps_prov_free(p2p);
goto out; goto out;
} }
utf8_escape((char *) msg.session_info, info_len, utf8_escape((char *) msg->session_info, info_len,
deferred_sess_resp, 2 * info_len + 1); deferred_sess_resp, 2 * info_len + 1);
if (p2p->cfg->prov_disc_fail) if (p2p->cfg->prov_disc_fail)
@ -1600,17 +1598,14 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
P2P_PROV_DISC_REJECTED, P2P_PROV_DISC_REJECTED,
adv_id, adv_mac, NULL); adv_id, adv_mac, NULL);
p2p_parse_free(&msg);
p2ps_prov_free(p2p); p2ps_prov_free(p2p);
goto out; goto out;
} }
/* Store the provisioning info */ /* Store the provisioning info */
dev->wps_prov_info = msg.wps_config_methods; dev->wps_prov_info = msg->wps_config_methods;
if (msg.intended_addr) if (msg->intended_addr)
os_memcpy(dev->interface_addr, msg.intended_addr, ETH_ALEN); os_memcpy(dev->interface_addr, msg->intended_addr, ETH_ALEN);
p2p_parse_free(&msg);
out: out:
dev->req_config_methods = 0; dev->req_config_methods = 0;
@ -1654,6 +1649,19 @@ out:
} }
void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len)
{
struct p2p_message msg;
if (p2p_parse(data, len, &msg))
return;
p2p_process_prov_disc_resp(p2p, &msg, sa, data + 1, len - 1);
p2p_parse_free(&msg);
}
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)
{ {