summaryrefslogtreecommitdiff
path: root/src/p2p
diff options
context:
space:
mode:
Diffstat (limited to 'src/p2p')
-rw-r--r--src/p2p/Makefile3
-rw-r--r--src/p2p/p2p.c2296
-rw-r--r--src/p2p/p2p.h514
-rw-r--r--src/p2p/p2p_build.c348
-rw-r--r--src/p2p/p2p_dev_disc.c88
-rw-r--r--src/p2p/p2p_go_neg.c655
-rw-r--r--src/p2p/p2p_group.c214
-rw-r--r--src/p2p/p2p_i.h192
-rw-r--r--src/p2p/p2p_invitation.c382
-rw-r--r--src/p2p/p2p_parse.c186
-rw-r--r--src/p2p/p2p_pd.c858
-rw-r--r--src/p2p/p2p_sd.c328
-rw-r--r--src/p2p/p2p_utils.c422
13 files changed, 4859 insertions, 1627 deletions
diff --git a/src/p2p/Makefile b/src/p2p/Makefile
index cffba620da04f..adfd3dfd5b9be 100644
--- a/src/p2p/Makefile
+++ b/src/p2p/Makefile
@@ -2,8 +2,7 @@ all:
@echo Nothing to be made.
clean:
- for d in $(SUBDIRS); do make -C $$d clean; done
- rm -f *~ *.o *.d
+ rm -f *~ *.o *.d *.gcno *.gcda *.gcov
install:
@echo Nothing to be made.
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index b994a44abc1cd..6adb3dc2049fb 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -13,6 +13,8 @@
#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"
@@ -42,21 +44,32 @@ static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx);
* P2P_PEER_EXPIRATION_AGE - Number of seconds after which inactive peer
* entries will be removed
*/
-#define P2P_PEER_EXPIRATION_AGE 300
+#ifndef P2P_PEER_EXPIRATION_AGE
+#define P2P_PEER_EXPIRATION_AGE 60
+#endif /* P2P_PEER_EXPIRATION_AGE */
#define P2P_PEER_EXPIRATION_INTERVAL (P2P_PEER_EXPIRATION_AGE / 2)
static void p2p_expire_peers(struct p2p_data *p2p)
{
struct p2p_device *dev, *n;
- struct os_time now;
+ struct os_reltime now;
size_t i;
- os_get_time(&now);
+ os_get_reltime(&now);
dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec)
continue;
+ if (dev == p2p->go_neg_peer) {
+ /*
+ * GO Negotiation is in progress with the peer, so
+ * don't expire the peer entry until GO Negotiation
+ * fails or times out.
+ */
+ continue;
+ }
+
if (p2p->cfg->go_connected &&
p2p->cfg->go_connected(p2p->cfg->cb_ctx,
dev->info.p2p_device_addr)) {
@@ -64,7 +77,7 @@ static void p2p_expire_peers(struct p2p_data *p2p)
* We are connected as a client to a group in which the
* peer is the GO, so do not expire the peer entry.
*/
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
continue;
}
@@ -78,12 +91,12 @@ static void p2p_expire_peers(struct p2p_data *p2p)
* The peer is connected as a client in a group where
* we are the GO, so do not expire the peer entry.
*/
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
continue;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Expiring old peer "
- "entry " MACSTR, MAC2STR(dev->info.p2p_device_addr));
+ p2p_dbg(p2p, "Expiring old peer entry " MACSTR,
+ MAC2STR(dev->info.p2p_device_addr));
dl_list_del(&dev->list);
p2p_device_free(p2p, dev);
}
@@ -128,16 +141,31 @@ static const char * p2p_state_txt(int state)
return "INVITE";
case P2P_INVITE_LISTEN:
return "INVITE_LISTEN";
- case P2P_SEARCH_WHEN_READY:
- return "SEARCH_WHEN_READY";
- case P2P_CONTINUE_SEARCH_WHEN_READY:
- return "CONTINUE_SEARCH_WHEN_READY";
default:
return "?";
}
}
+const char * p2p_get_state_txt(struct p2p_data *p2p)
+{
+ return p2p_state_txt(p2p->state);
+}
+
+
+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;
@@ -168,16 +196,23 @@ void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr)
void p2p_set_state(struct p2p_data *p2p, int new_state)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
+ p2p_dbg(p2p, "State %s -> %s",
p2p_state_txt(p2p->state), p2p_state_txt(new_state));
p2p->state = new_state;
+
+ if (new_state == P2P_IDLE && p2p->pending_channel) {
+ p2p_dbg(p2p, "Apply change in listen channel");
+ p2p->cfg->reg_class = p2p->pending_reg_class;
+ p2p->cfg->channel = p2p->pending_channel;
+ p2p->pending_reg_class = 0;
+ p2p->pending_channel = 0;
+ }
}
void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Set timeout (state=%s): %u.%06u sec",
+ p2p_dbg(p2p, "Set timeout (state=%s): %u.%06u sec",
p2p_state_txt(p2p->state), sec, usec);
eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
@@ -186,30 +221,40 @@ void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec)
void p2p_clear_timeout(struct p2p_data *p2p)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear timeout (state=%s)",
- p2p_state_txt(p2p->state));
+ p2p_dbg(p2p, "Clear timeout (state=%s)", p2p_state_txt(p2p->state));
eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
}
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
- int status)
+void p2p_go_neg_failed(struct p2p_data *p2p, int status)
{
struct p2p_go_neg_results res;
- p2p_clear_timeout(p2p);
- p2p_set_state(p2p, P2P_IDLE);
- if (p2p->go_neg_peer)
- p2p->go_neg_peer->wps_method = WPS_NOT_READY;
+ struct p2p_device *peer = p2p->go_neg_peer;
+
+ if (!peer)
+ return;
+
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+ 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;
+ peer->oob_pw_id = 0;
+ wpabuf_free(peer->go_neg_conf);
+ peer->go_neg_conf = NULL;
p2p->go_neg_peer = NULL;
os_memset(&res, 0, sizeof(res));
res.status = status;
- if (peer) {
- os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr,
- ETH_ALEN);
- os_memcpy(res.peer_interface_addr, peer->intended_addr,
- ETH_ALEN);
- }
+ os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
+ os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
}
@@ -220,19 +265,23 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
int freq;
struct wpabuf *ies;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Starting short listen state (state=%s)",
+ p2p_dbg(p2p, "Starting short listen state (state=%s)",
p2p_state_txt(p2p->state));
- freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
- p2p->cfg->channel);
+ if (p2p->pending_listen_freq) {
+ /* We have a pending p2p_listen request */
+ p2p_dbg(p2p, "p2p_listen command pending already");
+ return;
+ }
+
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
return;
}
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +
p2p->min_disc_int) * 100;
if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu)
@@ -243,24 +292,22 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
tu = p2p->cfg->max_listen * 1000 / 1024;
if (tu == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip listen state "
- "since duration was 0 TU");
+ p2p_dbg(p2p, "Skip listen state since duration was 0 TU");
p2p_set_timeout(p2p, 0, 0);
return;
}
- p2p->pending_listen_freq = freq;
- p2p->pending_listen_sec = 0;
- p2p->pending_listen_usec = 1024 * tu;
-
ies = p2p_build_probe_resp_ies(p2p);
if (ies == NULL)
return;
+ p2p->pending_listen_freq = freq;
+ p2p->pending_listen_sec = 0;
+ p2p->pending_listen_usec = 1024 * tu;
+
if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 * tu / 1000,
ies) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to start listen mode");
+ p2p_dbg(p2p, "Failed to start listen mode");
p2p->pending_listen_freq = 0;
}
wpabuf_free(ies);
@@ -272,30 +319,29 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
int freq;
struct wpabuf *ies;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Going to listen(only) state");
+ p2p_dbg(p2p, "Going to listen(only) state");
- freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
- p2p->cfg->channel);
+ if (p2p->pending_listen_freq) {
+ /* We have a pending p2p_listen request */
+ p2p_dbg(p2p, "p2p_listen command pending already");
+ return -1;
+ }
+
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
return -1;
}
- p2p->pending_listen_freq = freq;
p2p->pending_listen_sec = timeout / 1000;
p2p->pending_listen_usec = (timeout % 1000) * 1000;
if (p2p->p2p_scan_running) {
if (p2p->start_after_scan == P2P_AFTER_SCAN_CONNECT) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: p2p_scan running - connect is already "
- "pending - skip listen");
+ p2p_dbg(p2p, "p2p_scan running - connect is already pending - skip listen");
return 0;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: p2p_scan running - delay start of listen state");
+ p2p_dbg(p2p, "p2p_scan running - delay start of listen state");
p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
return 0;
}
@@ -304,9 +350,10 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
if (ies == NULL)
return -1;
+ p2p->pending_listen_freq = freq;
+
if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, timeout, ies) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to start listen mode");
+ p2p_dbg(p2p, "Failed to start listen mode");
p2p->pending_listen_freq = 0;
wpabuf_free(ies);
return -1;
@@ -322,8 +369,10 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
static void p2p_device_clear_reported(struct p2p_data *p2p)
{
struct p2p_device *dev;
- dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
dev->flags &= ~P2P_DEV_REPORTED;
+ dev->sd_reqs = 0;
+ }
}
@@ -384,13 +433,11 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p,
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
count++;
if (oldest == NULL ||
- os_time_before(&dev->last_seen, &oldest->last_seen))
+ os_reltime_before(&dev->last_seen, &oldest->last_seen))
oldest = dev;
}
if (count + 1 > p2p->cfg->max_peers && oldest) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Remove oldest peer entry to make room for a new "
- "peer");
+ p2p_dbg(p2p, "Remove oldest peer entry to make room for a new peer");
dl_list_del(&oldest->list);
p2p_device_free(p2p, oldest);
}
@@ -489,7 +536,7 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
os_memcpy(dev->interface_addr, cli->p2p_interface_addr,
ETH_ALEN);
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN);
os_memcpy(dev->member_in_go_iface, go_interface_addr,
ETH_ALEN);
@@ -499,8 +546,8 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
}
-static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
- const struct p2p_message *msg)
+static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev,
+ int probe_req, const struct p2p_message *msg)
{
os_memcpy(dev->info.device_name, msg->device_name,
sizeof(dev->info.device_name));
@@ -570,9 +617,77 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
}
if (!probe_req) {
- dev->info.config_methods = msg->config_methods ?
+ u16 new_config_methods;
+ new_config_methods = msg->config_methods ?
msg->config_methods : msg->wps_config_methods;
+ if (new_config_methods &&
+ dev->info.config_methods != new_config_methods) {
+ p2p_dbg(p2p, "Update peer " MACSTR
+ " config_methods 0x%x -> 0x%x",
+ MAC2STR(dev->info.p2p_device_addr),
+ dev->info.config_methods,
+ new_config_methods);
+ dev->info.config_methods = new_config_methods;
+ }
+ }
+}
+
+
+static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
+ size_t ies_len)
+{
+ const u8 *pos, *end;
+ u8 id, len;
+
+ wpabuf_free(dev->info.vendor_elems);
+ dev->info.vendor_elems = NULL;
+
+ end = ies + ies_len;
+
+ for (pos = ies; pos + 1 < end; pos += len) {
+ id = *pos++;
+ len = *pos++;
+
+ if (pos + len > end)
+ break;
+
+ if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3)
+ continue;
+
+ if (len >= 4) {
+ u32 type = WPA_GET_BE32(pos);
+
+ if (type == WPA_IE_VENDOR_TYPE ||
+ type == WMM_IE_VENDOR_TYPE ||
+ type == WPS_IE_VENDOR_TYPE ||
+ type == P2P_IE_VENDOR_TYPE ||
+ type == WFD_IE_VENDOR_TYPE)
+ continue;
+ }
+
+ /* Unknown vendor element - make raw IE data available */
+ if (wpabuf_resize(&dev->info.vendor_elems, 2 + len) < 0)
+ break;
+ wpabuf_put_data(dev->info.vendor_elems, pos - 2, 2 + len);
+ }
+}
+
+
+static int p2p_compare_wfd_info(struct p2p_device *dev,
+ const struct p2p_message *msg)
+{
+ if (dev->info.wfd_subelems && msg->wfd_subelems) {
+ if (dev->info.wfd_subelems->used != msg->wfd_subelems->used)
+ return 1;
+
+ return os_memcmp(dev->info.wfd_subelems->buf,
+ msg->wfd_subelems->buf,
+ dev->info.wfd_subelems->used);
}
+ if (dev->info.wfd_subelems || msg->wfd_subelems)
+ return 1;
+
+ return 0;
}
@@ -583,7 +698,7 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
* P2P Device Address or P2P Interface Address)
* @level: Signal level (signal strength of the received frame from the peer)
* @freq: Frequency on which the Beacon or Probe Response frame was received
- * @age_ms: Age of the information in milliseconds
+ * @rx_time: Time when the result was received
* @ies: IEs from the Beacon or Probe Response frame
* @ies_len: Length of ies buffer in octets
* @scan_res: Whether this was based on scan results
@@ -595,19 +710,19 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
* Info attributes.
*/
int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
- unsigned int age_ms, int level, const u8 *ies,
+ struct os_reltime *rx_time, int level, const u8 *ies,
size_t ies_len, int scan_res)
{
struct p2p_device *dev;
struct p2p_message msg;
const u8 *p2p_dev_addr;
+ int wfd_changed;
int i;
- struct os_time time_now, time_tmp_age, entry_ts;
+ struct os_reltime time_now;
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ies, ies_len, &msg)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to parse P2P IE for a device entry");
+ p2p_dbg(p2p, "Failed to parse P2P IE for a device entry");
p2p_parse_free(&msg);
return -1;
}
@@ -617,18 +732,15 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
else if (msg.device_id)
p2p_dev_addr = msg.device_id;
else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore scan data without P2P Device Info or "
- "P2P Device Id");
+ p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
p2p_parse_free(&msg);
return -1;
}
if (!is_zero_ether_addr(p2p->peer_filter) &&
os_memcmp(p2p_dev_addr, p2p->peer_filter, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not add peer "
- "filter for " MACSTR " due to peer filter",
- MAC2STR(p2p_dev_addr));
+ p2p_dbg(p2p, "Do not add peer filter for " MACSTR
+ " due to peer filter", MAC2STR(p2p_dev_addr));
p2p_parse_free(&msg);
return 0;
}
@@ -639,22 +751,27 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
return -1;
}
- os_get_time(&time_now);
- time_tmp_age.sec = age_ms / 1000;
- time_tmp_age.usec = (age_ms % 1000) * 1000;
- os_time_sub(&time_now, &time_tmp_age, &entry_ts);
+ if (rx_time == NULL) {
+ os_get_reltime(&time_now);
+ rx_time = &time_now;
+ }
/*
* Update the device entry only if the new peer
* entry is newer than the one previously stored.
*/
- if (dev->last_seen.usec > 0 &&
- os_time_before(&entry_ts, &dev->last_seen)) {
+ if (dev->last_seen.sec > 0 &&
+ os_reltime_before(rx_time, &dev->last_seen)) {
+ p2p_dbg(p2p, "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u)",
+ (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec,
+ (unsigned int) dev->last_seen.sec,
+ (unsigned int) dev->last_seen.usec);
p2p_parse_free(&msg);
return -1;
}
- os_memcpy(&dev->last_seen, &entry_ts, sizeof(struct os_time));
+ os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime));
dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
@@ -668,6 +785,12 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
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;
@@ -676,18 +799,15 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
else
ds_freq = 2407 + *msg.ds_params * 5;
if (freq != ds_freq) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Update Listen frequency based on DS "
- "Parameter Set IE: %d -> %d MHz",
+ p2p_dbg(p2p, "Update Listen frequency based on DS Parameter Set IE: %d -> %d MHz",
freq, ds_freq);
freq = ds_freq;
}
}
if (dev->listen_freq && dev->listen_freq != freq && scan_res) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Update Listen frequency based on scan "
- "results (" MACSTR " %d -> %d MHz (DS param %d)",
+ p2p_dbg(p2p, "Update Listen frequency based on scan results ("
+ MACSTR " %d -> %d MHz (DS param %d)",
MAC2STR(dev->info.p2p_device_addr), dev->listen_freq,
freq, msg.ds_params ? *msg.ds_params : -1);
}
@@ -698,7 +818,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
}
dev->info.level = level;
- p2p_copy_wps_info(dev, 0, &msg);
+ p2p_copy_wps_info(p2p, dev, 0, &msg);
for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
wpabuf_free(dev->info.wps_vendor_ext[i]);
@@ -714,6 +834,8 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
break;
}
+ wfd_changed = p2p_compare_wfd_info(dev, &msg);
+
if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
@@ -726,17 +848,39 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
p2p_parse_free(&msg);
- if (p2p_pending_sd_req(p2p, dev))
- dev->flags |= P2P_DEV_SD_SCHEDULE;
+ p2p_update_peer_vendor_elems(dev, ies, ies_len);
- if (dev->flags & P2P_DEV_REPORTED)
+ if (dev->flags & P2P_DEV_REPORTED && !wfd_changed &&
+ (!msg.adv_service_instance ||
+ (dev->flags & P2P_DEV_P2PS_REPORTED)))
return 0;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer found with Listen frequency %d MHz", freq);
+ p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
+ freq, (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec);
if (dev->flags & P2P_DEV_USER_REJECTED) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Do not report rejected device");
+ p2p_dbg(p2p, "Do not report rejected device");
+ return 0;
+ }
+
+ if (dev->info.config_methods == 0 &&
+ (freq == 2412 || freq == 2437 || freq == 2462)) {
+ /*
+ * If we have only seen a Beacon frame from a GO, we do not yet
+ * know what WPS config methods it supports. Since some
+ * applications use config_methods value from P2P-DEVICE-FOUND
+ * events, postpone reporting this peer until we've fully
+ * discovered its capabilities.
+ *
+ * At least for now, do this only if the peer was detected on
+ * one of the social channels since that peer can be easily be
+ * found again and there are no limitations of having to use
+ * passive scan on this channels, so this can be done through
+ * Probe Response frame that includes the config_methods
+ * information.
+ */
+ p2p_dbg(p2p, "Do not report peer " MACSTR
+ " with unknown config methods", MAC2STR(addr));
return 0;
}
@@ -744,6 +888,9 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
!(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;
}
@@ -756,8 +903,7 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
/*
* If GO Negotiation is in progress, report that it has failed.
*/
- p2p_go_neg_failed(p2p, dev, -1);
- p2p->go_neg_peer = NULL;
+ p2p_go_neg_failed(p2p, -1);
}
if (p2p->invite_peer == dev)
p2p->invite_peer = NULL;
@@ -777,6 +923,9 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
}
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);
}
@@ -824,9 +973,8 @@ static int p2p_get_next_prog_freq(struct p2p_data *p2p)
channel = c->reg_class[cl].channel[ch];
}
- freq = p2p_channel_to_freq(p2p->cfg->country, reg_class, channel);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Next progressive search "
- "channel: reg_class %u channel %u -> %d MHz",
+ freq = p2p_channel_to_freq(reg_class, channel);
+ p2p_dbg(p2p, "Next progressive search channel: reg_class %u channel %u -> %d MHz",
reg_class, channel, freq);
p2p->last_prog_scan_class = reg_class;
p2p->last_prog_scan_chan = channel;
@@ -845,9 +993,7 @@ static void p2p_search(struct p2p_data *p2p)
int res;
if (p2p->drv_in_listen) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still "
- "in Listen state - wait for it to end before "
- "continuing");
+ p2p_dbg(p2p, "Driver is still in Listen state - wait for it to end before continuing");
return;
}
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
@@ -855,31 +1001,18 @@ static void p2p_search(struct p2p_data *p2p)
if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
(freq = p2p_get_next_prog_freq(p2p)) > 0) {
type = P2P_SCAN_SOCIAL_PLUS_ONE;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
- "(+ freq %u)", freq);
+ p2p_dbg(p2p, "Starting search (+ freq %u)", freq);
} else {
type = P2P_SCAN_SOCIAL;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search");
+ p2p_dbg(p2p, "Starting search");
}
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
p2p->num_req_dev_types, p2p->req_dev_types,
p2p->find_dev_id, pw_id);
if (res < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Scan request failed");
+ p2p_dbg(p2p, "Scan request schedule failed");
p2p_continue_find(p2p);
- } else if (res == 1) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
- "p2p_scan at this point - will try again after "
- "previous scan completes");
- p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY);
- } else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
- p2p->p2p_scan_running = 1;
- eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
- eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
- p2p, NULL);
}
}
@@ -887,21 +1020,35 @@ static void p2p_search(struct p2p_data *p2p)
static void p2p_find_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct p2p_data *p2p = eloop_ctx;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Find timeout -> stop");
+ p2p_dbg(p2p, "Find timeout -> stop");
p2p_stop_find(p2p);
}
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status)
+{
+ if (status != 0) {
+ p2p_dbg(p2p, "Scan request failed");
+ /* Do continue find even for the first p2p_find_scan */
+ p2p_continue_find(p2p);
+ } else {
+ p2p_dbg(p2p, "Running p2p_scan");
+ p2p->p2p_scan_running = 1;
+ eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
+ eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
+ p2p, NULL);
+ }
+}
+
+
static int p2p_run_after_scan(struct p2p_data *p2p)
{
struct p2p_device *dev;
enum p2p_after_scan op;
if (p2p->after_scan_tx) {
- /* TODO: schedule p2p_run_after_scan to be called from TX
- * status callback(?) */
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending "
- "Action frame at p2p_scan completion");
+ p2p->after_scan_tx_in_progress = 1;
+ p2p_dbg(p2p, "Send pending Action frame at p2p_scan completion");
p2p->cfg->send_action(p2p->cfg->cb_ctx,
p2p->after_scan_tx->freq,
p2p->after_scan_tx->dst,
@@ -921,19 +1068,16 @@ static int p2p_run_after_scan(struct p2p_data *p2p)
case P2P_AFTER_SCAN_NOTHING:
break;
case P2P_AFTER_SCAN_LISTEN:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously "
- "requested Listen state");
+ p2p_dbg(p2p, "Start previously requested Listen state");
p2p_listen(p2p, p2p->pending_listen_sec * 1000 +
p2p->pending_listen_usec / 1000);
return 1;
case P2P_AFTER_SCAN_CONNECT:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously "
- "requested connect with " MACSTR,
+ p2p_dbg(p2p, "Start previously requested connect with " MACSTR,
MAC2STR(p2p->after_scan_peer));
dev = p2p_get_device(p2p, p2p->after_scan_peer);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer not "
- "known anymore");
+ p2p_dbg(p2p, "Peer not known anymore");
break;
}
p2p_connect_send(p2p, dev);
@@ -948,8 +1092,7 @@ static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct p2p_data *p2p = eloop_ctx;
int running;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan timeout "
- "(running=%d)", p2p->p2p_scan_running);
+ p2p_dbg(p2p, "p2p_scan timeout (running=%d)", p2p->p2p_scan_running);
running = p2p->p2p_scan_running;
/* Make sure we recover from missed scan results callback */
p2p->p2p_scan_running = 0;
@@ -967,18 +1110,51 @@ static void p2p_free_req_dev_types(struct p2p_data *p2p)
}
+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;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting find (type=%d)",
- type);
+ p2p_dbg(p2p, "Starting find (type=%d)", type);
+ os_get_reltime(&p2p->find_start);
if (p2p->p2p_scan_running) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan is "
- "already running");
+ p2p_dbg(p2p, "p2p_scan is already running");
}
p2p_free_req_dev_types(p2p);
@@ -998,6 +1174,47 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
} 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);
@@ -1013,6 +1230,19 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
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,
@@ -1029,22 +1259,12 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
return -1;
}
- if (res == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
- p2p->p2p_scan_running = 1;
- eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
- eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
- p2p, NULL);
- } else if (res == 1) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
- "p2p_scan at this point - will try again after "
- "previous scan completes");
- res = 0;
- p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
- eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
- } else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
- "p2p_scan");
+ if (res != 0 && p2p->p2p_scan_running) {
+ p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
+ /* wait for the previous p2p_scan to complete */
+ res = 0; /* do not report failure */
+ } else if (res != 0) {
+ p2p_dbg(p2p, "Failed to start p2p_scan");
p2p_set_state(p2p, P2P_IDLE);
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
}
@@ -1053,47 +1273,33 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
}
-int p2p_other_scan_completed(struct p2p_data *p2p)
-{
- if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) {
- p2p_set_state(p2p, P2P_SEARCH);
- p2p_search(p2p);
- return 1;
- }
- if (p2p->state != P2P_SEARCH_WHEN_READY)
- return 0;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
- "now that previous scan was completed");
- if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
- p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id, p2p->search_delay) < 0)
- return 0;
- return 1;
-}
-
-
void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
+ p2p_dbg(p2p, "Stopping find");
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p_clear_timeout(p2p);
- if (p2p->state == P2P_SEARCH)
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+ 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;
+ if (p2p->go_neg_peer)
+ p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
p2p->go_neg_peer = NULL;
p2p->sd_peer = NULL;
p2p->invite_peer = NULL;
p2p_stop_listen_for_freq(p2p, freq);
+ p2p->send_action_in_progress = 0;
}
void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
{
if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip stop_listen "
- "since we are on correct channel for response");
+ p2p_dbg(p2p, "Skip stop_listen since we are on correct channel for response");
return;
}
if (p2p->in_listen) {
@@ -1106,38 +1312,51 @@ void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
* when the operation gets canceled, so clear the internal
* variable that is tracking driver state.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear "
- "drv_in_listen (%d)", p2p->drv_in_listen);
+ p2p_dbg(p2p, "Clear drv_in_listen (%d)", p2p->drv_in_listen);
p2p->drv_in_listen = 0;
}
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
}
+void p2p_stop_listen(struct p2p_data *p2p)
+{
+ if (p2p->state != P2P_LISTEN_ONLY) {
+ p2p_dbg(p2p, "Skip stop_listen since not in listen_only state.");
+ return;
+ }
+
+ p2p_stop_listen_for_freq(p2p, 0);
+ p2p_set_state(p2p, P2P_IDLE);
+}
+
+
void p2p_stop_find(struct p2p_data *p2p)
{
+ p2p->pending_listen_freq = 0;
p2p_stop_find_for_freq(p2p, 0);
}
static int p2p_prepare_channel_pref(struct p2p_data *p2p,
unsigned int force_freq,
- unsigned int pref_freq)
+ unsigned int pref_freq, int go)
{
u8 op_class, op_channel;
unsigned int freq = force_freq ? force_freq : pref_freq;
- if (p2p_freq_to_channel(p2p->cfg->country, freq,
- &op_class, &op_channel) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported frequency %u MHz", freq);
+ p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d",
+ force_freq, pref_freq, go);
+ if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
+ p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
return -1;
}
- if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Frequency %u MHz (oper_class %u channel %u) not "
- "allowed for P2P", freq, op_class, op_channel);
+ if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) &&
+ (go || !p2p_channels_includes(&p2p->cfg->cli_channels, op_class,
+ op_channel))) {
+ p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
+ freq, op_class, op_channel);
return -1;
}
@@ -1161,34 +1380,74 @@ static int p2p_prepare_channel_pref(struct p2p_data *p2p,
static void p2p_prepare_channel_best(struct p2p_data *p2p)
{
u8 op_class, op_channel;
+ const int op_classes_5ghz[] = { 124, 115, 0 };
+ const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
+ const int op_classes_vht[] = { 128, 0 };
+
+ p2p_dbg(p2p, "Prepare channel best");
if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_overall) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
- &op_class, &op_channel) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best "
- "overall channel as operating channel preference");
+ p2p_freq_to_channel(p2p->best_freq_overall, &op_class, &op_channel)
+ == 0) {
+ p2p_dbg(p2p, "Select best overall channel as operating channel preference");
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_5) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
- &op_class, &op_channel) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 5 GHz "
- "channel as operating channel preference");
+ p2p_freq_to_channel(p2p->best_freq_5, &op_class, &op_channel)
+ == 0) {
+ p2p_dbg(p2p, "Select best 5 GHz channel as operating channel preference");
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_24) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
- &op_class, &op_channel) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 2.4 "
- "GHz channel as operating channel preference");
+ p2p_freq_to_channel(p2p->best_freq_24, &op_class,
+ &op_channel) == 0) {
+ p2p_dbg(p2p, "Select best 2.4 GHz channel as operating channel preference");
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
- } else {
+ } else if (p2p->cfg->num_pref_chan > 0 &&
+ p2p_channels_includes(&p2p->cfg->channels,
+ p2p->cfg->pref_chan[0].op_class,
+ p2p->cfg->pref_chan[0].chan)) {
+ p2p_dbg(p2p, "Select first pref_chan entry as operating channel preference");
+ p2p->op_reg_class = p2p->cfg->pref_chan[0].op_class;
+ p2p->op_channel = p2p->cfg->pref_chan[0].chan;
+ } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_vht,
+ &p2p->op_reg_class, &p2p->op_channel) ==
+ 0) {
+ p2p_dbg(p2p, "Select possible VHT channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
+ } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_ht40,
+ &p2p->op_reg_class, &p2p->op_channel) ==
+ 0) {
+ p2p_dbg(p2p, "Select possible HT40 channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
+ } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_5ghz,
+ &p2p->op_reg_class, &p2p->op_channel) ==
+ 0) {
+ p2p_dbg(p2p, "Select possible 5 GHz channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
+ } else if (p2p_channels_includes(&p2p->cfg->channels,
+ p2p->cfg->op_reg_class,
+ p2p->cfg->op_channel)) {
+ p2p_dbg(p2p, "Select pre-configured channel as operating channel preference");
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
+ } else if (p2p_channel_random_social(&p2p->cfg->channels,
+ &p2p->op_reg_class,
+ &p2p->op_channel) == 0) {
+ p2p_dbg(p2p, "Select random available social channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
+ } else {
+ /* Select any random available channel from the first available
+ * operating class */
+ p2p_channel_select(&p2p->cfg->channels, NULL,
+ &p2p->op_reg_class,
+ &p2p->op_channel);
+ p2p_dbg(p2p, "Select random available channel %d from operating class %d as operating channel preference",
+ p2p->op_channel, p2p->op_reg_class);
}
os_memcpy(&p2p->channels, &p2p->cfg->channels,
@@ -1202,6 +1461,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* @dev: Selected peer device
* @force_freq: Forced frequency in MHz or 0 if not forced
* @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * @go: Whether the local end will be forced to be GO
* Returns: 0 on success, -1 on failure (channel not supported for P2P)
*
* This function is used to do initial operating channel selection for GO
@@ -1209,18 +1469,27 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* may be further optimized in p2p_reselect_channel() once the peer information
* is available.
*/
-static int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
- unsigned int force_freq, unsigned int pref_freq)
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ unsigned int force_freq, unsigned int pref_freq, int go)
{
+ p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d",
+ force_freq, pref_freq, go);
if (force_freq || pref_freq) {
- if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) <
+ 0)
return -1;
} else {
p2p_prepare_channel_best(p2p);
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Own preference for operation channel: "
- "Operating Class %u Channel %u%s",
+ p2p_channels_dump(p2p, "prepared channels", &p2p->channels);
+ if (go)
+ p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
+ else if (!force_freq)
+ 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",
p2p->op_reg_class, p2p->op_channel,
force_freq ? " (forced)" : "");
@@ -1258,40 +1527,38 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- int pd_before_go_neg, unsigned int pref_freq)
+ int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id)
{
struct p2p_device *dev;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Request to start group negotiation - peer=" MACSTR
+ p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR
" GO Intent=%d Intended Interface Address=" MACSTR
- " wps_method=%d persistent_group=%d pd_before_go_neg=%d",
+ " wps_method=%d persistent_group=%d pd_before_go_neg=%d "
+ "oob_pw_id=%u",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
- wps_method, persistent_group, pd_before_go_neg);
+ wps_method, persistent_group, pd_before_go_neg, oob_pw_id);
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot connect to unknown P2P Device " MACSTR,
+ p2p_dbg(p2p, "Cannot connect to unknown P2P Device " MACSTR,
MAC2STR(peer_addr));
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+ go_intent == 15) < 0)
return -1;
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot connect to P2P Device " MACSTR
+ p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
" that is in a group and is not discoverable",
MAC2STR(peer_addr));
return -1;
}
if (dev->oper_freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot connect to P2P Device " MACSTR
+ p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
" with incomplete information",
MAC2STR(peer_addr));
return -1;
@@ -1319,8 +1586,18 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
if (pd_before_go_neg)
dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
- else
+ else {
dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+ /*
+ * Assign dialog token and tie breaker here to use the same
+ * values in each retry within the same GO Negotiation exchange.
+ */
+ dev->dialog_token++;
+ if (dev->dialog_token == 0)
+ dev->dialog_token = 1;
+ dev->tie_breaker = p2p->next_tie_breaker;
+ p2p->next_tie_breaker = !p2p->next_tie_breaker;
+ }
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
@@ -1337,19 +1614,17 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
* new GO Negotiation, e.g., when the pending frame was from a
* previous attempt at starting a GO Negotiation.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped "
- "previous pending Action frame TX that was waiting "
- "for p2p_scan completion");
+ p2p_dbg(p2p, "Dropped previous pending Action frame TX that was waiting for p2p_scan completion");
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
}
dev->wps_method = wps_method;
+ dev->oob_pw_id = oob_pw_id;
dev->status = P2P_SC_SUCCESS;
if (p2p->p2p_scan_running) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: p2p_scan running - delay connect send");
+ p2p_dbg(p2p, "p2p_scan running - delay connect send");
p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT;
os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);
return 0;
@@ -1365,26 +1640,25 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- unsigned int pref_freq)
+ unsigned int pref_freq, u16 oob_pw_id)
{
struct p2p_device *dev;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Request to authorize group negotiation - peer=" MACSTR
+ p2p_dbg(p2p, "Request to authorize group negotiation - peer=" MACSTR
" GO Intent=%d Intended Interface Address=" MACSTR
- " wps_method=%d persistent_group=%d",
+ " wps_method=%d persistent_group=%d oob_pw_id=%u",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
- wps_method, persistent_group);
+ wps_method, persistent_group, oob_pw_id);
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot authorize unknown P2P Device " MACSTR,
+ p2p_dbg(p2p, "Cannot authorize unknown P2P Device " MACSTR,
MAC2STR(peer_addr));
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent ==
+ 15) < 0)
return -1;
p2p->ssid_set = 0;
@@ -1405,6 +1679,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
dev->wps_method = wps_method;
+ dev->oob_pw_id = oob_pw_id;
dev->status = P2P_SC_SUCCESS;
return 0;
@@ -1414,18 +1689,16 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
struct p2p_device *dev, struct p2p_message *msg)
{
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
- p2p_copy_wps_info(dev, 0, msg);
+ p2p_copy_wps_info(p2p, dev, 0, msg);
if (msg->listen_channel) {
int freq;
- freq = p2p_channel_to_freq((char *) msg->listen_channel,
- msg->listen_channel[3],
+ freq = p2p_channel_to_freq(msg->listen_channel[3],
msg->listen_channel[4]);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown peer Listen channel: "
+ p2p_dbg(p2p, "Unknown peer Listen channel: "
"country=%c%c(0x%02x) reg_class=%u channel=%u",
msg->listen_channel[0],
msg->listen_channel[1],
@@ -1433,8 +1706,8 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
msg->listen_channel[3],
msg->listen_channel[4]);
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update "
- "peer " MACSTR " Listen channel: %u -> %u MHz",
+ p2p_dbg(p2p, "Update peer " MACSTR
+ " Listen channel: %u -> %u MHz",
MAC2STR(dev->info.p2p_device_addr),
dev->listen_freq, freq);
dev->listen_freq = freq;
@@ -1448,12 +1721,9 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Completed device entry based on data from "
- "GO Negotiation Request");
+ p2p_dbg(p2p, "Completed device entry based on data from GO Negotiation Request");
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Created device entry based on GO Neg Req: "
+ p2p_dbg(p2p, "Created device entry based on GO Neg Req: "
MACSTR " dev_capab=0x%x group_capab=0x%x name='%s' "
"listen_freq=%d",
MAC2STR(dev->info.p2p_device_addr),
@@ -1464,8 +1734,7 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
dev->flags &= ~P2P_DEV_GROUP_CLIENT_ONLY;
if (dev->flags & P2P_DEV_USER_REJECTED) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Do not report rejected device");
+ p2p_dbg(p2p, "Do not report rejected device");
return;
}
@@ -1487,8 +1756,15 @@ void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len)
int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params)
{
- p2p_build_ssid(p2p, params->ssid, &params->ssid_len);
- p2p_random(params->passphrase, 8);
+ 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, &params->ssid_len);
+ }
+ p2p->ssid_set = 0;
+
+ p2p_random(params->passphrase, p2p->cfg->passphrase_len);
return 0;
}
@@ -1498,13 +1774,9 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
struct p2p_go_neg_results res;
int go = peer->go_state == LOCAL_GO;
struct p2p_channels intersection;
- int freqs;
- size_t i, j;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation with " MACSTR " completed (%s will be "
- "GO)", MAC2STR(peer->info.p2p_device_addr),
- go ? "local end" : "peer");
+ p2p_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)",
+ MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer");
os_memset(&res, 0, sizeof(res));
res.role_go = go;
@@ -1520,12 +1792,11 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
if (go) {
/* Setup AP mode for WPS provisioning */
- res.freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->op_reg_class,
+ res.freq = p2p_channel_to_freq(p2p->op_reg_class,
p2p->op_channel);
os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
res.ssid_len = p2p->ssid_len;
- p2p_random(res.passphrase, 8);
+ p2p_random(res.passphrase, p2p->cfg->passphrase_len);
} else {
res.freq = peer->oper_freq;
if (p2p->ssid_len) {
@@ -1534,31 +1805,28 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
}
}
+ p2p_channels_dump(p2p, "own channels", &p2p->channels);
+ p2p_channels_dump(p2p, "peer channels", &peer->channels);
p2p_channels_intersect(&p2p->channels, &peer->channels,
&intersection);
- freqs = 0;
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c = &intersection.reg_class[i];
- if (freqs + 1 == P2P_MAX_CHANNELS)
- break;
- for (j = 0; j < c->channels; j++) {
- int freq;
- if (freqs + 1 == P2P_MAX_CHANNELS)
- break;
- freq = p2p_channel_to_freq(peer->country, c->reg_class,
- c->channel[j]);
- if (freq < 0)
- continue;
- res.freq_list[freqs++] = freq;
- }
+ if (go) {
+ p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
+ p2p_channels_dump(p2p, "intersection after no-GO removal",
+ &intersection);
}
+ p2p_channels_to_freqs(&intersection, res.freq_list,
+ P2P_MAX_CHANNELS);
+
res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
p2p_clear_timeout(p2p);
p2p->ssid_set = 0;
peer->go_neg_req_sent = 0;
peer->wps_method = WPS_NOT_READY;
+ peer->oob_pw_id = 0;
+ wpabuf_free(peer->go_neg_conf);
+ peer->go_neg_conf = NULL;
p2p_set_state(p2p, P2P_PROVISIONING);
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
@@ -1568,8 +1836,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: RX P2P Public Action from " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "RX P2P Public Action from " MACSTR, MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Public Action contents", data, len);
if (len < 1)
@@ -1605,8 +1872,7 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
p2p_process_dev_disc_resp(p2p, sa, data + 1, len - 1);
break;
default:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported P2P Public Action frame type %d",
+ p2p_dbg(p2p, "Unsupported P2P Public Action frame type %d",
data[0]);
break;
}
@@ -1624,20 +1890,15 @@ static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da,
case WLAN_PA_VENDOR_SPECIFIC:
data++;
len--;
- if (len < 3)
+ if (len < 4)
return;
- if (WPA_GET_BE24(data) != OUI_WFA)
+ if (WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE)
return;
- data += 3;
- len -= 3;
- if (len < 1)
- return;
-
- if (*data != P2P_OUI_TYPE)
- return;
+ data += 4;
+ len -= 4;
- p2p_rx_p2p_action(p2p, sa, data + 1, len - 1, freq);
+ p2p_rx_p2p_action(p2p, sa, data, len, freq);
break;
case WLAN_PA_GAS_INITIAL_REQ:
p2p_rx_gas_initial_req(p2p, sa, data + 1, len - 1, freq);
@@ -1670,27 +1931,20 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
if (len < 4)
return;
- if (WPA_GET_BE24(data) != OUI_WFA)
- return;
- data += 3;
- len -= 3;
-
- if (*data != P2P_OUI_TYPE)
+ if (WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE)
return;
- data++;
- len--;
+ data += 4;
+ len -= 4;
/* P2P action frame */
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: RX P2P Action from " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "RX P2P Action from " MACSTR, MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Action contents", data, len);
if (len < 1)
return;
switch (data[0]) {
case P2P_NOA:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received P2P Action - Notice of Absence");
+ p2p_dbg(p2p, "Received P2P Action - Notice of Absence");
/* TODO */
break;
case P2P_PRESENCE_REQ:
@@ -1703,8 +1957,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
p2p_process_go_disc_req(p2p, da, sa, data + 1, len - 1, freq);
break;
default:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received P2P Action - unknown type %u", data[0]);
+ p2p_dbg(p2p, "Received P2P Action - unknown type %u", data[0]);
break;
}
}
@@ -1715,8 +1968,17 @@ static void p2p_go_neg_start(void *eloop_ctx, void *timeout_ctx)
struct p2p_data *p2p = eloop_ctx;
if (p2p->go_neg_peer == NULL)
return;
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_go_neg_start");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p->go_neg_peer->status = P2P_SC_SUCCESS;
+ /*
+ * Set new timeout to make sure a previously set one does not expire
+ * too quickly while waiting for the GO Negotiation to complete.
+ */
+ p2p_set_timeout(p2p, 0, 500000);
p2p_connect_send(p2p, p2p->go_neg_peer);
}
@@ -1726,8 +1988,13 @@ static void p2p_invite_start(void *eloop_ctx, void *timeout_ctx)
struct p2p_data *p2p = eloop_ctx;
if (p2p->invite_peer == NULL)
return;
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_invite_start");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
- p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr);
+ p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
+ p2p->invite_dev_pw_id);
}
@@ -1760,7 +2027,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
if (dev) {
if (dev->country[0] == 0 && msg.listen_channel)
os_memcpy(dev->country, msg.listen_channel, 3);
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
p2p_parse_free(&msg);
return; /* already known */
}
@@ -1771,17 +2038,16 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
return;
}
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
dev->flags |= P2P_DEV_PROBE_REQ_ONLY;
if (msg.listen_channel) {
os_memcpy(dev->country, msg.listen_channel, 3);
- dev->listen_freq = p2p_channel_to_freq(dev->country,
- msg.listen_channel[3],
+ dev->listen_freq = p2p_channel_to_freq(msg.listen_channel[3],
msg.listen_channel[4]);
}
- p2p_copy_wps_info(dev, 1, &msg);
+ p2p_copy_wps_info(p2p, dev, 1, &msg);
if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
@@ -1790,8 +2056,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
p2p_parse_free(&msg);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Created device entry based on Probe Req: " MACSTR
+ p2p_dbg(p2p, "Created device entry based on Probe Req: " MACSTR
" dev_capab=0x%x group_capab=0x%x name='%s' listen_freq=%d",
MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab,
dev->info.group_capab, dev->info.device_name,
@@ -1807,7 +2072,7 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
dev = p2p_get_device(p2p, addr);
if (dev) {
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
return dev; /* already known */
}
@@ -1870,11 +2135,12 @@ int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps)
attr.num_req_dev_type))
return 1; /* Own Primary Device Type matches */
- for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
+ for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) {
if (dev_type_list_match(p2p->cfg->sec_dev_type[i],
attr.req_dev_type,
attr.num_req_dev_type))
- return 1; /* Own Secondary Device Type matches */
+ return 1; /* Own Secondary Device Type matches */
+ }
/* No matching device type found */
return 0;
@@ -1893,6 +2159,12 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
extra = wpabuf_len(p2p->wfd_ie_probe_resp);
#endif /* CONFIG_WIFI_DISPLAY */
+ 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;
@@ -1902,13 +2174,21 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
}
- p2p_build_wps_ie(p2p, buf, pw_id, 1);
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 1) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for Probe Response");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_probe_resp)
wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
+ wpabuf_put_buf(buf,
+ p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
+
/* P2P IE */
len = p2p_buf_add_ie_hdr(buf);
p2p_buf_add_capability(buf, p2p->dev_capab &
@@ -1919,40 +2199,35 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
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 is_11b(u8 rate)
+static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
{
- return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
-}
+ struct p2ps_advertisement *adv_data;
+ p2p_dbg(p2p, "ASP find - ASP list: %p", p2p->p2ps_adv_list);
-static int supp_rates_11b_only(struct ieee802_11_elems *elems)
-{
- int num_11b = 0, num_others = 0;
- int i;
+ /* 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;
- if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
- return 0;
-
- for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
- if (is_11b(elems->supp_rates[i]))
- num_11b++;
- else
- num_others++;
- }
-
- for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
- i++) {
- if (is_11b(elems->ext_supp_rates[i]))
- num_11b++;
- else
- num_others++;
+ 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 num_11b > 0 && num_others == 0;
+ return 0;
}
@@ -1966,19 +2241,16 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
struct p2p_message msg;
struct wpabuf *ies;
- if (!p2p->in_listen || !p2p->drv_in_listen) {
- /* not in Listen state - ignore Probe Request */
- return P2P_PREQ_NOT_LISTEN;
- }
-
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
ParseFailed) {
/* Ignore invalid Probe Request frames */
+ p2p_dbg(p2p, "Could not parse Probe Request frame - ignore it");
return P2P_PREQ_MALFORMED;
}
if (elems.p2p == NULL) {
/* not a P2P probe - ignore it */
+ p2p_dbg(p2p, "Not a P2P probe - ignore it");
return P2P_PREQ_NOT_P2P;
}
@@ -1986,11 +2258,15 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
/* Not sent to the broadcast address or our P2P Device Address
*/
+ p2p_dbg(p2p, "Probe Req DA " MACSTR " not ours - ignore it",
+ MAC2STR(dst));
return P2P_PREQ_NOT_PROCESSED;
}
if (bssid && !is_broadcast_ether_addr(bssid)) {
/* Not sent to the Wildcard BSSID */
+ p2p_dbg(p2p, "Probe Req BSSID " MACSTR " not wildcard - ignore it",
+ MAC2STR(bssid));
return P2P_PREQ_NOT_PROCESSED;
}
@@ -1998,23 +2274,86 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
0) {
/* not using P2P Wildcard SSID - ignore */
+ p2p_dbg(p2p, "Probe Req not using P2P Wildcard SSID - ignore it");
return P2P_PREQ_NOT_PROCESSED;
}
if (supp_rates_11b_only(&elems)) {
/* Indicates support for 11b rates only */
+ p2p_dbg(p2p, "Probe Req with 11b rates only supported - ignore it");
return P2P_PREQ_NOT_P2P;
}
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
/* Could not parse P2P attributes */
+ p2p_dbg(p2p, "Could not parse P2P attributes in Probe Req - ignore it");
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_dbg(p2p, "Probe Req requested Device ID " MACSTR " did not match - ignore it",
+ MAC2STR(msg.device_id));
p2p_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
@@ -2023,6 +2362,7 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
if (msg.wps_attributes &&
!p2p_match_dev_type(p2p, msg.wps_attributes)) {
/* No match with Requested Device Type */
+ p2p_dbg(p2p, "Probe Req requestred Device Type did not match - ignore it");
p2p_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
@@ -2030,11 +2370,11 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
if (!p2p->cfg->send_probe_resp) {
/* Response generated elsewhere */
+ p2p_dbg(p2p, "Probe Resp generated elsewhere - do not generate additional response");
return P2P_PREQ_NOT_PROCESSED;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Reply to P2P Probe Request in Listen state");
+ p2p_dbg(p2p, "Reply to P2P Probe Request in Listen state");
/*
* We do not really have a specific BSS that this frame is advertising,
@@ -2106,27 +2446,28 @@ p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
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 &&
os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN)
- == 0) {
+ == 0 &&
+ !(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
/* Received a Probe Request from GO Negotiation peer */
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Found GO Negotiation peer - try to start GO "
- "negotiation from timeout");
+ p2p_dbg(p2p, "Found GO Negotiation peer - try to start GO negotiation from timeout");
+ eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
return P2P_PREQ_PROCESSED;
}
if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
p2p->invite_peer &&
+ (p2p->invite_peer->flags & P2P_DEV_WAIT_INV_REQ_ACK) &&
os_memcmp(addr, p2p->invite_peer->info.p2p_device_addr, ETH_ALEN)
== 0) {
/* Received a Probe Request from Invite peer */
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Found Invite peer - try to start Invite from "
- "timeout");
+ p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout");
+ eloop_cancel_timeout(p2p_invite_start, p2p, NULL);
eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
return P2P_PREQ_PROCESSED;
}
@@ -2203,6 +2544,9 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
extra = wpabuf_len(p2p->wfd_ie_assoc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]);
+
/*
* (Re)Association Request - P2P IE
* P2P Capability attribute (shall be present)
@@ -2218,6 +2562,10 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ])
+ wpabuf_put_buf(tmp,
+ p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]);
+
peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
lpos = p2p_buf_add_ie_hdr(tmp);
@@ -2256,6 +2604,132 @@ int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end)
}
+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;
+}
+
+
int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr)
{
struct p2p_message msg;
@@ -2301,24 +2775,20 @@ static void p2p_clear_go_neg(struct p2p_data *p2p)
void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr)
{
if (p2p->go_neg_peer == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No pending Group Formation - "
- "ignore WPS registration success notification");
+ p2p_dbg(p2p, "No pending Group Formation - ignore WPS registration success notification");
return; /* No pending Group Formation */
}
if (os_memcmp(mac_addr, p2p->go_neg_peer->intended_addr, ETH_ALEN) !=
0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore WPS registration success notification "
- "for " MACSTR " (GO Negotiation peer " MACSTR ")",
+ p2p_dbg(p2p, "Ignore WPS registration success notification for "
+ MACSTR " (GO Negotiation peer " MACSTR ")",
MAC2STR(mac_addr),
MAC2STR(p2p->go_neg_peer->intended_addr));
return; /* Ignore unexpected peer address */
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Group Formation completed successfully with " MACSTR,
+ p2p_dbg(p2p, "Group Formation completed successfully with " MACSTR,
MAC2STR(mac_addr));
p2p_clear_go_neg(p2p);
@@ -2328,14 +2798,11 @@ void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr)
void p2p_group_formation_failed(struct p2p_data *p2p)
{
if (p2p->go_neg_peer == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No pending Group Formation - "
- "ignore group formation failure notification");
+ p2p_dbg(p2p, "No pending Group Formation - ignore group formation failure notification");
return; /* No pending Group Formation */
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Group Formation failed with " MACSTR,
+ p2p_dbg(p2p, "Group Formation failed with " MACSTR,
MAC2STR(p2p->go_neg_peer->intended_addr));
p2p_clear_go_neg(p2p);
@@ -2346,7 +2813,8 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
{
struct p2p_data *p2p;
- if (cfg->max_peers < 1)
+ if (cfg->max_peers < 1 ||
+ cfg->passphrase_len < 8 || cfg->passphrase_len > 63)
return NULL;
p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg));
@@ -2375,11 +2843,14 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
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_get_random(&p2p->next_tie_breaker, 1);
+ if (os_get_random(&p2p->next_tie_breaker, 1) < 0)
+ p2p->next_tie_breaker = 0;
p2p->next_tie_breaker &= 0x01;
if (cfg->sd_request)
p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
@@ -2395,6 +2866,11 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
p2p->go_timeout = 100;
p2p->client_timeout = 20;
+ p2p->num_p2p_sd_queries = 0;
+
+ p2p_dbg(p2p, "initialized");
+ p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+ p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
return p2p;
}
@@ -2402,6 +2878,8 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
void p2p_deinit(struct p2p_data *p2p)
{
+ struct p2ps_advertisement *adv, *prev;
+
#ifdef CONFIG_WIFI_DISPLAY
wpabuf_free(p2p->wfd_ie_beacon);
wpabuf_free(p2p->wfd_ie_probe_req);
@@ -2419,6 +2897,8 @@ void p2p_deinit(struct p2p_data *p2p)
eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
+ eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
p2p_flush(p2p);
p2p_free_req_dev_types(p2p);
os_free(p2p->cfg->dev_name);
@@ -2428,9 +2908,19 @@ void p2p_deinit(struct p2p_data *p2p)
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);
+
+ adv = p2p->p2ps_adv_list;
+ while (adv) {
+ prev = adv;
+ adv = adv->next;
+ os_free(prev);
+ }
+
os_free(p2p);
}
@@ -2458,13 +2948,15 @@ int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr)
if (dev == NULL)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unauthorizing " MACSTR,
- MAC2STR(addr));
+ p2p_dbg(p2p, "Unauthorizing " MACSTR, MAC2STR(addr));
- if (p2p->go_neg_peer == dev)
+ if (p2p->go_neg_peer == dev) {
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
p2p->go_neg_peer = NULL;
+ }
dev->wps_method = WPS_NOT_READY;
+ dev->oob_pw_id = 0;
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
@@ -2619,55 +3111,105 @@ int p2p_set_country(struct p2p_data *p2p, const char *country)
}
+static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
+{
+ if (dev->sd_pending_bcast_queries == 0) {
+ /* Initialize with total number of registered broadcast
+ * SD queries. */
+ dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
+ }
+
+ if (p2p_start_sd(p2p, dev) == 0)
+ return 1;
+
+ if (dev->req_config_methods &&
+ !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
+ p2p_dbg(p2p, "Send pending Provision Discovery Request to "
+ MACSTR " (config methods 0x%x)",
+ MAC2STR(dev->info.p2p_device_addr),
+ dev->req_config_methods);
+ if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
void p2p_continue_find(struct p2p_data *p2p)
{
struct p2p_device *dev;
+ int found;
+
p2p_set_state(p2p, P2P_SEARCH);
+
+ /* Continue from the device following the last iteration */
+ found = 0;
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
- if (dev->flags & P2P_DEV_SD_SCHEDULE) {
- if (p2p_start_sd(p2p, dev) == 0)
- return;
- else
- break;
- } else if (dev->req_config_methods &&
- !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provision Discovery Request to "
- MACSTR " (config methods 0x%x)",
- MAC2STR(dev->info.p2p_device_addr),
- dev->req_config_methods);
- if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
- return;
+ if (dev == p2p->last_p2p_find_oper) {
+ found = 1;
+ continue;
+ }
+ if (!found)
+ continue;
+ if (p2p_pre_find_operation(p2p, dev) > 0) {
+ p2p->last_p2p_find_oper = dev;
+ return;
}
}
+ /*
+ * Wrap around to the beginning of the list and continue until the last
+ * iteration device.
+ */
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (p2p_pre_find_operation(p2p, dev) > 0) {
+ p2p->last_p2p_find_oper = dev;
+ return;
+ }
+ if (dev == p2p->last_p2p_find_oper)
+ break;
+ }
+
p2p_listen_in_find(p2p, 1);
}
static void p2p_sd_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Discovery Query TX callback: success=%d",
+ p2p_dbg(p2p, "Service Discovery Query TX callback: success=%d",
success);
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (!success) {
- if (p2p->sd_peer) {
- p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
- p2p->sd_peer = NULL;
- }
- p2p_continue_find(p2p);
+ if (p2p->sd_peer)
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->sd_peer = NULL;
+ if (p2p->state != P2P_IDLE)
+ p2p_continue_find(p2p);
return;
}
if (p2p->sd_peer == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No SD peer entry known");
- p2p_continue_find(p2p);
+ p2p_dbg(p2p, "No SD peer entry known");
+ if (p2p->state != P2P_IDLE)
+ p2p_continue_find(p2p);
return;
}
+ 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--;
+
+ /*
+ * If there are no pending broadcast queries for this device,
+ * mark it as done (-1).
+ */
+ if (p2p->sd_peer->sd_pending_bcast_queries == 0)
+ p2p->sd_peer->sd_pending_bcast_queries = -1;
+ }
+
/* Wait for response from the peer */
p2p_set_state(p2p, P2P_SD_DURING_FIND);
p2p_set_timeout(p2p, 0, 200000);
@@ -2682,9 +3224,6 @@ static void p2p_retry_pd(struct p2p_data *p2p)
{
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.
@@ -2697,13 +3236,13 @@ static void p2p_retry_pd(struct p2p_data *p2p)
if (!dev->req_config_methods)
continue;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provision Discovery Request to "
+ p2p_dbg(p2p, "Send pending Provision Discovery Request to "
MACSTR " (config methods 0x%x)",
MAC2STR(dev->info.p2p_device_addr),
dev->req_config_methods);
p2p_send_prov_disc_req(p2p, dev,
- dev->flags & P2P_DEV_PD_FOR_JOIN, 0);
+ dev->flags & P2P_DEV_PD_FOR_JOIN,
+ p2p->pd_force_freq);
return;
}
}
@@ -2711,8 +3250,7 @@ static void p2p_retry_pd(struct p2p_data *p2p)
static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Provision Discovery Request TX callback: success=%d",
+ p2p_dbg(p2p, "Provision Discovery Request TX callback: success=%d",
success);
/*
@@ -2759,11 +3297,71 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
}
+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,
- unsigned int age, int level, const u8 *ies,
+ struct os_reltime *rx_time, int level, const u8 *ies,
size_t ies_len)
{
- p2p_add_device(p2p, bssid, freq, age, level, ies, ies_len, 1);
+ if (os_reltime_before(rx_time, &p2p->find_start)) {
+ /*
+ * The driver may have cached (e.g., in cfg80211 BSS table) the
+ * scan results for relatively long time. To avoid reporting
+ * stale information, update P2P peers only based on results
+ * that have based on frames received after the last p2p_find
+ * operation was started.
+ */
+ p2p_dbg(p2p, "Ignore old scan result for " MACSTR
+ " (rx_time=%u.%06u)",
+ MAC2STR(bssid), (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec);
+ return 0;
+ }
+
+ p2p_add_device(p2p, bssid, freq, rx_time, level, ies, ies_len, 1);
return 0;
}
@@ -2772,8 +3370,7 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
void p2p_scan_res_handled(struct p2p_data *p2p)
{
if (!p2p->p2p_scan_running) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan was not "
- "running, but scan results received");
+ p2p_dbg(p2p, "p2p_scan was not running, but scan results received");
}
p2p->p2p_scan_running = 0;
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
@@ -2787,6 +3384,7 @@ void p2p_scan_res_handled(struct p2p_data *p2p)
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
{
+ u8 dev_capab;
u8 *len;
#ifdef CONFIG_WIFI_DISPLAY
@@ -2794,9 +3392,20 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
wpabuf_put_buf(ies, p2p->wfd_ie_probe_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P])
+ wpabuf_put_buf(ies,
+ 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)
@@ -2806,6 +3415,10 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
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);
}
@@ -2820,6 +3433,10 @@ size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
len += wpabuf_len(p2p->wfd_ie_probe_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p && p2p->vendor_elem &&
+ p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P])
+ len += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]);
+
return len;
}
@@ -2833,14 +3450,12 @@ int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
{
struct p2p_device *dev = p2p->go_neg_peer;
+ int timeout;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation Request TX callback: success=%d",
- success);
+ p2p_dbg(p2p, "GO Negotiation Request TX callback: success=%d", success);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No pending GO Negotiation");
+ p2p_dbg(p2p, "No pending GO Negotiation");
return;
}
@@ -2857,9 +3472,7 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
if (!success &&
(dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY) &&
!is_zero_ether_addr(dev->member_in_go_dev)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer " MACSTR " did not acknowledge request - "
- "try to use device discoverability through its GO",
+ p2p_dbg(p2p, "Peer " MACSTR " did not acknowledge request - try to use device discoverability through its GO",
MAC2STR(dev->info.p2p_device_addr));
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_send_dev_disc_req(p2p, dev);
@@ -2871,35 +3484,56 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
* channel.
*/
p2p_set_state(p2p, P2P_CONNECT);
- p2p_set_timeout(p2p, 0, success ? 200000 : 100000);
+ timeout = success ? 500000 : 100000;
+ if (!success && p2p->go_neg_peer &&
+ (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE)) {
+ unsigned int r;
+ /*
+ * Peer is expected to wait our response and we will skip the
+ * listen phase. Add some randomness to the wait time here to
+ * make it less likely to hit cases where we could end up in
+ * sync with peer not listening.
+ */
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
+ timeout += r % 100000;
+ }
+ p2p_set_timeout(p2p, 0, timeout);
}
static void p2p_go_neg_resp_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation Response TX callback: success=%d",
+ p2p_dbg(p2p, "GO Negotiation Response TX callback: success=%d",
success);
if (!p2p->go_neg_peer && p2p->state == P2P_PROVISIONING) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore TX callback event - GO Negotiation is "
- "not running anymore");
+ p2p_dbg(p2p, "Ignore TX callback event - GO Negotiation is not running anymore");
return;
}
p2p_set_state(p2p, P2P_CONNECT);
- p2p_set_timeout(p2p, 0, 250000);
+ p2p_set_timeout(p2p, 0, 500000);
}
-static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success)
+static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success,
+ const u8 *addr)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation Response (failure) TX callback: "
- "success=%d", success);
+ 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,
- p2p->go_neg_peer->status);
+ p2p_go_neg_failed(p2p, p2p->go_neg_peer->status);
+ 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);
}
@@ -2908,16 +3542,45 @@ static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
{
struct p2p_device *dev;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation Confirm TX callback: result=%d",
- result);
- p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
if (result == P2P_SEND_ACTION_FAILED) {
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p_go_neg_failed(p2p, -1);
return;
}
+
+ dev = p2p->go_neg_peer;
+
if (result == P2P_SEND_ACTION_NO_ACK) {
/*
+ * Retry GO Negotiation Confirmation
+ * P2P_GO_NEG_CNF_MAX_RETRY_COUNT times if we did not receive
+ * ACK for confirmation.
+ */
+ if (dev && dev->go_neg_conf &&
+ dev->go_neg_conf_sent <= P2P_GO_NEG_CNF_MAX_RETRY_COUNT) {
+ p2p_dbg(p2p, "GO Negotiation Confirm retry %d",
+ dev->go_neg_conf_sent);
+ p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
+ if (p2p_send_action(p2p, dev->go_neg_conf_freq,
+ dev->info.p2p_device_addr,
+ p2p->cfg->dev_addr,
+ dev->info.p2p_device_addr,
+ wpabuf_head(dev->go_neg_conf),
+ wpabuf_len(dev->go_neg_conf), 0) >=
+ 0) {
+ dev->go_neg_conf_sent++;
+ return;
+ }
+ p2p_dbg(p2p, "Failed to re-send Action frame");
+
+ /*
+ * Continue with the assumption that the first attempt
+ * went through and just the ACK frame was lost.
+ */
+ }
+
+ /*
* It looks like the TX status for GO Negotiation Confirm is
* often showing failure even when the peer has actually
* received the frame. Since the peer may change channels
@@ -2927,13 +3590,11 @@ static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
* peer did indeed receive the frame, continue regardless of
* the TX status.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Assume GO Negotiation Confirm TX was actually "
- "received by the peer even though Ack was not "
- "reported");
+ p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported");
}
- dev = p2p->go_neg_peer;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+
if (dev == NULL)
return;
@@ -2948,16 +3609,20 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
enum p2p_pending_action_state state;
int success;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Action frame TX callback (state=%d freq=%u dst=" MACSTR
- " src=" MACSTR " bssid=" MACSTR " result=%d",
+ p2p_dbg(p2p, "Action frame TX callback (state=%d freq=%u dst=" MACSTR
+ " 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;
switch (state) {
case P2P_NO_PENDING_ACTION:
+ if (p2p->send_action_in_progress) {
+ p2p->send_action_in_progress = 0;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ }
+ p2p_check_after_scan_tx_continuation(p2p);
break;
case P2P_PENDING_GO_NEG_REQUEST:
p2p_go_neg_req_cb(p2p, success);
@@ -2966,7 +3631,7 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
p2p_go_neg_resp_cb(p2p, success);
break;
case P2P_PENDING_GO_NEG_RESPONSE_FAILURE:
- p2p_go_neg_resp_failure_cb(p2p, success);
+ p2p_go_neg_resp_failure_cb(p2p, success, dst);
break;
case P2P_PENDING_GO_NEG_CONFIRM:
p2p_go_neg_conf_cb(p2p, result);
@@ -2977,6 +3642,9 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
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;
@@ -2993,6 +3661,8 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
p2p_go_disc_req_cb(p2p, success);
break;
}
+
+ p2p->after_scan_tx_in_progress = 0;
}
@@ -3000,23 +3670,18 @@ void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq,
unsigned int duration)
{
if (freq == p2p->pending_client_disc_freq) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Client discoverability remain-awake completed");
+ p2p_dbg(p2p, "Client discoverability remain-awake completed");
p2p->pending_client_disc_freq = 0;
return;
}
if (freq != p2p->pending_listen_freq) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected listen callback for freq=%u "
- "duration=%u (pending_listen_freq=%u)",
+ p2p_dbg(p2p, "Unexpected listen callback for freq=%u duration=%u (pending_listen_freq=%u)",
freq, duration, p2p->pending_listen_freq);
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Starting Listen timeout(%u,%u) on freq=%u based on "
- "callback",
+ p2p_dbg(p2p, "Starting Listen timeout(%u,%u) on freq=%u based on callback",
p2p->pending_listen_sec, p2p->pending_listen_usec,
p2p->pending_listen_freq);
p2p->in_listen = 1;
@@ -3037,18 +3702,15 @@ void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq,
int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver ended Listen "
- "state (freq=%u)", freq);
+ p2p_dbg(p2p, "Driver ended Listen state (freq=%u)", freq);
p2p->drv_in_listen = 0;
if (p2p->in_listen)
return 0; /* Internal timeout will trigger the next step */
if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
if (p2p->go_neg_peer->connect_reqs >= 120) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Timeout on sending GO Negotiation "
- "Request without getting response");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
+ p2p_go_neg_failed(p2p, -1);
return 0;
}
@@ -3065,9 +3727,7 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
* operation while in p2p_find. Avoid an attempt to
* restart a scan here.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan "
- "already in progress - do not try to start a "
- "new one");
+ p2p_dbg(p2p, "p2p_scan already in progress - do not try to start a new one");
return 1;
}
if (p2p->pending_listen_freq) {
@@ -3076,15 +3736,12 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
* offchannel operation for some reason. p2p_search()
* will be started from internal timeout.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Listen "
- "operation did not seem to start - delay "
- "search phase to avoid busy loop");
+ p2p_dbg(p2p, "Listen operation did not seem to start - delay search phase to avoid busy loop");
p2p_set_timeout(p2p, 0, 100000);
return 1;
}
if (p2p->search_delay) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
- "search operation by %u ms",
+ p2p_dbg(p2p, "Delay search operation by %u ms",
p2p->search_delay);
p2p_set_timeout(p2p, p2p->search_delay / 1000,
(p2p->search_delay % 1000) * 1000);
@@ -3103,10 +3760,21 @@ static void p2p_timeout_connect(struct p2p_data *p2p)
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (p2p->go_neg_peer &&
(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Wait for GO "
- "Negotiation Confirm timed out - assume GO "
- "Negotiation failed");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_dbg(p2p, "Wait for GO Negotiation Confirm timed out - assume GO Negotiation failed");
+ p2p_go_neg_failed(p2p, -1);
+ return;
+ }
+ if (p2p->go_neg_peer &&
+ (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE) &&
+ p2p->go_neg_peer->connect_reqs < 120) {
+ p2p_dbg(p2p, "Peer expected to wait our response - skip listen");
+ p2p_connect_send(p2p, p2p->go_neg_peer);
+ return;
+ }
+ if (p2p->go_neg_peer && p2p->go_neg_peer->oob_go_neg_freq > 0) {
+ p2p_dbg(p2p, "Skip connect-listen since GO Neg channel known (OOB)");
+ p2p_set_state(p2p, P2P_CONNECT_LISTEN);
+ p2p_set_timeout(p2p, 0, 30000);
return;
}
p2p_set_state(p2p, P2P_CONNECT_LISTEN);
@@ -3118,17 +3786,13 @@ static void p2p_timeout_connect_listen(struct p2p_data *p2p)
{
if (p2p->go_neg_peer) {
if (p2p->drv_in_listen) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is "
- "still in Listen state; wait for it to "
- "complete");
+ p2p_dbg(p2p, "Driver is still in Listen state; wait for it to complete");
return;
}
if (p2p->go_neg_peer->connect_reqs >= 120) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Timeout on sending GO Negotiation "
- "Request without getting response");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
+ p2p_go_neg_failed(p2p, -1);
return;
}
@@ -3141,13 +3805,13 @@ static void p2p_timeout_connect_listen(struct p2p_data *p2p)
static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p)
{
- /*
- * TODO: could remain constantly in Listen state for some time if there
- * are no other concurrent uses for the radio. For now, go to listen
- * state once per second to give other uses a chance to use the radio.
- */
p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
- p2p_set_timeout(p2p, 0, 500000);
+
+ if (p2p->cfg->is_concurrent_session_active &&
+ p2p->cfg->is_concurrent_session_active(p2p->cfg->cb_ctx))
+ p2p_set_timeout(p2p, 0, 500000);
+ else
+ p2p_set_timeout(p2p, 0, 200000);
}
@@ -3156,23 +3820,11 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
struct p2p_device *dev = p2p->go_neg_peer;
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown GO Neg peer - stop GO Neg wait");
+ p2p_dbg(p2p, "Unknown GO Neg peer - stop GO Neg wait");
return;
}
- dev->wait_count++;
- if (dev->wait_count >= 120) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Timeout on waiting peer to become ready for GO "
- "Negotiation");
- p2p_go_neg_failed(p2p, dev, -1);
- return;
- }
-
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Go to Listen state while waiting for the peer to become "
- "ready for GO Negotiation");
+ p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
p2p_listen_in_find(p2p, 0);
}
@@ -3180,11 +3832,9 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
static void p2p_timeout_sd_during_find(struct p2p_data *p2p)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Discovery Query timeout");
+ p2p_dbg(p2p, "Service Discovery Query timeout");
if (p2p->sd_peer) {
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
p2p->sd_peer = NULL;
}
p2p_continue_find(p2p);
@@ -3193,8 +3843,7 @@ static void p2p_timeout_sd_during_find(struct p2p_data *p2p)
static void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Provision Discovery Request timeout");
+ p2p_dbg(p2p, "Provision Discovery Request timeout");
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_continue_find(p2p);
}
@@ -3202,6 +3851,9 @@ static void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p)
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;
/*
@@ -3212,8 +3864,7 @@ static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
if (!p2p->user_initiated_pd)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: User initiated Provision Discovery Request timeout");
+ p2p_dbg(p2p, "User initiated Provision Discovery Request timeout");
if (p2p->pd_retries) {
p2p->pd_retries--;
@@ -3231,12 +3882,18 @@ static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
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);
}
}
@@ -3251,8 +3908,7 @@ static void p2p_timeout_invite(struct p2p_data *p2p)
* Better remain on operating channel instead of listen channel
* when running a group.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Inviting in "
- "active GO role - wait on operating channel");
+ p2p_dbg(p2p, "Inviting in active GO role - wait on operating channel");
p2p_set_timeout(p2p, 0, 100000);
return;
}
@@ -3265,14 +3921,15 @@ static void p2p_timeout_invite_listen(struct p2p_data *p2p)
if (p2p->invite_peer && p2p->invite_peer->invitation_reqs < 100) {
p2p_set_state(p2p, P2P_INVITE);
p2p_invite_send(p2p, p2p->invite_peer,
- p2p->invite_go_dev_addr);
+ p2p->invite_go_dev_addr, p2p->invite_dev_pw_id);
} else {
if (p2p->invite_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Request retry limit reached");
+ p2p_dbg(p2p, "Invitation Request retry limit reached");
if (p2p->cfg->invitation_result)
p2p->cfg->invitation_result(
- p2p->cfg->cb_ctx, -1, NULL);
+ p2p->cfg->cb_ctx, -1, NULL, NULL,
+ p2p->invite_peer->info.p2p_device_addr,
+ 0, 0);
}
p2p_set_state(p2p, P2P_IDLE);
}
@@ -3283,10 +3940,13 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct p2p_data *p2p = eloop_ctx;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Timeout (state=%s)",
- p2p_state_txt(p2p->state));
+ p2p_dbg(p2p, "Timeout (state=%s)", p2p_state_txt(p2p->state));
p2p->in_listen = 0;
+ if (p2p->drv_in_listen) {
+ p2p_dbg(p2p, "Driver is still in listen state - stop it");
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ }
switch (p2p->state) {
case P2P_IDLE:
@@ -3299,8 +3959,7 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
if (p2p->pending_action_state == P2P_PENDING_PD)
p2p_timeout_prov_disc_req(p2p);
if (p2p->search_delay && !p2p->in_search_delay) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
- "search operation by %u ms",
+ p2p_dbg(p2p, "Delay search operation by %u ms",
p2p->search_delay);
p2p->in_search_delay = 1;
p2p_set_timeout(p2p, p2p->search_delay / 1000,
@@ -3324,9 +3983,7 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
p2p_timeout_prov_disc_req(p2p);
if (p2p->ext_listen_only) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Extended Listen Timing - Listen State "
- "completed");
+ p2p_dbg(p2p, "Extended Listen Timing - Listen State completed");
p2p->ext_listen_only = 0;
p2p_set_state(p2p, P2P_IDLE);
}
@@ -3351,10 +4008,6 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
case P2P_INVITE_LISTEN:
p2p_timeout_invite_listen(p2p);
break;
- case P2P_SEARCH_WHEN_READY:
- break;
- case P2P_CONTINUE_SEARCH_WHEN_READY:
- break;
}
}
@@ -3364,11 +4017,10 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr)
struct p2p_device *dev;
dev = p2p_get_device(p2p, peer_addr);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Local request to reject "
- "connection attempts by peer " MACSTR, MAC2STR(peer_addr));
+ p2p_dbg(p2p, "Local request to reject connection attempts by peer "
+ MACSTR, MAC2STR(peer_addr));
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
- " unknown", MAC2STR(peer_addr));
+ p2p_dbg(p2p, "Peer " MACSTR " unknown", MAC2STR(peer_addr));
return -1;
}
dev->status = P2P_SC_FAIL_REJECTED_BY_USER;
@@ -3388,6 +4040,10 @@ const char * p2p_wps_method_text(enum p2p_wps_method method)
return "Keypad";
case WPS_PBC:
return "PBC";
+ case WPS_NFC:
+ return "NFC";
+ case WPS_P2PS:
+ return "P2PS";
}
return "??";
@@ -3438,7 +4094,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
struct p2p_device *dev;
int res;
char *pos, *end;
- struct os_time now;
+ struct os_reltime now;
if (info == NULL)
return -1;
@@ -3449,7 +4105,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
pos = buf;
end = buf + buflen;
- os_get_time(&now);
+ os_get_reltime(&now);
res = os_snprintf(pos, end - pos,
"age=%d\n"
"listen_freq=%d\n"
@@ -3464,9 +4120,8 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"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%s%s\n"
+ "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
"status=%d\n"
- "wait_count=%u\n"
"invitation_reqs=%u\n",
(int) (now.sec - dev->last_seen.sec),
dev->listen_freq,
@@ -3487,13 +4142,12 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
dev->flags & P2P_DEV_REPORTED ? "[REPORTED]" : "",
dev->flags & P2P_DEV_NOT_YET_READY ?
"[NOT_YET_READY]" : "",
- dev->flags & P2P_DEV_SD_INFO ? "[SD_INFO]" : "",
- dev->flags & P2P_DEV_SD_SCHEDULE ? "[SD_SCHEDULE]" :
- "",
dev->flags & P2P_DEV_PD_PEER_DISPLAY ?
"[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 ?
@@ -3511,9 +4165,8 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
dev->flags & P2P_DEV_PD_FOR_JOIN ?
"[PD_FOR_JOIN]" : "",
dev->status,
- dev->wait_count,
dev->invitation_reqs);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -3523,7 +4176,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"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;
}
@@ -3533,7 +4186,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"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;
}
@@ -3541,7 +4194,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
#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;
@@ -3550,7 +4203,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
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;
}
@@ -3569,12 +4222,10 @@ int p2p_peer_known(struct p2p_data *p2p, const u8 *addr)
void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
{
if (enabled) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client "
- "discoverability enabled");
+ p2p_dbg(p2p, "Client discoverability enabled");
p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client "
- "discoverability disabled");
+ p2p_dbg(p2p, "Client discoverability disabled");
p2p->dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
}
}
@@ -3623,9 +4274,9 @@ int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr,
{
struct wpabuf *req;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send Presence Request to "
- "GO " MACSTR " (own interface " MACSTR ") freq=%u dur1=%u "
- "int1=%u dur2=%u int2=%u",
+ p2p_dbg(p2p, "Send Presence Request to GO " MACSTR
+ " (own interface " MACSTR ") freq=%u dur1=%u int1=%u "
+ "dur2=%u int2=%u",
MAC2STR(go_interface_addr), MAC2STR(own_interface_addr),
freq, duration1, interval1, duration2, interval2);
@@ -3638,8 +4289,7 @@ int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr,
if (p2p_send_action(p2p, freq, go_interface_addr, own_interface_addr,
go_interface_addr,
wpabuf_head(req), wpabuf_len(req), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(req);
@@ -3685,8 +4335,7 @@ static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
u8 noa[50];
int noa_len;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received P2P Action - P2P Presence Request");
+ p2p_dbg(p2p, "Received P2P Action - P2P Presence Request");
for (g = 0; g < p2p->num_groups; g++) {
if (os_memcmp(da, p2p_group_get_interface_addr(p2p->groups[g]),
@@ -3696,23 +4345,20 @@ static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
}
}
if (group == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore P2P Presence Request for unknown group "
+ p2p_dbg(p2p, "Ignore P2P Presence Request for unknown group "
MACSTR, MAC2STR(da));
return;
}
if (p2p_parse(data, len, &msg) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to parse P2P Presence Request");
+ p2p_dbg(p2p, "Failed to parse P2P Presence Request");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
parsed = 1;
if (msg.noa == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No NoA attribute in P2P Presence Request");
+ p2p_dbg(p2p, "No NoA attribute in P2P Presence Request");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
@@ -3736,8 +4382,7 @@ fail:
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, rx_freq, sa, da, da,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(resp);
}
@@ -3748,33 +4393,32 @@ static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da,
{
struct p2p_message msg;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received P2P Action - P2P Presence Response");
+ p2p_dbg(p2p, "Received P2P Action - P2P Presence Response");
if (p2p_parse(data, len, &msg) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to parse P2P Presence Response");
+ p2p_dbg(p2p, "Failed to parse P2P Presence Response");
return;
}
if (msg.status == NULL || msg.noa == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Status or NoA attribute in P2P Presence "
- "Response");
+ p2p_dbg(p2p, "No Status or NoA attribute in P2P Presence Response");
p2p_parse_free(&msg);
return;
}
+ if (p2p->cfg->presence_resp) {
+ p2p->cfg->presence_resp(p2p->cfg->cb_ctx, sa, *msg.status,
+ msg.noa, msg.noa_len);
+ }
+
if (*msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: P2P Presence Request was rejected: status %u",
+ p2p_dbg(p2p, "P2P Presence Request was rejected: status %u",
*msg.status);
p2p_parse_free(&msg);
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: P2P Presence Request was accepted");
+ p2p_dbg(p2p, "P2P Presence Request was accepted");
wpa_hexdump(MSG_DEBUG, "P2P: P2P Presence Response - NoA",
msg.noa, msg.noa_len);
/* TODO: process NoA */
@@ -3793,6 +4437,15 @@ static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx)
p2p_ext_listen_timeout, p2p, NULL);
}
+ if ((p2p->cfg->is_p2p_in_progress &&
+ p2p->cfg->is_p2p_in_progress(p2p->cfg->cb_ctx)) ||
+ (p2p->pending_action_state == P2P_PENDING_PD &&
+ p2p->pd_retries > 0)) {
+ p2p_dbg(p2p, "Operation in progress - skip Extended Listen timeout (%s)",
+ p2p_state_txt(p2p->state));
+ return;
+ }
+
if (p2p->state == P2P_LISTEN_ONLY && p2p->ext_listen_only) {
/*
* This should not really happen, but it looks like the Listen
@@ -3800,25 +4453,20 @@ static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx)
* running at an inconvenient time. As a workaround, allow new
* Extended Listen operation to be started.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Previous "
- "Extended Listen operation had not been completed - "
- "try again");
+ p2p_dbg(p2p, "Previous Extended Listen operation had not been completed - try again");
p2p->ext_listen_only = 0;
p2p_set_state(p2p, P2P_IDLE);
}
if (p2p->state != P2P_IDLE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip Extended "
- "Listen timeout in active state (%s)",
- p2p_state_txt(p2p->state));
+ p2p_dbg(p2p, "Skip Extended Listen timeout in active state (%s)", p2p_state_txt(p2p->state));
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Extended Listen timeout");
+ p2p_dbg(p2p, "Extended Listen timeout");
p2p->ext_listen_only = 1;
if (p2p_listen(p2p, p2p->ext_listen_period) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
- "Listen state for Extended Listen Timing");
+ p2p_dbg(p2p, "Failed to start Listen state for Extended Listen Timing");
p2p->ext_listen_only = 0;
}
}
@@ -3829,25 +4477,22 @@ int p2p_ext_listen(struct p2p_data *p2p, unsigned int period,
{
if (period > 65535 || interval > 65535 || period > interval ||
(period == 0 && interval > 0) || (period > 0 && interval == 0)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid Extended Listen Timing request: "
- "period=%u interval=%u", period, interval);
+ p2p_dbg(p2p, "Invalid Extended Listen Timing request: period=%u interval=%u",
+ period, interval);
return -1;
}
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
if (interval == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Disabling Extended Listen Timing");
+ p2p_dbg(p2p, "Disabling Extended Listen Timing");
p2p->ext_listen_period = 0;
p2p->ext_listen_interval = 0;
return 0;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Enabling Extended Listen Timing: period %u msec, "
- "interval %u msec", period, interval);
+ p2p_dbg(p2p, "Enabling Extended Listen Timing: period %u msec, interval %u msec",
+ period, interval);
p2p->ext_listen_period = period;
p2p->ext_listen_interval = interval;
p2p->ext_listen_interval_sec = interval / 1000;
@@ -3872,11 +4517,12 @@ void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ie, ie_len, &msg))
return;
- if (msg.minor_reason_code == NULL)
+ if (msg.minor_reason_code == NULL) {
+ p2p_parse_free(&msg);
return;
+ }
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: Deauthentication notification BSSID " MACSTR
+ p2p_dbg(p2p, "Deauthentication notification BSSID " MACSTR
" reason_code=%u minor_reason_code=%u",
MAC2STR(bssid), reason_code, *msg.minor_reason_code);
@@ -3895,11 +4541,12 @@ void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ie, ie_len, &msg))
return;
- if (msg.minor_reason_code == NULL)
+ if (msg.minor_reason_code == NULL) {
+ p2p_parse_free(&msg);
return;
+ }
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: Disassociation notification BSSID " MACSTR
+ p2p_dbg(p2p, "Disassociation notification BSSID " MACSTR
" reason_code=%u minor_reason_code=%u",
MAC2STR(bssid), reason_code, *msg.minor_reason_code);
@@ -3910,34 +4557,65 @@ void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
{
if (enabled) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P "
- "Device operations enabled");
+ p2p_dbg(p2p, "Managed P2P Device operations enabled");
p2p->dev_capab |= P2P_DEV_CAPAB_INFRA_MANAGED;
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P "
- "Device operations disabled");
+ p2p_dbg(p2p, "Managed P2P Device operations disabled");
p2p->dev_capab &= ~P2P_DEV_CAPAB_INFRA_MANAGED;
}
}
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
+int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
+ u8 *op_channel)
{
- if (p2p_channel_to_freq(p2p->cfg->country, reg_class, channel) < 0)
+ return p2p_channel_random_social(&p2p->channels, op_class, op_channel);
+}
+
+
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+ u8 forced)
+{
+ if (p2p_channel_to_freq(reg_class, channel) < 0)
+ return -1;
+
+ /*
+ * Listen channel was set in configuration or set by control interface;
+ * cannot override it.
+ */
+ if (p2p->cfg->channel_forced && forced == 0) {
+ p2p_dbg(p2p,
+ "Listen channel was previously configured - do not override based on optimization");
return -1;
+ }
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set Listen channel: "
- "reg_class %u channel %u", reg_class, channel);
- p2p->cfg->reg_class = reg_class;
- p2p->cfg->channel = channel;
+ 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;
+ p2p->cfg->channel = channel;
+ p2p->cfg->channel_forced = forced;
+ } else {
+ p2p_dbg(p2p, "Defer setting listen channel");
+ p2p->pending_reg_class = reg_class;
+ p2p->pending_channel = channel;
+ p2p->pending_channel_forced = forced;
+ }
return 0;
}
+u8 p2p_get_listen_channel(struct p2p_data *p2p)
+{
+ return p2p->cfg->channel;
+}
+
+
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
{
- wpa_hexdump_ascii(MSG_DEBUG, "P2P: New SSID postfix", postfix, len);
+ p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
if (postfix == NULL) {
p2p->cfg->ssid_postfix_len = 0;
return 0;
@@ -3953,12 +4631,11 @@ int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
int cfg_op_channel)
{
- if (p2p_channel_to_freq(p2p->cfg->country, op_reg_class, op_channel)
- < 0)
+ if (p2p_channel_to_freq(op_reg_class, op_channel) < 0)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
- "reg_class %u channel %u", op_reg_class, op_channel);
+ p2p_dbg(p2p, "Set Operating channel: reg_class %u channel %u",
+ op_reg_class, op_channel);
p2p->cfg->op_reg_class = op_reg_class;
p2p->cfg->op_channel = op_channel;
p2p->cfg->cfg_op_channel = cfg_op_channel;
@@ -3988,6 +4665,31 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
}
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+ const struct wpa_freq_range_list *list)
+{
+ struct wpa_freq_range *tmp;
+
+ if (list == NULL || list->num == 0) {
+ os_free(p2p->no_go_freq.range);
+ p2p->no_go_freq.range = NULL;
+ p2p->no_go_freq.num = 0;
+ return 0;
+ }
+
+ tmp = os_calloc(list->num, sizeof(struct wpa_freq_range));
+ if (tmp == NULL)
+ return -1;
+ os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range));
+ os_free(p2p->no_go_freq.range);
+ p2p->no_go_freq.range = tmp;
+ p2p->no_go_freq.num = list->num;
+ p2p_dbg(p2p, "Updated no GO chan list");
+
+ return 0;
+}
+
+
int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
u8 *iface_addr)
{
@@ -4014,18 +4716,16 @@ void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr)
{
os_memcpy(p2p->peer_filter, addr, ETH_ALEN);
if (is_zero_ether_addr(p2p->peer_filter))
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Disable peer "
- "filter");
+ p2p_dbg(p2p, "Disable peer filter");
else
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Enable peer "
- "filter for " MACSTR, MAC2STR(p2p->peer_filter));
+ p2p_dbg(p2p, "Enable peer filter for " MACSTR,
+ MAC2STR(p2p->peer_filter));
}
void p2p_set_cross_connect(struct p2p_data *p2p, int enabled)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Cross connection %s",
- enabled ? "enabled" : "disabled");
+ p2p_dbg(p2p, "Cross connection %s", enabled ? "enabled" : "disabled");
if (p2p->cross_connect == enabled)
return;
p2p->cross_connect = enabled;
@@ -4046,16 +4746,22 @@ int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr)
void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Intra BSS distribution %s",
+ p2p_dbg(p2p, "Intra BSS distribution %s",
enabled ? "enabled" : "disabled");
p2p->cfg->p2p_intra_bss = enabled;
}
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan)
+void p2p_update_channel_list(struct p2p_data *p2p,
+ const struct p2p_channels *chan,
+ const struct p2p_channels *cli_chan)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update channel list");
+ p2p_dbg(p2p, "Update channel list");
os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
+ p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+ os_memcpy(&p2p->cfg->cli_channels, cli_chan,
+ sizeof(struct p2p_channels));
+ p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
}
@@ -4064,11 +4770,9 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
size_t len, unsigned int wait_time)
{
if (p2p->p2p_scan_running) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay Action "
- "frame TX until p2p_scan completes");
+ p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes");
if (p2p->after_scan_tx) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped "
- "previous pending Action frame TX");
+ p2p_dbg(p2p, "Dropped previous pending Action frame TX");
os_free(p2p->after_scan_tx);
}
p2p->after_scan_tx = os_malloc(sizeof(*p2p->after_scan_tx) +
@@ -4093,14 +4797,21 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
int freq_overall)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Best channel: 2.4 GHz: %d,"
- " 5 GHz: %d, overall: %d", freq_24, freq_5, freq_overall);
+ p2p_dbg(p2p, "Best channel: 2.4 GHz: %d, 5 GHz: %d, overall: %d",
+ freq_24, freq_5, freq_overall);
p2p->best_freq_24 = freq_24;
p2p->best_freq_5 = freq_5;
p2p->best_freq_overall = freq_overall;
}
+void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq)
+{
+ p2p_dbg(p2p, "Own frequency preference: %d MHz", freq);
+ p2p->own_freq_preference = freq;
+}
+
+
const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p)
{
if (p2p == NULL || p2p->go_neg_peer == NULL)
@@ -4129,7 +4840,7 @@ p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next)
dev = dl_list_first(&dev->list,
struct p2p_device,
list);
- if (&dev->list == &p2p->devices)
+ if (!dev || &dev->list == &p2p->devices)
return NULL;
} while (dev->flags & P2P_DEV_PROBE_REQ_ONLY);
}
@@ -4141,7 +4852,7 @@ p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next)
dev = dl_list_first(&dev->list,
struct p2p_device,
list);
- if (&dev->list == &p2p->devices)
+ if (!dev || &dev->list == &p2p->devices)
return NULL;
}
}
@@ -4154,8 +4865,7 @@ int p2p_in_progress(struct p2p_data *p2p)
{
if (p2p == NULL)
return 0;
- if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY ||
- p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY)
+ if (p2p->state == P2P_SEARCH)
return 2;
return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
}
@@ -4171,13 +4881,6 @@ void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
}
-void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay)
-{
- if (p2p && p2p->search_delay < delay)
- p2p->search_delay = delay;
-}
-
-
#ifdef CONFIG_WIFI_DISPLAY
static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
@@ -4187,7 +4890,7 @@ static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
for (g = 0; g < p2p->num_groups; g++) {
group = p2p->groups[g];
- p2p_group_update_ies(group);
+ p2p_group_force_beacon_update_ies(group);
}
}
@@ -4312,9 +5015,322 @@ int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
p2p->min_disc_int = min_disc_int;
p2p->max_disc_int = max_disc_int;
p2p->max_disc_tu = max_disc_tu;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set discoverable interval: "
- "min=%d max=%d max_tu=%d", min_disc_int, max_disc_int,
- max_disc_tu);
+ p2p_dbg(p2p, "Set discoverable interval: min=%d max=%d max_tu=%d",
+ min_disc_int, max_disc_int, max_disc_tu);
return 0;
}
+
+
+void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[500];
+
+ if (!p2p->cfg->debug_print)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ buf[sizeof(buf) - 1] = '\0';
+ va_end(ap);
+ p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_DEBUG, buf);
+}
+
+
+void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[500];
+
+ if (!p2p->cfg->debug_print)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ buf[sizeof(buf) - 1] = '\0';
+ va_end(ap);
+ p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_INFO, buf);
+}
+
+
+void p2p_err(struct p2p_data *p2p, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[500];
+
+ if (!p2p->cfg->debug_print)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ buf[sizeof(buf) - 1] = '\0';
+ va_end(ap);
+ p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_ERROR, buf);
+}
+
+
+void p2p_loop_on_known_peers(struct p2p_data *p2p,
+ void (*peer_callback)(struct p2p_peer_info *peer,
+ void *user_data),
+ void *user_data)
+{
+ struct p2p_device *dev, *n;
+
+ dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
+ peer_callback(&dev->info, user_data);
+ }
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len)
+{
+ struct wpabuf *buf;
+ u8 op_class, channel;
+ enum p2p_role_indication role = P2P_DEVICE_NOT_IN_GROUP;
+
+ buf = wpabuf_alloc(1000);
+ if (buf == NULL)
+ return NULL;
+
+ op_class = p2p->cfg->reg_class;
+ channel = p2p->cfg->channel;
+
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
+ p2p_buf_add_device_info(buf, p2p, NULL);
+
+ if (p2p->num_groups > 0) {
+ int freq = p2p_group_get_freq(p2p->groups[0]);
+ role = P2P_GO_IN_A_GROUP;
+ if (p2p_freq_to_channel(freq, &op_class, &channel) < 0) {
+ p2p_dbg(p2p,
+ "Unknown GO operating frequency %d MHz for NFC handover",
+ freq);
+ wpabuf_free(buf);
+ return NULL;
+ }
+ } else if (client_freq > 0) {
+ role = P2P_CLIENT_IN_A_GROUP;
+ if (p2p_freq_to_channel(client_freq, &op_class, &channel) < 0) {
+ p2p_dbg(p2p,
+ "Unknown client operating frequency %d MHz for NFC handover",
+ client_freq);
+ wpabuf_free(buf);
+ return NULL;
+ }
+ }
+
+ p2p_buf_add_oob_go_neg_channel(buf, p2p->cfg->country, op_class,
+ channel, role);
+
+ if (p2p->num_groups > 0) {
+ /* Limit number of clients to avoid very long message */
+ p2p_buf_add_group_info(p2p->groups[0], buf, 5);
+ p2p_group_buf_add_id(p2p->groups[0], buf);
+ } else if (client_freq > 0 &&
+ go_dev_addr && !is_zero_ether_addr(go_dev_addr) &&
+ ssid && ssid_len > 0) {
+ /*
+ * Add the optional P2P Group ID to indicate in which group this
+ * device is a P2P Client.
+ */
+ p2p_buf_add_group_id(buf, go_dev_addr, ssid, ssid_len);
+ }
+
+ return buf;
+}
+
+
+struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len)
+{
+ return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid,
+ ssid_len);
+}
+
+
+struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len)
+{
+ return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid,
+ ssid_len);
+}
+
+
+int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
+ struct p2p_nfc_params *params)
+{
+ struct p2p_message msg;
+ struct p2p_device *dev;
+ const u8 *p2p_dev_addr;
+ int freq;
+ enum p2p_role_indication role;
+
+ params->next_step = NO_ACTION;
+
+ if (p2p_parse_ies_separate(params->wsc_attr, params->wsc_len,
+ params->p2p_attr, params->p2p_len, &msg)) {
+ p2p_dbg(p2p, "Failed to parse WSC/P2P attributes from NFC");
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ if (msg.p2p_device_addr)
+ p2p_dev_addr = msg.p2p_device_addr;
+ else if (msg.device_id)
+ p2p_dev_addr = msg.device_id;
+ else {
+ p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ if (msg.oob_dev_password) {
+ os_memcpy(params->oob_dev_pw, msg.oob_dev_password,
+ msg.oob_dev_password_len);
+ params->oob_dev_pw_len = msg.oob_dev_password_len;
+ }
+
+ dev = p2p_create_device(p2p, p2p_dev_addr);
+ if (dev == NULL) {
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ params->peer = &dev->info;
+
+ os_get_reltime(&dev->last_seen);
+ dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
+ p2p_copy_wps_info(p2p, dev, 0, &msg);
+
+ if (!msg.oob_go_neg_channel) {
+ p2p_dbg(p2p, "OOB GO Negotiation Channel attribute not included");
+ return -1;
+ }
+
+ if (msg.oob_go_neg_channel[3] == 0 &&
+ msg.oob_go_neg_channel[4] == 0)
+ freq = 0;
+ else
+ freq = p2p_channel_to_freq(msg.oob_go_neg_channel[3],
+ msg.oob_go_neg_channel[4]);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Unknown peer OOB GO Neg channel");
+ return -1;
+ }
+ role = msg.oob_go_neg_channel[5];
+
+ if (role == P2P_GO_IN_A_GROUP) {
+ p2p_dbg(p2p, "Peer OOB GO operating channel: %u MHz", freq);
+ params->go_freq = freq;
+ } else if (role == P2P_CLIENT_IN_A_GROUP) {
+ p2p_dbg(p2p, "Peer (client) OOB GO operating channel: %u MHz",
+ freq);
+ params->go_freq = freq;
+ } else
+ p2p_dbg(p2p, "Peer OOB GO Neg channel: %u MHz", freq);
+ dev->oob_go_neg_freq = freq;
+
+ if (!params->sel && role != P2P_GO_IN_A_GROUP) {
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Own listen channel not known");
+ return -1;
+ }
+ p2p_dbg(p2p, "Use own Listen channel as OOB GO Neg channel: %u MHz", freq);
+ dev->oob_go_neg_freq = freq;
+ }
+
+ if (msg.group_id) {
+ os_memcpy(params->go_dev_addr, msg.group_id, ETH_ALEN);
+ params->go_ssid_len = msg.group_id_len - ETH_ALEN;
+ os_memcpy(params->go_ssid, msg.group_id + ETH_ALEN,
+ params->go_ssid_len);
+ }
+
+ if (dev->flags & P2P_DEV_USER_REJECTED) {
+ p2p_dbg(p2p, "Do not report rejected device");
+ p2p_parse_free(&msg);
+ return 0;
+ }
+
+ if (!(dev->flags & P2P_DEV_REPORTED)) {
+ p2p->cfg->dev_found(p2p->cfg->cb_ctx, p2p_dev_addr, &dev->info,
+ !(dev->flags & P2P_DEV_REPORTED_ONCE));
+ dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+ }
+ p2p_parse_free(&msg);
+
+ if (role == P2P_GO_IN_A_GROUP && p2p->num_groups > 0)
+ params->next_step = BOTH_GO;
+ else if (role == P2P_GO_IN_A_GROUP)
+ params->next_step = JOIN_GROUP;
+ else if (role == P2P_CLIENT_IN_A_GROUP) {
+ dev->flags |= P2P_DEV_GROUP_CLIENT_ONLY;
+ params->next_step = PEER_CLIENT;
+ } else if (p2p->num_groups > 0)
+ params->next_step = AUTH_JOIN;
+ else if (params->sel)
+ params->next_step = INIT_GO_NEG;
+ else
+ params->next_step = RESP_GO_NEG;
+
+ return 0;
+}
+
+
+void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id,
+ int go_intent,
+ const u8 *own_interface_addr)
+{
+
+ p2p->authorized_oob_dev_pw_id = dev_pw_id;
+ if (dev_pw_id == 0) {
+ p2p_dbg(p2p, "NFC OOB Password unauthorized for static handover");
+ return;
+ }
+
+ p2p_dbg(p2p, "NFC OOB Password (id=%u) authorized for static handover",
+ dev_pw_id);
+
+ p2p->go_intent = go_intent;
+ os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len)
+{
+ if (len < 8 || len > 63)
+ return -1;
+ p2p->cfg->passphrase_len = len;
+ return 0;
+}
+
+
+void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem)
+{
+ p2p->vendor_elem = vendor_elem;
+}
+
+
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct p2p_data *p2p = eloop_ctx;
+
+ p2p_dbg(p2p,
+ "Timeout on waiting peer to become ready for GO Negotiation");
+ p2p_go_neg_failed(p2p, -1);
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 2d8b2c25750b7..2402db6a7eb94 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -9,6 +9,18 @@
#ifndef P2P_H
#define P2P_H
+#include "wps/wps_defs.h"
+
+/* P2P ASP Setup Capability */
+#define P2PS_SETUP_NONE 0
+#define P2PS_SETUP_NEW BIT(0)
+#define P2PS_SETUP_CLIENT BIT(1)
+#define P2PS_SETUP_GROUP_OWNER BIT(2)
+
+#define P2PS_WILD_HASH_STR "org.wi-fi.wfds"
+#define P2PS_HASH_LEN 6
+#define P2P_MAX_QUERY_HASH 6
+
/**
* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
*/
@@ -50,7 +62,8 @@ struct p2p_channels {
};
enum p2p_wps_method {
- WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
+ WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC, WPS_NFC,
+ WPS_P2PS
};
/**
@@ -77,6 +90,8 @@ struct p2p_go_neg_results {
int ht40;
+ int vht;
+
/**
* ssid - SSID of the group
*/
@@ -138,11 +153,99 @@ struct p2p_go_neg_results {
unsigned int peer_config_timeout;
};
+struct p2ps_provision {
+ /**
+ * status - Remote returned provisioning status code
+ */
+ int status;
+
+ /**
+ * adv_id - P2PS Advertisement ID
+ */
+ u32 adv_id;
+
+ /**
+ * session_id - P2PS Session ID
+ */
+ u32 session_id;
+
+ /**
+ * method - WPS Method (to be) used to establish session
+ */
+ u16 method;
+
+ /**
+ * conncap - Connection Capabilities negotiated between P2P peers
+ */
+ u8 conncap;
+
+ /**
+ * role - Info about the roles to be used for this connection
+ */
+ u8 role;
+
+ /**
+ * session_mac - MAC address of the peer that started the session
+ */
+ u8 session_mac[ETH_ALEN];
+
+ /**
+ * adv_mac - MAC address of the peer advertised the service
+ */
+ u8 adv_mac[ETH_ALEN];
+
+ /**
+ * info - Vendor defined extra Provisioning information
+ */
+ char info[0];
+};
+
+struct p2ps_advertisement {
+ struct p2ps_advertisement *next;
+
+ /**
+ * svc_info - Pointer to (internal) Service defined information
+ */
+ char *svc_info;
+
+ /**
+ * id - P2PS Advertisement ID
+ */
+ u32 id;
+
+ /**
+ * config_methods - WPS Methods which are allowed for this service
+ */
+ u16 config_methods;
+
+ /**
+ * state - Current state of the service: 0 - Out Of Service, 1-255 Vendor defined
+ */
+ u8 state;
+
+ /**
+ * auto_accept - Automatically Accept provisioning request if possible.
+ */
+ u8 auto_accept;
+
+ /**
+ * hash - 6 octet Service Name has to match against incoming Probe Requests
+ */
+ u8 hash[P2PS_HASH_LEN];
+
+ /**
+ * svc_name - NULL Terminated UTF-8 Service Name, and svc_info storage
+ */
+ char svc_name[0];
+};
+
+
struct p2p_data;
enum p2p_scan_type {
P2P_SCAN_SOCIAL,
P2P_SCAN_FULL,
+ P2P_SCAN_SPECIFIC,
P2P_SCAN_SOCIAL_PLUS_ONE
};
@@ -226,6 +329,19 @@ struct p2p_peer_info {
* wfd_subelems - Wi-Fi Display subelements from WFD IE(s)
*/
struct wpabuf *wfd_subelems;
+
+ /**
+ * vendor_elems - Unrecognized vendor elements
+ *
+ * This buffer includes any other vendor element than P2P, WPS, and WFD
+ * IE(s) from the frame that was used to discover the peer.
+ */
+ struct wpabuf *vendor_elems;
+
+ /**
+ * p2ps_instance - P2PS Application Service Info
+ */
+ struct wpabuf *p2ps_instance;
};
enum p2p_prov_disc_status {
@@ -233,6 +349,7 @@ enum p2p_prov_disc_status {
P2P_PROV_DISC_TIMEOUT,
P2P_PROV_DISC_REJECTED,
P2P_PROV_DISC_TIMEOUT_JOIN,
+ P2P_PROV_DISC_INFO_UNAVAILABLE,
};
struct p2p_channel {
@@ -263,6 +380,12 @@ struct p2p_config {
u8 channel;
/**
+ * channel_forced - the listen channel was forced by configuration
+ * or by control interface and cannot be overridden
+ */
+ u8 channel_forced;
+
+ /**
* Regulatory class for own operational channel
*/
u8 op_reg_class;
@@ -287,6 +410,20 @@ struct p2p_config {
struct p2p_channels channels;
/**
+ * cli_channels - Additional client channels
+ *
+ * This list of channels (if any) will be used when advertising local
+ * channels during GO Negotiation or Invitation for the cases where the
+ * local end may become the client. This may allow the peer to become a
+ * GO on additional channels if it supports these options. The main use
+ * case for this is to include passive-scan channels on devices that may
+ * not know their current location and have configured most channels to
+ * not allow initiation of radition (i.e., another device needs to take
+ * master responsibilities).
+ */
+ struct p2p_channels cli_channels;
+
+ /**
* num_pref_chan - Number of pref_chan entries
*/
unsigned int num_pref_chan;
@@ -371,15 +508,26 @@ struct p2p_config {
unsigned int max_listen;
/**
- * msg_ctx - Context to use with wpa_msg() calls
+ * passphrase_len - Passphrase length (8..63)
+ *
+ * This parameter controls the length of the random passphrase that is
+ * generated at the GO.
*/
- void *msg_ctx;
+ unsigned int passphrase_len;
/**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
+ /**
+ * debug_print - Debug print
+ * @ctx: Callback context from cb_ctx
+ * @level: Debug verbosity level (MSG_*)
+ * @msg: Debug message
+ */
+ void (*debug_print)(void *ctx, int level, const char *msg);
+
/* Callbacks to request lower layer driver operations */
@@ -398,7 +546,8 @@ struct p2p_config {
* operation to be completed. Type type argument specifies which type
* of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the
* social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL
- * indicates that all channels are to be scanned.
+ * indicates that all channels are to be scanned. @P2P_SCAN_SPECIFIC
+ * request a scan of a single channel specified by freq.
* @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels
* plus one extra channel specified by freq.
*
@@ -545,6 +694,12 @@ struct p2p_config {
void (*dev_lost)(void *ctx, const u8 *dev_addr);
/**
+ * find_stopped - Notification of a p2p_find operation stopping
+ * @ctx: Callback context from cb_ctx
+ */
+ void (*find_stopped)(void *ctx);
+
+ /**
* go_neg_req_rx - Notification of a receive GO Negotiation Request
* @ctx: Callback context from cb_ctx
* @src: Source address of the message triggering this notification
@@ -656,6 +811,9 @@ struct p2p_config {
* @ctx: Callback context from cb_ctx
* @peer: Source address of the response
* @status: Cause of failure, will not be %P2P_PROV_DISC_SUCCESS
+ * @adv_id: If non-zero, then the adv_id of the PD Request
+ * @adv_mac: P2P Device Address of the advertizer
+ * @deferred_session_resp: Deferred session response sent by advertizer
*
* This callback is used to indicate either a failure or no response
* to an earlier provision discovery request.
@@ -664,7 +822,9 @@ struct p2p_config {
* is not used or failures do not need to be indicated.
*/
void (*prov_disc_fail)(void *ctx, const u8 *peer,
- enum p2p_prov_disc_status status);
+ enum p2p_prov_disc_status status,
+ u32 adv_id, const u8 *adv_mac,
+ const char *deferred_session_resp);
/**
* invitation_process - Optional callback for processing Invitations
@@ -680,6 +840,9 @@ struct p2p_config {
* @persistent_group: Whether this is an invitation to reinvoke a
* persistent group (instead of invitation to join an active
* group)
+ * @channels: Available operating channels for the group
+ * @dev_pw_id: Device Password ID for NFC static handover or -1 if not
+ * used
* Returns: Status code (P2P_SC_*)
*
* This optional callback can be used to implement persistent reconnect
@@ -700,7 +863,9 @@ struct p2p_config {
u8 (*invitation_process)(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *go_dev_addr, const u8 *ssid,
size_t ssid_len, int *go, u8 *group_bssid,
- int *force_freq, int persistent_group);
+ int *force_freq, int persistent_group,
+ const struct p2p_channels *channels,
+ int dev_pw_id);
/**
* invitation_received - Callback on Invitation Request RX
@@ -729,6 +894,11 @@ struct p2p_config {
* @ctx: Callback context from cb_ctx
* @status: Negotiation result (Status Code)
* @bssid: P2P Group BSSID or %NULL if not received
+ * @channels: Available operating channels for the group
+ * @addr: Peer address
+ * @freq: Frequency (in MHz) indicated during invitation or 0
+ * @peer_oper_freq: Operating frequency (in MHz) advertized by the peer
+ * during invitation or 0
*
* This callback is used to indicate result of an Invitation procedure
* started with a call to p2p_invite(). The indicated status code is
@@ -736,7 +906,9 @@ struct p2p_config {
* (P2P_SC_SUCCESS) indicating success or -1 to indicate a timeout or a
* local failure in transmitting the Invitation Request.
*/
- void (*invitation_result)(void *ctx, int status, const u8 *bssid);
+ void (*invitation_result)(void *ctx, int status, const u8 *bssid,
+ const struct p2p_channels *channels,
+ const u8 *addr, int freq, int peer_oper_freq);
/**
* go_connected - Check whether we are connected to a GO
@@ -746,6 +918,111 @@ struct p2p_config {
* or 0 if not.
*/
int (*go_connected)(void *ctx, const u8 *dev_addr);
+
+ /**
+ * presence_resp - Callback on Presence Response
+ * @ctx: Callback context from cb_ctx
+ * @src: Source address (GO's P2P Interface Address)
+ * @status: Result of the request (P2P_SC_*)
+ * @noa: Returned NoA value
+ * @noa_len: Length of the NoA buffer in octets
+ */
+ void (*presence_resp)(void *ctx, const u8 *src, u8 status,
+ const u8 *noa, size_t noa_len);
+
+ /**
+ * is_concurrent_session_active - Check whether concurrent session is
+ * active on other virtual interfaces
+ * @ctx: Callback context from cb_ctx
+ * Returns: 1 if concurrent session is active on other virtual interface
+ * or 0 if not.
+ */
+ int (*is_concurrent_session_active)(void *ctx);
+
+ /**
+ * is_p2p_in_progress - Check whether P2P operation is in progress
+ * @ctx: Callback context from cb_ctx
+ * Returns: 1 if P2P operation (e.g., group formation) is in progress
+ * or 0 if not.
+ */
+ int (*is_p2p_in_progress)(void *ctx);
+
+ /**
+ * Determine if we have a persistent group we share with remote peer
+ * @ctx: Callback context from cb_ctx
+ * @addr: Peer device address to search for
+ * @ssid: Persistent group SSID or %NULL if any
+ * @ssid_len: Length of @ssid
+ * @go_dev_addr: Buffer for returning intended GO P2P Device Address
+ * @ret_ssid: Buffer for returning group SSID
+ * @ret_ssid_len: Buffer for returning length of @ssid
+ * Returns: 1 if a matching persistent group was found, 0 otherwise
+ */
+ int (*get_persistent_group)(void *ctx, const u8 *addr, const u8 *ssid,
+ size_t ssid_len, u8 *go_dev_addr,
+ u8 *ret_ssid, size_t *ret_ssid_len);
+
+ /**
+ * Get information about a possible local GO role
+ * @ctx: Callback context from cb_ctx
+ * @intended_addr: Buffer for returning intended GO interface address
+ * @ssid: Buffer for returning group SSID
+ * @ssid_len: Buffer for returning length of @ssid
+ * @group_iface: Buffer for returning whether a separate group interface
+ * would be used
+ * Returns: 1 if GO info found, 0 otherwise
+ *
+ * This is used to compose New Group settings (SSID, and intended
+ * address) during P2PS provisioning if results of provisioning *might*
+ * result in our being an autonomous GO.
+ */
+ int (*get_go_info)(void *ctx, u8 *intended_addr,
+ u8 *ssid, size_t *ssid_len, int *group_iface);
+
+ /**
+ * remove_stale_groups - Remove stale P2PS groups
+ *
+ * Because P2PS stages *potential* GOs, and remote devices can remove
+ * credentials unilaterally, we need to make sure we don't let stale
+ * unusable groups build up.
+ */
+ int (*remove_stale_groups)(void *ctx, const u8 *peer, const u8 *go,
+ const u8 *ssid, size_t ssid_len);
+
+ /**
+ * p2ps_prov_complete - P2PS provisioning complete
+ *
+ * When P2PS provisioning completes (successfully or not) we must
+ * transmit all of the results to the upper layers.
+ */
+ void (*p2ps_prov_complete)(void *ctx, u8 status, const u8 *dev,
+ const u8 *adv_mac, const u8 *ses_mac,
+ const u8 *grp_mac, u32 adv_id, u32 ses_id,
+ u8 conncap, int passwd_id,
+ const u8 *persist_ssid,
+ size_t persist_ssid_size, int response_done,
+ int prov_start, const char *session_info);
+
+ /**
+ * prov_disc_resp_cb - Callback for indicating completion of PD Response
+ * @ctx: Callback context from cb_ctx
+ * Returns: 1 if operation was started, 0 otherwise
+ *
+ * This callback can be used to perform any pending actions after
+ * provisioning. It is mainly used for P2PS pending group creation.
+ */
+ int (*prov_disc_resp_cb)(void *ctx);
+
+ /**
+ * p2ps_group_capability - Determine group capability
+ *
+ * This function can be used to determine group capability based on
+ * information from P2PS PD exchange and the current state of ongoing
+ * groups and driver capabilities.
+ *
+ * P2PS_SETUP_* bitmap is used as the parameters and return value.
+ */
+ u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role);
};
@@ -852,12 +1129,26 @@ enum p2p_discovery_type {
* requested device types.
* @dev_id: Device ID to search for or %NULL to find all devices
* @search_delay: Extra delay in milliseconds between search iterations
+ * @seek_count: Number of ASP Service Strings in the seek_string array
+ * @seek_string: ASP Service Strings to query for in Probe Requests
+ * @freq: Requested first scan frequency (in MHz) to modify type ==
+ * P2P_FIND_START_WITH_FULL behavior. 0 = Use normal full scan.
+ * If p2p_find is already in progress, this parameter is ignored and full
+ * scan will be executed.
* Returns: 0 on success, -1 on failure
*/
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_string, int freq);
+
+/**
+ * p2p_notify_scan_trigger_status - Indicate scan trigger status
+ * @p2p: P2P module context from p2p_init()
+ * @status: 0 on success, -1 on failure
+ */
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status);
/**
* p2p_stop_find - Stop P2P Find (Device Discovery)
@@ -889,6 +1180,12 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq);
int p2p_listen(struct p2p_data *p2p, unsigned int timeout);
/**
+ * p2p_stop_listen - Stop P2P Listen
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_stop_listen(struct p2p_data *p2p);
+
+/**
* p2p_connect - Start P2P group formation (GO negotiation)
* @p2p: P2P module context from p2p_init()
* @peer_addr: MAC address of the peer P2P client
@@ -914,7 +1211,7 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- int pd_before_go_neg, unsigned int pref_freq);
+ int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id);
/**
* p2p_authorize - Authorize P2P group formation (GO negotiation)
@@ -942,7 +1239,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- unsigned int pref_freq);
+ unsigned int pref_freq, u16 oob_pw_id);
/**
* p2p_reject - Reject peer device (explicitly block connection attempts)
@@ -956,6 +1253,7 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
* p2p_prov_disc_req - Send Provision Discovery Request
* @p2p: P2P module context from p2p_init()
* @peer_addr: MAC address of the peer P2P client
+ * @p2ps_prov: Provisioning info for P2PS
* @config_methods: WPS Config Methods value (only one bit set)
* @join: Whether this is used by a client joining an active group
* @force_freq: Forced TX frequency for the frame (mainly for the join case)
@@ -971,7 +1269,8 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
* indicated with the p2p_config::prov_disc_resp() callback.
*/
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
- u16 config_methods, int join, int force_freq,
+ struct p2ps_provision *p2ps_prov, u16 config_methods,
+ int join, int force_freq,
int user_initiated_pd);
/**
@@ -1042,12 +1341,16 @@ enum p2p_invite_role {
* @force_freq: The only allowed channel frequency in MHz or 0
* @go_dev_addr: Forced GO Device Address or %NULL if none
* @persistent_group: Whether this is to reinvoke a persistent group
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ * force_freq == 0)
+ * @dev_pw_id: Device Password ID from OOB Device Password (NFC) static handover
+ * case or -1 if not used
* Returns: 0 on success, -1 on failure
*/
int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
unsigned int force_freq, const u8 *go_dev_addr,
- int persistent_group);
+ int persistent_group, unsigned int pref_freq, int dev_pw_id);
/**
* p2p_presence_req - Request GO presence
@@ -1183,7 +1486,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
* @p2p: P2P module context from p2p_init()
* @bssid: BSSID of the scan result
* @freq: Frequency of the channel on which the device was found in MHz
- * @age: Age of the scan result in milliseconds
+ * @rx_time: Time when the result was received
* @level: Signal level (signal strength of the received Beacon/Probe Response
* frame)
* @ies: Pointer to IEs from the scan result
@@ -1205,7 +1508,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
* start of a pending operation, e.g., to start a pending GO negotiation.
*/
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- unsigned int age, int level, const u8 *ies,
+ struct os_reltime *rx_time, int level, const u8 *ies,
size_t ies_len);
/**
@@ -1312,6 +1615,11 @@ struct p2p_group_config {
size_t ssid_len;
/**
+ * freq - Operating channel of the group
+ */
+ int freq;
+
+ /**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
@@ -1587,7 +1895,24 @@ void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
*/
void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel);
+/**
+ * p2p_config_get_random_social - Return a random social channel
+ * @p2p: P2P config
+ * @op_class: Selected operating class
+ * @op_channel: Selected social channel
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used before p2p_init is called. A random social channel
+ * from supports bands 2.4 GHz (channels 1,6,11) and 60 GHz (channel 2) is
+ * returned on success.
+ */
+int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
+ u8 *op_channel);
+
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+ u8 forced);
+
+u8 p2p_get_listen_channel(struct p2p_data *p2p);
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len);
@@ -1614,6 +1939,12 @@ int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr);
*/
void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+ unsigned int freq);
+
+int p2p_channels_to_freqs(const struct p2p_channels *channels,
+ int *freq_list, unsigned int max_len);
+
/**
* p2p_supported_freq - Check whether channel is supported for P2P
* @p2p: P2P module context from p2p_init()
@@ -1622,7 +1953,34 @@ void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
*/
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
+/**
+ * p2p_supported_freq_go - Check whether channel is supported for P2P GO operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq);
+
+/**
+ * p2p_supported_freq_cli - Check whether channel is supported for P2P client operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq);
+
+/**
+ * p2p_get_pref_freq - Get channel from preferred channel list
+ * @p2p: P2P module context from p2p_init()
+ * @channels: List of channels
+ * Returns: Preferred channel
+ */
+unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
+ const struct p2p_channels *channels);
+
+void p2p_update_channel_list(struct p2p_data *p2p,
+ const struct p2p_channels *chan,
+ const struct p2p_channels *cli_chan);
/**
* p2p_set_best_channels - Update best channel information
@@ -1634,6 +1992,17 @@ void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
int freq_overall);
+/**
+ * p2p_set_own_freq_preference - Set own preference for channel
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Frequency (MHz) of the preferred channel or 0 if no preference
+ *
+ * This function can be used to set a preference on the operating channel based
+ * on frequencies used on the other virtual interfaces that share the same
+ * radio. If non-zero, this is used to try to avoid multi-channel concurrency.
+ */
+void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq);
+
const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p);
/**
@@ -1644,11 +2013,18 @@ const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p);
unsigned int p2p_get_group_num_members(struct p2p_group *group);
/**
+ * p2p_client_limit_reached - Check if client limit is reached
+ * @group: P2P group context from p2p_group_init()
+ * Returns: 1 if no of clients limit reached
+ */
+int p2p_client_limit_reached(struct p2p_group *group);
+
+/**
* p2p_iterate_group_members - Iterate group members
* @group: P2P group context from p2p_group_init()
* @next: iteration pointer, must be a pointer to a void * that is set to %NULL
* on the first call and not modified later
- * Returns: A P2P Interface Address for each call and %NULL for no more members
+ * Returns: A P2P Device Address for each call and %NULL for no more members
*/
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
@@ -1670,6 +2046,26 @@ const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr);
/**
+ * p2p_group_get_config - Get the group configuration
+ * @group: P2P group context from p2p_group_init()
+ * Returns: The group configuration pointer
+ */
+const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group);
+
+/**
+ * p2p_loop_on_all_groups - Run the given callback on all groups
+ * @p2p: P2P module context from p2p_init()
+ * @group_callback: The callback function pointer
+ * @user_data: Some user data pointer which can be %NULL
+ *
+ * The group_callback function can stop the iteration by returning 0.
+ */
+void p2p_loop_on_all_groups(struct p2p_data *p2p,
+ int (*group_callback)(struct p2p_group *group,
+ void *user_data),
+ void *user_data);
+
+/**
* p2p_get_peer_found - Get P2P peer info structure of a found peer
* @p2p: P2P module context from p2p_init()
* @addr: P2P Device Address of the peer or %NULL to indicate the first peer
@@ -1719,18 +2115,21 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
const struct p2p_channel *pref_chan);
/**
- * p2p_in_progress - Check whether a P2P operation is progress
+ * p2p_set_no_go_freq - Set no GO channel ranges
* @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ * @list: Channel ranges or %NULL to remove restriction
+ * Returns: 0 on success, -1 on failure
*/
-int p2p_in_progress(struct p2p_data *p2p);
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+ const struct wpa_freq_range_list *list);
/**
- * p2p_other_scan_completed - Notify completion of non-P2P scan
+ * p2p_in_progress - Check whether a P2P operation is progress
* @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation was started
+ * Returns: 0 if P2P module is idle, 1 if an operation is in progress but not
+ * in search state, or 2 if search state operation is in progress
*/
-int p2p_other_scan_completed(struct p2p_data *p2p);
+int p2p_in_progress(struct p2p_data *p2p);
const char * p2p_wps_method_text(enum p2p_wps_method method);
@@ -1743,8 +2142,6 @@ const char * p2p_wps_method_text(enum p2p_wps_method method);
void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
u8 client_timeout);
-void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay);
-
int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie);
@@ -1780,4 +2177,71 @@ struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
int max_disc_tu);
+/**
+ * p2p_get_state_txt - Get current P2P state for debug purposes
+ * @p2p: P2P module context from p2p_init()
+ * Returns: Name of the current P2P module state
+ *
+ * It should be noted that the P2P module state names are internal information
+ * and subject to change at any point, i.e., this information should be used
+ * mainly for debugging purposes.
+ */
+const char * p2p_get_state_txt(struct p2p_data *p2p);
+
+struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len);
+struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len);
+
+struct p2p_nfc_params {
+ int sel;
+ const u8 *wsc_attr;
+ size_t wsc_len;
+ const u8 *p2p_attr;
+ size_t p2p_len;
+
+ enum {
+ NO_ACTION, JOIN_GROUP, AUTH_JOIN, INIT_GO_NEG, RESP_GO_NEG,
+ BOTH_GO, PEER_CLIENT
+ } next_step;
+ struct p2p_peer_info *peer;
+ u8 oob_dev_pw[WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_LEN];
+ size_t oob_dev_pw_len;
+ int go_freq;
+ u8 go_dev_addr[ETH_ALEN];
+ u8 go_ssid[32];
+ size_t go_ssid_len;
+};
+
+int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
+ struct p2p_nfc_params *params);
+
+void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id,
+ int go_intent,
+ const u8 *own_interface_addr);
+
+int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len);
+
+void p2p_loop_on_known_peers(struct p2p_data *p2p,
+ void (*peer_callback)(struct p2p_peer_info *peer,
+ void *user_data),
+ void *user_data);
+
+void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem);
+
+void p2p_set_intended_addr(struct p2p_data *p2p, const u8 *intended_addr);
+
+struct p2ps_advertisement *
+p2p_service_p2ps_id(struct p2p_data *p2p, u32 adv_id);
+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);
+int p2p_service_del_asp(struct p2p_data *p2p, u32 adv_id);
+struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 5838d35e977ee..92c920662edb3 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -17,8 +17,7 @@
void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token)
{
wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
wpabuf_put_u8(buf, subtype); /* OUI Subtype */
wpabuf_put_u8(buf, dialog_token);
@@ -31,8 +30,7 @@ void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype,
{
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
wpabuf_put_u8(buf, subtype); /* OUI Subtype */
wpabuf_put_u8(buf, dialog_token);
@@ -47,8 +45,7 @@ u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf)
/* P2P IE header */
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
len = wpabuf_put(buf, 1); /* IE length to be filled */
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
wpa_printf(MSG_DEBUG, "P2P: * P2P IE header");
return len;
}
@@ -167,15 +164,18 @@ void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
if (peer->wps_method == WPS_PBC)
methods |= WPS_CONFIG_PUSHBUTTON;
else if (peer->wps_method == WPS_PIN_DISPLAY ||
- peer->wps_method == WPS_PIN_KEYPAD)
+ peer->wps_method == WPS_PIN_KEYPAD) {
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+ methods |= WPS_CONFIG_P2PS;
+ }
} else if (p2p->cfg->config_methods) {
methods |= p2p->cfg->config_methods &
(WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
- WPS_CONFIG_KEYPAD);
+ WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS);
} else {
methods |= WPS_CONFIG_PUSHBUTTON;
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+ methods |= WPS_CONFIG_P2PS;
}
wpabuf_put_be16(buf, methods);
@@ -258,6 +258,7 @@ void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr,
wpabuf_put_data(buf, ssid, ssid_len);
wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
MAC2STR(dev_addr));
+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len);
}
@@ -327,13 +328,282 @@ void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p)
}
-static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
- const char *val)
+void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
+ u8 oper_class, u8 channel,
+ enum p2p_role_indication role)
+{
+ /* OOB Group Owner Negotiation Channel */
+ wpabuf_put_u8(buf, P2P_ATTR_OOB_GO_NEG_CHANNEL);
+ wpabuf_put_le16(buf, 6);
+ wpabuf_put_data(buf, country, 3);
+ wpabuf_put_u8(buf, oper_class); /* Operating Class */
+ wpabuf_put_u8(buf, channel); /* Channel Number */
+ wpabuf_put_u8(buf, (u8) role); /* Role indication */
+ wpa_printf(MSG_DEBUG, "P2P: * OOB GO Negotiation Channel: Operating "
+ "Class %u Channel %u Role %d",
+ oper_class, channel, role);
+}
+
+
+void p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p)
+{
+ if (!p2p)
+ return;
+
+ /* Service Hash */
+ wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH);
+ wpabuf_put_le16(buf, p2p->p2ps_seek_count * P2PS_HASH_LEN);
+ wpabuf_put_data(buf, p2p->query_hash,
+ p2p->p2ps_seek_count * P2PS_HASH_LEN);
+ wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash",
+ p2p->query_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
+}
+
+
+void p2p_buf_add_session_info(struct wpabuf *buf, const char *info)
+{
+ size_t info_len = 0;
+
+ if (info && info[0])
+ info_len = os_strlen(info);
+
+ /* Session Information Data Info */
+ wpabuf_put_u8(buf, P2P_ATTR_SESSION_INFORMATION_DATA);
+ wpabuf_put_le16(buf, (u16) info_len);
+
+ if (info) {
+ wpabuf_put_data(buf, info, info_len);
+ wpa_printf(MSG_DEBUG, "P2P: * Session Info Data (%s)", info);
+ }
+}
+
+
+void p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap)
+{
+ /* Connection Capability Info */
+ wpabuf_put_u8(buf, P2P_ATTR_CONNECTION_CAPABILITY);
+ wpabuf_put_le16(buf, 1);
+ wpabuf_put_u8(buf, connection_cap);
+ wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
+ connection_cap);
+}
+
+
+void p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac)
+{
+ if (!buf || !mac)
+ return;
+
+ /* Advertisement ID Info */
+ wpabuf_put_u8(buf, P2P_ATTR_ADVERTISEMENT_ID);
+ wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
+ wpabuf_put_le32(buf, id);
+ wpabuf_put_data(buf, mac, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID (%x) " MACSTR,
+ id, MAC2STR(mac));
+}
+
+
+void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
+ u8 hash_count, const u8 *hash,
+ struct p2ps_advertisement *adv_list)
+{
+ struct p2ps_advertisement *adv;
+ struct wpabuf *tmp_buf;
+ u8 *tag_len = NULL, *ie_len = NULL;
+ size_t svc_len = 0, remaining = 0, total_len = 0;
+
+ if (!adv_list || !hash)
+ return;
+
+ /* Allocate temp buffer, allowing for overflow of 1 instance */
+ tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN);
+ if (!tmp_buf)
+ return;
+
+ for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN;
+ adv = adv->next) {
+ u8 count = hash_count;
+ const u8 *test = hash;
+
+ while (count--) {
+ /* Check for wildcard */
+ if (os_memcmp(test, p2p->wild_card_hash,
+ P2PS_HASH_LEN) == 0) {
+ total_len = MAX_SVC_ADV_LEN + 1;
+ goto wild_hash;
+ }
+
+ if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0)
+ goto hash_match;
+
+ test += P2PS_HASH_LEN;
+ }
+
+ /* No matches found - Skip this Adv Instance */
+ continue;
+
+hash_match:
+ if (!tag_len) {
+ tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+ remaining = 255 - 4;
+ if (!ie_len) {
+ wpabuf_put_u8(tmp_buf,
+ P2P_ATTR_ADVERTISED_SERVICE);
+ ie_len = wpabuf_put(tmp_buf, sizeof(u16));
+ remaining -= (sizeof(u8) + sizeof(u16));
+ }
+ }
+
+ svc_len = os_strlen(adv->svc_name);
+
+ if (7 + svc_len + total_len > MAX_SVC_ADV_LEN) {
+ /* Can't fit... return wildcard */
+ total_len = MAX_SVC_ADV_LEN + 1;
+ break;
+ }
+
+ if (remaining <= (sizeof(adv->id) +
+ sizeof(adv->config_methods))) {
+ size_t front = remaining;
+ size_t back = (sizeof(adv->id) +
+ sizeof(adv->config_methods)) - front;
+ u8 holder[sizeof(adv->id) +
+ sizeof(adv->config_methods)];
+
+ /* This works even if front or back == 0 */
+ WPA_PUT_LE32(holder, adv->id);
+ WPA_PUT_BE16(&holder[sizeof(adv->id)],
+ adv->config_methods);
+ wpabuf_put_data(tmp_buf, holder, front);
+ p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+ tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+ wpabuf_put_data(tmp_buf, &holder[front], back);
+ remaining = 255 - (sizeof(adv->id) +
+ sizeof(adv->config_methods)) - back;
+ } else {
+ wpabuf_put_le32(tmp_buf, adv->id);
+ wpabuf_put_be16(tmp_buf, adv->config_methods);
+ remaining -= (sizeof(adv->id) +
+ sizeof(adv->config_methods));
+ }
+
+ /* We are guaranteed at least one byte for svc_len */
+ wpabuf_put_u8(tmp_buf, svc_len);
+ remaining -= sizeof(u8);
+
+ if (remaining < svc_len) {
+ size_t front = remaining;
+ size_t back = svc_len - front;
+
+ wpabuf_put_data(tmp_buf, adv->svc_name, front);
+ p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+ tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+
+ /* In rare cases, we must split across 3 attributes */
+ if (back > 255 - 4) {
+ wpabuf_put_data(tmp_buf,
+ &adv->svc_name[front], 255 - 4);
+ back -= 255 - 4;
+ front += 255 - 4;
+ p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+ tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+ }
+
+ wpabuf_put_data(tmp_buf, &adv->svc_name[front], back);
+ remaining = 255 - 4 - back;
+ } else {
+ wpabuf_put_data(tmp_buf, adv->svc_name, svc_len);
+ remaining -= svc_len;
+ }
+
+ /* adv_id config_methods svc_string */
+ total_len += sizeof(u32) + sizeof(u16) + sizeof(u8) + svc_len;
+ }
+
+ if (tag_len)
+ p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+
+ if (ie_len)
+ WPA_PUT_LE16(ie_len, (u16) total_len);
+
+wild_hash:
+ /* If all fit, return matching instances, otherwise the wildcard */
+ if (total_len <= MAX_SVC_ADV_LEN) {
+ wpabuf_put_buf(buf, tmp_buf);
+ } else {
+ char *wild_card = P2PS_WILD_HASH_STR;
+ u8 wild_len;
+
+ /* Insert wildcard instance */
+ tag_len = p2p_buf_add_ie_hdr(buf);
+ wpabuf_put_u8(buf, P2P_ATTR_ADVERTISED_SERVICE);
+ ie_len = wpabuf_put(buf, sizeof(u16));
+
+ wild_len = (u8) os_strlen(wild_card);
+ wpabuf_put_le32(buf, 0);
+ wpabuf_put_be16(buf, 0);
+ wpabuf_put_u8(buf, wild_len);
+ wpabuf_put_data(buf, wild_card, wild_len);
+
+ WPA_PUT_LE16(ie_len, 4 + 2 + 1 + wild_len);
+ p2p_buf_update_ie_hdr(buf, tag_len);
+ }
+
+ wpabuf_free(tmp_buf);
+}
+
+
+void p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac)
+{
+ if (!buf || !mac)
+ return;
+
+ /* Session ID Info */
+ wpabuf_put_u8(buf, P2P_ATTR_SESSION_ID);
+ wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
+ wpabuf_put_le32(buf, id);
+ wpabuf_put_data(buf, mac, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "P2P: * Session ID Info (%x) " MACSTR,
+ id, MAC2STR(mac));
+}
+
+
+void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len, const u8 *mask)
+{
+ if (!buf || !len || !mask)
+ return;
+
+ /* Feature Capability */
+ wpabuf_put_u8(buf, P2P_ATTR_FEATURE_CAPABILITY);
+ wpabuf_put_le16(buf, len);
+ wpabuf_put_data(buf, mask, len);
+ wpa_printf(MSG_DEBUG, "P2P: * Feature Capability (%d)", len);
+}
+
+
+void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
+ const u8 *ssid, size_t ssid_len)
+{
+ /* P2P Group ID */
+ wpabuf_put_u8(buf, P2P_ATTR_PERSISTENT_GROUP);
+ wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
+ wpabuf_put_data(buf, dev_addr, ETH_ALEN);
+ wpabuf_put_data(buf, ssid, ssid_len);
+ wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
+ MAC2STR(dev_addr));
+}
+
+
+static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
+ const char *val)
{
size_t len;
- wpabuf_put_be16(buf, attr);
len = val ? os_strlen(val) : 0;
+ if (wpabuf_tailroom(buf) < 4 + len)
+ return -1;
+ wpabuf_put_be16(buf, attr);
#ifndef CONFIG_WPS_STRICT
if (len == 0) {
/*
@@ -341,36 +611,46 @@ static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
* attributes. As a workaround, send a space character if the
* device attribute string is empty.
*/
+ if (wpabuf_tailroom(buf) < 3)
+ return -1;
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, ' ');
- return;
+ return 0;
}
#endif /* CONFIG_WPS_STRICT */
wpabuf_put_be16(buf, len);
if (val)
wpabuf_put_data(buf, val, len);
+ return 0;
}
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
- int all_attr)
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+ int all_attr)
{
u8 *len;
int i;
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
len = wpabuf_put(buf, 1);
wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
- wps_build_version(buf);
+ if (wps_build_version(buf) < 0)
+ return -1;
if (all_attr) {
+ if (wpabuf_tailroom(buf) < 5)
+ return -1;
wpabuf_put_be16(buf, ATTR_WPS_STATE);
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
}
if (pw_id >= 0) {
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
/* Device Password ID */
wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
wpabuf_put_be16(buf, 2);
@@ -380,33 +660,47 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
}
if (all_attr) {
+ if (wpabuf_tailroom(buf) < 5)
+ return -1;
wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
- wps_build_uuid_e(buf, p2p->cfg->uuid);
- p2p_add_wps_string(buf, ATTR_MANUFACTURER,
- p2p->cfg->manufacturer);
- p2p_add_wps_string(buf, ATTR_MODEL_NAME, p2p->cfg->model_name);
- p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
- p2p->cfg->model_number);
- p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
- p2p->cfg->serial_number);
-
+ if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MANUFACTURER,
+ p2p->cfg->manufacturer) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MODEL_NAME,
+ p2p->cfg->model_name) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
+ p2p->cfg->model_number) < 0 ||
+ p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
+ p2p->cfg->serial_number) < 0)
+ return -1;
+
+ if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN)
+ return -1;
wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
- p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name);
+ if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name)
+ < 0)
+ return -1;
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
wpabuf_put_be16(buf, 2);
wpabuf_put_be16(buf, p2p->cfg->config_methods);
}
- wps_build_wfa_ext(buf, 0, NULL, 0);
+ if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
+ return -1;
if (all_attr && p2p->cfg->num_sec_dev_types) {
+ if (wpabuf_tailroom(buf) <
+ 4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types)
+ return -1;
wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
p2p->cfg->num_sec_dev_types);
@@ -428,4 +722,6 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
}
p2p_buf_update_ie_hdr(buf, len);
+
+ return 0;
}
diff --git a/src/p2p/p2p_dev_disc.c b/src/p2p/p2p_dev_disc.c
index c976b7c6d62b2..86bae1a2c0db8 100644
--- a/src/p2p/p2p_dev_disc.c
+++ b/src/p2p/p2p_dev_disc.c
@@ -42,8 +42,7 @@ static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p,
void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Device Discoverability Request TX callback: success=%d",
+ p2p_dbg(p2p, "Device Discoverability Request TX callback: success=%d",
success);
if (!success) {
@@ -56,9 +55,7 @@ void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success)
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO acknowledged Device Discoverability Request - wait "
- "for response");
+ p2p_dbg(p2p, "GO acknowledged Device Discoverability Request - wait for response");
/*
* TODO: is the remain-on-channel from Action frame TX long enough for
* most cases or should we try to increase its duration and/or start
@@ -71,12 +68,11 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
{
struct p2p_device *go;
struct wpabuf *req;
+ unsigned int wait_time;
go = p2p_get_device(p2p, dev->member_in_go_dev);
if (go == NULL || dev->oper_freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Could not find peer entry for GO and frequency "
- "to send Device Discoverability Request");
+ p2p_dbg(p2p, "Could not find peer entry for GO and frequency to send Device Discoverability Request");
return -1;
}
@@ -84,8 +80,7 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
if (req == NULL)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending Device Discoverability Request to GO " MACSTR
+ p2p_dbg(p2p, "Sending Device Discoverability Request to GO " MACSTR
" for client " MACSTR,
MAC2STR(go->info.p2p_device_addr),
MAC2STR(dev->info.p2p_device_addr));
@@ -94,11 +89,13 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr,
ETH_ALEN);
p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST;
+ wait_time = 1000;
+ if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen)
+ wait_time = p2p->cfg->max_listen;
if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr,
p2p->cfg->dev_addr, go->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 1000) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(req), wpabuf_len(req), wait_time) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(req);
/* TODO: how to recover from failure? */
return -1;
@@ -131,8 +128,7 @@ static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status)
void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Device Discoverability Response TX callback: success=%d",
+ p2p_dbg(p2p, "Device Discoverability Response TX callback: success=%d",
success);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
}
@@ -147,8 +143,7 @@ static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token,
if (resp == NULL)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending Device Discoverability Response to " MACSTR
+ p2p_dbg(p2p, "Sending Device Discoverability Response to " MACSTR
" (status %u freq %d)",
MAC2STR(addr), status, freq);
@@ -156,8 +151,7 @@ static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token,
if (p2p_send_action(p2p, freq, addr, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(resp);
@@ -170,17 +164,14 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
struct p2p_message msg;
size_t g;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Device Discoverability Request from " MACSTR
+ p2p_dbg(p2p, "Received Device Discoverability Request from " MACSTR
" (freq=%d)", MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
return;
if (msg.dialog_token == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid Dialog Token 0 (must be nonzero) in "
- "Device Discoverability Request");
+ p2p_dbg(p2p, "Invalid Dialog Token 0 (must be nonzero) in Device Discoverability Request");
p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
P2P_SC_FAIL_INVALID_PARAMS);
p2p_parse_free(&msg);
@@ -188,9 +179,7 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
}
if (msg.device_id == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: P2P Device ID attribute missing from Device "
- "Discoverability Request");
+ p2p_dbg(p2p, "P2P Device ID attribute missing from Device Discoverability Request");
p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
P2P_SC_FAIL_INVALID_PARAMS);
p2p_parse_free(&msg);
@@ -200,9 +189,7 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
for (g = 0; g < p2p->num_groups; g++) {
if (p2p_group_go_discover(p2p->groups[g], msg.device_id, sa,
rx_freq) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scheduled "
- "GO Discoverability Request for the target "
- "device");
+ p2p_dbg(p2p, "Scheduled GO Discoverability Request for the target device");
/*
* P2P group code will use a callback to indicate TX
* status, so that we can reply to the request once the
@@ -217,9 +204,7 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
}
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Requested client "
- "was not found in any group or did not support client "
- "discoverability");
+ p2p_dbg(p2p, "Requested client was not found in any group or did not support client discoverability");
p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE);
p2p_parse_free(&msg);
@@ -233,15 +218,13 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
struct p2p_device *go;
u8 status;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Device Discoverability Response from " MACSTR,
+ p2p_dbg(p2p, "Received Device Discoverability Response from " MACSTR,
MAC2STR(sa));
go = p2p->pending_client_disc_go;
if (go == NULL ||
os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected "
- "Device Discoverability Response");
+ p2p_dbg(p2p, "Ignore unexpected Device Discoverability Response");
return;
}
@@ -254,9 +237,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
}
if (msg.dialog_token != go->dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore Device "
- "Discoverability Response with unexpected dialog "
- "token %u (expected %u)",
+ p2p_dbg(p2p, "Ignore Device Discoverability Response with unexpected dialog token %u (expected %u)",
msg.dialog_token, go->dialog_token);
p2p_parse_free(&msg);
return;
@@ -265,17 +246,14 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
status = *msg.status;
p2p_parse_free(&msg);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Device Discoverability Response status %u", status);
+ p2p_dbg(p2p, "Device Discoverability Response status %u", status);
if (p2p->go_neg_peer == NULL ||
os_memcmp(p2p->pending_client_disc_addr,
p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 ||
os_memcmp(p2p->go_neg_peer->member_in_go_dev,
go->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending "
- "operation with the client discoverability peer "
- "anymore");
+ p2p_dbg(p2p, "No pending operation with the client discoverability peer anymore");
return;
}
@@ -284,8 +262,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
* Peer is expected to be awake for at least 100 TU; try to
* connect immediately.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Client discoverability request succeeded");
+ p2p_dbg(p2p, "Client discoverability request succeeded");
if (p2p->state == P2P_CONNECT) {
/*
* Change state to force the timeout to start in
@@ -301,8 +278,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
* Client discoverability request failed; try to connect from
* timeout.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Client discoverability request failed");
+ p2p_dbg(p2p, "Client discoverability request failed");
p2p_set_timeout(p2p, 0, 500000);
}
@@ -311,14 +287,12 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
void p2p_go_disc_req_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Discoverability Request TX callback: success=%d",
+ p2p_dbg(p2p, "GO Discoverability Request TX callback: success=%d",
success);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (p2p->pending_dev_disc_dialog_token == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending Device "
- "Discoverability Request");
+ p2p_dbg(p2p, "No pending Device Discoverability Request");
return;
}
@@ -338,9 +312,7 @@ void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
unsigned int tu;
struct wpabuf *ies;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GO Discoverability Request - remain awake for "
- "100 TU");
+ p2p_dbg(p2p, "Received GO Discoverability Request - remain awake for 100 TU");
ies = p2p_build_probe_resp_ies(p2p);
if (ies == NULL)
@@ -351,9 +323,7 @@ void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
tu = 100;
if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, rx_freq, 1024 * tu / 1000,
ies) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to start listen mode for client "
- "discoverability");
+ p2p_dbg(p2p, "Failed to start listen mode for client discoverability");
}
wpabuf_free(ies);
}
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 2fdc47fc5d0f2..98abf9d2293e9 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -9,7 +9,9 @@
#include "includes.h"
#include "common.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -49,8 +51,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
os_memcpy(dev->country, pos, 3);
wpa_hexdump_ascii(MSG_DEBUG, "P2P: Peer country", pos, 3);
if (pos[2] != 0x04 && os_memcmp(pos, p2p->cfg->country, 2) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: Mismatching country (ours=%c%c peer's=%c%c)",
+ p2p_info(p2p, "Mismatching country (ours=%c%c peer's=%c%c)",
p2p->cfg->country[0], p2p->cfg->country[1],
pos[0], pos[1]);
return -1;
@@ -61,8 +62,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes];
cl->reg_class = *pos++;
if (pos + 1 + pos[0] > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: Invalid peer Channel List");
+ p2p_info(p2p, "Invalid peer Channel List");
return -1;
}
channels = *pos++;
@@ -76,14 +76,12 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
}
p2p_channels_intersect(own, &dev->channels, &intersection);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own reg_classes %d "
- "peer reg_classes %d intersection reg_classes %d",
+ p2p_dbg(p2p, "Own reg_classes %d peer reg_classes %d intersection reg_classes %d",
(int) own->reg_classes,
(int) dev->channels.reg_classes,
(int) intersection.reg_classes);
if (intersection.reg_classes == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: No common channels found");
+ p2p_info(p2p, "No common channels found");
return -1;
}
return 0;
@@ -107,6 +105,10 @@ u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
return DEV_PW_USER_SPECIFIED;
case WPS_PBC:
return DEV_PW_PUSHBUTTON;
+ case WPS_NFC:
+ return DEV_PW_NFC_CONNECTION_HANDOVER;
+ case WPS_P2PS:
+ return DEV_PW_P2PS_DEFAULT;
default:
return DEV_PW_DEFAULT;
}
@@ -122,6 +124,10 @@ static const char * p2p_wps_method_str(enum p2p_wps_method wps_method)
return "Keypad";
case WPS_PBC:
return "PBC";
+ case WPS_NFC:
+ return "NFC";
+ case WPS_P2PS:
+ return "P2PS";
default:
return "??";
}
@@ -135,19 +141,20 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
u8 *len;
u8 group_capab;
size_t extra = 0;
+ u16 pw_id;
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
extra = wpabuf_len(p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
- peer->dialog_token++;
- if (peer->dialog_token == 0)
- peer->dialog_token = 1;
p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token);
len = p2p_buf_add_ie_hdr(buf);
@@ -164,9 +171,7 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
p2p_buf_add_capability(buf, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
- p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) |
- p2p->next_tie_breaker);
- p2p->next_tie_breaker = !p2p->next_tie_breaker;
+ p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker);
p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
p2p->cfg->channel);
@@ -181,13 +186,23 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
+ pw_id = p2p_wps_method_pw_id(peer->wps_method);
+ if (peer->oob_pw_id)
+ pw_id = peer->oob_pw_id;
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+
return buf;
}
@@ -199,8 +214,7 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
u16 config_method;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Use PD-before-GO-Neg workaround for " MACSTR,
+ p2p_dbg(p2p, "Use PD-before-GO-Neg workaround for " MACSTR,
MAC2STR(dev->info.p2p_device_addr));
if (dev->wps_method == WPS_PIN_DISPLAY)
config_method = WPS_CONFIG_KEYPAD;
@@ -208,17 +222,20 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
config_method = WPS_CONFIG_DISPLAY;
else if (dev->wps_method == WPS_PBC)
config_method = WPS_CONFIG_PUSHBUTTON;
+ else if (dev->wps_method == WPS_P2PS)
+ config_method = WPS_CONFIG_P2PS;
else
return -1;
return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
- config_method, 0, 0, 1);
+ NULL, config_method, 0, 0, 1);
}
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+ if (dev->oob_go_neg_freq > 0)
+ freq = dev->oob_go_neg_freq;
if (freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen/Operating frequency known for the "
- "peer " MACSTR " to send GO Negotiation Request",
+ p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+ MACSTR " to send GO Negotiation Request",
MAC2STR(dev->info.p2p_device_addr));
return -1;
}
@@ -226,18 +243,17 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
req = p2p_build_go_neg_req(p2p, dev);
if (req == NULL)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending GO Negotiation Request");
+ p2p_dbg(p2p, "Sending GO Negotiation Request");
p2p_set_state(p2p, P2P_CONNECT);
p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;
p2p->go_neg_peer = dev;
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->connect_reqs++;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(req), wpabuf_len(req), 500) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
/* Use P2P find to recover and retry */
p2p_set_timeout(p2p, 0, 0);
} else
@@ -258,15 +274,18 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
u8 *len;
u8 group_capab;
size_t extra = 0;
+ u16 pw_id;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Building GO Negotiation Response");
+ p2p_dbg(p2p, "Building GO Negotiation Response");
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
extra = wpabuf_len(p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -294,8 +313,7 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
if (peer && peer->go_state == REMOTE_GO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating "
- "Channel attribute");
+ p2p_dbg(p2p, "Omit Operating Channel attribute");
} else {
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
p2p->op_reg_class,
@@ -322,15 +340,22 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- p2p_build_wps_ie(p2p, buf,
- p2p_wps_method_pw_id(peer ? peer->wps_method :
- WPS_NOT_READY), 0);
+ pw_id = p2p_wps_method_pw_id(peer ? peer->wps_method : WPS_NOT_READY);
+ if (peer && peer->oob_pw_id)
+ pw_id = peer->oob_pw_id;
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
return buf;
}
@@ -354,16 +379,41 @@ void p2p_reselect_channel(struct p2p_data *p2p,
int freq;
u8 op_reg_class, op_channel;
unsigned int i;
+ const int op_classes_5ghz[] = { 124, 115, 0 };
+ const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
+ const int op_classes_vht[] = { 128, 0 };
+
+ if (p2p->own_freq_preference > 0 &&
+ p2p_freq_to_channel(p2p->own_freq_preference,
+ &op_reg_class, &op_channel) == 0 &&
+ p2p_channels_includes(intersection, op_reg_class, op_channel)) {
+ p2p_dbg(p2p, "Pick own channel preference (reg_class %u channel %u) from intersection",
+ op_reg_class, op_channel);
+ p2p->op_reg_class = op_reg_class;
+ p2p->op_channel = op_channel;
+ return;
+ }
+
+ if (p2p->best_freq_overall > 0 &&
+ p2p_freq_to_channel(p2p->best_freq_overall,
+ &op_reg_class, &op_channel) == 0 &&
+ p2p_channels_includes(intersection, op_reg_class, op_channel)) {
+ p2p_dbg(p2p, "Pick best overall channel (reg_class %u channel %u) from intersection",
+ op_reg_class, op_channel);
+ p2p->op_reg_class = op_reg_class;
+ p2p->op_channel = op_channel;
+ return;
+ }
/* First, try to pick the best channel from another band */
- freq = p2p_channel_to_freq(p2p->cfg->country, p2p->op_reg_class,
- p2p->op_channel);
+ freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel);
if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
+ !p2p_channels_includes(intersection, p2p->op_reg_class,
+ p2p->op_channel) &&
+ p2p_freq_to_channel(p2p->best_freq_5,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 5 GHz "
- "channel (reg_class %u channel %u) from intersection",
+ p2p_dbg(p2p, "Pick best 5 GHz channel (reg_class %u channel %u) from intersection",
op_reg_class, op_channel);
p2p->op_reg_class = op_reg_class;
p2p->op_channel = op_channel;
@@ -371,11 +421,12 @@ void p2p_reselect_channel(struct p2p_data *p2p,
}
if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
+ !p2p_channels_includes(intersection, p2p->op_reg_class,
+ p2p->op_channel) &&
+ p2p_freq_to_channel(p2p->best_freq_24,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 2.4 GHz "
- "channel (reg_class %u channel %u) from intersection",
+ p2p_dbg(p2p, "Pick best 2.4 GHz channel (reg_class %u channel %u) from intersection",
op_reg_class, op_channel);
p2p->op_reg_class = op_reg_class;
p2p->op_channel = op_channel;
@@ -389,27 +440,34 @@ void p2p_reselect_channel(struct p2p_data *p2p,
p2p->cfg->pref_chan[i].chan)) {
p2p->op_reg_class = p2p->cfg->pref_chan[i].op_class;
p2p->op_channel = p2p->cfg->pref_chan[i].chan;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick "
- "highest preferred chnnel (op_class %u "
- "channel %u) from intersection",
+ p2p_dbg(p2p, "Pick highest preferred channel (op_class %u channel %u) from intersection",
p2p->op_reg_class, p2p->op_channel);
return;
}
}
+ /* Try a channel where we might be able to use VHT */
+ if (p2p_channel_select(intersection, op_classes_vht,
+ &p2p->op_reg_class, &p2p->op_channel) == 0) {
+ p2p_dbg(p2p, "Pick possible VHT channel (op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+
/* Try a channel where we might be able to use HT40 */
- for (i = 0; i < intersection->reg_classes; i++) {
- struct p2p_reg_class *c = &intersection->reg_class[i];
- if (c->reg_class == 116 || c->reg_class == 117 ||
- c->reg_class == 126 || c->reg_class == 127) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Pick possible HT40 channel (reg_class "
- "%u channel %u) from intersection",
- c->reg_class, c->channel[0]);
- p2p->op_reg_class = c->reg_class;
- p2p->op_channel = c->channel[0];
- return;
- }
+ if (p2p_channel_select(intersection, op_classes_ht40,
+ &p2p->op_reg_class, &p2p->op_channel) == 0) {
+ p2p_dbg(p2p, "Pick possible HT40 channel (op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+
+ /* Prefer a 5 GHz channel */
+ if (p2p_channel_select(intersection, op_classes_5ghz,
+ &p2p->op_reg_class, &p2p->op_channel) == 0) {
+ p2p_dbg(p2p, "Pick possible 5 GHz channel (op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
}
/*
@@ -419,9 +477,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
*/
if (p2p_channels_includes(intersection, p2p->op_reg_class,
p2p->op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Using original operating class and channel "
- "(op_class %u channel %u) from intersection",
+ p2p_dbg(p2p, "Using original operating class and channel (op_class %u channel %u) from intersection",
p2p->op_reg_class, p2p->op_channel);
return;
}
@@ -431,55 +487,48 @@ void p2p_reselect_channel(struct p2p_data *p2p,
* no better options seems to be available.
*/
cl = &intersection->reg_class[0];
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick another channel "
- "(reg_class %u channel %u) from intersection",
+ p2p_dbg(p2p, "Pick another channel (reg_class %u channel %u) from intersection",
cl->reg_class, cl->channel[0]);
p2p->op_reg_class = cl->reg_class;
p2p->op_channel = cl->channel[0];
}
-static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
- u8 *status)
+int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ u8 *status)
{
- struct p2p_channels intersection;
- size_t i;
-
- p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
+ struct p2p_channels tmp, intersection;
+
+ p2p_channels_dump(p2p, "own channels", &p2p->channels);
+ p2p_channels_dump(p2p, "peer channels", &dev->channels);
+ p2p_channels_intersect(&p2p->channels, &dev->channels, &tmp);
+ p2p_channels_dump(p2p, "intersection", &tmp);
+ p2p_channels_remove_freqs(&tmp, &p2p->no_go_freq);
+ p2p_channels_dump(p2p, "intersection after no-GO removal", &tmp);
+ p2p_channels_intersect(&tmp, &p2p->cfg->channels, &intersection);
+ p2p_channels_dump(p2p, "intersection with local channel list",
+ &intersection);
if (intersection.reg_classes == 0 ||
intersection.reg_class[0].channels == 0) {
*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
+ p2p_dbg(p2p, "No common channels found");
return -1;
}
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c;
- c = &intersection.reg_class[i];
- wpa_printf(MSG_DEBUG, "P2P: reg_class %u", c->reg_class);
- wpa_hexdump(MSG_DEBUG, "P2P: channels",
- c->channel, c->channels);
- }
-
if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
p2p->op_channel)) {
if (dev->flags & P2P_DEV_FORCE_FREQ) {
*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer does "
- "not support the forced channel");
+ p2p_dbg(p2p, "Peer does not support the forced channel");
return -1;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
- "channel (op_class %u channel %u) not acceptable to "
- "the peer", p2p->op_reg_class, p2p->op_channel);
+ p2p_dbg(p2p, "Selected operating channel (op_class %u channel %u) not acceptable to the peer",
+ p2p->op_reg_class, p2p->op_channel);
p2p_reselect_channel(p2p, &intersection);
} else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
!p2p->cfg->cfg_op_channel) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Try to optimize "
- "channel selection with peer information received; "
- "previously selected op_class %u channel %u",
+ p2p_dbg(p2p, "Try to optimize channel selection with peer information received; previously selected op_class %u channel %u",
p2p->op_reg_class, p2p->op_channel);
p2p_reselect_channel(p2p, &intersection);
}
@@ -503,17 +552,14 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
int tie_breaker = 0;
int freq;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GO Negotiation Request from " MACSTR
- "(freq=%d)", MAC2STR(sa), rx_freq);
+ p2p_dbg(p2p, "Received GO Negotiation Request from " MACSTR "(freq=%d)",
+ MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
return;
if (!msg.capability) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Capability attribute missing from GO "
- "Negotiation Request");
+ p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Request");
#ifdef CONFIG_P2P_STRICT
goto fail;
#endif /* CONFIG_P2P_STRICT */
@@ -522,53 +568,42 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
if (msg.go_intent)
tie_breaker = *msg.go_intent & 0x01;
else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory GO Intent attribute missing from GO "
- "Negotiation Request");
+ p2p_dbg(p2p, "Mandatory GO Intent attribute missing from GO Negotiation Request");
#ifdef CONFIG_P2P_STRICT
goto fail;
#endif /* CONFIG_P2P_STRICT */
}
if (!msg.config_timeout) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Configuration Timeout attribute "
- "missing from GO Negotiation Request");
+ p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Request");
#ifdef CONFIG_P2P_STRICT
goto fail;
#endif /* CONFIG_P2P_STRICT */
}
if (!msg.listen_channel) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen Channel attribute received");
+ p2p_dbg(p2p, "No Listen Channel attribute received");
goto fail;
}
if (!msg.operating_channel) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Operating Channel attribute received");
+ p2p_dbg(p2p, "No Operating Channel attribute received");
goto fail;
}
if (!msg.channel_list) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Channel List attribute received");
+ p2p_dbg(p2p, "No Channel List attribute received");
goto fail;
}
if (!msg.intended_addr) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Intended P2P Interface Address attribute "
- "received");
+ p2p_dbg(p2p, "No Intended P2P Interface Address attribute received");
goto fail;
}
if (!msg.p2p_device_info) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No P2P Device Info attribute received");
+ p2p_dbg(p2p, "No P2P Device Info attribute received");
goto fail;
}
if (os_memcmp(msg.p2p_device_addr, sa, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected GO Negotiation Request SA=" MACSTR
+ p2p_dbg(p2p, "Unexpected GO Negotiation Request SA=" MACSTR
" != dev_addr=" MACSTR,
MAC2STR(sa), MAC2STR(msg.p2p_device_addr));
goto fail;
@@ -577,133 +612,177 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
dev = p2p_get_device(p2p, sa);
if (msg.status && *msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected Status attribute (%d) in GO "
- "Negotiation Request", *msg.status);
+ p2p_dbg(p2p, "Unexpected Status attribute (%d) in GO Negotiation Request",
+ *msg.status);
+ if (dev && p2p->go_neg_peer == dev &&
+ *msg.status == P2P_SC_FAIL_REJECTED_BY_USER) {
+ /*
+ * This mechanism for using Status attribute in GO
+ * Negotiation Request is not compliant with the P2P
+ * specification, but some deployed devices use it to
+ * indicate rejection of GO Negotiation in a case where
+ * they have sent out GO Negotiation Response with
+ * status 1. The P2P specification explicitly disallows
+ * this. To avoid unnecessary interoperability issues
+ * and extra frames, mark the pending negotiation as
+ * failed and do not reply to this GO Negotiation
+ * Request frame.
+ */
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p_go_neg_failed(p2p, *msg.status);
+ p2p_parse_free(&msg);
+ return;
+ }
goto fail;
}
if (dev == NULL)
dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg);
- else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY)
+ else if ((dev->flags & P2P_DEV_PROBE_REQ_ONLY) ||
+ !(dev->flags & P2P_DEV_REPORTED))
p2p_add_dev_info(p2p, sa, dev, &msg);
+ else if (!dev->listen_freq && !dev->oper_freq) {
+ /*
+ * This may happen if the peer entry was added based on PD
+ * Request and no Probe Request/Response frame has been received
+ * from this peer (or that information has timed out).
+ */
+ p2p_dbg(p2p, "Update peer " MACSTR
+ " based on GO Neg Req since listen/oper freq not known",
+ MAC2STR(dev->info.p2p_device_addr));
+ p2p_add_dev_info(p2p, sa, dev, &msg);
+ }
+
+ if (p2p->go_neg_peer && p2p->go_neg_peer == dev)
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+
if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: User has rejected this peer");
+ p2p_dbg(p2p, "User has rejected this peer");
status = P2P_SC_FAIL_REJECTED_BY_USER;
- } else if (dev == NULL || dev->wps_method == WPS_NOT_READY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Not ready for GO negotiation with " MACSTR,
+ } else if (dev == NULL ||
+ (dev->wps_method == WPS_NOT_READY &&
+ (p2p->authorized_oob_dev_pw_id == 0 ||
+ p2p->authorized_oob_dev_pw_id !=
+ msg.dev_password_id))) {
+ p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
- if (dev)
- dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
p2p->cfg->go_neg_req_rx(p2p->cfg->cb_ctx, sa,
msg.dev_password_id);
} else if (p2p->go_neg_peer && p2p->go_neg_peer != dev) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Already in Group Formation with another peer");
+ p2p_dbg(p2p, "Already in Group Formation with another peer");
status = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
} else {
int go;
if (!p2p->go_neg_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting "
- "GO Negotiation with previously authorized "
- "peer");
+ p2p_dbg(p2p, "Starting GO Negotiation with previously authorized peer");
if (!(dev->flags & P2P_DEV_FORCE_FREQ)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Use default channel settings");
+ p2p_dbg(p2p, "Use default channel settings");
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
os_memcpy(&p2p->channels, &p2p->cfg->channels,
sizeof(struct p2p_channels));
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Use previously configured "
- "forced channel settings");
+ p2p_dbg(p2p, "Use previously configured forced channel settings");
}
}
dev->flags &= ~P2P_DEV_NOT_YET_READY;
if (!msg.go_intent) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No GO Intent attribute received");
+ p2p_dbg(p2p, "No GO Intent attribute received");
goto fail;
}
if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid GO Intent value (%u) received",
+ p2p_dbg(p2p, "Invalid GO Intent value (%u) received",
*msg.go_intent >> 1);
goto fail;
}
if (dev->go_neg_req_sent &&
os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Do not reply since peer has higher "
- "address and GO Neg Request already sent");
+ p2p_dbg(p2p, "Do not reply since peer has higher address and GO Neg Request already sent");
p2p_parse_free(&msg);
return;
}
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
if (go < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Incompatible GO Intent");
+ p2p_dbg(p2p, "Incompatible GO Intent");
status = P2P_SC_FAIL_BOTH_GO_INTENT_15;
goto fail;
}
if (p2p_peer_channels(p2p, dev, msg.channel_list,
msg.channel_list_len) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
+ p2p_dbg(p2p, "No common channels found");
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
switch (msg.dev_password_id) {
case DEV_PW_REGISTRAR_SPECIFIED:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: PIN from peer Display");
+ p2p_dbg(p2p, "PIN from peer Display");
if (dev->wps_method != WPS_PIN_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_USER_SPECIFIED:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer entered PIN on Keypad");
+ p2p_dbg(p2p, "Peer entered PIN on Keypad");
if (dev->wps_method != WPS_PIN_DISPLAY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_PUSHBUTTON:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer using pushbutton");
+ p2p_dbg(p2p, "Peer using pushbutton");
if (dev->wps_method != WPS_PBC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ case DEV_PW_P2PS_DEFAULT:
+ p2p_dbg(p2p, "Peer using P2PS pin");
+ if (dev->wps_method != WPS_P2PS) {
+ p2p_dbg(p2p,
+ "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
default:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported Device Password ID %d",
+ if (msg.dev_password_id &&
+ msg.dev_password_id == dev->oob_pw_id) {
+ p2p_dbg(p2p, "Peer using NFC");
+ if (dev->wps_method != WPS_NFC) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(
+ dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ }
+#ifdef CONFIG_WPS_NFC
+ if (p2p->authorized_oob_dev_pw_id &&
+ msg.dev_password_id ==
+ p2p->authorized_oob_dev_pw_id) {
+ p2p_dbg(p2p, "Using static handover with our device password from NFC Tag");
+ dev->wps_method = WPS_NFC;
+ dev->oob_pw_id = p2p->authorized_oob_dev_pw_id;
+ break;
+ }
+#endif /* CONFIG_WPS_NFC */
+ p2p_dbg(p2p, "Unsupported Device Password ID %d",
msg.dev_password_id);
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
@@ -713,20 +792,17 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
goto fail;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
- dev->oper_freq = p2p_channel_to_freq((const char *)
- msg.operating_channel,
- msg.operating_channel[3],
+ dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
msg.operating_channel[4]);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
- "channel preference: %d MHz", dev->oper_freq);
+ p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
+ dev->oper_freq);
if (msg.config_timeout) {
dev->go_timeout = msg.config_timeout[0];
dev->client_timeout = msg.config_timeout[1];
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation with " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
if (p2p->state != P2P_IDLE)
p2p_stop_find_for_freq(p2p, rx_freq);
p2p_set_state(p2p, P2P_GO_NEG);
@@ -734,6 +810,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
dev->dialog_token = msg.dialog_token;
os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
p2p->go_neg_peer = dev;
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
status = P2P_SC_SUCCESS;
}
@@ -745,17 +822,14 @@ fail:
p2p_parse_free(&msg);
if (resp == NULL)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending GO Negotiation Response");
+ p2p_dbg(p2p, "Sending GO Negotiation Response");
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
wpabuf_free(resp);
return;
}
@@ -778,9 +852,8 @@ fail:
P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 250) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(resp), wpabuf_len(resp), 500) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(resp);
@@ -798,14 +871,16 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
u8 group_capab;
size_t extra = 0;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Building GO Negotiation Confirm");
+ p2p_dbg(p2p, "Building GO Negotiation Confirm");
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
extra = wpabuf_len(p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -850,6 +925,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+
return buf;
}
@@ -858,20 +936,17 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
struct p2p_device *dev;
- struct wpabuf *conf;
int go = -1;
struct p2p_message msg;
u8 status = P2P_SC_SUCCESS;
int freq;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GO Negotiation Response from " MACSTR
+ p2p_dbg(p2p, "Received GO Negotiation Response from " MACSTR
" (freq=%d)", MAC2STR(sa), rx_freq);
dev = p2p_get_device(p2p, sa);
if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
dev != p2p->go_neg_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Not ready for GO negotiation with " MACSTR,
+ p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
return;
}
@@ -880,45 +955,42 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
return;
if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Was not expecting GO Negotiation Response - "
- "ignore");
+ p2p_dbg(p2p, "Was not expecting GO Negotiation Response - ignore");
p2p_parse_free(&msg);
return;
}
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
if (msg.dialog_token != dev->dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected Dialog Token %u (expected %u)",
+ p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
return;
}
if (!msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Status attribute received");
+ p2p_dbg(p2p, "No Status attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (*msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation rejected: status %d",
- *msg.status);
+ p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
dev->go_neg_req_sent = 0;
if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Wait for the peer to become ready for "
- "GO Negotiation");
+ p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
dev->flags |= P2P_DEV_NOT_YET_READY;
- dev->wait_count = 0;
- p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p,
+ NULL);
+ eloop_register_timeout(120, 0, p2p_go_neg_wait_timeout,
+ p2p, NULL);
+ if (p2p->state == P2P_CONNECT_LISTEN)
+ p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
+ else
+ p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
p2p_set_timeout(p2p, 0, 0);
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Stop GO Negotiation attempt");
- p2p_go_neg_failed(p2p, dev, *msg.status);
+ p2p_dbg(p2p, "Stop GO Negotiation attempt");
+ p2p_go_neg_failed(p2p, *msg.status);
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_parse_free(&msg);
@@ -926,9 +998,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
}
if (!msg.capability) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Capability attribute missing from GO "
- "Negotiation Response");
+ p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Response");
#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
@@ -936,9 +1006,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
}
if (!msg.p2p_device_info) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory P2P Device Info attribute missing "
- "from GO Negotiation Response");
+ p2p_dbg(p2p, "Mandatory P2P Device Info attribute missing from GO Negotiation Response");
#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
@@ -946,22 +1014,18 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
}
if (!msg.intended_addr) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Intended P2P Interface Address attribute "
- "received");
+ p2p_dbg(p2p, "No Intended P2P Interface Address attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (!msg.go_intent) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No GO Intent attribute received");
+ p2p_dbg(p2p, "No GO Intent attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid GO Intent value (%u) received",
+ p2p_dbg(p2p, "Invalid GO Intent value (%u) received",
*msg.go_intent >> 1);
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
@@ -969,8 +1033,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
if (go < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Incompatible GO Intent");
+ p2p_dbg(p2p, "Incompatible GO Intent");
status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
goto fail;
}
@@ -980,20 +1043,14 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p->ssid_len = msg.group_id_len - ETH_ALEN;
os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len);
} else if (!go) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory P2P Group ID attribute missing from "
- "GO Negotiation Response");
+ p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Response");
p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
-#endif /* CONFIG_P2P_STRICT */
}
if (!msg.config_timeout) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Configuration Timeout attribute "
- "missing from GO Negotiation Response");
+ p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Response");
#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
@@ -1008,76 +1065,81 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
* Note: P2P Client may omit Operating Channel attribute to
* indicate it does not have a preference.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Operating Channel attribute received");
+ p2p_dbg(p2p, "No Operating Channel attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (!msg.channel_list) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Channel List attribute received");
+ p2p_dbg(p2p, "No Channel List attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (p2p_peer_channels(p2p, dev, msg.channel_list,
msg.channel_list_len) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
+ p2p_dbg(p2p, "No common channels found");
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
if (msg.operating_channel) {
- dev->oper_freq = p2p_channel_to_freq((const char *)
- msg.operating_channel,
- msg.operating_channel[3],
+ dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
msg.operating_channel[4]);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
- "channel preference: %d MHz", dev->oper_freq);
+ p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
+ dev->oper_freq);
} else
dev->oper_freq = 0;
switch (msg.dev_password_id) {
case DEV_PW_REGISTRAR_SPECIFIED:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: PIN from peer Display");
+ p2p_dbg(p2p, "PIN from peer Display");
if (dev->wps_method != WPS_PIN_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_USER_SPECIFIED:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer entered PIN on Keypad");
+ p2p_dbg(p2p, "Peer entered PIN on Keypad");
if (dev->wps_method != WPS_PIN_DISPLAY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_PUSHBUTTON:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer using pushbutton");
+ p2p_dbg(p2p, "Peer using pushbutton");
if (dev->wps_method != WPS_PBC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ case DEV_PW_P2PS_DEFAULT:
+ p2p_dbg(p2p, "P2P: Peer using P2PS default pin");
+ if (dev->wps_method != WPS_P2PS) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
default:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported Device Password ID %d",
+ if (msg.dev_password_id &&
+ msg.dev_password_id == dev->oob_pw_id) {
+ p2p_dbg(p2p, "Peer using NFC");
+ if (dev->wps_method != WPS_NFC) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ }
+ p2p_dbg(p2p, "Unsupported Device Password ID %d",
msg.dev_password_id);
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
@@ -1089,18 +1151,19 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p_set_state(p2p, P2P_GO_NEG);
p2p_clear_timeout(p2p);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation with " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
fail:
- conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status,
- msg.operating_channel, go);
+ /* Store GO Negotiation Confirmation to allow retransmission */
+ wpabuf_free(dev->go_neg_conf);
+ dev->go_neg_conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token,
+ status, msg.operating_channel,
+ go);
p2p_parse_free(&msg);
- if (conf == NULL)
+ if (dev->go_neg_conf == NULL)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending GO Negotiation Confirm");
+ p2p_dbg(p2p, "Sending GO Negotiation Confirm");
if (status == P2P_SC_SUCCESS) {
p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
@@ -1110,13 +1173,22 @@ fail:
freq = rx_freq;
else
freq = dev->listen_freq;
+
+ dev->go_neg_conf_freq = freq;
+ dev->go_neg_conf_sent = 0;
+
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
- wpabuf_head(conf), wpabuf_len(conf), 0) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
- p2p_go_neg_failed(p2p, dev, -1);
+ wpabuf_head(dev->go_neg_conf),
+ wpabuf_len(dev->go_neg_conf), 200) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
+ p2p_go_neg_failed(p2p, -1);
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ } else
+ dev->go_neg_conf_sent++;
+ if (status != P2P_SC_SUCCESS) {
+ p2p_dbg(p2p, "GO Negotiation failed");
+ p2p_go_neg_failed(p2p, status);
}
- wpabuf_free(conf);
}
@@ -1126,22 +1198,18 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
struct p2p_device *dev;
struct p2p_message msg;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GO Negotiation Confirm from " MACSTR,
+ p2p_dbg(p2p, "Received GO Negotiation Confirm from " MACSTR,
MAC2STR(sa));
dev = p2p_get_device(p2p, sa);
if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
dev != p2p->go_neg_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Not ready for GO negotiation with " MACSTR,
+ p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
return;
}
if (p2p->pending_action_state == P2P_PENDING_GO_NEG_RESPONSE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopped waiting "
- "for TX status on GO Negotiation Response since we "
- "already received Confirmation");
+ p2p_dbg(p2p, "Stopped waiting for TX status on GO Negotiation Response since we already received Confirmation");
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
}
@@ -1149,31 +1217,28 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
return;
if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Was not expecting GO Negotiation Confirm - "
- "ignore");
+ p2p_dbg(p2p, "Was not expecting GO Negotiation Confirm - ignore");
+ p2p_parse_free(&msg);
return;
}
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (msg.dialog_token != dev->dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected Dialog Token %u (expected %u)",
+ p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
return;
}
if (!msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Status attribute received");
+ p2p_dbg(p2p, "No Status attribute received");
p2p_parse_free(&msg);
return;
}
if (*msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation rejected: status %d",
- *msg.status);
+ p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
+ p2p_go_neg_failed(p2p, *msg.status);
p2p_parse_free(&msg);
return;
}
@@ -1183,30 +1248,31 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
p2p->ssid_len = msg.group_id_len - ETH_ALEN;
os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len);
} else if (dev->go_state == REMOTE_GO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory P2P Group ID attribute missing from "
- "GO Negotiation Confirmation");
+ p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Confirmation");
p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
+ p2p_go_neg_failed(p2p, P2P_SC_FAIL_INVALID_PARAMS);
p2p_parse_free(&msg);
return;
-#endif /* CONFIG_P2P_STRICT */
}
if (!msg.operating_channel) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Operating Channel attribute missing "
- "from GO Negotiation Confirmation");
+ p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
#ifdef CONFIG_P2P_STRICT
p2p_parse_free(&msg);
return;
#endif /* CONFIG_P2P_STRICT */
+ } else if (dev->go_state == REMOTE_GO) {
+ int oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
+ msg.operating_channel[4]);
+ if (oper_freq != dev->oper_freq) {
+ p2p_dbg(p2p, "Updated peer (GO) operating channel preference from %d MHz to %d MHz",
+ dev->oper_freq, oper_freq);
+ dev->oper_freq = oper_freq;
+ }
}
if (!msg.channel_list) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Operating Channel attribute missing "
- "from GO Negotiation Confirmation");
+ p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
#ifdef CONFIG_P2P_STRICT
p2p_parse_free(&msg);
return;
@@ -1220,9 +1286,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
* This should not happen since GO negotiation has already
* been completed.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected GO Neg state - do not know which end "
- "becomes GO");
+ p2p_dbg(p2p, "Unexpected GO Neg state - do not know which end becomes GO");
return;
}
@@ -1234,8 +1298,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
* the group so that we will remain on the current channel to
* acknowledge any possible retransmission from the peer.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: 20 ms wait on current "
- "channel before starting group");
+ p2p_dbg(p2p, "20 ms wait on current channel before starting group");
os_sleep(0, 20000);
p2p_go_complete(p2p, dev);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 86873205b8301..41ca99faaf481 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
@@ -154,6 +155,7 @@ static void p2p_group_add_common_ies(struct p2p_group *group,
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (group->num_members >= group->cfg->max_clients)
group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT;
+ group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
p2p_buf_add_capability(ie, dev_capab, group_capab);
}
@@ -169,6 +171,39 @@ static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa)
}
+static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems)
+{
+ struct wpabuf *ie;
+ const u8 *pos, *end;
+ size_t len;
+
+ if (subelems == NULL)
+ return NULL;
+
+ len = wpabuf_len(subelems) + 100;
+
+ ie = wpabuf_alloc(len);
+ if (ie == NULL)
+ return NULL;
+
+ pos = wpabuf_head(subelems);
+ end = pos + wpabuf_len(subelems);
+
+ while (end > pos) {
+ size_t frag_len = end - pos;
+ if (frag_len > 251)
+ frag_len = 251;
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(ie, 4 + frag_len);
+ wpabuf_put_be32(ie, P2P_IE_VENDOR_TYPE);
+ wpabuf_put_data(ie, pos, frag_len);
+ pos += frag_len;
+ }
+
+ return ie;
+}
+
+
static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
{
struct wpabuf *ie;
@@ -180,6 +215,10 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
extra = wpabuf_len(group->p2p->wfd_ie_beacon);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO])
+ extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]);
+
ie = wpabuf_alloc(257 + extra);
if (ie == NULL)
return NULL;
@@ -189,6 +228,11 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO])
+ wpabuf_put_buf(ie,
+ group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]);
+
len = p2p_buf_add_ie_hdr(ie);
p2p_group_add_common_ies(group, ie);
p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
@@ -345,8 +389,8 @@ wifi_display_build_go_ie(struct p2p_group *group)
} else {
WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len -
2);
- wpa_printf(MSG_DEBUG, "WFD: WFD Session Info: %u descriptors",
- count);
+ p2p_dbg(group->p2p, "WFD: WFD Session Info: %u descriptors",
+ count);
}
wfd_ie = wifi_display_encaps(wfd_subelems);
@@ -364,46 +408,69 @@ static void wifi_display_group_update(struct p2p_group *group)
#endif /* CONFIG_WIFI_DISPLAY */
-static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
+void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf,
+ int max_clients)
{
u8 *group_info;
- struct wpabuf *ie;
+ int count = 0;
struct p2p_group_member *m;
- u8 *len;
- size_t extra = 0;
-#ifdef CONFIG_WIFI_DISPLAY
- if (group->wfd_ie)
- extra += wpabuf_len(group->wfd_ie);
-#endif /* CONFIG_WIFI_DISPLAY */
+ p2p_dbg(group->p2p, "* P2P Group Info");
+ group_info = wpabuf_put(buf, 0);
+ wpabuf_put_u8(buf, P2P_ATTR_GROUP_INFO);
+ wpabuf_put_le16(buf, 0); /* Length to be filled */
+ for (m = group->members; m; m = m->next) {
+ p2p_client_info(buf, m);
+ count++;
+ if (max_clients >= 0 && count >= max_clients)
+ break;
+ }
+ WPA_PUT_LE16(group_info + 1,
+ (u8 *) wpabuf_put(buf, 0) - group_info - 3);
+}
- ie = wpabuf_alloc(257 + extra);
- if (ie == NULL)
- return NULL;
-#ifdef CONFIG_WIFI_DISPLAY
- if (group->wfd_ie)
- wpabuf_put_buf(ie, group->wfd_ie);
-#endif /* CONFIG_WIFI_DISPLAY */
+void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf)
+{
+ p2p_buf_add_group_id(buf, group->p2p->cfg->dev_addr, group->cfg->ssid,
+ group->cfg->ssid_len);
+}
- len = p2p_buf_add_ie_hdr(ie);
- p2p_group_add_common_ies(group, ie);
- p2p_group_add_noa(ie, group->noa);
+static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
+{
+ struct wpabuf *p2p_subelems, *ie;
+
+ p2p_subelems = wpabuf_alloc(500);
+ if (p2p_subelems == NULL)
+ return NULL;
+
+ p2p_group_add_common_ies(group, p2p_subelems);
+ p2p_group_add_noa(p2p_subelems, group->noa);
/* P2P Device Info */
- p2p_buf_add_device_info(ie, group->p2p, NULL);
-
- /* P2P Group Info */
- group_info = wpabuf_put(ie, 0);
- wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO);
- wpabuf_put_le16(ie, 0); /* Length to be filled */
- for (m = group->members; m; m = m->next)
- p2p_client_info(ie, m);
- WPA_PUT_LE16(group_info + 1,
- (u8 *) wpabuf_put(ie, 0) - group_info - 3);
+ p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
- p2p_buf_update_ie_hdr(ie, len);
+ /* P2P Group Info: Only when at least one P2P Client is connected */
+ if (group->members)
+ p2p_buf_add_group_info(group, p2p_subelems, -1);
+
+ ie = p2p_group_encaps_probe_resp(p2p_subelems);
+ wpabuf_free(p2p_subelems);
+
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]) {
+ struct wpabuf *extra;
+ extra = wpabuf_dup(group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]);
+ ie = wpabuf_concat(extra, ie);
+ }
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie) {
+ struct wpabuf *wfd = wpabuf_dup(group->wfd_ie);
+ ie = wpabuf_concat(wfd, ie);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
return ie;
}
@@ -537,6 +604,8 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
if (group == NULL)
return -1;
+ p2p_add_device(group->p2p, addr, 0, NULL, 0, ie, len, 0);
+
m = os_zalloc(sizeof(*m));
if (m == NULL)
return -1;
@@ -556,7 +625,7 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
m->next = group->members;
group->members = m;
group->num_members++;
- wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
+ p2p_dbg(group->p2p, "Add client " MACSTR
" to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u",
MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0,
m->client_info ? 1 : 0,
@@ -582,6 +651,10 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
extra = wpabuf_len(group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP])
+ extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]);
+
/*
* (Re)Association Response - P2P IE
* Status attribute (shall be present when association request is
@@ -597,6 +670,11 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
wpabuf_put_buf(resp, group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP])
+ wpabuf_put_buf(resp,
+ group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]);
+
rlen = p2p_buf_add_ie_hdr(resp);
if (status != P2P_SC_SUCCESS)
p2p_buf_add_status(resp, status);
@@ -609,8 +687,8 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
{
if (p2p_group_remove_member(group, addr)) {
- wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove "
- "client " MACSTR " from group; num_members=%u/%u",
+ p2p_dbg(group->p2p, "Remove client " MACSTR
+ " from group; num_members=%u/%u",
MAC2STR(addr), group->num_members,
group->cfg->max_clients);
if (group->num_members == group->cfg->max_clients - 1)
@@ -822,20 +900,18 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
m = p2p_group_get_client(group, dev_id);
if (m == NULL || m->client_info == NULL) {
- wpa_printf(MSG_DEBUG, "P2P: Requested client was not in this "
- "group " MACSTR,
- MAC2STR(group->cfg->interface_addr));
+ p2p_dbg(group->p2p, "Requested client was not in this group "
+ MACSTR, MAC2STR(group->cfg->interface_addr));
return -1;
}
if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
- wpa_printf(MSG_DEBUG, "P2P: Requested client does not support "
- "client discoverability");
+ p2p_dbg(group->p2p, "Requested client does not support client discoverability");
return -1;
}
- wpa_printf(MSG_DEBUG, "P2P: Schedule GO Discoverability Request to be "
- "sent to " MACSTR, MAC2STR(dev_id));
+ p2p_dbg(group->p2p, "Schedule GO Discoverability Request to be sent to "
+ MACSTR, MAC2STR(dev_id));
req = p2p_build_go_disc_req();
if (req == NULL)
@@ -850,8 +926,7 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
group->cfg->interface_addr,
wpabuf_head(req), wpabuf_len(req), 200) < 0)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(req);
@@ -876,7 +951,7 @@ u8 p2p_group_presence_req(struct p2p_group *group,
m = p2p_group_get_client_iface(group, client_interface_addr);
if (m == NULL || m->client_info == NULL) {
- wpa_printf(MSG_DEBUG, "P2P: Client was not in this group");
+ p2p_dbg(group->p2p, "Client was not in this group");
return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
}
@@ -889,9 +964,9 @@ u8 p2p_group_presence_req(struct p2p_group *group,
else
curr_noa_len = -1;
if (curr_noa_len < 0)
- wpa_printf(MSG_DEBUG, "P2P: Failed to fetch current NoA");
+ p2p_dbg(group->p2p, "Failed to fetch current NoA");
else if (curr_noa_len == 0)
- wpa_printf(MSG_DEBUG, "P2P: No NoA being advertized");
+ p2p_dbg(group->p2p, "No NoA being advertized");
else
wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
curr_noa_len);
@@ -906,10 +981,22 @@ u8 p2p_group_presence_req(struct p2p_group *group,
unsigned int p2p_get_group_num_members(struct p2p_group *group)
{
+ if (!group)
+ return 0;
+
return group->num_members;
}
+int p2p_client_limit_reached(struct p2p_group *group)
+{
+ if (!group || !group->cfg)
+ return 1;
+
+ return group->num_members >= group->cfg->max_clients;
+}
+
+
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
{
struct p2p_group_member *iter = *next;
@@ -924,7 +1011,7 @@ const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
if (!iter)
return NULL;
- return iter->addr;
+ return iter->dev_addr;
}
@@ -951,3 +1038,36 @@ int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
group->cfg->ssid_len) == 0;
}
+
+
+void p2p_group_force_beacon_update_ies(struct p2p_group *group)
+{
+ group->beacon_update = 1;
+ p2p_group_update_ies(group);
+}
+
+
+int p2p_group_get_freq(struct p2p_group *group)
+{
+ return group->cfg->freq;
+}
+
+
+const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group)
+{
+ return group->cfg;
+}
+
+
+void p2p_loop_on_all_groups(struct p2p_data *p2p,
+ int (*group_callback)(struct p2p_group *group,
+ void *user_data),
+ void *user_data)
+{
+ unsigned int i;
+
+ for (i = 0; i < p2p->num_groups; i++) {
+ if (!group_callback(p2p->groups[i], user_data))
+ break;
+ }
+}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 27fef0182941a..6af19ceda450e 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -12,6 +12,17 @@
#include "utils/list.h"
#include "p2p.h"
+#define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1
+
+enum p2p_role_indication;
+
+/*
+ * To force Service Instances to fit within a single P2P Tag, MAX_SVC_ADV_LEN
+ * must equal 248 or less. Must have a minimum size of 19.
+ */
+#define MAX_SVC_ADV_LEN 600
+#define MAX_SVC_ADV_IE_LEN (9 + MAX_SVC_ADV_LEN + (5 * (MAX_SVC_ADV_LEN / 240)))
+
enum p2p_go_state {
UNKNOWN_GO,
LOCAL_GO,
@@ -23,9 +34,11 @@ enum p2p_go_state {
*/
struct p2p_device {
struct dl_list list;
- struct os_time last_seen;
+ struct os_reltime last_seen;
int listen_freq;
+ int oob_go_neg_freq;
enum p2p_wps_method wps_method;
+ u16 oob_pw_id;
struct p2p_peer_info info;
@@ -52,6 +65,7 @@ struct p2p_device {
int go_neg_req_sent;
enum p2p_go_state go_state;
u8 dialog_token;
+ u8 tie_breaker;
u8 intended_addr[ETH_ALEN];
char country[3];
@@ -76,8 +90,6 @@ struct p2p_device {
#define P2P_DEV_PROBE_REQ_ONLY BIT(0)
#define P2P_DEV_REPORTED BIT(1)
#define P2P_DEV_NOT_YET_READY BIT(2)
-#define P2P_DEV_SD_INFO BIT(3)
-#define P2P_DEV_SD_SCHEDULE BIT(4)
#define P2P_DEV_PD_PEER_DISPLAY BIT(5)
#define P2P_DEV_PD_PEER_KEYPAD BIT(6)
#define P2P_DEV_USER_REJECTED BIT(7)
@@ -91,18 +103,40 @@ struct p2p_device {
#define P2P_DEV_REPORTED_ONCE BIT(15)
#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
#define P2P_DEV_PD_BEFORE_GO_NEG BIT(17)
+#define P2P_DEV_NO_PREF_CHAN BIT(18)
+#define P2P_DEV_WAIT_INV_REQ_ACK BIT(19)
+#define P2P_DEV_P2PS_REPORTED BIT(20)
+#define P2P_DEV_PD_PEER_P2PS BIT(21)
unsigned int flags;
int status; /* enum p2p_status_code */
unsigned int wait_count;
unsigned int connect_reqs;
unsigned int invitation_reqs;
+ unsigned int sd_reqs;
u16 ext_listen_period;
u16 ext_listen_interval;
u8 go_timeout;
u8 client_timeout;
+
+ /**
+ * go_neg_conf_sent - Number of GO Negotiation Confirmation retries
+ */
+ u8 go_neg_conf_sent;
+
+ /**
+ * freq - Frquency on which the GO Negotiation Confirmation is sent
+ */
+ int go_neg_conf_freq;
+
+ /**
+ * go_neg_conf - GO Negotiation Confirmation frame
+ */
+ struct wpabuf *go_neg_conf;
+
+ int sd_pending_bcast_queries;
};
struct p2p_sd_query {
@@ -203,16 +237,6 @@ struct p2p_data {
* P2P_INVITE_LISTEN - Listen during Invite
*/
P2P_INVITE_LISTEN,
-
- /**
- * P2P_SEARCH_WHEN_READY - Waiting to start Search
- */
- P2P_SEARCH_WHEN_READY,
-
- /**
- * P2P_CONTINUE_SEARCH_WHEN_READY - Waiting to continue Search
- */
- P2P_CONTINUE_SEARCH_WHEN_READY,
} state;
/**
@@ -245,8 +269,17 @@ struct p2p_data {
*/
struct p2p_device *invite_peer;
+ /**
+ * last_p2p_find_oper - Pointer to last pre-find operation peer
+ */
+ struct p2p_device *last_p2p_find_oper;
+
const u8 *invite_go_dev_addr;
u8 invite_go_dev_addr_buf[ETH_ALEN];
+ int invite_dev_pw_id;
+
+ unsigned int retry_invite_req:1;
+ unsigned int retry_invite_req_sent:1;
/**
* sd_peer - Pointer to Service Discovery peer
@@ -258,6 +291,12 @@ struct p2p_data {
*/
struct p2p_sd_query *sd_query;
+ /**
+ * num_p2p_sd_queries - Total number of broadcast SD queries present in
+ * the list
+ */
+ int num_p2p_sd_queries;
+
/* GO Negotiation data */
/**
@@ -314,6 +353,8 @@ struct p2p_data {
*/
struct p2p_channels channels;
+ struct wpa_freq_range_list no_go_freq;
+
enum p2p_pending_action_state {
P2P_NO_PENDING_ACTION,
P2P_PENDING_GO_NEG_REQUEST,
@@ -322,6 +363,7 @@ struct p2p_data {
P2P_PENDING_GO_NEG_CONFIRM,
P2P_PENDING_SD,
P2P_PENDING_PD,
+ P2P_PENDING_PD_RESPONSE,
P2P_PENDING_INVITATION_REQUEST,
P2P_PENDING_INVITATION_RESPONSE,
P2P_PENDING_DEV_DISC_REQUEST,
@@ -383,6 +425,8 @@ struct p2p_data {
} start_after_scan;
u8 after_scan_peer[ETH_ALEN];
struct p2p_pending_action_tx *after_scan_tx;
+ unsigned int after_scan_tx_in_progress:1;
+ unsigned int send_action_in_progress:1;
/* Requested device types for find/search */
unsigned int num_req_dev_types;
@@ -390,6 +434,8 @@ struct p2p_data {
u8 *find_dev_id;
u8 find_dev_id_buf[ETH_ALEN];
+ struct os_reltime find_start; /* time of last p2p_find start */
+
struct p2p_group **groups;
size_t num_groups;
@@ -413,6 +459,7 @@ struct p2p_data {
int best_freq_24;
int best_freq_5;
int best_freq_overall;
+ int own_freq_preference;
/**
* wps_vendor_ext - WPS Vendor Extensions to add
@@ -436,6 +483,14 @@ struct p2p_data {
*/
int pd_retries;
+ /**
+ * pd_force_freq - Forced frequency for PD retries or 0 to auto-select
+ *
+ * This is is used during PD retries for join-a-group case to use the
+ * correct operating frequency determined from a BSS entry for the GO.
+ */
+ int pd_force_freq;
+
u8 go_timeout;
u8 client_timeout;
@@ -443,6 +498,20 @@ struct p2p_data {
unsigned int search_delay;
int in_search_delay;
+ u8 pending_reg_class;
+ u8 pending_channel;
+ u8 pending_channel_forced;
+
+ /* ASP Support */
+ struct p2ps_advertisement *p2ps_adv_list;
+ struct p2ps_provision *p2ps_prov;
+ u8 wild_card_hash[P2PS_HASH_LEN];
+ u8 query_hash[P2P_MAX_QUERY_HASH * P2PS_HASH_LEN];
+ u8 query_count;
+ u8 p2ps_seek;
+ u8 p2ps_seek_count;
+ u8 p2ps_svc_found;
+
#ifdef CONFIG_WIFI_DISPLAY
struct wpabuf *wfd_ie_beacon;
struct wpabuf *wfd_ie_probe_req;
@@ -456,6 +525,10 @@ struct p2p_data {
struct wpabuf *wfd_assoc_bssid;
struct wpabuf *wfd_coupled_sink_info;
#endif /* CONFIG_WIFI_DISPLAY */
+
+ u16 authorized_oob_dev_pw_id;
+
+ struct wpabuf **vendor_elem;
};
/**
@@ -497,6 +570,8 @@ struct p2p_message {
const u8 *minor_reason_code;
+ const u8 *oob_go_neg_channel;
+
/* P2P Device Info */
const u8 *p2p_device_info;
size_t p2p_device_info_len;
@@ -508,6 +583,7 @@ struct p2p_message {
/* WPS IE */
u16 dev_password_id;
+ int dev_password_id_present;
u16 wps_config_methods;
const u8 *wps_pri_dev_type;
const u8 *wps_sec_dev_type_list;
@@ -522,12 +598,39 @@ struct p2p_message {
size_t model_number_len;
const u8 *serial_number;
size_t serial_number_len;
+ const u8 *oob_dev_password;
+ size_t oob_dev_password_len;
/* DS Parameter Set IE */
const u8 *ds_params;
/* SSID IE */
const u8 *ssid;
+
+ /* P2PS */
+ u8 service_hash_count;
+ const u8 *service_hash;
+
+ const u8 *session_info;
+ size_t session_info_len;
+
+ const u8 *conn_cap;
+
+ const u8 *adv_id;
+ const u8 *adv_mac;
+
+ const u8 *adv_service_instance;
+ size_t adv_service_instance_len;
+
+ const u8 *session_id;
+ const u8 *session_mac;
+
+ const u8 *feature_cap;
+ size_t feature_cap_len;
+
+ const u8 *persistent_dev;
+ const u8 *persistent_ssid;
+ size_t persistent_ssid_len;
};
@@ -551,19 +654,33 @@ struct p2p_group_info {
/* p2p_utils.c */
int p2p_random(char *buf, size_t len);
-int p2p_channel_to_freq(const char *country, int reg_class, int channel);
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
- u8 *channel);
+int p2p_channel_to_freq(int op_class, int channel);
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
void p2p_channels_intersect(const struct p2p_channels *a,
const struct p2p_channels *b,
struct p2p_channels *res);
+void p2p_channels_union_inplace(struct p2p_channels *res,
+ const struct p2p_channels *b);
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res);
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+ const struct wpa_freq_range_list *list);
int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
u8 channel);
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+ const struct p2p_channels *chan);
+int p2p_channel_select(struct p2p_channels *chans, const int *classes,
+ u8 *op_class, u8 *op_channel);
+int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
+ u8 *op_channel);
/* p2p_parse.c */
int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg);
int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg);
int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg);
+int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p,
+ size_t p2p_len, struct p2p_message *msg);
void p2p_parse_free(struct p2p_message *msg);
int p2p_attr_text(struct wpabuf *data, char *buf, char *end);
int p2p_group_info_parse(const u8 *gi, size_t gi_len,
@@ -586,7 +703,12 @@ u8 p2p_group_presence_req(struct p2p_group *group,
int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
size_t group_id_len);
void p2p_group_update_ies(struct p2p_group *group);
+void p2p_group_force_beacon_update_ies(struct p2p_group *group);
struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g);
+void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf,
+ int max_clients);
+void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf);
+int p2p_group_get_freq(struct p2p_group *group);
void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
@@ -618,8 +740,23 @@ void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
u16 interval);
void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p);
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
- int all_attr);
+void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
+ u8 oper_class, u8 channel,
+ enum p2p_role_indication role);
+void p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p);
+void p2p_buf_add_session_info(struct wpabuf *buf, const char *info);
+void p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap);
+void p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac);
+void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
+ u8 count, const u8 *hash,
+ struct p2ps_advertisement *adv_list);
+void p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac);
+void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len,
+ const u8 *mask);
+void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
+ const u8 *ssid, size_t ssid_len);
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+ int all_attr);
/* p2p_sd.c */
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
@@ -665,7 +802,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len);
int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
- const u8 *go_dev_addr);
+ const u8 *go_dev_addr, int dev_pw_id);
void p2p_invitation_req_cb(struct p2p_data *p2p, int success);
void p2p_invitation_resp_cb(struct p2p_data *p2p, int success);
@@ -693,13 +830,12 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
struct p2p_device *dev, struct p2p_message *msg);
int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
- unsigned int age_ms, int level, const u8 *ies,
+ struct os_reltime *rx_time, int level, const u8 *ies,
size_t ies_len, int scan_res);
struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
const u8 *addr);
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
- int status);
+void p2p_go_neg_failed(struct p2p_data *p2p, int status);
void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer);
int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps);
int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
@@ -710,5 +846,17 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
size_t len, unsigned int wait_time);
void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ unsigned int force_freq, unsigned int pref_freq,
+ int go);
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ u8 *status);
+void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+void p2p_err(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
#endif /* P2P_I_H */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 983dd6b36e405..558c6dd0c58fa 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -10,13 +10,15 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "p2p_i.h"
#include "p2p.h"
static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
struct p2p_device *peer,
- const u8 *go_dev_addr)
+ const u8 *go_dev_addr,
+ int dev_pw_id)
{
struct wpabuf *buf;
u8 *len;
@@ -44,6 +46,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
extra = wpabuf_len(wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -62,8 +67,11 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
p2p->client_timeout);
p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ?
P2P_INVITATION_FLAGS_TYPE : 0);
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
- p2p->op_reg_class, p2p->op_channel);
+ if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT ||
+ !(peer->flags & P2P_DEV_NO_PREF_CHAN))
+ p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p->op_reg_class,
+ p2p->op_channel);
if (p2p->inv_bssid_set)
p2p_buf_add_group_bssid(buf, p2p->inv_bssid);
p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
@@ -82,6 +90,14 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
wpabuf_put_buf(buf, wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
+
+ if (dev_pw_id >= 0) {
+ /* WSC IE in Invitation Request for NFC static handover */
+ p2p_build_wps_ie(p2p, buf, dev_pw_id, 0);
+ }
+
return buf;
}
@@ -158,13 +174,12 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
u8 group_bssid[ETH_ALEN], *bssid;
int op_freq = 0;
u8 reg_class = 0, channel = 0;
- struct p2p_channels intersection, *channels = NULL;
+ struct p2p_channels all_channels, intersection, *channels = NULL;
int persistent;
os_memset(group_bssid, 0, sizeof(group_bssid));
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Invitation Request from " MACSTR " (freq=%d)",
+ p2p_dbg(p2p, "Received Invitation Request from " MACSTR " (freq=%d)",
MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
@@ -172,14 +187,12 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
dev = p2p_get_device(p2p, sa);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Request from unknown peer "
- MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Invitation Request from unknown peer " MACSTR,
+ MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
0)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Request add device failed "
+ p2p_dbg(p2p, "Invitation Request add device failed "
MACSTR, MAC2STR(sa));
status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
goto fail;
@@ -187,18 +200,16 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
dev = p2p_get_device(p2p, sa);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Reject Invitation Request from unknown "
- "peer " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Reject Invitation Request from unknown peer "
+ MACSTR, MAC2STR(sa));
status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
goto fail;
}
}
if (!msg.group_id || !msg.channel_list) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory attribute missing in Invitation "
- "Request from " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Mandatory attribute missing in Invitation Request from "
+ MACSTR, MAC2STR(sa));
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
@@ -211,46 +222,61 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
* the request was for a persistent group if the attribute is
* missing.
*/
- wpa_printf(MSG_DEBUG, "P2P: Mandatory Invitation Flags "
- "attribute missing from Invitation Request");
+ p2p_dbg(p2p, "Mandatory Invitation Flags attribute missing from Invitation Request");
persistent = 1;
}
- if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev,
+ p2p_channels_union(&p2p->cfg->channels, &p2p->cfg->cli_channels,
+ &all_channels);
+
+ if (p2p_peer_channels_check(p2p, &all_channels, dev,
msg.channel_list, msg.channel_list_len) <
0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
+ p2p_dbg(p2p, "No common channels found");
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
+ p2p_channels_dump(p2p, "own channels", &p2p->cfg->channels);
+ p2p_channels_dump(p2p, "own client channels", &all_channels);
+ p2p_channels_dump(p2p, "peer channels", &dev->channels);
+ p2p_channels_intersect(&all_channels, &dev->channels,
+ &intersection);
+ p2p_channels_dump(p2p, "intersection", &intersection);
+
if (p2p->cfg->invitation_process) {
status = p2p->cfg->invitation_process(
p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id,
msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
- &go, group_bssid, &op_freq, persistent);
+ &go, group_bssid, &op_freq, persistent, &intersection,
+ msg.dev_password_id_present ? msg.dev_password_id : -1);
+ }
+
+ if (go) {
+ p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+ &intersection);
+ p2p_channels_dump(p2p, "intersection(GO)", &intersection);
+ if (intersection.reg_classes == 0) {
+ p2p_dbg(p2p, "No common channels found (GO)");
+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ goto fail;
+ }
}
if (op_freq) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invitation "
- "processing forced frequency %d MHz", op_freq);
- if (p2p_freq_to_channel(p2p->cfg->country, op_freq,
- &reg_class, &channel) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown forced freq %d MHz from "
- "invitation_process()", op_freq);
+ p2p_dbg(p2p, "Invitation processing forced frequency %d MHz",
+ op_freq);
+ if (p2p_freq_to_channel(op_freq, &reg_class, &channel) < 0) {
+ p2p_dbg(p2p, "Unknown forced freq %d MHz from invitation_process()",
+ op_freq);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
- &intersection);
if (!p2p_channels_includes(&intersection, reg_class, channel))
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: forced freq %d MHz not in the supported "
- "channels interaction", op_freq);
+ p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
+ op_freq);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
@@ -258,28 +284,21 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
if (status == P2P_SC_SUCCESS)
channels = &intersection;
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No forced channel from invitation processing - "
- "figure out best one to use");
+ p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use");
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
- &intersection);
/* Default to own configuration as a starting point */
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own default "
- "op_class %d channel %d",
+ p2p_dbg(p2p, "Own default op_class %d channel %d",
p2p->op_reg_class, p2p->op_channel);
/* Use peer preference if specified and compatible */
if (msg.operating_channel) {
int req_freq;
req_freq = p2p_channel_to_freq(
- (const char *) msg.operating_channel,
msg.operating_channel[3],
msg.operating_channel[4]);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer "
- "operating channel preference: %d MHz",
+ p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
req_freq);
if (req_freq > 0 &&
p2p_channels_includes(&intersection,
@@ -287,56 +306,47 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
msg.operating_channel[4])) {
p2p->op_reg_class = msg.operating_channel[3];
p2p->op_channel = msg.operating_channel[4];
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Use peer preference op_class %d "
- "channel %d",
+ p2p_dbg(p2p, "Use peer preference op_class %d channel %d",
p2p->op_reg_class, p2p->op_channel);
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot use peer channel "
- "preference");
+ p2p_dbg(p2p, "Cannot use peer channel preference");
}
}
- if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
+ /* Reselect the channel only for the case of the GO */
+ if (go &&
+ !p2p_channels_includes(&intersection, p2p->op_reg_class,
p2p->op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Initially selected channel (op_class %d "
- "channel %d) not in channel intersection - try "
- "to reselect",
+ p2p_dbg(p2p, "Initially selected channel (op_class %d channel %d) not in channel intersection - try to reselect",
p2p->op_reg_class, p2p->op_channel);
p2p_reselect_channel(p2p, &intersection);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Re-selection result: op_class %d "
- "channel %d",
+ p2p_dbg(p2p, "Re-selection result: op_class %d channel %d",
p2p->op_reg_class, p2p->op_channel);
if (!p2p_channels_includes(&intersection,
p2p->op_reg_class,
p2p->op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer does not support selected "
- "operating channel (reg_class=%u "
- "channel=%u)",
+ p2p_dbg(p2p, "Peer does not support selected operating channel (reg_class=%u channel=%u)",
p2p->op_reg_class, p2p->op_channel);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
+ } else if (go && !(dev->flags & P2P_DEV_FORCE_FREQ) &&
+ !p2p->cfg->cfg_op_channel) {
+ p2p_dbg(p2p, "Try to reselect channel selection with peer information received; previously selected op_class %u channel %u",
+ p2p->op_reg_class, p2p->op_channel);
+ p2p_reselect_channel(p2p, &intersection);
}
- op_freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->op_reg_class,
+ op_freq = p2p_channel_to_freq(p2p->op_reg_class,
p2p->op_channel);
if (op_freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown operational channel "
- "(country=%c%c reg_class=%u channel=%u)",
+ p2p_dbg(p2p, "Unknown operational channel (country=%c%c reg_class=%u channel=%u)",
p2p->cfg->country[0], p2p->cfg->country[1],
p2p->op_reg_class, p2p->op_channel);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
- "channel - %d MHz", op_freq);
+ p2p_dbg(p2p, "Selected operating channel - %d MHz", op_freq);
if (status == P2P_SC_SUCCESS) {
reg_class = p2p->op_reg_class;
@@ -359,12 +369,10 @@ fail:
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
goto out;
}
@@ -378,12 +386,17 @@ fail:
p2p->inv_group_bssid_ptr = p2p->inv_group_bssid;
} else
p2p->inv_group_bssid_ptr = NULL;
- if (msg.group_id_len - ETH_ALEN <= 32) {
- os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN,
- msg.group_id_len - ETH_ALEN);
- p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN;
+ if (msg.group_id) {
+ if (msg.group_id_len - ETH_ALEN <= 32) {
+ os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN,
+ msg.group_id_len - ETH_ALEN);
+ p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN;
+ }
+ os_memcpy(p2p->inv_go_dev_addr, msg.group_id, ETH_ALEN);
+ } else {
+ p2p->inv_ssid_len = 0;
+ os_memset(p2p->inv_go_dev_addr, 0, ETH_ALEN);
}
- os_memcpy(p2p->inv_go_dev_addr, msg.group_id, ETH_ALEN);
p2p->inv_status = status;
p2p->inv_op_freq = op_freq;
@@ -391,8 +404,7 @@ fail:
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
out:
@@ -406,40 +418,120 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
{
struct p2p_device *dev;
struct p2p_message msg;
+ struct p2p_channels intersection, *channels = NULL;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Invitation Response from " MACSTR,
+ p2p_dbg(p2p, "Received Invitation Response from " MACSTR,
MAC2STR(sa));
dev = p2p_get_device(p2p, sa);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore Invitation Response from unknown peer "
+ p2p_dbg(p2p, "Ignore Invitation Response from unknown peer "
MACSTR, MAC2STR(sa));
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
if (dev != p2p->invite_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore unexpected Invitation Response from peer "
+ p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer "
MACSTR, MAC2STR(sa));
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
- if (p2p_parse(data, len, &msg))
+ if (p2p_parse(data, len, &msg)) {
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
+ }
if (!msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Status attribute missing in "
- "Invitation Response from " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from "
+ MACSTR, MAC2STR(sa));
p2p_parse_free(&msg);
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
- if (p2p->cfg->invitation_result)
+ /*
+ * We should not really receive a replayed response twice since
+ * duplicate frames are supposed to be dropped. However, not all drivers
+ * do that for pre-association frames. We did not use to verify dialog
+ * token matches for invitation response frames, but that check can be
+ * safely used to drop a replayed response to the previous Invitation
+ * Request in case the suggested operating channel was changed. This
+ * allows a duplicated reject frame to be dropped with the assumption
+ * that the real response follows after it.
+ */
+ if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+ p2p->retry_invite_req_sent &&
+ msg.dialog_token != dev->dialog_token) {
+ p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
+ msg.dialog_token, dev->dialog_token);
+ p2p_parse_free(&msg);
+ return;
+ }
+
+ if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+ p2p->retry_invite_req &&
+ p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class,
+ &p2p->op_channel) == 0) {
+ p2p->retry_invite_req = 0;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ p2p_set_state(p2p, P2P_INVITE);
+ p2p_dbg(p2p, "Resend Invitation Request setting op_class %u channel %u as operating channel",
+ p2p->op_reg_class, p2p->op_channel);
+ p2p->retry_invite_req_sent = 1;
+ p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
+ p2p->invite_dev_pw_id);
+ p2p_parse_free(&msg);
+ return;
+ }
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->retry_invite_req = 0;
+
+ if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) {
+ p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
+ MACSTR, MAC2STR(sa));
+#ifdef CONFIG_P2P_STRICT
+ p2p_parse_free(&msg);
+ return;
+#endif /* CONFIG_P2P_STRICT */
+ /* Try to survive without peer channel list */
+ channels = &p2p->channels;
+ } else if (!msg.channel_list) {
+ /* Non-success cases are not required to include Channel List */
+ channels = &p2p->channels;
+ } else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
+ msg.channel_list,
+ msg.channel_list_len) < 0) {
+ p2p_dbg(p2p, "No common channels found");
+ p2p_parse_free(&msg);
+ return;
+ } else {
+ p2p_channels_intersect(&p2p->channels, &dev->channels,
+ &intersection);
+ channels = &intersection;
+ }
+
+ if (p2p->cfg->invitation_result) {
+ int peer_oper_freq = 0;
+ int freq = p2p_channel_to_freq(p2p->op_reg_class,
+ p2p->op_channel);
+ if (freq < 0)
+ freq = 0;
+
+ if (msg.operating_channel) {
+ peer_oper_freq = p2p_channel_to_freq(
+ msg.operating_channel[3],
+ msg.operating_channel[4]);
+ if (peer_oper_freq < 0)
+ peer_oper_freq = 0;
+ }
+
p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
- msg.group_bssid);
+ msg.group_bssid, channels, sa,
+ freq, peer_oper_freq);
+ }
p2p_parse_free(&msg);
@@ -450,38 +542,39 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
- const u8 *go_dev_addr)
+ const u8 *go_dev_addr, int dev_pw_id)
{
struct wpabuf *req;
int freq;
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+ if (freq <= 0)
+ freq = dev->oob_go_neg_freq;
if (freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen/Operating frequency known for the "
- "peer " MACSTR " to send Invitation Request",
+ p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+ MACSTR " to send Invitation Request",
MAC2STR(dev->info.p2p_device_addr));
return -1;
}
- req = p2p_build_invitation_req(p2p, dev, go_dev_addr);
+ req = p2p_build_invitation_req(p2p, dev, go_dev_addr, dev_pw_id);
if (req == NULL)
return -1;
if (p2p->state != P2P_IDLE)
p2p_stop_listen_for_freq(p2p, freq);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending Invitation Request");
+ p2p_dbg(p2p, "Sending Invitation Request");
p2p_set_state(p2p, P2P_INVITE);
p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST;
p2p->invite_peer = dev;
dev->invitation_reqs++;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(req), wpabuf_len(req), 500) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
/* Use P2P find to recover and retry */
p2p_set_timeout(p2p, 0, 0);
+ } else {
+ dev->flags |= P2P_DEV_WAIT_INV_REQ_ACK;
}
wpabuf_free(req);
@@ -492,31 +585,34 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
void p2p_invitation_req_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Request TX callback: success=%d", success);
+ p2p_dbg(p2p, "Invitation Request TX callback: success=%d", success);
if (p2p->invite_peer == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No pending Invite");
+ p2p_dbg(p2p, "No pending Invite");
return;
}
+ if (success)
+ p2p->invite_peer->flags &= ~P2P_DEV_WAIT_INV_REQ_ACK;
+
/*
* Use P2P find, if needed, to find the other device from its listen
* channel.
*/
p2p_set_state(p2p, P2P_INVITE);
- p2p_set_timeout(p2p, 0, 100000);
+ p2p_set_timeout(p2p, 0, success ? 500000 : 100000);
}
void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Response TX callback: success=%d", success);
+ p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- if (success && p2p->cfg->invitation_received) {
+ if (!success)
+ p2p_dbg(p2p, "Assume Invitation Response was actually received by the peer even though Ack was not reported");
+
+ if (p2p->cfg->invitation_received) {
p2p->cfg->invitation_received(p2p->cfg->cb_ctx,
p2p->inv_sa,
p2p->inv_group_bssid_ptr,
@@ -531,41 +627,55 @@ void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
unsigned int force_freq, const u8 *go_dev_addr,
- int persistent_group)
+ int persistent_group, unsigned int pref_freq, int dev_pw_id)
{
struct p2p_device *dev;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Request to invite peer " MACSTR " role=%d persistent=%d "
+ p2p_dbg(p2p, "Request to invite peer " MACSTR " role=%d persistent=%d "
"force_freq=%u",
MAC2STR(peer), role, persistent_group, force_freq);
if (bssid)
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation for BSSID " MACSTR, MAC2STR(bssid));
+ p2p_dbg(p2p, "Invitation for BSSID " MACSTR, MAC2STR(bssid));
if (go_dev_addr) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation for GO Device Address " MACSTR,
+ p2p_dbg(p2p, "Invitation for GO Device Address " MACSTR,
MAC2STR(go_dev_addr));
os_memcpy(p2p->invite_go_dev_addr_buf, go_dev_addr, ETH_ALEN);
p2p->invite_go_dev_addr = p2p->invite_go_dev_addr_buf;
} else
p2p->invite_go_dev_addr = NULL;
- wpa_hexdump_ascii(MSG_DEBUG, "P2P: Invitation for SSID",
+ wpa_hexdump_ascii(MSG_DEBUG, "Invitation for SSID",
ssid, ssid_len);
+ if (dev_pw_id >= 0) {
+ p2p_dbg(p2p, "Invitation to use Device Password ID %d",
+ dev_pw_id);
+ }
+ p2p->invite_dev_pw_id = dev_pw_id;
+ p2p->retry_invite_req = role == P2P_INVITE_ROLE_GO &&
+ persistent_group && !force_freq;
+ p2p->retry_invite_req_sent = 0;
dev = p2p_get_device(p2p, peer);
- if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot invite unknown P2P Device " MACSTR,
+ if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 &&
+ dev->oob_go_neg_freq <= 0)) {
+ p2p_dbg(p2p, "Cannot invite unknown P2P Device " MACSTR,
MAC2STR(peer));
return -1;
}
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+ role != P2P_INVITE_ROLE_CLIENT) < 0)
+ return -1;
+
+ if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
+ !pref_freq)
+ dev->flags |= P2P_DEV_NO_PREF_CHAN;
+ else
+ dev->flags &= ~P2P_DEV_NO_PREF_CHAN;
+
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot invite a P2P Device " MACSTR
+ p2p_dbg(p2p, "Cannot invite a P2P Device " MACSTR
" that is in a group and is not discoverable",
MAC2STR(peer));
}
@@ -574,26 +684,6 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
dev->invitation_reqs = 0;
- if (force_freq) {
- if (p2p_freq_to_channel(p2p->cfg->country, force_freq,
- &p2p->op_reg_class, &p2p->op_channel) <
- 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported frequency %u MHz",
- force_freq);
- return -1;
- }
- p2p->channels.reg_classes = 1;
- p2p->channels.reg_class[0].channels = 1;
- p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
- p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
- } else {
- p2p->op_reg_class = p2p->cfg->op_reg_class;
- p2p->op_channel = p2p->cfg->op_channel;
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- }
-
if (p2p->state != P2P_IDLE)
p2p_stop_find(p2p);
@@ -604,5 +694,5 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
os_memcpy(p2p->inv_ssid, ssid, ssid_len);
p2p->inv_ssid_len = ssid_len;
p2p->inv_persistent = persistent_group;
- return p2p_invite_send(p2p, dev, go_dev_addr);
+ return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id);
}
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index 097a31de19d34..fd6a4610d839f 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -268,6 +268,125 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u",
*msg->minor_reason_code);
break;
+ case P2P_ATTR_OOB_GO_NEG_CHANNEL:
+ if (len < 6) {
+ wpa_printf(MSG_DEBUG, "P2P: Too short OOB GO Neg "
+ "Channel attribute (length %d)", len);
+ return -1;
+ }
+ msg->oob_go_neg_channel = data;
+ wpa_printf(MSG_DEBUG, "P2P: * OOB GO Neg Channel: "
+ "Country %c%c(0x%02x) Operating Class %d "
+ "Channel Number %d Role %d",
+ data[0], data[1], data[2], data[3], data[4],
+ data[5]);
+ break;
+ case P2P_ATTR_SERVICE_HASH:
+ if (len < P2PS_HASH_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Service Hash (length %u)",
+ len);
+ return -1;
+ }
+ msg->service_hash_count = len / P2PS_HASH_LEN;
+ msg->service_hash = data;
+ wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash(s)", data, len);
+ break;
+ case P2P_ATTR_SESSION_INFORMATION_DATA:
+ msg->session_info = data;
+ msg->session_info_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %u bytes - %p",
+ len, data);
+ break;
+ case P2P_ATTR_CONNECTION_CAPABILITY:
+ if (len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Connection Capability (length %u)",
+ len);
+ return -1;
+ }
+ msg->conn_cap = data;
+ wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
+ *msg->conn_cap);
+ break;
+ case P2P_ATTR_ADVERTISEMENT_ID:
+ if (len < 10) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Advertisement ID (length %u)",
+ len);
+ return -1;
+ }
+ msg->adv_id = data;
+ msg->adv_mac = &data[sizeof(u32)];
+ wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID %x",
+ WPA_GET_LE32(data));
+ break;
+ case P2P_ATTR_ADVERTISED_SERVICE:
+ if (len < 8) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Service Instance (length %u)",
+ len);
+ return -1;
+ }
+ msg->adv_service_instance = data;
+ msg->adv_service_instance_len = len;
+ if (len <= 255 + 8) {
+ char str[256];
+ u8 namelen;
+
+ namelen = data[6];
+ if (namelen > len - 7)
+ break;
+ os_memcpy(str, &data[7], namelen);
+ str[namelen] = '\0';
+ wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %x-%s",
+ WPA_GET_LE32(data), str);
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %p",
+ data);
+ }
+ break;
+ case P2P_ATTR_SESSION_ID:
+ if (len < sizeof(u32) + ETH_ALEN) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Session ID Info (length %u)",
+ len);
+ return -1;
+ }
+ msg->session_id = data;
+ msg->session_mac = &data[sizeof(u32)];
+ wpa_printf(MSG_DEBUG, "P2P: * Session ID: %x " MACSTR,
+ WPA_GET_LE32(data), MAC2STR(msg->session_mac));
+ break;
+ case P2P_ATTR_FEATURE_CAPABILITY:
+ if (!len) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Feature Capability (length %u)",
+ len);
+ return -1;
+ }
+ msg->feature_cap = data;
+ msg->feature_cap_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * Feature Cap (length=%u)", len);
+ break;
+ case P2P_ATTR_PERSISTENT_GROUP:
+ {
+ if (len < ETH_ALEN) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Persistent Group Info (length %u)",
+ len);
+ return -1;
+ }
+
+ msg->persistent_dev = data;
+ msg->persistent_ssid_len = len - ETH_ALEN;
+ msg->persistent_ssid = &data[ETH_ALEN];
+ wpa_printf(MSG_DEBUG, "P2P: * Persistent Group: " MACSTR " %s",
+ MAC2STR(msg->persistent_dev),
+ wpa_ssid_txt(msg->persistent_ssid,
+ msg->persistent_ssid_len));
+ break;
+ }
default:
wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
"(length %d)", id, len);
@@ -296,23 +415,27 @@ int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg)
while (pos < end) {
u16 attr_len;
- if (pos + 2 >= end) {
+ u8 id;
+
+ if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute");
return -1;
}
- attr_len = WPA_GET_LE16(pos + 1);
+ id = *pos++;
+ attr_len = WPA_GET_LE16(pos);
+ pos += 2;
wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u",
- pos[0], attr_len);
- if (pos + 3 + attr_len > end) {
+ id, attr_len);
+ if (attr_len > end - pos) {
wpa_printf(MSG_DEBUG, "P2P: Attribute underflow "
"(len=%u left=%d)",
- attr_len, (int) (end - pos - 3));
+ attr_len, (int) (end - pos));
wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos);
return -1;
}
- if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg))
+ if (p2p_parse_attribute(id, pos, attr_len, msg))
return -1;
- pos += 3 + attr_len;
+ pos += attr_len;
}
return 0;
@@ -340,6 +463,7 @@ static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id);
wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d",
msg->dev_password_id);
+ msg->dev_password_id_present = 1;
}
if (attr.primary_dev_type) {
char devtype[WPS_DEV_TYPE_BUFSIZE];
@@ -367,6 +491,9 @@ static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
msg->serial_number = attr.serial_number;
msg->serial_number_len = attr.serial_number_len;
+ msg->oob_dev_password = attr.oob_dev_password;
+ msg->oob_dev_password_len = attr.oob_dev_password_len;
+
return 0;
}
@@ -450,6 +577,33 @@ int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg)
}
+int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p,
+ size_t p2p_len, struct p2p_message *msg)
+{
+ os_memset(msg, 0, sizeof(*msg));
+
+ msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len);
+ if (msg->wps_attributes &&
+ p2p_parse_wps_ie(msg->wps_attributes, msg)) {
+ p2p_parse_free(msg);
+ return -1;
+ }
+
+ msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len);
+ if (msg->p2p_attributes &&
+ p2p_parse_p2p_ie(msg->p2p_attributes, msg)) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data");
+ if (msg->p2p_attributes)
+ wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data",
+ msg->p2p_attributes);
+ p2p_parse_free(msg);
+ return -1;
+ }
+
+ return 0;
+}
+
+
/**
* p2p_parse_free - Free temporary data from P2P parsing
* @msg: Parsed attributes
@@ -559,7 +713,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
"dev=" MACSTR " iface=" MACSTR,
MAC2STR(cli->p2p_device_addr),
MAC2STR(cli->p2p_interface_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -570,7 +724,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
wps_dev_type_bin2str(cli->pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -579,7 +733,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
wps_dev_type_bin2str(
&cli->sec_dev_types[s * 8],
devtype, sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -594,7 +748,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
}
ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -628,7 +782,7 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
"p2p_dev_capab=0x%x\n"
"p2p_group_capab=0x%x\n",
msg.capability[0], msg.capability[1]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -640,14 +794,14 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
wps_dev_type_bin2str(msg.pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n",
msg.device_name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -655,14 +809,14 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR
"\n",
MAC2STR(msg.p2p_device_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n",
msg.config_methods);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index ca33f17a17b8f..328b1e029ce57 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -39,20 +40,145 @@ static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
}
+static void p2ps_add_new_group_info(struct p2p_data *p2p, struct wpabuf *buf)
+{
+ int found;
+ u8 intended_addr[ETH_ALEN];
+ u8 ssid[32];
+ size_t ssid_len;
+ int group_iface;
+
+ if (!p2p->cfg->get_go_info)
+ return;
+
+ found = p2p->cfg->get_go_info(
+ p2p->cfg->cb_ctx, intended_addr, ssid,
+ &ssid_len, &group_iface);
+ if (found) {
+ p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
+ ssid, ssid_len);
+ p2p_buf_add_intended_addr(buf, intended_addr);
+ } else {
+ if (!p2p->ssid_set) {
+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ p2p->ssid_set = 1;
+ }
+
+ /* Add pre-composed P2P Group ID */
+ p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
+ p2p->ssid, p2p->ssid_len);
+
+ if (group_iface)
+ p2p_buf_add_intended_addr(
+ buf, p2p->intended_addr);
+ else
+ p2p_buf_add_intended_addr(
+ buf, p2p->cfg->dev_addr);
+ }
+}
+
+
+static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
+ struct wpabuf *buf, u16 config_methods)
+{
+ struct p2ps_provision *prov = p2p->p2ps_prov;
+ u8 feat_cap_mask[] = { 1, 0 };
+ int shared_group = 0;
+ u8 ssid[32];
+ size_t ssid_len;
+ u8 go_dev_addr[ETH_ALEN];
+
+ /* If we might be explicite group owner, add GO details */
+ if (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
+ P2PS_SETUP_NEW))
+ p2ps_add_new_group_info(p2p, buf);
+
+ if (prov->status >= 0)
+ p2p_buf_add_status(buf, (u8) prov->status);
+ else
+ prov->method = config_methods;
+
+ if (p2p->cfg->get_persistent_group) {
+ shared_group = p2p->cfg->get_persistent_group(
+ p2p->cfg->cb_ctx, dev->info.p2p_device_addr, NULL, 0,
+ go_dev_addr, ssid, &ssid_len);
+ }
+
+ /* Add Operating Channel if conncap includes GO */
+ if (shared_group ||
+ (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
+ P2PS_SETUP_NEW))) {
+ u8 tmp;
+
+ p2p_go_select_channel(p2p, dev, &tmp);
+
+ if (p2p->op_reg_class && p2p->op_channel)
+ p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p->op_reg_class,
+ p2p->op_channel);
+ else
+ p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p->cfg->op_reg_class,
+ p2p->cfg->op_channel);
+ }
+
+ p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->cfg->channels);
+
+ if (prov->info[0])
+ p2p_buf_add_session_info(buf, prov->info);
+
+ p2p_buf_add_connection_capability(buf, prov->conncap);
+
+ p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac);
+
+ if (shared_group || prov->conncap == P2PS_SETUP_NEW ||
+ prov->conncap ==
+ (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) ||
+ prov->conncap ==
+ (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) {
+ /* Add Config Timeout */
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+ p2p->client_timeout);
+ }
+
+ p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
+ p2p->cfg->channel);
+
+ p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac);
+
+ p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
+ feat_cap_mask);
+
+ if (shared_group)
+ p2p_buf_add_persistent_group_info(buf, go_dev_addr,
+ ssid, ssid_len);
+}
+
+
static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
- u8 dialog_token,
- u16 config_methods,
- struct p2p_device *go)
+ struct p2p_device *dev,
+ int join)
{
struct wpabuf *buf;
u8 *len;
size_t extra = 0;
+ u8 dialog_token = dev->dialog_token;
+ u16 config_methods = dev->req_config_methods;
+ struct p2p_device *go = join ? dev : NULL;
+ u8 group_capab;
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_prov_disc_req)
extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
+
+ if (p2p->p2ps_prov)
+ extra += os_strlen(p2p->p2ps_prov->info) + 1 +
+ sizeof(struct p2ps_provision);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -60,10 +186,23 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
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->p2ps_prov) {
+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ if (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, 0);
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+ group_capab);
p2p_buf_add_device_info(buf, p2p, NULL);
- if (go) {
+ if (p2p->p2ps_prov) {
+ p2ps_add_pd_req_attrs(p2p, dev, buf, config_methods);
+ } else if (go) {
p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
go->oper_ssid, go->oper_ssid_len);
}
@@ -77,18 +216,27 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
+
return buf;
}
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
+ struct p2p_device *dev,
u8 dialog_token,
+ enum p2p_status_code status,
u16 config_methods,
+ u32 adv_id,
const u8 *group_id,
- size_t group_id_len)
+ size_t group_id_len,
+ const u8 *persist_ssid,
+ size_t persist_ssid_len)
{
struct wpabuf *buf;
size_t extra = 0;
+ int persist = 0;
#ifdef CONFIG_WIFI_DISPLAY
struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
@@ -111,12 +259,106 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
extra = wpabuf_len(wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
- buf = wpabuf_alloc(100 + extra);
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
+ /* Add P2P IE for P2PS */
+ if (p2p->p2ps_prov && p2p->p2ps_prov->adv_id == adv_id) {
+ u8 feat_cap_mask[] = { 1, 0 };
+ u8 *len = p2p_buf_add_ie_hdr(buf);
+ struct p2ps_provision *prov = p2p->p2ps_prov;
+ u8 group_capab;
+
+ if (!status && prov->status != -1)
+ status = prov->status;
+
+ p2p_buf_add_status(buf, status);
+ group_capab = P2P_GROUP_CAPAB_PERSISTENT_GROUP |
+ P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ if (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 (persist_ssid && p2p->cfg->get_persistent_group &&
+ (status == P2P_SC_SUCCESS ||
+ status == P2P_SC_SUCCESS_DEFERRED)) {
+ u8 ssid[32];
+ size_t ssid_len;
+ u8 go_dev_addr[ETH_ALEN];
+
+ persist = p2p->cfg->get_persistent_group(
+ p2p->cfg->cb_ctx,
+ dev->info.p2p_device_addr,
+ persist_ssid, persist_ssid_len, go_dev_addr,
+ ssid, &ssid_len);
+ if (persist)
+ p2p_buf_add_persistent_group_info(
+ buf, go_dev_addr, ssid, ssid_len);
+ }
+
+ if (!persist && (prov->conncap & P2PS_SETUP_GROUP_OWNER))
+ p2ps_add_new_group_info(p2p, buf);
+
+ /* Add Operating Channel if conncap indicates GO */
+ if (persist || (prov->conncap & P2PS_SETUP_GROUP_OWNER)) {
+ u8 tmp;
+
+ if (dev)
+ p2p_go_select_channel(p2p, dev, &tmp);
+
+ if (p2p->op_reg_class && p2p->op_channel)
+ p2p_buf_add_operating_channel(
+ buf, p2p->cfg->country,
+ p2p->op_reg_class,
+ p2p->op_channel);
+ else
+ p2p_buf_add_operating_channel(
+ buf, p2p->cfg->country,
+ p2p->cfg->op_reg_class,
+ p2p->cfg->op_channel);
+ }
+
+ p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ &p2p->cfg->channels);
+
+ if (!persist && (status == P2P_SC_SUCCESS ||
+ status == P2P_SC_SUCCESS_DEFERRED))
+ p2p_buf_add_connection_capability(buf, prov->conncap);
+
+ p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac);
+
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+ p2p->client_timeout);
+
+ p2p_buf_add_session_id(buf, prov->session_id,
+ prov->session_mac);
+
+ p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
+ feat_cap_mask);
+ p2p_buf_update_ie_hdr(buf, len);
+ } else if (status != P2P_SC_SUCCESS || adv_id) {
+ u8 *len = p2p_buf_add_ie_hdr(buf);
+
+ p2p_buf_add_status(buf, status);
+
+ if (p2p->p2ps_prov)
+ p2p_buf_add_advertisement_id(buf, adv_id,
+ p2p->p2ps_prov->adv_mac);
+
+ p2p_buf_update_ie_hdr(buf, len);
+ }
+
/* WPS IE with Config Methods attribute */
p2p_build_wps_ie_config_methods(buf, config_methods);
@@ -125,38 +367,74 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
wpabuf_put_buf(buf, wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
+
return buf;
}
+static int p2ps_setup_p2ps_prov(struct p2p_data *p2p, u32 adv_id,
+ u32 session_id, u16 method,
+ const u8 *session_mac, const u8 *adv_mac)
+{
+ struct p2ps_provision *tmp;
+
+ if (!p2p->p2ps_prov) {
+ p2p->p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + 1);
+ if (!p2p->p2ps_prov)
+ return -1;
+ } else {
+ os_memset(p2p->p2ps_prov, 0, sizeof(struct p2ps_provision) + 1);
+ }
+
+ tmp = p2p->p2ps_prov;
+ tmp->adv_id = adv_id;
+ tmp->session_id = session_id;
+ tmp->method = method;
+ os_memcpy(tmp->session_mac, session_mac, ETH_ALEN);
+ os_memcpy(tmp->adv_mac, adv_mac, ETH_ALEN);
+ tmp->info[0] = '\0';
+
+ return 0;
+}
+
+
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
struct p2p_message msg;
struct p2p_device *dev;
int freq;
- int reject = 1;
+ enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
struct wpabuf *resp;
+ u32 adv_id = 0;
+ struct p2ps_advertisement *p2ps_adv = NULL;
+ u8 conncap = P2PS_SETUP_NEW;
+ u8 auto_accept = 0;
+ u32 session_id = 0;
+ u8 session_mac[ETH_ALEN];
+ u8 adv_mac[ETH_ALEN];
+ u8 group_mac[ETH_ALEN];
+ int passwd_id = DEV_PW_DEFAULT;
+ u16 config_methods;
if (p2p_parse(data, len, &msg))
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Provision Discovery Request from " MACSTR
+ p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
" with config methods 0x%x (freq=%d)",
MAC2STR(sa), msg.wps_config_methods, rx_freq);
dev = p2p_get_device(p2p, sa);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Provision Discovery Request from "
- "unknown peer " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
+ MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
0)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Provision Discovery Request add device "
- "failed " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Provision Discovery Request add device failed "
+ MACSTR, MAC2STR(sa));
}
} else if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
@@ -165,13 +443,13 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
if (!(msg.wps_config_methods &
(WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
- WPS_CONFIG_PUSHBUTTON))) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported "
- "Config Methods in Provision Discovery Request");
+ WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_P2PS))) {
+ p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
goto out;
}
- if (msg.group_id) {
+ /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
+ if (!msg.adv_id && msg.group_id) {
size_t i;
for (i = 0; i < p2p->num_groups; i++) {
if (p2p_group_is_group_id_match(p2p->groups[i],
@@ -180,64 +458,319 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
break;
}
if (i == p2p->num_groups) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: PD "
- "request for unknown P2P Group ID - reject");
+ p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
goto out;
}
}
- if (dev)
+ if (dev) {
dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
- P2P_DEV_PD_PEER_KEYPAD);
+ P2P_DEV_PD_PEER_KEYPAD |
+ P2P_DEV_PD_PEER_P2PS);
+
+ /* Remove stale persistent groups */
+ if (p2p->cfg->remove_stale_groups) {
+ p2p->cfg->remove_stale_groups(
+ p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
+ msg.persistent_dev,
+ msg.persistent_ssid, msg.persistent_ssid_len);
+ }
+ }
if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+ p2p_dbg(p2p, "Peer " MACSTR
" requested us to show a PIN on display", MAC2STR(sa));
if (dev)
dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+ passwd_id = DEV_PW_USER_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+ p2p_dbg(p2p, "Peer " MACSTR
" requested us to write its PIN using keypad",
MAC2STR(sa));
if (dev)
dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
+ passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
+ } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
+ p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
+ MAC2STR(sa));
+ if (dev)
+ dev->flags |= P2P_DEV_PD_PEER_P2PS;
+ passwd_id = DEV_PW_P2PS_DEFAULT;
}
- reject = 0;
+ reject = P2P_SC_SUCCESS;
+
+ os_memset(session_mac, 0, ETH_ALEN);
+ os_memset(adv_mac, 0, ETH_ALEN);
+ os_memset(group_mac, 0, ETH_ALEN);
+
+ if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac &&
+ (msg.status || msg.conn_cap)) {
+ u8 remote_conncap;
+
+ if (msg.intended_addr)
+ os_memcpy(group_mac, msg.intended_addr, ETH_ALEN);
+
+ os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
+ os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+
+ session_id = WPA_GET_LE32(msg.session_id);
+ adv_id = WPA_GET_LE32(msg.adv_id);
+
+ if (!msg.status)
+ p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
+
+ p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv);
+
+ if (msg.conn_cap)
+ conncap = *msg.conn_cap;
+ remote_conncap = conncap;
+
+ if (p2ps_adv) {
+ auto_accept = p2ps_adv->auto_accept;
+ conncap = p2p->cfg->p2ps_group_capability(
+ p2p->cfg->cb_ctx, conncap, auto_accept);
+
+ p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
+ auto_accept, remote_conncap, conncap);
+
+ if (p2ps_adv->config_methods &&
+ !(msg.wps_config_methods &
+ p2ps_adv->config_methods)) {
+ p2p_dbg(p2p,
+ "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
+ p2ps_adv->config_methods,
+ msg.wps_config_methods);
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ } else if (!p2ps_adv->state) {
+ p2p_dbg(p2p, "P2PS state unavailable");
+ reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+ } else if (!conncap) {
+ p2p_dbg(p2p, "Conncap resolution failed");
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ }
+
+ if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+ p2p_dbg(p2p, "Keypad - always defer");
+ auto_accept = 0;
+ }
+
+ if (auto_accept || reject != P2P_SC_SUCCESS) {
+ struct p2ps_provision *tmp;
+
+ if (reject == P2P_SC_SUCCESS && !conncap) {
+ reject =
+ P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ }
+
+ if (p2ps_setup_p2ps_prov(
+ p2p, adv_id, session_id,
+ msg.wps_config_methods,
+ session_mac, adv_mac) < 0) {
+ reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+ goto out;
+ }
+
+ tmp = p2p->p2ps_prov;
+ if (conncap) {
+ tmp->conncap = conncap;
+ tmp->status = P2P_SC_SUCCESS;
+ } else {
+ tmp->conncap = auto_accept;
+ tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ }
+
+ if (reject != P2P_SC_SUCCESS)
+ goto out;
+ }
+ } else if (!msg.status) {
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ goto out;
+ }
+
+ if (!msg.status && !auto_accept &&
+ (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
+ struct p2ps_provision *tmp;
+
+ if (!conncap) {
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ goto out;
+ }
+
+ if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
+ msg.wps_config_methods,
+ session_mac, adv_mac) < 0) {
+ reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+ goto out;
+ }
+ tmp = p2p->p2ps_prov;
+ reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+ tmp->status = reject;
+ }
+
+ if (msg.status) {
+ if (*msg.status &&
+ *msg.status != P2P_SC_SUCCESS_DEFERRED) {
+ reject = *msg.status;
+ } else if (*msg.status == P2P_SC_SUCCESS_DEFERRED &&
+ p2p->p2ps_prov) {
+ u16 method = p2p->p2ps_prov->method;
+
+ conncap = p2p->cfg->p2ps_group_capability(
+ p2p->cfg->cb_ctx, remote_conncap,
+ p2p->p2ps_prov->conncap);
+
+ p2p_dbg(p2p,
+ "Conncap: local:%d remote:%d result:%d",
+ p2p->p2ps_prov->conncap,
+ remote_conncap, conncap);
+
+ /*
+ * Ensure that if we asked for PIN originally,
+ * our method is consistent with original
+ * request.
+ */
+ if (method & WPS_CONFIG_DISPLAY)
+ method = WPS_CONFIG_KEYPAD;
+ else if (method & WPS_CONFIG_KEYPAD)
+ method = WPS_CONFIG_DISPLAY;
+
+ /* Reject this "Deferred Accept* if incompatible
+ * conncap or method */
+ if (!conncap ||
+ !(msg.wps_config_methods & method))
+ reject =
+ P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ else
+ reject = P2P_SC_SUCCESS;
+
+ p2p->p2ps_prov->status = reject;
+ p2p->p2ps_prov->conncap = conncap;
+ }
+ }
+ }
out:
- resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
- reject ? 0 : msg.wps_config_methods,
- msg.group_id, msg.group_id_len);
+ if (reject == P2P_SC_SUCCESS ||
+ reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
+ config_methods = msg.wps_config_methods;
+ else
+ config_methods = 0;
+ resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, reject,
+ config_methods, adv_id,
+ msg.group_id, msg.group_id_len,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len);
if (resp == NULL) {
p2p_parse_free(&msg);
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending Provision Discovery Response");
+ p2p_dbg(p2p, "Sending Provision Discovery Response");
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
wpabuf_free(resp);
p2p_parse_free(&msg);
return;
}
- p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+ 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), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
- }
+ p2p_dbg(p2p, "Failed to send Action frame");
+ } else
+ p2p->send_action_in_progress = 1;
wpabuf_free(resp);
- if (!reject && p2p->cfg->prov_disc_req) {
+ if (!p2p->cfg->p2ps_prov_complete) {
+ /* Don't emit anything */
+ } else if (msg.status && *msg.status != P2P_SC_SUCCESS &&
+ *msg.status != P2P_SC_SUCCESS_DEFERRED) {
+ reject = *msg.status;
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
+ sa, adv_mac, session_mac,
+ NULL, adv_id, session_id,
+ 0, 0, msg.persistent_ssid,
+ msg.persistent_ssid_len,
+ 0, 0, NULL);
+ } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
+ p2p->p2ps_prov) {
+ p2p->p2ps_prov->status = reject;
+ p2p->p2ps_prov->conncap = conncap;
+
+ if (reject != P2P_SC_SUCCESS)
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
+ sa, adv_mac, session_mac,
+ NULL, adv_id,
+ session_id, conncap, 0,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len, 0,
+ 0, NULL);
+ else
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
+ *msg.status,
+ sa, adv_mac, session_mac,
+ group_mac, adv_id,
+ session_id, conncap,
+ passwd_id,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len, 0,
+ 0, NULL);
+ } else if (msg.status && p2p->p2ps_prov) {
+ p2p->p2ps_prov->status = P2P_SC_SUCCESS;
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa,
+ adv_mac, session_mac, group_mac,
+ adv_id, session_id, conncap,
+ passwd_id,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len,
+ 0, 0, NULL);
+ } else if (msg.status) {
+ } else if (auto_accept && reject == P2P_SC_SUCCESS) {
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
+ sa, adv_mac, session_mac,
+ group_mac, adv_id, session_id,
+ conncap, passwd_id,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len,
+ 0, 0, NULL);
+ } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
+ (!msg.session_info || !msg.session_info_len)) {
+ p2p->p2ps_prov->method = msg.wps_config_methods;
+
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
+ sa, adv_mac, session_mac,
+ group_mac, adv_id, session_id,
+ conncap, passwd_id,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len,
+ 0, 1, NULL);
+ } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+ size_t buf_len = msg.session_info_len;
+ char *buf = os_malloc(2 * buf_len + 1);
+
+ if (buf) {
+ p2p->p2ps_prov->method = msg.wps_config_methods;
+
+ utf8_escape((char *) msg.session_info, buf_len,
+ buf, 2 * buf_len + 1);
+
+ p2p->cfg->p2ps_prov_complete(
+ p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa,
+ adv_mac, session_mac, group_mac, adv_id,
+ session_id, conncap, passwd_id,
+ msg.persistent_ssid, msg.persistent_ssid_len,
+ 0, 1, buf);
+
+ os_free(buf);
+ }
+ }
+
+ if (reject == P2P_SC_SUCCESS && p2p->cfg->prov_disc_req) {
const u8 *dev_addr = sa;
if (msg.p2p_device_addr)
dev_addr = msg.p2p_device_addr;
@@ -259,30 +792,63 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
{
struct p2p_message msg;
struct p2p_device *dev;
- u16 report_config_methods = 0;
+ u16 report_config_methods = 0, req_config_methods;
+ u8 status = P2P_SC_SUCCESS;
int success = 0;
+ u32 adv_id = 0;
+ u8 conncap = P2PS_SETUP_NEW;
+ u8 adv_mac[ETH_ALEN];
+ u8 group_mac[ETH_ALEN];
+ int passwd_id = DEV_PW_DEFAULT;
if (p2p_parse(data, len, &msg))
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Provision Discovery Response from " MACSTR
+ /* Parse the P2PS members present */
+ if (msg.status)
+ status = *msg.status;
+
+ if (msg.intended_addr)
+ os_memcpy(group_mac, msg.intended_addr, ETH_ALEN);
+ else
+ os_memset(group_mac, 0, ETH_ALEN);
+
+ if (msg.adv_mac)
+ os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+ else
+ os_memset(adv_mac, 0, ETH_ALEN);
+
+ if (msg.adv_id)
+ adv_id = WPA_GET_LE32(msg.adv_id);
+
+ if (msg.conn_cap) {
+ conncap = *msg.conn_cap;
+
+ /* Switch bits to local relative */
+ switch (conncap) {
+ case P2PS_SETUP_GROUP_OWNER:
+ conncap = P2PS_SETUP_CLIENT;
+ break;
+ case P2PS_SETUP_CLIENT:
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ break;
+ }
+ }
+
+ p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
" with config methods 0x%x",
MAC2STR(sa), msg.wps_config_methods);
dev = p2p_get_device(p2p, sa);
if (dev == NULL || !dev->req_config_methods) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore Provision Discovery Response from "
- MACSTR " with no pending request", MAC2STR(sa));
+ p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
+ " with no pending request", MAC2STR(sa));
p2p_parse_free(&msg);
return;
}
if (dev->dialog_token != msg.dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "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);
p2p_parse_free(&msg);
return;
@@ -294,6 +860,12 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
}
/*
+ * Use a local copy of the requested config methods since
+ * p2p_reset_pending_pd() can clear this in the peer entry.
+ */
+ req_config_methods = dev->req_config_methods;
+
+ /*
* If the response is from the peer to whom a user initiated request
* was sent earlier, we reset that state info here.
*/
@@ -301,28 +873,114 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
p2p_reset_pending_pd(p2p);
- if (msg.wps_config_methods != dev->req_config_methods) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
- "our Provision Discovery Request");
+ 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",
+ msg.wps_config_methods, req_config_methods);
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
- P2P_PROV_DISC_REJECTED);
+ P2P_PROV_DISC_REJECTED,
+ adv_id, adv_mac, NULL);
p2p_parse_free(&msg);
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
goto out;
}
- report_config_methods = dev->req_config_methods;
+ report_config_methods = req_config_methods;
dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
- P2P_DEV_PD_PEER_KEYPAD);
- if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+ P2P_DEV_PD_PEER_KEYPAD |
+ P2P_DEV_PD_PEER_P2PS);
+ if (req_config_methods & WPS_CONFIG_DISPLAY) {
+ p2p_dbg(p2p, "Peer " MACSTR
" accepted to show a PIN on display", MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
+ passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+ p2p_dbg(p2p, "Peer " MACSTR
" accepted to write our PIN using keypad",
MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+ passwd_id = DEV_PW_USER_SPECIFIED;
+ } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
+ p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN",
+ MAC2STR(sa));
+ dev->flags |= P2P_DEV_PD_PEER_P2PS;
+ passwd_id = DEV_PW_P2PS_DEFAULT;
+ }
+
+ if ((msg.conn_cap || msg.persistent_dev) &&
+ msg.adv_id &&
+ (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
+ p2p->p2ps_prov) {
+ if (p2p->cfg->p2ps_prov_complete) {
+ p2p->cfg->p2ps_prov_complete(
+ p2p->cfg->cb_ctx, status, sa, adv_mac,
+ p2p->p2ps_prov->session_mac,
+ group_mac, adv_id, p2p->p2ps_prov->session_id,
+ conncap, passwd_id, msg.persistent_ssid,
+ msg.persistent_ssid_len, 1, 0, NULL);
+ }
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
+ }
+
+ if (status != P2P_SC_SUCCESS &&
+ status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
+ status != P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) {
+ if (p2p->cfg->p2ps_prov_complete)
+ p2p->cfg->p2ps_prov_complete(
+ p2p->cfg->cb_ctx, status, sa, adv_mac,
+ p2p->p2ps_prov->session_mac,
+ group_mac, adv_id, p2p->p2ps_prov->session_id,
+ 0, 0, NULL, 0, 1, 0, NULL);
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
+ }
+
+ if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+ if (p2p->cfg->remove_stale_groups) {
+ p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx,
+ dev->info.p2p_device_addr,
+ NULL, NULL, 0);
+ }
+
+ if (msg.session_info && msg.session_info_len) {
+ size_t info_len = msg.session_info_len;
+ char *deferred_sess_resp = os_malloc(2 * info_len + 1);
+
+ if (!deferred_sess_resp) {
+ p2p_parse_free(&msg);
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
+ goto out;
+ }
+ utf8_escape((char *) msg.session_info, info_len,
+ deferred_sess_resp, 2 * info_len + 1);
+
+ if (p2p->cfg->prov_disc_fail)
+ p2p->cfg->prov_disc_fail(
+ p2p->cfg->cb_ctx, sa,
+ P2P_PROV_DISC_INFO_UNAVAILABLE,
+ adv_id, adv_mac,
+ deferred_sess_resp);
+ os_free(deferred_sess_resp);
+ } else
+ if (p2p->cfg->prov_disc_fail)
+ p2p->cfg->prov_disc_fail(
+ p2p->cfg->cb_ctx, sa,
+ P2P_PROV_DISC_INFO_UNAVAILABLE,
+ adv_id, adv_mac, NULL);
+ } else if (msg.wps_config_methods != dev->req_config_methods ||
+ status != P2P_SC_SUCCESS) {
+ p2p_dbg(p2p, "Peer rejected our Provision Discovery Request");
+ if (p2p->cfg->prov_disc_fail)
+ p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
+ P2P_PROV_DISC_REJECTED, 0,
+ NULL, NULL);
+ p2p_parse_free(&msg);
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
+ goto out;
}
/* Store the provisioning info */
@@ -335,10 +993,8 @@ out:
dev->req_config_methods = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Start GO Neg after the PD-before-GO-Neg "
- "workaround with " MACSTR,
- MAC2STR(dev->info.p2p_device_addr));
+ p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
+ MACSTR, MAC2STR(dev->info.p2p_device_addr));
dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
p2p_connect_send(p2p, dev);
return;
@@ -346,6 +1002,11 @@ out:
if (success && p2p->cfg->prov_disc_resp)
p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
report_config_methods);
+
+ if (p2p->state == P2P_PD_DURING_FIND) {
+ p2p_clear_timeout(p2p);
+ p2p_continue_find(p2p);
+ }
}
@@ -361,9 +1022,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
freq = dev->listen_freq > 0 ? dev->listen_freq :
dev->oper_freq;
if (freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen/Operating frequency known for the "
- "peer " MACSTR " to send Provision Discovery Request",
+ p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+ MACSTR " to send Provision Discovery Request",
MAC2STR(dev->info.p2p_device_addr));
return -1;
}
@@ -371,8 +1031,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot use PD with P2P Device " MACSTR
+ p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
" that is in a group and is not discoverable",
MAC2STR(dev->info.p2p_device_addr));
return -1;
@@ -380,9 +1039,33 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
/* TODO: use device discoverability request through GO */
}
- req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
- dev->req_config_methods,
- join ? dev : NULL);
+ if (p2p->p2ps_prov) {
+ if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) {
+ if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY)
+ dev->req_config_methods = WPS_CONFIG_KEYPAD;
+ else if (p2p->p2ps_prov->method == WPS_CONFIG_KEYPAD)
+ dev->req_config_methods = WPS_CONFIG_DISPLAY;
+ else
+ dev->req_config_methods = WPS_CONFIG_P2PS;
+ } else {
+ /* Order of preference, based on peer's capabilities */
+ if (p2p->p2ps_prov->method)
+ dev->req_config_methods =
+ p2p->p2ps_prov->method;
+ else if (dev->info.config_methods & WPS_CONFIG_P2PS)
+ dev->req_config_methods = WPS_CONFIG_P2PS;
+ else if (dev->info.config_methods & WPS_CONFIG_DISPLAY)
+ dev->req_config_methods = WPS_CONFIG_DISPLAY;
+ else
+ dev->req_config_methods = WPS_CONFIG_KEYPAD;
+ }
+ p2p_dbg(p2p,
+ "Building PD Request based on P2PS config method 0x%x status %d --> req_config_methods 0x%x",
+ p2p->p2ps_prov->method, p2p->p2ps_prov->status,
+ dev->req_config_methods);
+ }
+
+ req = p2p_build_prov_disc_req(p2p, dev, join);
if (req == NULL)
return -1;
@@ -392,8 +1075,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
wpabuf_head(req), wpabuf_len(req), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(req);
return -1;
}
@@ -406,6 +1088,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
+ struct p2ps_provision *p2ps_prov,
u16 config_methods, int join, int force_freq,
int user_initiated_pd)
{
@@ -415,20 +1098,30 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
if (dev == NULL)
dev = p2p_get_device_interface(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision "
- "Discovery Request destination " MACSTR
+ p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
" not yet known", MAC2STR(peer_addr));
+ os_free(p2ps_prov);
return -1;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery "
- "Request with " MACSTR " (config methods 0x%x)",
+ p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
+ " (config methods 0x%x)",
MAC2STR(peer_addr), config_methods);
- if (config_methods == 0)
+ if (config_methods == 0 && !p2ps_prov) {
+ os_free(p2ps_prov);
return -1;
+ }
+
+ if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED &&
+ p2p->p2ps_prov) {
+ /* Use cached method from deferred provisioning */
+ p2ps_prov->method = p2p->p2ps_prov->method;
+ }
/* Reset provisioning info */
dev->wps_prov_info = 0;
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = p2ps_prov;
dev->req_config_methods = config_methods;
if (join)
@@ -438,14 +1131,14 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
p2p->state != P2P_LISTEN_ONLY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other "
- "operations; postpone Provision Discovery Request "
- "with " MACSTR " (config methods 0x%x)",
+ p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
+ MACSTR " (config methods 0x%x)",
MAC2STR(peer_addr), config_methods);
return 0;
}
p2p->user_initiated_pd = user_initiated_pd;
+ p2p->pd_force_freq = force_freq;
if (p2p->user_initiated_pd)
p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
@@ -481,4 +1174,5 @@ void p2p_reset_pending_pd(struct p2p_data *p2p)
p2p->user_initiated_pd = 0;
os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
p2p->pd_retries = 0;
+ p2p->pd_force_freq = 0;
}
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index abe1d6b586615..1a2af04b80043 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -52,6 +52,7 @@ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
{
struct p2p_sd_query *q;
int wsd = 0;
+ int count = 0;
if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
return NULL; /* peer does not support SD */
@@ -64,15 +65,52 @@ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
/* Use WSD only if the peer indicates support or it */
if (q->wsd && !wsd)
continue;
- if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
- return q;
+ /* if the query is a broadcast query */
+ if (q->for_all_peers) {
+ /*
+ * check if there are any broadcast queries pending for
+ * this device
+ */
+ if (dev->sd_pending_bcast_queries <= 0)
+ return NULL;
+ /* query number that needs to be send to the device */
+ if (count == dev->sd_pending_bcast_queries - 1)
+ goto found;
+ count++;
+ }
if (!q->for_all_peers &&
os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) ==
0)
- return q;
+ goto found;
}
return NULL;
+
+found:
+ if (dev->sd_reqs > 100) {
+ p2p_dbg(p2p, "Too many SD request attempts to " MACSTR
+ " - skip remaining queries",
+ MAC2STR(dev->info.p2p_device_addr));
+ return NULL;
+ }
+ return q;
+}
+
+
+static void p2p_decrease_sd_bc_queries(struct p2p_data *p2p, int query_number)
+{
+ struct p2p_device *dev;
+
+ p2p->num_p2p_sd_queries--;
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (query_number <= dev->sd_pending_bcast_queries - 1) {
+ /*
+ * Query not yet sent to the device and it is to be
+ * removed, so update the pending count.
+ */
+ dev->sd_pending_bcast_queries--;
+ }
+ }
}
@@ -80,10 +118,16 @@ static int p2p_unlink_sd_query(struct p2p_data *p2p,
struct p2p_sd_query *query)
{
struct p2p_sd_query *q, *prev;
+ int query_number = 0;
+
q = p2p->sd_queries;
prev = NULL;
while (q) {
if (q == query) {
+ /* If the query is a broadcast query, decrease one from
+ * all the devices */
+ if (query->for_all_peers)
+ p2p_decrease_sd_bc_queries(p2p, query_number);
if (prev)
prev->next = q->next;
else
@@ -92,6 +136,8 @@ static int p2p_unlink_sd_query(struct p2p_data *p2p,
p2p->sd_query = NULL;
return 1;
}
+ if (q->for_all_peers)
+ query_number++;
prev = q;
q = q->next;
}
@@ -118,6 +164,7 @@ void p2p_free_sd_queries(struct p2p_data *p2p)
q = q->next;
p2p_free_sd_query(prev);
}
+ p2p->num_p2p_sd_queries = 0;
}
@@ -133,8 +180,7 @@ static struct wpabuf * p2p_build_sd_query(u16 update_indic,
/* ANQP Query Request Frame */
len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
wpabuf_put_buf(buf, tlvs);
gas_anqp_set_element_len(buf, len_pos);
@@ -157,8 +203,7 @@ static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst,
wpabuf_head(req), wpabuf_len(req), 200) < 0)
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(req);
}
@@ -181,8 +226,7 @@ static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
if (tlvs) {
/* ANQP Query Response Frame */
len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
/* Service Update Indicator */
wpabuf_put_le16(buf, update_indic);
wpabuf_put_buf(buf, tlvs);
@@ -213,8 +257,7 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
/* ANQP Query Response Frame */
wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
/* Service Update Indicator */
wpabuf_put_le16(buf, update_indic);
}
@@ -232,12 +275,12 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
int ret = 0;
struct p2p_sd_query *query;
int freq;
+ unsigned int wait_time;
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
if (freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen/Operating frequency known for the "
- "peer " MACSTR " to send SD Request",
+ p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+ MACSTR " to send SD Request",
MAC2STR(dev->info.p2p_device_addr));
return -1;
}
@@ -246,23 +289,25 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
if (query == NULL)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Start Service Discovery with " MACSTR,
+ p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
MAC2STR(dev->info.p2p_device_addr));
req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs);
if (req == NULL)
return -1;
+ dev->sd_reqs++;
p2p->sd_peer = dev;
p2p->sd_query = query;
p2p->pending_action_state = P2P_PENDING_SD;
+ wait_time = 5000;
+ if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen)
+ wait_time = p2p->cfg->max_listen;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 5000) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(req), wpabuf_len(req), wait_time) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
ret = -1;
}
@@ -290,8 +335,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0)
return;
@@ -300,14 +344,12 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
return;
dialog_token = *pos++;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GAS Initial Request from " MACSTR " (dialog token %u, "
- "freq %d)",
+ p2p_dbg(p2p, "GAS Initial Request from " MACSTR
+ " (dialog token %u, freq %d)",
MAC2STR(sa), dialog_token, rx_freq);
if (*pos != WLAN_EID_ADV_PROTO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected IE in GAS Initial Request: %u", *pos);
+ p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos);
return;
}
pos++;
@@ -315,15 +357,13 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
slen = *pos++;
next = pos + slen;
if (next > end || slen < 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid IE in GAS Initial Request");
+ p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
return;
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported GAS advertisement protocol id %u",
+ p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
*pos);
return;
}
@@ -342,8 +382,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
if (pos + 4 > end)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+ p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
@@ -351,30 +390,21 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
slen = WPA_GET_LE16(pos);
pos += 2;
if (pos + slen > end || slen < 3 + 1) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid ANQP Query Request length");
+ p2p_dbg(p2p, "Invalid ANQP Query Request length");
return;
}
- if (WPA_GET_BE24(pos) != OUI_WFA) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+ if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
+ p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
+ WPA_GET_BE32(pos));
return;
}
- pos += 3;
-
- if (*pos != P2P_OUI_TYPE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP vendor type %u", *pos);
- return;
- }
- pos++;
+ pos += 4;
if (pos + 2 > end)
return;
update_indic = WPA_GET_LE16(pos);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Update Indicator: %u", update_indic);
+ p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
pos += 2;
p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token,
@@ -390,8 +420,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
/* TODO: fix the length limit to match with the maximum frame length */
if (wpabuf_len(resp_tlvs) > 1400) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response long "
- "enough to require fragmentation");
+ p2p_dbg(p2p, "SD response long enough to require fragmentation");
if (p2p->sd_resp) {
/*
* TODO: Could consider storing the fragmented response
@@ -400,14 +429,12 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
* Though, that would eat more memory, so there are
* also benefits to just using a single buffer.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop "
- "previous SD response");
+ p2p_dbg(p2p, "Drop previous SD response");
wpabuf_free(p2p->sd_resp);
}
p2p->sd_resp = wpabuf_dup(resp_tlvs);
if (p2p->sd_resp == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_ERROR, "P2P: Failed to "
- "allocate SD response fragmentation area");
+ p2p_err(p2p, "Failed to allocate SD response fragmentation area");
return;
}
os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN);
@@ -417,8 +444,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS,
1, p2p->srv_update_indic, NULL);
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response fits "
- "in initial response");
+ p2p_dbg(p2p, "SD response fits in initial response");
resp = p2p_build_sd_response(dialog_token,
WLAN_STATUS_SUCCESS, 0,
p2p->srv_update_indic, resp_tlvs);
@@ -430,8 +456,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(resp);
}
@@ -451,21 +476,18 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore unexpected GAS Initial Response from "
+ p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from "
MACSTR, MAC2STR(sa));
return;
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_clear_timeout(p2p);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GAS Initial Response from " MACSTR " (len=%d)",
+ p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)",
MAC2STR(sa), (int) len);
if (len < 5 + 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Too short GAS Initial Response frame");
+ p2p_dbg(p2p, "Too short GAS Initial Response frame");
return;
}
@@ -475,20 +497,16 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos += 2;
comeback_delay = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: dialog_token=%u status_code=%u comeback_delay=%u",
+ p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u",
dialog_token, status_code, comeback_delay);
if (status_code) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Discovery failed: status code %u",
+ p2p_dbg(p2p, "Service Discovery failed: status code %u",
status_code);
return;
}
if (*pos != WLAN_EID_ADV_PROTO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected IE in GAS Initial Response: %u",
- *pos);
+ p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos);
return;
}
pos++;
@@ -496,15 +514,13 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
slen = *pos++;
next = pos + slen;
if (next > end || slen < 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid IE in GAS Initial Response");
+ p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
return;
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported GAS advertisement protocol id %u",
+ p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
*pos);
return;
}
@@ -512,27 +528,22 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Response */
if (pos + 2 > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query "
- "Response");
+ p2p_dbg(p2p, "Too short Query Response");
return;
}
slen = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d",
- slen);
+ p2p_dbg(p2p, "Query Response Length: %d", slen);
if (pos + slen > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query "
- "Response data");
+ p2p_dbg(p2p, "Not enough Query Response data");
return;
}
end = pos + slen;
if (comeback_delay) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Fragmented "
- "response - request fragments");
+ p2p_dbg(p2p, "Fragmented response - request fragments");
if (p2p->sd_rx_resp) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop "
- "old SD reassembly buffer");
+ p2p_dbg(p2p, "Drop old SD reassembly buffer");
wpabuf_free(p2p->sd_rx_resp);
p2p->sd_rx_resp = NULL;
}
@@ -544,8 +555,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
if (pos + 4 > end)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+ p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
@@ -553,41 +563,29 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
slen = WPA_GET_LE16(pos);
pos += 2;
if (pos + slen > end || slen < 3 + 1) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid ANQP Query Response length");
+ p2p_dbg(p2p, "Invalid ANQP Query Response length");
return;
}
- if (WPA_GET_BE24(pos) != OUI_WFA) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+ if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
+ p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
+ WPA_GET_BE32(pos));
return;
}
- pos += 3;
-
- if (*pos != P2P_OUI_TYPE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP vendor type %u", *pos);
- return;
- }
- pos++;
+ pos += 4;
if (pos + 2 > end)
return;
update_indic = WPA_GET_LE16(pos);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Update Indicator: %u", update_indic);
+ p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
pos += 2;
- p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
- p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
p2p->sd_peer = NULL;
if (p2p->sd_query) {
if (!p2p->sd_query->for_all_peers) {
struct p2p_sd_query *q;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Remove completed SD query %p",
+ p2p_dbg(p2p, "Remove completed SD query %p",
p2p->sd_query);
q = p2p->sd_query;
p2p_unlink_sd_query(p2p, p2p->sd_query);
@@ -615,22 +613,20 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
if (len < 1)
return;
dialog_token = *data;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dialog Token: %u",
- dialog_token);
+ p2p_dbg(p2p, "Dialog Token: %u", dialog_token);
if (dialog_token != p2p->sd_resp_dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
- "response fragment for dialog token %u", dialog_token);
+ p2p_dbg(p2p, "No pending SD response fragment for dialog token %u",
+ dialog_token);
return;
}
if (p2p->sd_resp == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
- "response fragment available");
+ p2p_dbg(p2p, "No pending SD response fragment available");
return;
}
if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
- "response fragment for " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "No pending SD response fragment for " MACSTR,
+ MAC2STR(sa));
return;
}
@@ -647,19 +643,16 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
wpabuf_len(p2p->sd_resp));
if (resp == NULL)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send GAS Comeback "
- "Response (frag_id %d more=%d frag_len=%d)",
+ p2p_dbg(p2p, "Send GAS Comeback Response (frag_id %d more=%d frag_len=%d)",
p2p->sd_frag_id, more, (int) frag_len);
p2p->sd_frag_id++;
p2p->sd_resp_pos += frag_len;
if (more) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: %d more bytes "
- "remain to be sent",
+ p2p_dbg(p2p, "%d more bytes remain to be sent",
(int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos));
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: All fragments of "
- "SD response sent");
+ p2p_dbg(p2p, "All fragments of SD response sent");
wpabuf_free(p2p->sd_resp);
p2p->sd_resp = NULL;
}
@@ -668,8 +661,7 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(resp);
}
@@ -692,21 +684,18 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore unexpected GAS Comeback Response from "
+ p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from "
MACSTR, MAC2STR(sa));
return;
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_clear_timeout(p2p);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GAS Comeback Response from " MACSTR " (len=%d)",
+ p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)",
MAC2STR(sa), (int) len);
if (len < 6 + 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Too short GAS Comeback Response frame");
+ p2p_dbg(p2p, "Too short GAS Comeback Response frame");
return;
}
@@ -719,22 +708,19 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos++;
comeback_delay = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
+ p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
"comeback_delay=%u",
dialog_token, status_code, frag_id, more_frags,
comeback_delay);
/* TODO: check frag_id match */
if (status_code) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Discovery failed: status code %u",
+ p2p_dbg(p2p, "Service Discovery failed: status code %u",
status_code);
return;
}
if (*pos != WLAN_EID_ADV_PROTO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected IE in GAS Comeback Response: %u",
+ p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u",
*pos);
return;
}
@@ -743,15 +729,13 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
slen = *pos++;
next = pos + slen;
if (next > end || slen < 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid IE in GAS Comeback Response");
+ p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
return;
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported GAS advertisement protocol id %u",
+ p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
*pos);
return;
}
@@ -759,22 +743,18 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Response */
if (pos + 2 > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query "
- "Response");
+ p2p_dbg(p2p, "Too short Query Response");
return;
}
slen = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d",
- slen);
+ p2p_dbg(p2p, "Query Response Length: %d", slen);
if (pos + slen > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query "
- "Response data");
+ p2p_dbg(p2p, "Not enough Query Response data");
return;
}
if (slen == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No Query Response "
- "data");
+ p2p_dbg(p2p, "No Query Response data");
return;
}
end = pos + slen;
@@ -791,77 +771,60 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
if (pos + 4 > end)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+ p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
slen = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: ANQP Query Response "
- "length: %u", slen);
+ p2p_dbg(p2p, "ANQP Query Response length: %u", slen);
if (slen < 3 + 1) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid ANQP Query Response length");
+ p2p_dbg(p2p, "Invalid ANQP Query Response length");
return;
}
if (pos + 4 > end)
return;
- if (WPA_GET_BE24(pos) != OUI_WFA) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+ if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
+ p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
+ WPA_GET_BE32(pos));
return;
}
- pos += 3;
-
- if (*pos != P2P_OUI_TYPE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP vendor type %u", *pos);
- return;
- }
- pos++;
+ pos += 4;
if (pos + 2 > end)
return;
p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Update Indicator: %u", p2p->sd_rx_update_indic);
+ p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
pos += 2;
skip_nqp_header:
if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0)
return;
wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Current SD reassembly "
- "buffer length: %u",
+ p2p_dbg(p2p, "Current SD reassembly buffer length: %u",
(unsigned int) wpabuf_len(p2p->sd_rx_resp));
if (more_frags) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: More fragments "
- "remains");
+ p2p_dbg(p2p, "More fragments remains");
/* TODO: what would be a good size limit? */
if (wpabuf_len(p2p->sd_rx_resp) > 64000) {
wpabuf_free(p2p->sd_rx_resp);
p2p->sd_rx_resp = NULL;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too long "
- "SD response - drop it");
+ p2p_dbg(p2p, "Too long SD response - drop it");
return;
}
p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
return;
}
- p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
- p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
p2p->sd_peer = NULL;
if (p2p->sd_query) {
if (!p2p->sd_query->for_all_peers) {
struct p2p_sd_query *q;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Remove completed SD query %p",
+ p2p_dbg(p2p, "Remove completed SD query %p",
p2p->sd_query);
q = p2p->sd_query;
p2p_unlink_sd_query(p2p, p2p->sd_query);
@@ -904,12 +867,20 @@ void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
q->next = p2p->sd_queries;
p2p->sd_queries = q;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p", q);
+ p2p_dbg(p2p, "Added SD Query %p", q);
if (dst == NULL) {
struct p2p_device *dev;
- dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
- dev->flags &= ~P2P_DEV_SD_INFO;
+
+ p2p->num_p2p_sd_queries++;
+
+ /* Update all the devices for the newly added broadcast query */
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (dev->sd_pending_bcast_queries <= 0)
+ dev->sd_pending_bcast_queries = 1;
+ else
+ dev->sd_pending_bcast_queries++;
+ }
}
return q;
@@ -938,8 +909,7 @@ void p2p_sd_service_update(struct p2p_data *p2p)
int p2p_sd_cancel_request(struct p2p_data *p2p, void *req)
{
if (p2p_unlink_sd_query(p2p, req)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cancel pending SD query %p", req);
+ p2p_dbg(p2p, "Cancel pending SD query %p", req);
p2p_free_sd_query(req);
return 0;
}
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index bcc690d8469bb..f32751d79ca8b 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "common/ieee802_11_common.h"
#include "p2p_i.h"
@@ -46,127 +47,69 @@ int p2p_random(char *buf, size_t len)
}
-static int p2p_channel_to_freq_j4(int reg_class, int channel)
-{
- /* Table J-4 in P802.11REVmb/D4.0 - Global operating classes */
- /* TODO: more regulatory classes */
- switch (reg_class) {
- case 81:
- /* channels 1..13 */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 82:
- /* channel 14 */
- if (channel != 14)
- return -1;
- return 2414 + 5 * channel;
- case 83: /* channels 1..9; 40 MHz */
- case 84: /* channels 5..13; 40 MHz */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 115: /* channels 36,40,44,48; indoor only */
- case 118: /* channels 52,56,60,64; dfs */
- if (channel < 36 || channel > 64)
- return -1;
- return 5000 + 5 * channel;
- case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 116: /* channels 36,44; 40 MHz; indoor only */
- case 117: /* channels 40,48; 40 MHz; indoor only */
- case 119: /* channels 52,60; 40 MHz; dfs */
- case 120: /* channels 56,64; 40 MHz; dfs */
- if (channel < 36 || channel > 64)
- return -1;
- return 5000 + 5 * channel;
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- }
- return -1;
-}
-
-
/**
* p2p_channel_to_freq - Convert channel info to frequency
- * @country: Country code
- * @reg_class: Regulatory class
+ * @op_class: Operating class
* @channel: Channel number
* Returns: Frequency in MHz or -1 if the specified channel is unknown
*/
-int p2p_channel_to_freq(const char *country, int reg_class, int channel)
+int p2p_channel_to_freq(int op_class, int channel)
{
- if (country[2] == 0x04)
- return p2p_channel_to_freq_j4(reg_class, channel);
-
- /* These are mainly for backwards compatibility; to be removed */
- switch (reg_class) {
- case 1: /* US/1, EU/1, JP/1 = 5 GHz, channels 36,40,44,48 */
- if (channel < 36 || channel > 48)
- return -1;
- return 5000 + 5 * channel;
- case 3: /* US/3 = 5 GHz, channels 149,153,157,161 */
- case 5: /* US/5 = 5 GHz, channels 149,153,157,161 */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 4: /* EU/4 = 2.407 GHz, channels 1..13 */
- case 12: /* US/12 = 2.407 GHz, channels 1..11 */
- case 30: /* JP/30 = 2.407 GHz, channels 1..13 */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 31: /* JP/31 = 2.414 GHz, channel 14 */
- if (channel != 14)
- return -1;
- return 2414 + 5 * channel;
- }
-
- return -1;
+ return ieee80211_chan_to_freq(NULL, op_class, channel);
}
/**
* p2p_freq_to_channel - Convert frequency into channel info
- * @country: Country code
- * @reg_class: Buffer for returning regulatory class
+ * @op_class: Buffer for returning operating class
* @channel: Buffer for returning channel number
* Returns: 0 on success, -1 if the specified frequency is unknown
*/
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
- u8 *channel)
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
{
/* TODO: more operating classes */
if (freq >= 2412 && freq <= 2472) {
- *reg_class = 81; /* 2.407 GHz, channels 1..13 */
+ if ((freq - 2407) % 5)
+ return -1;
+
+ *op_class = 81; /* 2.407 GHz, channels 1..13 */
*channel = (freq - 2407) / 5;
return 0;
}
if (freq == 2484) {
- *reg_class = 82; /* channel 14 */
+ *op_class = 82; /* channel 14 */
*channel = 14;
return 0;
}
if (freq >= 5180 && freq <= 5240) {
- *reg_class = 115; /* 5 GHz, channels 36..48 */
+ if ((freq - 5000) % 5)
+ return -1;
+
+ *op_class = 115; /* 5 GHz, channels 36..48 */
*channel = (freq - 5000) / 5;
return 0;
}
if (freq >= 5745 && freq <= 5805) {
- *reg_class = 124; /* 5 GHz, channels 149..161 */
+ if ((freq - 5000) % 5)
+ return -1;
+
+ *op_class = 124; /* 5 GHz, channels 149..161 */
*channel = (freq - 5000) / 5;
return 0;
}
+ if (freq >= 58320 && freq <= 64800) {
+ if ((freq - 58320) % 2160)
+ return -1;
+
+ *op_class = 180; /* 60 GHz, channels 1..4 */
+ *channel = (freq - 56160) / 2160;
+ return 0;
+ }
+
return -1;
}
@@ -230,6 +173,115 @@ void p2p_channels_intersect(const struct p2p_channels *a,
}
+static void p2p_op_class_union(struct p2p_reg_class *cl,
+ const struct p2p_reg_class *b_cl)
+{
+ size_t i, j;
+
+ for (i = 0; i < b_cl->channels; i++) {
+ for (j = 0; j < cl->channels; j++) {
+ if (b_cl->channel[i] == cl->channel[j])
+ break;
+ }
+ if (j == cl->channels) {
+ if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
+ return;
+ cl->channel[cl->channels++] = b_cl->channel[i];
+ }
+ }
+}
+
+
+/**
+ * p2p_channels_union_inplace - Inplace union of channel lists
+ * @res: Input data and place for returning union of the channel sets
+ * @b: Second set of channels
+ */
+void p2p_channels_union_inplace(struct p2p_channels *res,
+ const struct p2p_channels *b)
+{
+ size_t i, j;
+
+ for (i = 0; i < res->reg_classes; i++) {
+ struct p2p_reg_class *cl = &res->reg_class[i];
+ for (j = 0; j < b->reg_classes; j++) {
+ const struct p2p_reg_class *b_cl = &b->reg_class[j];
+ if (cl->reg_class != b_cl->reg_class)
+ continue;
+ p2p_op_class_union(cl, b_cl);
+ }
+ }
+
+ for (j = 0; j < b->reg_classes; j++) {
+ const struct p2p_reg_class *b_cl = &b->reg_class[j];
+
+ for (i = 0; i < res->reg_classes; i++) {
+ struct p2p_reg_class *cl = &res->reg_class[i];
+ if (cl->reg_class == b_cl->reg_class)
+ break;
+ }
+
+ if (i == res->reg_classes) {
+ if (res->reg_classes == P2P_MAX_REG_CLASSES)
+ return;
+ os_memcpy(&res->reg_class[res->reg_classes++],
+ b_cl, sizeof(struct p2p_reg_class));
+ }
+ }
+}
+
+
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res)
+{
+ os_memcpy(res, a, sizeof(*res));
+ p2p_channels_union_inplace(res, b);
+}
+
+
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+ const struct wpa_freq_range_list *list)
+{
+ size_t o, c;
+
+ if (list == NULL)
+ return;
+
+ o = 0;
+ while (o < chan->reg_classes) {
+ struct p2p_reg_class *op = &chan->reg_class[o];
+
+ c = 0;
+ while (c < op->channels) {
+ int freq = p2p_channel_to_freq(op->reg_class,
+ op->channel[c]);
+ if (freq > 0 && freq_range_list_includes(list, freq)) {
+ op->channels--;
+ os_memmove(&op->channel[c],
+ &op->channel[c + 1],
+ op->channels - c);
+ } else
+ c++;
+ }
+
+ if (op->channels == 0) {
+ chan->reg_classes--;
+ os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1],
+ (chan->reg_classes - o) *
+ sizeof(struct p2p_reg_class));
+ } else
+ o++;
+ }
+}
+
+
/**
* p2p_channels_includes - Check whether a channel is included in the list
* @channels: List of supported channels
@@ -254,12 +306,208 @@ int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
}
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+ unsigned int freq)
+{
+ size_t i, j;
+ for (i = 0; i < channels->reg_classes; i++) {
+ const struct p2p_reg_class *reg = &channels->reg_class[i];
+ for (j = 0; j < reg->channels; j++) {
+ if (p2p_channel_to_freq(reg->reg_class,
+ reg->channel[j]) == (int) freq)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
{
u8 op_reg_class, op_channel;
- if (p2p_freq_to_channel(p2p->cfg->country, freq,
- &op_reg_class, &op_channel) < 0)
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
return 0;
return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
op_channel);
}
+
+
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
+{
+ u8 op_reg_class, op_channel;
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+ return 0;
+ return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+ op_channel) &&
+ !freq_range_list_includes(&p2p->no_go_freq, freq);
+}
+
+
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
+{
+ u8 op_reg_class, op_channel;
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+ return 0;
+ return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+ op_channel) ||
+ p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
+ op_channel);
+}
+
+
+unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
+ const struct p2p_channels *channels)
+{
+ unsigned int i;
+ int freq = 0;
+ const struct p2p_channels *tmpc = channels ?
+ channels : &p2p->cfg->channels;
+
+ if (tmpc == NULL)
+ return 0;
+
+ for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
+ freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
+ p2p->cfg->pref_chan[i].chan);
+ if (p2p_channels_includes_freq(tmpc, freq))
+ return freq;
+ }
+ return 0;
+}
+
+
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+ const struct p2p_channels *chan)
+{
+ char buf[500], *pos, *end;
+ size_t i, j;
+ int ret;
+
+ pos = buf;
+ end = pos + sizeof(buf);
+
+ for (i = 0; i < chan->reg_classes; i++) {
+ const struct p2p_reg_class *c;
+ c = &chan->reg_class[i];
+ ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+
+ for (j = 0; j < c->channels; j++) {
+ ret = os_snprintf(pos, end - pos, "%s%u",
+ j == 0 ? "" : ",",
+ c->channel[j]);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+ }
+ }
+ *pos = '\0';
+
+ p2p_dbg(p2p, "%s:%s", title, buf);
+}
+
+
+static u8 p2p_channel_pick_random(const u8 *channels, unsigned int num_channels)
+{
+ unsigned int r;
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
+ r %= num_channels;
+ return channels[r];
+}
+
+
+int p2p_channel_select(struct p2p_channels *chans, const int *classes,
+ u8 *op_class, u8 *op_channel)
+{
+ unsigned int i, j;
+
+ for (j = 0; classes == NULL || classes[j]; j++) {
+ for (i = 0; i < chans->reg_classes; i++) {
+ struct p2p_reg_class *c = &chans->reg_class[i];
+
+ if (c->channels == 0)
+ continue;
+
+ if (classes == NULL || c->reg_class == classes[j]) {
+ /*
+ * Pick one of the available channels in the
+ * operating class at random.
+ */
+ *op_class = c->reg_class;
+ *op_channel = p2p_channel_pick_random(
+ c->channel, c->channels);
+ return 0;
+ }
+ }
+ if (classes == NULL)
+ break;
+ }
+
+ return -1;
+}
+
+
+int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
+ u8 *op_channel)
+{
+ u8 chan[4];
+ unsigned int num_channels = 0;
+
+ /* Try to find available social channels from 2.4 GHz */
+ if (p2p_channels_includes(chans, 81, 1))
+ chan[num_channels++] = 1;
+ if (p2p_channels_includes(chans, 81, 6))
+ chan[num_channels++] = 6;
+ if (p2p_channels_includes(chans, 81, 11))
+ chan[num_channels++] = 11;
+
+ /* Try to find available social channels from 60 GHz */
+ if (p2p_channels_includes(chans, 180, 2))
+ chan[num_channels++] = 2;
+
+ if (num_channels == 0)
+ return -1;
+
+ *op_channel = p2p_channel_pick_random(chan, num_channels);
+ if (*op_channel == 2)
+ *op_class = 180;
+ else
+ *op_class = 81;
+
+ return 0;
+}
+
+
+int p2p_channels_to_freqs(const struct p2p_channels *channels, int *freq_list,
+ unsigned int max_len)
+{
+ unsigned int i, idx;
+
+ if (!channels || max_len == 0)
+ return 0;
+
+ for (i = 0, idx = 0; i < channels->reg_classes; i++) {
+ const struct p2p_reg_class *c = &channels->reg_class[i];
+ unsigned int j;
+
+ if (idx + 1 == max_len)
+ break;
+ for (j = 0; j < c->channels; j++) {
+ int freq;
+ if (idx + 1 == max_len)
+ break;
+ freq = p2p_channel_to_freq(c->reg_class,
+ c->channel[j]);
+ if (freq < 0)
+ continue;
+ freq_list[idx++] = freq;
+ }
+ }
+
+ freq_list[idx] = 0;
+
+ return idx;
+}