#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "crypto/sha256.h"
+#include "crypto/crypto.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
#include "p2p.h"
}
+struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p)
+{
+ return p2p ? p2p->p2ps_adv_list : NULL;
+}
+
+
+void p2p_set_intended_addr(struct p2p_data *p2p, const u8 *intended_addr)
+{
+ if (p2p && intended_addr)
+ os_memcpy(p2p->intended_addr, intended_addr, ETH_ALEN);
+}
+
+
u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
{
struct p2p_device *dev = NULL;
if (!peer)
return;
- p2p_clear_timeout(p2p);
eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
- p2p_set_state(p2p, P2P_IDLE);
+ if (p2p->state != P2P_SEARCH) {
+ /*
+ * Clear timeouts related to GO Negotiation if no new p2p_find
+ * has been started.
+ */
+ p2p_clear_timeout(p2p);
+ p2p_set_state(p2p, P2P_IDLE);
+ }
peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
peer->wps_method = WPS_NOT_READY;
if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
os_memcpy(dev->interface_addr, addr, ETH_ALEN);
if (msg.ssid &&
+ msg.ssid[1] <= sizeof(dev->oper_ssid) &&
(msg.ssid[1] != P2P_WILDCARD_SSID_LEN ||
os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN)
!= 0)) {
dev->oper_ssid_len = msg.ssid[1];
}
+ if (msg.adv_service_instance && msg.adv_service_instance_len) {
+ wpabuf_free(dev->info.p2ps_instance);
+ dev->info.p2ps_instance = wpabuf_alloc_copy(
+ msg.adv_service_instance, msg.adv_service_instance_len);
+ }
+
if (freq >= 2412 && freq <= 2484 && msg.ds_params &&
*msg.ds_params >= 1 && *msg.ds_params <= 14) {
int ds_freq;
p2p_update_peer_vendor_elems(dev, ies, ies_len);
- if (dev->flags & P2P_DEV_REPORTED && !wfd_changed)
+ if (dev->flags & P2P_DEV_REPORTED && !wfd_changed &&
+ (!msg.adv_service_instance ||
+ (dev->flags & P2P_DEV_P2PS_REPORTED)))
return 0;
p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
!(dev->flags & P2P_DEV_REPORTED_ONCE));
dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+ if (msg.adv_service_instance)
+ dev->flags |= P2P_DEV_P2PS_REPORTED;
+
return 0;
}
wpabuf_free(dev->info.wfd_subelems);
wpabuf_free(dev->info.vendor_elems);
wpabuf_free(dev->go_neg_conf);
+ wpabuf_free(dev->info.p2ps_instance);
os_free(dev);
}
}
+static int p2ps_gen_hash(struct p2p_data *p2p, const char *str, u8 *hash)
+{
+ u8 buf[SHA256_MAC_LEN];
+ char str_buf[256];
+ const u8 *adv_array;
+ size_t i, adv_len;
+
+ if (!str || !hash)
+ return 0;
+
+ if (!str[0]) {
+ os_memcpy(hash, p2p->wild_card_hash, P2PS_HASH_LEN);
+ return 1;
+ }
+
+ adv_array = (u8 *) str_buf;
+ adv_len = os_strlen(str);
+
+ for (i = 0; str[i] && i < adv_len; i++) {
+ if (str[i] >= 'A' && str[i] <= 'Z')
+ str_buf[i] = str[i] - 'A' + 'a';
+ else
+ str_buf[i] = str[i];
+ }
+
+ if (sha256_vector(1, &adv_array, &adv_len, buf))
+ return 0;
+
+ os_memcpy(hash, buf, P2PS_HASH_LEN);
+ return 1;
+}
+
+
int p2p_find(struct p2p_data *p2p, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id, unsigned int search_delay)
+ const u8 *dev_id, unsigned int search_delay,
+ u8 seek_count, const char **seek, int freq)
{
int res;
} else
p2p->find_dev_id = NULL;
+ if (seek_count == 0 || !seek) {
+ /* Not an ASP search */
+ p2p->p2ps_seek = 0;
+ } else if (seek_count == 1 && seek && (!seek[0] || !seek[0][0])) {
+ /*
+ * An empty seek string means no hash values, but still an ASP
+ * search.
+ */
+ p2p->p2ps_seek_count = 0;
+ p2p->p2ps_seek = 1;
+ } else if (seek && seek_count <= P2P_MAX_QUERY_HASH) {
+ u8 buf[P2PS_HASH_LEN];
+ int i;
+
+ p2p->p2ps_seek_count = seek_count;
+ for (i = 0; i < seek_count; i++) {
+ if (!p2ps_gen_hash(p2p, seek[i], buf))
+ continue;
+
+ /* If asking for wildcard, don't do others */
+ if (os_memcmp(buf, p2p->wild_card_hash,
+ P2PS_HASH_LEN) == 0) {
+ p2p->p2ps_seek_count = 0;
+ break;
+ }
+
+ os_memcpy(&p2p->query_hash[i * P2PS_HASH_LEN], buf,
+ P2PS_HASH_LEN);
+ }
+ p2p->p2ps_seek = 1;
+ } else {
+ p2p->p2ps_seek_count = 0;
+ p2p->p2ps_seek = 1;
+ }
+
+ /* Special case to perform wildcard search */
+ if (p2p->p2ps_seek_count == 0 && p2p->p2ps_seek) {
+ p2p->p2ps_seek_count = 1;
+ os_memcpy(&p2p->query_hash, p2p->wild_card_hash, P2PS_HASH_LEN);
+ }
+
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
p2p_clear_timeout(p2p);
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p, NULL);
switch (type) {
case P2P_FIND_START_WITH_FULL:
+ if (freq > 0) {
+ /*
+ * Start with the specified channel and then move to
+ * social channels only scans.
+ */
+ res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx,
+ P2P_SCAN_SPECIFIC, freq,
+ p2p->num_req_dev_types,
+ p2p->req_dev_types, dev_id,
+ DEV_PW_DEFAULT);
+ break;
+ }
+ /* fall through */
case P2P_FIND_PROGRESSIVE:
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
p2p->num_req_dev_types,
p2p_dbg(p2p, "Stopping find");
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p_clear_timeout(p2p);
- if (p2p->state == P2P_SEARCH)
+ if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND)
p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
+
+ p2p->p2ps_seek_count = 0;
+
p2p_set_state(p2p, P2P_IDLE);
p2p_free_req_dev_types(p2p);
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
p2p->sd_peer = NULL;
p2p->invite_peer = NULL;
p2p_stop_listen_for_freq(p2p, freq);
+ p2p->send_action_in_progress = 0;
}
if (go)
p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
else if (!force_freq)
- p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
- &p2p->channels);
+ p2p_channels_union_inplace(&p2p->channels,
+ &p2p->cfg->cli_channels);
p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params)
{
- p2p_build_ssid(p2p, params->ssid, ¶ms->ssid_len);
+ if (p2p->ssid_set) {
+ os_memcpy(params->ssid, p2p->ssid, p2p->ssid_len);
+ params->ssid_len = p2p->ssid_len;
+ } else {
+ p2p_build_ssid(p2p, params->ssid, ¶ms->ssid_len);
+ }
+ p2p->ssid_set = 0;
+
p2p_random(params->passphrase, p2p->cfg->passphrase_len);
return 0;
}
rx_freq);
break;
case P2P_INVITATION_RESP:
- p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
break;
case P2P_PROV_DISC_REQ:
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
+ if (p2p->query_count)
+ extra += MAX_SVC_ADV_IE_LEN;
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
p2p_buf_add_device_info(buf, p2p, NULL);
p2p_buf_update_ie_hdr(buf, len);
+ if (p2p->query_count) {
+ p2p_buf_add_service_instance(buf, p2p, p2p->query_count,
+ p2p->query_hash,
+ p2p->p2ps_adv_list);
+ }
+
return buf;
}
+static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
+{
+ struct p2ps_advertisement *adv_data;
+
+ p2p_dbg(p2p, "ASP find - ASP list: %p", p2p->p2ps_adv_list);
+
+ /* Wildcard always matches if we have actual services */
+ if (os_memcmp(hash, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
+ return p2p->p2ps_adv_list != NULL;
+
+ adv_data = p2p->p2ps_adv_list;
+ while (adv_data) {
+ p2p_dbg(p2p, "ASP hash: %x =? %x", hash[0], adv_data->hash[0]);
+ if (os_memcmp(hash, adv_data->hash, P2PS_HASH_LEN) == 0)
+ return 1;
+ adv_data = adv_data->next;
+ }
+
+ return 0;
+}
+
+
static enum p2p_probe_req_status
p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
const u8 *bssid, const u8 *ie, size_t ie_len)
struct p2p_message msg;
struct wpabuf *ies;
- if (!p2p->in_listen || !p2p->drv_in_listen) {
- /* not in Listen state - ignore Probe Request */
- p2p_dbg(p2p, "Not in Listen state (in_listen=%d drv_in_listen=%d) - ignore Probe Request",
- p2p->in_listen, p2p->drv_in_listen);
- return P2P_PREQ_NOT_LISTEN;
- }
-
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
ParseFailed) {
/* Ignore invalid Probe Request frames */
return P2P_PREQ_NOT_P2P;
}
+ p2p->p2ps_svc_found = 0;
+
+ if (msg.service_hash && msg.service_hash_count) {
+ const u8 *hash = msg.service_hash;
+ u8 *dest = p2p->query_hash;
+ u8 i;
+
+ p2p->query_count = 0;
+ for (i = 0; i < msg.service_hash_count; i++) {
+ if (p2p_service_find_asp(p2p, hash)) {
+ p2p->p2ps_svc_found = 1;
+
+ if (!os_memcmp(hash, p2p->wild_card_hash,
+ P2PS_HASH_LEN)) {
+ /* We found match(es) but wildcard
+ * will return all */
+ p2p->query_count = 1;
+ os_memcpy(p2p->query_hash, hash,
+ P2PS_HASH_LEN);
+ break;
+ }
+
+ /* Save each matching hash */
+ if (p2p->query_count < P2P_MAX_QUERY_HASH) {
+ os_memcpy(dest, hash, P2PS_HASH_LEN);
+ dest += P2PS_HASH_LEN;
+ p2p->query_count++;
+ } else {
+ /* We found match(es) but too many to
+ * return all */
+ p2p->query_count = 0;
+ break;
+ }
+ }
+ hash += P2PS_HASH_LEN;
+ }
+
+ p2p_dbg(p2p, "ASP adv found: %d", p2p->p2ps_svc_found);
+
+ /* Probed hash unknown */
+ if (!p2p->p2ps_svc_found) {
+ p2p_parse_free(&msg);
+ return P2P_PREQ_NOT_PROCESSED;
+ }
+ } else {
+ /* This is not a P2PS Probe Request */
+ p2p->query_count = 0;
+ p2p_dbg(p2p, "No P2PS Hash in Probe Request");
+
+ if (!p2p->in_listen || !p2p->drv_in_listen) {
+ /* not in Listen state - ignore Probe Request */
+ p2p_dbg(p2p, "Not in Listen state (in_listen=%d drv_in_listen=%d) - ignore Probe Request",
+ p2p->in_listen, p2p->drv_in_listen);
+ p2p_parse_free(&msg);
+ return P2P_PREQ_NOT_LISTEN;
+ }
+ }
+
if (msg.device_id &&
os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
/* Device ID did not match */
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
+ p2p->query_count = 0;
if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
p2p->go_neg_peer &&
size_t tmplen;
int res;
u8 group_capab;
+ struct p2p_message msg;
if (p2p_ie == NULL)
return 0; /* WLAN AP is not a P2P manager */
+ os_memset(&msg, 0, sizeof(msg));
+ if (p2p_parse_p2p_ie(p2p_ie, &msg) < 0)
+ return 0;
+
+ p2p_dbg(p2p, "BSS P2P manageability %s",
+ msg.manageability ? "enabled" : "disabled");
+
+ if (!msg.manageability)
+ return 0;
+
/*
* (Re)Association Request - P2P IE
* P2P Capability attribute (shall be present)
}
+struct p2ps_advertisement *
+p2p_service_p2ps_id(struct p2p_data *p2p, u32 adv_id)
+{
+ struct p2ps_advertisement *adv_data;
+
+ if (!p2p)
+ return NULL;
+
+ adv_data = p2p->p2ps_adv_list;
+ while (adv_data) {
+ if (adv_data->id == adv_id)
+ return adv_data;
+ adv_data = adv_data->next;
+ }
+
+ return NULL;
+}
+
+
+int p2p_service_del_asp(struct p2p_data *p2p, u32 adv_id)
+{
+ struct p2ps_advertisement *adv_data;
+ struct p2ps_advertisement **prior;
+
+ if (!p2p)
+ return -1;
+
+ adv_data = p2p->p2ps_adv_list;
+ prior = &p2p->p2ps_adv_list;
+ while (adv_data) {
+ if (adv_data->id == adv_id) {
+ p2p_dbg(p2p, "Delete ASP adv_id=0x%x", adv_id);
+ *prior = adv_data->next;
+ os_free(adv_data);
+ return 0;
+ }
+ prior = &adv_data->next;
+ adv_data = adv_data->next;
+ }
+
+ return -1;
+}
+
+
+int p2p_service_add_asp(struct p2p_data *p2p, int auto_accept, u32 adv_id,
+ const char *adv_str, u8 svc_state, u16 config_methods,
+ const char *svc_info)
+{
+ struct p2ps_advertisement *adv_data, *tmp, **prev;
+ u8 buf[P2PS_HASH_LEN];
+ size_t adv_data_len, adv_len, info_len = 0;
+
+ if (!p2p || !adv_str || !adv_str[0])
+ return -1;
+
+ if (!(config_methods & p2p->cfg->config_methods)) {
+ p2p_dbg(p2p, "Config methods not supported svc: 0x%x dev: 0x%x",
+ config_methods, p2p->cfg->config_methods);
+ return -1;
+ }
+
+ if (!p2ps_gen_hash(p2p, adv_str, buf))
+ return -1;
+
+ if (svc_info)
+ info_len = os_strlen(svc_info);
+ adv_len = os_strlen(adv_str);
+ adv_data_len = sizeof(struct p2ps_advertisement) + adv_len + 1 +
+ info_len + 1;
+
+ adv_data = os_zalloc(adv_data_len);
+ if (!adv_data)
+ return -1;
+
+ os_memcpy(adv_data->hash, buf, P2PS_HASH_LEN);
+ adv_data->id = adv_id;
+ adv_data->state = svc_state;
+ adv_data->config_methods = config_methods & p2p->cfg->config_methods;
+ adv_data->auto_accept = (u8) auto_accept;
+ os_memcpy(adv_data->svc_name, adv_str, adv_len);
+
+ if (svc_info && info_len) {
+ adv_data->svc_info = &adv_data->svc_name[adv_len + 1];
+ os_memcpy(adv_data->svc_info, svc_info, info_len);
+ }
+
+ /*
+ * Group Advertisements by service string. They do not need to be
+ * sorted, but groups allow easier Probe Response instance grouping
+ */
+ tmp = p2p->p2ps_adv_list;
+ prev = &p2p->p2ps_adv_list;
+ while (tmp) {
+ if (tmp->id == adv_data->id) {
+ if (os_strcmp(tmp->svc_name, adv_data->svc_name) != 0) {
+ os_free(adv_data);
+ return -1;
+ }
+ adv_data->next = tmp->next;
+ *prev = adv_data;
+ os_free(tmp);
+ goto inserted;
+ } else {
+ if (os_strcmp(tmp->svc_name, adv_data->svc_name) == 0) {
+ adv_data->next = tmp->next;
+ tmp->next = adv_data;
+ goto inserted;
+ }
+ }
+ prev = &tmp->next;
+ tmp = tmp->next;
+ }
+
+ /* No svc_name match found */
+ adv_data->next = p2p->p2ps_adv_list;
+ p2p->p2ps_adv_list = adv_data;
+
+inserted:
+ p2p_dbg(p2p,
+ "Added ASP advertisement adv_id=0x%x config_methods=0x%x svc_state=0x%x adv_str='%s'",
+ adv_id, adv_data->config_methods, svc_state, adv_str);
+
+ return 0;
+}
+
+
+void p2p_service_flush_asp(struct p2p_data *p2p)
+{
+ struct p2ps_advertisement *adv, *prev;
+
+ if (!p2p)
+ return;
+
+ adv = p2p->p2ps_adv_list;
+ while (adv) {
+ prev = adv;
+ adv = adv->next;
+ os_free(prev);
+ }
+
+ p2p->p2ps_adv_list = NULL;
+ p2p_dbg(p2p, "All ASP advertisements flushed");
+}
+
+
int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr)
{
struct p2p_message msg;
p2p->cfg->num_pref_chan = 0;
}
+ p2ps_gen_hash(p2p, P2PS_WILD_HASH_STR, p2p->wild_card_hash);
+
p2p->min_disc_int = 1;
p2p->max_disc_int = 3;
p2p->max_disc_tu = -1;
os_free(p2p->cfg->serial_number);
os_free(p2p->cfg->pref_chan);
os_free(p2p->groups);
+ os_free(p2p->p2ps_prov);
wpabuf_free(p2p->sd_resp);
os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
os_free(p2p->no_go_freq.range);
+ p2p_service_flush_asp(p2p);
+
os_free(p2p);
}
if (p2p->sd_peer)
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p->sd_peer = NULL;
- p2p_continue_find(p2p);
+ if (p2p->state != P2P_IDLE)
+ p2p_continue_find(p2p);
return;
}
if (p2p->sd_peer == NULL) {
p2p_dbg(p2p, "No SD peer entry known");
- p2p_continue_find(p2p);
+ if (p2p->state != P2P_IDLE)
+ p2p_continue_find(p2p);
return;
}
- if (p2p->sd_query->for_all_peers) {
+ if (p2p->sd_query && p2p->sd_query->for_all_peers) {
/* Update the pending broadcast SD query count for this device
*/
p2p->sd_peer->sd_pending_bcast_queries--;
{
struct p2p_device *dev;
- if (p2p->state != P2P_IDLE)
- return;
-
/*
* Retry the prov disc req attempt only for the peer that the user had
* requested.
}
+static int p2p_check_after_scan_tx_continuation(struct p2p_data *p2p)
+{
+ if (p2p->after_scan_tx_in_progress) {
+ p2p->after_scan_tx_in_progress = 0;
+ if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING &&
+ p2p_run_after_scan(p2p))
+ return 1;
+ if (p2p->state == P2P_SEARCH) {
+ p2p_dbg(p2p, "Continue find after after_scan_tx completion");
+ p2p_continue_find(p2p);
+ }
+ }
+
+ return 0;
+}
+
+
+static void p2p_prov_disc_resp_cb(struct p2p_data *p2p, int success)
+{
+ p2p_dbg(p2p, "Provision Discovery Response TX callback: success=%d",
+ success);
+
+ if (p2p->send_action_in_progress) {
+ p2p->send_action_in_progress = 0;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ }
+
+ p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+ if (!success)
+ goto continue_search;
+
+ if (!p2p->cfg->prov_disc_resp_cb ||
+ p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1)
+ goto continue_search;
+
+ p2p_dbg(p2p,
+ "Post-Provision Discovery operations started - do not try to continue other P2P operations");
+ return;
+
+continue_search:
+ p2p_check_after_scan_tx_continuation(p2p);
+}
+
+
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
struct os_reltime *rx_time, int level, const u8 *ies,
size_t ies_len)
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
{
+ u8 dev_capab;
u8 *len;
#ifdef CONFIG_WIFI_DISPLAY
p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]);
len = p2p_buf_add_ie_hdr(ies);
- p2p_buf_add_capability(ies, p2p->dev_capab &
- ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
+
+ dev_capab = p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+
+ /* P2PS requires Probe Request frames to include SD bit */
+ if (p2p->p2ps_seek && p2p->p2ps_seek_count)
+ dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
+
+ p2p_buf_add_capability(ies, dev_capab, 0);
+
if (dev_id)
p2p_buf_add_device_id(ies, dev_id);
if (p2p->cfg->reg_class && p2p->cfg->channel)
if (p2p->ext_listen_interval)
p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period,
p2p->ext_listen_interval);
+
+ if (p2p->p2ps_seek && p2p->p2ps_seek_count)
+ p2p_buf_add_service_hash(ies, p2p);
+
/* TODO: p2p_buf_add_operating_channel() if GO */
p2p_buf_update_ie_hdr(ies, len);
}
p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success);
if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
p2p_go_neg_failed(p2p, p2p->go_neg_peer->status);
- } else if (success) {
+ return;
+ }
+
+ if (success) {
struct p2p_device *dev;
dev = p2p_get_device(p2p, addr);
if (dev &&
dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
}
+
+ if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND)
+ p2p_continue_find(p2p);
}
int success;
p2p_dbg(p2p, "Action frame TX callback (state=%d freq=%u dst=" MACSTR
- " src=" MACSTR " bssid=" MACSTR " result=%d",
+ " src=" MACSTR " bssid=" MACSTR " result=%d p2p_state=%s)",
p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src),
- MAC2STR(bssid), result);
+ MAC2STR(bssid), result, p2p_state_txt(p2p->state));
success = result == P2P_SEND_ACTION_SUCCESS;
state = p2p->pending_action_state;
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
p2p->send_action_in_progress = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
}
- if (p2p->after_scan_tx_in_progress) {
- p2p->after_scan_tx_in_progress = 0;
- if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING &&
- p2p_run_after_scan(p2p))
- break;
- if (p2p->state == P2P_SEARCH) {
- p2p_dbg(p2p, "Continue find after after_scan_tx completion");
- p2p_continue_find(p2p);
- }
- }
+ p2p_check_after_scan_tx_continuation(p2p);
break;
case P2P_PENDING_GO_NEG_REQUEST:
p2p_go_neg_req_cb(p2p, success);
case P2P_PENDING_PD:
p2p_prov_disc_cb(p2p, success);
break;
+ case P2P_PENDING_PD_RESPONSE:
+ p2p_prov_disc_resp_cb(p2p, success);
+ break;
case P2P_PENDING_INVITATION_REQUEST:
p2p_invitation_req_cb(p2p, success);
break;
static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
{
+ u32 adv_id = 0;
+ u8 *adv_mac = NULL;
+
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
/*
for_join = 1;
}
+ if (p2p->p2ps_prov) {
+ adv_id = p2p->p2ps_prov->adv_id;
+ adv_mac = p2p->p2ps_prov->adv_mac;
+ }
+
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
p2p->pending_pd_devaddr,
for_join ?
P2P_PROV_DISC_TIMEOUT_JOIN :
- P2P_PROV_DISC_TIMEOUT);
+ P2P_PROV_DISC_TIMEOUT,
+ adv_id, adv_mac, NULL);
p2p_reset_pending_pd(p2p);
}
}
return "PBC";
case WPS_NFC:
return "NFC";
+ case WPS_P2PS:
+ return "P2PS";
}
return "??";
"country=%c%c\n"
"oper_freq=%d\n"
"req_config_methods=0x%x\n"
- "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
+ "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
"status=%d\n"
"invitation_reqs=%u\n",
(int) (now.sec - dev->last_seen.sec),
"[PD_PEER_DISPLAY]" : "",
dev->flags & P2P_DEV_PD_PEER_KEYPAD ?
"[PD_PEER_KEYPAD]" : "",
+ dev->flags & P2P_DEV_PD_PEER_P2PS ?
+ "[PD_PEER_P2PS]" : "",
dev->flags & P2P_DEV_USER_REJECTED ?
"[USER_REJECTED]" : "",
dev->flags & P2P_DEV_PEER_WAITING_RESPONSE ?
"[PD_FOR_JOIN]" : "",
dev->status,
dev->invitation_reqs);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
"ext_listen_interval=%u\n",
dev->ext_listen_period,
dev->ext_listen_interval);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
"oper_ssid=%s\n",
wpa_ssid_txt(dev->oper_ssid,
dev->oper_ssid_len));
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
#ifdef CONFIG_WIFI_DISPLAY
if (dev->info.wfd_subelems) {
res = os_snprintf(pos, end - pos, "wfd_subelems=");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
wpabuf_len(dev->info.wfd_subelems));
res = os_snprintf(pos, end - pos, "\n");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
if (p2p_channel_to_freq(reg_class, channel) < 0)
return -1;
- p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
- reg_class, channel);
-
/*
* Listen channel was set in configuration or set by control interface;
* cannot override it.
*/
- if (p2p->cfg->channel_forced && forced == 0)
+ if (p2p->cfg->channel_forced && forced == 0) {
+ p2p_dbg(p2p,
+ "Listen channel was previously configured - do not override based on optimization");
return -1;
+ }
+
+ p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
+ reg_class, channel);
if (p2p->state == P2P_IDLE) {
p2p->cfg->reg_class = reg_class;