Update to new version 0.8.16 from BRCM
Sync with main tree commit b8349523e460493fa0b4de36c689595109e45e91
Author: Neeraj Kumar Garg <neerajkg@broadcom.com>
Date: Tue Dec 27 23:21:45 2011 +0200
P2P: Reject p2p_group_add if forced frequency is not acceptable
Change-Id: Icb4541a371b05c270e80440d7a7fdea7f33ff61e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
old mode 100644
new mode 100755
index bef3926..8c768f6
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -17,6 +17,9 @@
#include "common.h"
#include "eloop.h"
#include "common/ieee802_11_defs.h"
+#ifdef ANDROID_P2P
+#include "common/wpa_ctrl.h"
+#endif
#include "common/ieee802_11_common.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
@@ -106,12 +109,42 @@
return "INVITE";
case P2P_INVITE_LISTEN:
return "INVITE_LISTEN";
+ case P2P_SEARCH_WHEN_READY:
+ return "SEARCH_WHEN_READY";
default:
return "?";
}
}
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
+{
+ struct p2p_device *dev = NULL;
+
+ if (!addr || !p2p)
+ return 0;
+
+ dev = p2p_get_device(p2p, addr);
+ if (dev)
+ return dev->wps_prov_info;
+ else
+ return 0;
+}
+
+
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+{
+ struct p2p_device *dev = NULL;
+
+ if (!iface_addr || !p2p)
+ return;
+
+ dev = p2p_get_device_interface(p2p, iface_addr);
+ if (dev)
+ dev->wps_prov_info = 0;
+}
+
+
void p2p_set_state(struct p2p_data *p2p, int new_state)
{
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
@@ -144,6 +177,8 @@
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;
p2p->go_neg_peer = NULL;
os_memset(&res, 0, sizeof(res));
@@ -219,6 +254,12 @@
p2p->pending_listen_usec = (timeout % 1000) * 1000;
if (p2p->p2p_scan_running) {
+ if (p2p->start_after_scan == P2P_AFTER_SCAN_NOTHING) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "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->start_after_scan = P2P_AFTER_SCAN_LISTEN;
@@ -363,7 +404,7 @@
* group, the information will be restored in the loop following this.
*/
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
- if (os_memcpy(dev->member_in_go_iface, go_interface_addr,
+ if (os_memcmp(dev->member_in_go_iface, go_interface_addr,
ETH_ALEN) == 0) {
os_memset(dev->member_in_go_iface, 0, ETH_ALEN);
os_memset(dev->member_in_go_dev, 0, ETH_ALEN);
@@ -372,6 +413,9 @@
for (c = 0; c < info.num_clients; c++) {
struct p2p_client_info *cli = &info.client[c];
+ if (os_memcmp(cli->p2p_device_addr, p2p->cfg->dev_addr,
+ ETH_ALEN) == 0)
+ continue; /* ignore our own entry */
dev = p2p_get_device(p2p, cli->p2p_device_addr);
if (dev) {
/*
@@ -574,11 +618,6 @@
freq, msg.ds_params ? *msg.ds_params : -1);
}
dev->listen_freq = freq;
-#ifdef ANDROID_BRCM_P2P_PATCH
- if(msg.group_info)
- dev->go_state = REMOTE_GO;
-#endif
-
if (msg.group_info)
dev->oper_freq = freq;
dev->info.level = level;
@@ -631,9 +670,10 @@
int i;
if (p2p->go_neg_peer == dev) {
-#ifdef ANDROID_BRCM_P2P_PATCH
+ /*
+ * If GO Negotiation is in progress, report that it has failed.
+ */
p2p_go_neg_failed(p2p, dev, -1);
-#endif
p2p->go_neg_peer = NULL;
}
if (p2p->invite_peer == dev)
@@ -787,19 +827,18 @@
enum p2p_after_scan op;
if (p2p->after_scan_tx) {
- int ret;
/* 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");
- ret = p2p->cfg->send_action(p2p->cfg->cb_ctx,
- p2p->after_scan_tx->freq,
- p2p->after_scan_tx->dst,
- p2p->after_scan_tx->src,
- p2p->after_scan_tx->bssid,
- (u8 *) (p2p->after_scan_tx + 1),
- p2p->after_scan_tx->len,
- p2p->after_scan_tx->wait_time);
+ p2p->cfg->send_action(p2p->cfg->cb_ctx,
+ p2p->after_scan_tx->freq,
+ p2p->after_scan_tx->dst,
+ p2p->after_scan_tx->src,
+ p2p->after_scan_tx->bssid,
+ (u8 *) (p2p->after_scan_tx + 1),
+ p2p->after_scan_tx->len,
+ p2p->after_scan_tx->wait_time);
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
return 1;
@@ -888,6 +927,7 @@
p2p_device_clear_reported(p2p);
p2p_set_state(p2p, P2P_SEARCH);
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+ p2p->last_p2p_find_timeout = timeout;
if (timeout)
eloop_register_timeout(timeout, 0, p2p_find_timeout,
p2p, NULL);
@@ -913,21 +953,47 @@
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");
+ p2p_set_state(p2p, P2P_IDLE);
+ eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
}
return res;
}
+int p2p_other_scan_completed(struct p2p_data *p2p)
+{
+ 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) < 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");
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p_clear_timeout(p2p);
p2p_set_state(p2p, P2P_IDLE);
+#ifdef ANDROID_P2P
+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+#endif
+
p2p_free_req_dev_types(p2p);
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
p2p->go_neg_peer = NULL;
@@ -938,6 +1004,16 @@
"since we are on correct channel for response");
return;
}
+ if (p2p->drv_in_listen) {
+ /*
+ * The driver may not deliver callback to p2p_listen_end()
+ * 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->drv_in_listen = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
}
@@ -1027,6 +1103,26 @@
}
+static void p2p_set_dev_persistent(struct p2p_device *dev,
+ int persistent_group)
+{
+ switch (persistent_group) {
+ case 0:
+ dev->flags &= ~(P2P_DEV_PREFER_PERSISTENT_GROUP |
+ P2P_DEV_PREFER_PERSISTENT_RECONN);
+ break;
+ case 1:
+ dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
+ dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_RECONN;
+ break;
+ case 2:
+ dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP |
+ P2P_DEV_PREFER_PERSISTENT_RECONN;
+ break;
+ }
+}
+
+
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
@@ -1044,6 +1140,7 @@
if (p2p_prepare_channel(p2p, force_freq) < 0)
return -1;
+ p2p->ssid_set = 0;
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,
@@ -1083,10 +1180,7 @@
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
- if (persistent_group)
- dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
- else
- dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+ p2p_set_dev_persistent(dev, persistent_group);
p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
@@ -1156,10 +1250,7 @@
dev->flags &= ~P2P_DEV_USER_REJECTED;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
- if (persistent_group)
- dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
- else
- dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+ p2p_set_dev_persistent(dev, persistent_group);
p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
@@ -1270,8 +1361,12 @@
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
res.wps_method = peer->wps_method;
- if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
- res.persistent_group = 1;
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+ res.persistent_group = 2;
+ else
+ res.persistent_group = 1;
+ }
if (go) {
/* Setup AP mode for WPS provisioning */
@@ -1311,6 +1406,7 @@
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;
@@ -1367,9 +1463,9 @@
}
-void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da, const u8 *sa,
- const u8 *bssid, const u8 *data, size_t len,
- int freq)
+static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da,
+ const u8 *sa, const u8 *bssid, const u8 *data,
+ size_t len, int freq)
{
if (len < 1)
return;
@@ -1514,6 +1610,7 @@
if (dev) {
if (dev->country[0] == 0 && msg.listen_channel)
os_memcpy(dev->country, msg.listen_channel, 3);
+ os_get_time(&dev->last_seen);
p2p_parse_free(&msg);
return; /* already known */
}
@@ -1653,13 +1750,47 @@
}
-static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
+static int is_11b(u8 rate)
+{
+ return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+}
+
+
+static int supp_rates_11b_only(struct ieee802_11_elems *elems)
+{
+ int num_11b = 0, num_others = 0;
+ int i;
+
+ 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++;
+ }
+
+ return num_11b > 0 && num_others == 0;
+}
+
+
+static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
+ const u8 *dst, const u8 *bssid, const u8 *ie,
size_t ie_len)
{
struct ieee802_11_elems elems;
struct wpabuf *buf;
struct ieee80211_mgmt *resp;
- struct wpabuf *wps;
+ struct p2p_message msg;
struct wpabuf *ies;
if (!p2p->in_listen || !p2p->drv_in_listen) {
@@ -1678,6 +1809,18 @@
return;
}
+ if (dst && !is_broadcast_ether_addr(dst) &&
+ os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
+ /* Not sent to the broadcast address or our P2P Device Address
+ */
+ return;
+ }
+
+ if (bssid && !is_broadcast_ether_addr(bssid)) {
+ /* Not sent to the Wildcard BSSID */
+ return;
+ }
+
if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
0) {
@@ -1685,14 +1828,32 @@
return;
}
- /* Check Requested Device Type match */
- wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
- if (wps && !p2p_match_dev_type(p2p, wps)) {
- wpabuf_free(wps);
- /* No match with Requested Device Type */
+ if (supp_rates_11b_only(&elems)) {
+ /* Indicates support for 11b rates only */
return;
}
- wpabuf_free(wps);
+
+ os_memset(&msg, 0, sizeof(msg));
+ if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
+ /* Could not parse P2P attributes */
+ return;
+ }
+
+ if (msg.device_id &&
+ os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
+ /* Device ID did not match */
+ p2p_parse_free(&msg);
+ return;
+ }
+
+ /* Check Requested Device Type match */
+ if (msg.wps_attributes &&
+ !p2p_match_dev_type(p2p, msg.wps_attributes)) {
+ /* No match with Requested Device Type */
+ p2p_parse_free(&msg);
+ return;
+ }
+ p2p_parse_free(&msg);
if (!p2p->cfg->send_probe_resp)
return; /* Response generated elsewhere */
@@ -1759,12 +1920,12 @@
}
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
- size_t ie_len)
+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+ const u8 *bssid, const u8 *ie, size_t ie_len)
{
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
- p2p_reply_probe(p2p, addr, ie, ie_len);
+ p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
p2p->go_neg_peer &&
@@ -2221,11 +2382,11 @@
} else if (dev->req_config_methods &&
!(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provisioning Discovery Request to "
+ "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)
+ if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
return;
}
}
@@ -2267,7 +2428,7 @@
* p2p_retry_pd - Retry any pending provision disc requests in IDLE state
* @p2p: P2P module context from p2p_init()
*/
-void p2p_retry_pd(struct p2p_data *p2p)
+static void p2p_retry_pd(struct p2p_data *p2p)
{
struct p2p_device *dev;
@@ -2290,11 +2451,11 @@
continue;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provisioning Discovery Request to "
+ "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, 0);
+ p2p_send_prov_disc_req(p2p, dev, 0, 0);
return;
}
}
@@ -2395,6 +2556,12 @@
}
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
+{
+ return 100;
+}
+
+
int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
{
return p2p_attr_text(p2p_ie, buf, end);
@@ -2674,15 +2841,7 @@
* state once per second to give other uses a chance to use the radio.
*/
p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
-#ifdef ANDROID_BRCM_P2P_PATCH
- /*
- * We need to be back in Listen state soon enough so that we don't miss
- * the GO Nego req from the peer.
- */
- p2p_set_timeout(p2p, 0, 0);
-#else
- p2p_set_timeout(p2p, 1, 0);
-#endif
+ p2p_set_timeout(p2p, 0, 500000);
}
@@ -2862,6 +3021,8 @@
case P2P_INVITE_LISTEN:
p2p_timeout_invite_listen(p2p);
break;
+ case P2P_SEARCH_WHEN_READY:
+ break;
}
}
@@ -2884,13 +3045,11 @@
}
-static const char * p2p_wps_method_text(enum p2p_wps_method method)
+const char * p2p_wps_method_text(enum p2p_wps_method method)
{
switch (method) {
case WPS_NOT_READY:
return "not-ready";
- case WPS_PIN_LABEL:
- return "Label";
case WPS_PIN_DISPLAY:
return "Display";
case WPS_PIN_KEYPAD:
@@ -2918,14 +3077,10 @@
}
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
- char *buf, size_t buflen)
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+ const u8 *addr, int next)
{
struct p2p_device *dev;
- int res;
- char *pos, *end;
- struct os_time now;
- char devtype[WPS_DEV_TYPE_BUFSIZE];
if (addr)
dev = p2p_get_device(p2p, addr);
@@ -2939,35 +3094,37 @@
}
if (dev == NULL)
+ return NULL;
+
+ return &dev->info;
+}
+
+
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+ char *buf, size_t buflen)
+{
+ struct p2p_device *dev;
+ int res;
+ char *pos, *end;
+ struct os_time now;
+
+ if (info == NULL)
return -1;
+ dev = (struct p2p_device *) (((u8 *) info) -
+ offsetof(struct p2p_device, info));
+
pos = buf;
end = buf + buflen;
- res = os_snprintf(pos, end - pos, MACSTR "\n",
- MAC2STR(dev->info.p2p_device_addr));
- if (res < 0 || res >= end - pos)
- return pos - buf;
- pos += res;
-
os_get_time(&now);
res = os_snprintf(pos, end - pos,
"age=%d\n"
"listen_freq=%d\n"
- "level=%d\n"
"wps_method=%s\n"
"interface_addr=" MACSTR "\n"
"member_in_go_dev=" MACSTR "\n"
"member_in_go_iface=" MACSTR "\n"
- "pri_dev_type=%s\n"
- "device_name=%s\n"
- "manufacturer=%s\n"
- "model_name=%s\n"
- "model_number=%s\n"
- "serial_number=%s\n"
- "config_methods=0x%x\n"
- "dev_capab=0x%x\n"
- "group_capab=0x%x\n"
"go_neg_req_sent=%d\n"
"go_state=%s\n"
"dialog_token=%u\n"
@@ -2981,21 +3138,10 @@
"invitation_reqs=%u\n",
(int) (now.sec - dev->last_seen.sec),
dev->listen_freq,
- dev->info.level,
p2p_wps_method_text(dev->wps_method),
MAC2STR(dev->interface_addr),
MAC2STR(dev->member_in_go_dev),
MAC2STR(dev->member_in_go_iface),
- wps_dev_type_bin2str(dev->info.pri_dev_type,
- devtype, sizeof(devtype)),
- dev->info.device_name,
- dev->info.manufacturer,
- dev->info.model_name,
- dev->info.model_number,
- dev->info.serial_number,
- dev->info.config_methods,
- dev->info.dev_capab,
- dev->info.group_capab,
dev->go_neg_req_sent,
p2p_go_state_text(dev->go_state),
dev->dialog_token,
@@ -3064,6 +3210,12 @@
}
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr)
+{
+ return p2p_get_device(p2p, addr) != NULL;
+}
+
+
void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
{
if (enabled) {
@@ -3624,3 +3776,20 @@
return &dev->info;
}
+
+#ifdef ANDROID_P2P
+int p2p_search_in_progress(struct p2p_data *p2p)
+{
+ if (p2p == NULL)
+ return 0;
+
+ return p2p->state == P2P_SEARCH;
+}
+#endif
+
+int p2p_in_progress(struct p2p_data *p2p)
+{
+ if (p2p == NULL)
+ return 0;
+ return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
old mode 100644
new mode 100755
index 72c90b1..05b4a16
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -56,7 +56,7 @@
};
enum p2p_wps_method {
- WPS_NOT_READY, WPS_PIN_LABEL, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
+ WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
};
/**
@@ -120,6 +120,9 @@
/**
* persistent_group - Whether the group should be made persistent
+ * 0 = not persistent
+ * 1 = persistent group without persistent reconnect
+ * 2 = persistent group with persistent reconnect
*/
int persistent_group;
@@ -292,17 +295,6 @@
*/
u8 dev_addr[ETH_ALEN];
-#ifdef ANDROID_BRCM_P2P_PATCH
- /**
- * p2p_dev_addr - P2P Device Address
- *
- * Holds the p2p device address. If the driver uses primary mac address
- * for p2p operations, then this will hold the same value as that of
- * dev_addr.
- */
- u8 p2p_dev_addr[ETH_ALEN];
-#endif
-
/**
* dev_name - Device Name
*/
@@ -602,6 +594,8 @@
* @supp_config_methods: Supported configuration Methods
* @dev_capab: Device Capabilities
* @group_capab: Group Capabilities
+ * @group_id: P2P Group ID (or %NULL if not included)
+ * @group_id_len: Length of P2P Group ID
*
* This callback is used to indicate reception of a Provision Discovery
* Request frame that the P2P module accepted.
@@ -609,7 +603,8 @@
void (*prov_disc_req)(void *ctx, const u8 *peer, u16 config_methods,
const u8 *dev_addr, const u8 *pri_dev_type,
const char *dev_name, u16 supp_config_methods,
- u8 dev_capab, u8 group_capab);
+ u8 dev_capab, u8 group_capab,
+ const u8 *group_id, size_t group_id_len);
/**
* prov_disc_resp - Callback on Provisiong Discovery Response
@@ -857,7 +852,9 @@
* @go_intent: Local GO intent value (1..15)
* @own_interface_addr: Intended interface address to use with the group
* @force_freq: The only allowed channel frequency in MHz or 0
- * @persistent_group: Whether to create a persistent group
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
* Returns: 0 on success, -1 on failure
*/
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
@@ -873,7 +870,9 @@
* @go_intent: Local GO intent value (1..15)
* @own_interface_addr: Intended interface address to use with the group
* @force_freq: The only allowed channel frequency in MHz or 0
- * @persistent_group: Whether to create a persistent group
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
* Returns: 0 on success, -1 on failure
*
* This is like p2p_connect(), but the actual group negotiation is not
@@ -898,6 +897,7 @@
* @peer_addr: MAC address of the peer P2P client
* @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)
* Returns: 0 on success, -1 on failure
*
* This function can be used to request a discovered P2P peer to display a PIN
@@ -909,7 +909,7 @@
* 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);
+ u16 config_methods, int join, int force_freq);
/**
* p2p_sd_request - Schedule a service discovery query
@@ -1039,6 +1039,28 @@
*/
void p2p_group_formation_failed(struct p2p_data *p2p);
+/**
+ * p2p_get_provisioning_info - Get any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @addr: Peer P2P Device Address
+ * Returns: WPS provisioning information (WPS config method) or 0 if no
+ * information is available
+ *
+ * This function is used to retrieve stored WPS provisioning info for the given
+ * peer.
+ */
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr);
+
+/**
+ * p2p_clear_provisioning_info - Clear any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @iface_addr: Peer P2P Interface Address
+ *
+ * This function is used to clear stored WPS provisioning info for the given
+ * peer.
+ */
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
+
/* Event notifications from lower layer driver operations */
@@ -1046,12 +1068,14 @@
* p2p_probe_req_rx - Report reception of a Probe Request frame
* @p2p: P2P module context from p2p_init()
* @addr: Source MAC address
+ * @dst: Destination MAC address if available or %NULL
+ * @bssid: BSSID if available or %NULL
* @ie: Information elements from the Probe Request frame body
* @ie_len: Length of ie buffer in octets
* Returns: 0 to indicate the frame was not processed or 1 if it was
*/
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
- size_t ie_len);
+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+ const u8 *bssid, const u8 *ie, size_t ie_len);
/**
* p2p_rx_action - Report received Action frame
@@ -1173,6 +1197,9 @@
struct p2p_group_config {
/**
* persistent_group - Whether the group is persistent
+ * 0 = not a persistent group
+ * 1 = persistent group without persistent reconnect
+ * 2 = persistent group with persistent reconnect
*/
int persistent_group;
@@ -1244,16 +1271,6 @@
*/
int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
const u8 *ie, size_t len);
-#ifdef ANDROID_BRCM_P2P_PATCH
-/**
- * p2p_group_get_dev_addr - Retreive the device address of an assocated P2P
- * client.
- * @group: P2P group context from p2p_group_init()
- * @addr: Interface address of the P2P client
- * Returns: P2P dev_addr on success, NULL on failure
- */
-u8 *p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
-#endif /*ANDROID_BRCM_P2P_PATCH */
/**
* p2p_group_assoc_resp_ie - Build P2P IE for (re)association response
@@ -1363,6 +1380,13 @@
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies);
/**
+ * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
+ * @p2p: P2P module context from p2p_init()
+ * Returns: Number of octets that p2p_scan_ie() may add to the buffer
+ */
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p);
+
+/**
* p2p_go_params - Generate random P2P group parameters
* @p2p: P2P module context from p2p_init()
* @params: Buffer for parameters
@@ -1392,16 +1416,36 @@
const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie);
/**
- * p2p_get_peer_info - Get P2P peer information in text format
+ * p2p_get_peer_info - Get P2P peer information
* @p2p: P2P module context from p2p_init()
* @addr: P2P Device Address of the peer or %NULL to indicate the first peer
* @next: Whether to select the peer entry following the one indicated by addr
+ * Returns: Pointer to peer info or %NULL if not found
+ */
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+ const u8 *addr, int next);
+
+/**
+ * p2p_get_peer_info_txt - Get internal P2P peer information in text format
+ * @info: Pointer to P2P peer info from p2p_get_peer_info()
* @buf: Buffer for returning text
* @buflen: Maximum buffer length
* Returns: Number of octets written to the buffer or -1 on failure
+ *
+ * Note: This information is internal to the P2P module and subject to change.
+ * As such, this should not really be used by external programs for purposes
+ * other than debugging.
*/
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
- char *buf, size_t buflen);
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+ char *buf, size_t buflen);
+
+/**
+ * p2p_peer_known - Check whether P2P peer is known
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer
+ * Returns: 1 if the specified device is in the P2P peer table or 0 if not
+ */
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr);
/**
* p2p_set_client_discoverability - Set client discoverability capability
@@ -1415,7 +1459,7 @@
void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
/**
- * p2p_set_manageD_oper - Set managed P2P Device operations capability
+ * p2p_set_managed_oper - Set managed P2P Device operations capability
* @p2p: P2P module context from p2p_init()
* @enabled: Whether managed P2P Device operations will be enabled
*/
@@ -1490,6 +1534,15 @@
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
/**
+ * p2p_group_get_dev_addr - Get a P2P Device Address of a client in a group
+ * @group: P2P group context from p2p_group_init()
+ * @addr: P2P Interface Address of the client
+ * Returns: P2P Device Address of the client if found or %NULL if no match
+ * found
+ */
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
+
+/**
* 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
@@ -1528,4 +1581,29 @@
int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
int cfg_op_channel);
+/**
+ * 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 is in progress
+ */
+int p2p_in_progress(struct p2p_data *p2p);
+
+#ifdef ANDROID_P2P
+/**
+ * p2p_in_progress - Check whether a P2P SEARCH is in progress
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ */
+int p2p_search_in_progress(struct p2p_data *p2p);
+#endif
+
+/**
+ * p2p_other_scan_completed - Notify completion of non-P2P scan
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation was started
+ */
+int p2p_other_scan_completed(struct p2p_data *p2p);
+
+const char * p2p_wps_method_text(enum p2p_wps_method method);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index d59e54b..a82e16d 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -164,27 +164,20 @@
len = wpabuf_put(buf, 2); /* IE length to be filled */
/* P2P Device address */
-#ifdef ANDROID_BRCM_P2P_PATCH
- /*
- * P2P_ADDR: Supplicant uses primary mac addr for p2p and hence advertises that. To
- * to make it compatible with solution using virtual interface for P2P, a new variable
- * is added to hold the actual p2p device address.
- */
- wpabuf_put_data(buf, p2p->cfg->p2p_dev_addr, ETH_ALEN);
-#else
wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
-#endif
/* Config Methods */
methods = 0;
if (peer && peer->wps_method != WPS_NOT_READY) {
if (peer->wps_method == WPS_PBC)
methods |= WPS_CONFIG_PUSHBUTTON;
- else if (peer->wps_method == WPS_PIN_LABEL)
- methods |= WPS_CONFIG_LABEL;
else if (peer->wps_method == WPS_PIN_DISPLAY ||
peer->wps_method == WPS_PIN_KEYPAD)
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+ } else if (p2p->cfg->config_methods) {
+ methods |= p2p->cfg->config_methods &
+ (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
+ WPS_CONFIG_KEYPAD);
} else {
methods |= WPS_CONFIG_PUSHBUTTON;
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index f5937b9..eb85f51 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -107,8 +107,6 @@
static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
{
switch (wps_method) {
- case WPS_PIN_LABEL:
- return DEV_PW_DEFAULT;
case WPS_PIN_DISPLAY:
return DEV_PW_REGISTRAR_SPECIFIED;
case WPS_PIN_KEYPAD:
@@ -124,8 +122,6 @@
static const char * p2p_wps_method_str(enum p2p_wps_method wps_method)
{
switch (wps_method) {
- case WPS_PIN_LABEL:
- return "Label";
case WPS_PIN_DISPLAY:
return "Display";
case WPS_PIN_KEYPAD:
@@ -156,8 +152,11 @@
len = p2p_buf_add_ie_hdr(buf);
group_capab = 0;
- if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ }
if (p2p->cross_connect)
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (p2p->cfg->p2p_intra_bss)
@@ -246,8 +245,12 @@
p2p_buf_add_status(buf, status);
group_capab = 0;
if (peer && peer->go_state == LOCAL_GO) {
- if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+ group_capab |=
+ P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ }
if (p2p->cross_connect)
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (p2p->cfg->p2p_intra_bss)
@@ -491,15 +494,7 @@
}
if (dev->go_neg_req_sent &&
-#ifdef ANDROID_BRCM_P2P_PATCH
- /* P2P_ADDR: compare against the p2p device address. The own mac
- address may not not be the actual p2p device address, if you
- are using a virtual interface.
- */
- os_memcmp(sa, p2p->cfg->p2p_dev_addr, ETH_ALEN) > 0) {
-#else
os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
-#endif
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Do not reply since peer has higher "
"address and GO Neg Request already sent");
@@ -524,18 +519,6 @@
}
switch (msg.dev_password_id) {
- case DEV_PW_DEFAULT:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: PIN from peer Label");
- if (dev->wps_method != WPS_PIN_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "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_REGISTRAR_SPECIFIED:
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: PIN from peer Display");
@@ -551,8 +534,7 @@
case DEV_PW_USER_SPECIFIED:
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Peer entered PIN on Keypad");
- if (dev->wps_method != WPS_PIN_LABEL &&
- dev->wps_method != WPS_PIN_DISPLAY) {
+ if (dev->wps_method != WPS_PIN_DISPLAY) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: We have wps_method=%s -> "
"incompatible",
@@ -606,7 +588,10 @@
p2p->op_channel))
p2p_reselect_channel(p2p, &intersection);
- p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ if (!p2p->ssid_set) {
+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ p2p->ssid_set = 1;
+ }
}
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
@@ -695,8 +680,12 @@
p2p_buf_add_status(buf, status);
group_capab = 0;
if (peer->go_state == LOCAL_GO) {
- if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+ group_capab |=
+ P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ }
if (p2p->cross_connect)
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (p2p->cfg->p2p_intra_bss)
@@ -907,18 +896,6 @@
dev->oper_freq = 0;
switch (msg.dev_password_id) {
- case DEV_PW_DEFAULT:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: PIN from peer Label");
- if (dev->wps_method != WPS_PIN_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "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_REGISTRAR_SPECIFIED:
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: PIN from peer Display");
@@ -934,8 +911,7 @@
case DEV_PW_USER_SPECIFIED:
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Peer entered PIN on Keypad");
- if (dev->wps_method != WPS_PIN_LABEL &&
- dev->wps_method != WPS_PIN_DISPLAY) {
+ if (dev->wps_method != WPS_PIN_DISPLAY) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: We have wps_method=%s -> "
"incompatible",
@@ -988,7 +964,10 @@
p2p->op_channel))
p2p_reselect_channel(p2p, &intersection);
- p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ if (!p2p->ssid_set) {
+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ p2p->ssid_set = 1;
+ }
}
p2p_set_state(p2p, P2P_GO_NEG);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 0d05319..59d1507 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -147,8 +147,11 @@
dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
- if (group->cfg->persistent_group)
+ if (group->cfg->persistent_group) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ if (group->cfg->persistent_group == 2)
+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ }
if (group->p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
if (group->group_formation)
@@ -183,12 +186,7 @@
len = p2p_buf_add_ie_hdr(ie);
p2p_group_add_common_ies(group, ie);
-#ifdef ANDROID_BRCM_P2P_PATCH
- /* P2P_ADDR: Use p2p_dev_addr instead of own mac addr*/
- p2p_buf_add_device_id(ie, group->p2p->cfg->p2p_dev_addr);
-#else
p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
-#endif
p2p_group_add_noa(ie, group->noa);
p2p_buf_update_ie_hdr(ie, len);
@@ -315,6 +313,36 @@
}
+static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr)
+{
+ struct p2p_group_member *m, *prev;
+
+ if (group == NULL)
+ return 0;
+
+ m = group->members;
+ prev = NULL;
+ while (m) {
+ if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
+ break;
+ prev = m;
+ m = m->next;
+ }
+
+ if (m == NULL)
+ return 0;
+
+ if (prev)
+ prev->next = m->next;
+ else
+ group->members = m->next;
+ p2p_group_free_member(m);
+ group->num_members--;
+
+ return 1;
+}
+
+
int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
const u8 *ie, size_t len)
{
@@ -334,6 +362,8 @@
m->dev_addr);
}
+ p2p_group_remove_member(group, addr);
+
m->next = group->members;
group->members = m;
group->num_members++;
@@ -376,27 +406,7 @@
void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
{
- struct p2p_group_member *m, *prev;
-
- if (group == NULL)
- return;
-
- m = group->members;
- prev = NULL;
- while (m) {
- if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
- break;
- prev = m;
- m = m->next;
- }
-
- if (m) {
- if (prev)
- prev->next = m->next;
- else
- group->members = m->next;
- p2p_group_free_member(m);
- group->num_members--;
+ 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",
MAC2STR(addr), group->num_members,
@@ -499,11 +509,7 @@
} else {
if (group->noa) {
if (wpabuf_size(group->noa) >= noa_len) {
- #ifdef ANDROID_BRCM_P2P_PATCH
group->noa->used = 0;
- #else
- group->noa->size = 0;
- #endif
wpabuf_put_data(group->noa, noa, noa_len);
} else {
wpabuf_free(group->noa);
@@ -551,19 +557,19 @@
return NULL;
}
-#ifdef ANDROID_BRCM_P2P_PATCH
-u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
+
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
{
struct p2p_group_member *m;
- m = p2p_group_get_client_iface(group, addr);
-
- if (m)
- return m->dev_addr;
- else
+ if (group == NULL)
return NULL;
+ m = p2p_group_get_client_iface(group, addr);
+ if (m && !is_zero_ether_addr(m->dev_addr))
+ return m->dev_addr;
+ return NULL;
}
-#endif /* ANDROID_BRCM_P2P_PATCH */
+
static struct wpabuf * p2p_build_go_disc_req(void)
{
@@ -662,11 +668,11 @@
else
wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
curr_noa_len);
-#ifndef ANDROID_BRCM_P2P_PATCH
+
/* TODO: properly process request and store copy */
- if (curr_noa_len > 0)
+ if (curr_noa_len > 0 || curr_noa_len == -1)
return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
-#endif
+
return P2P_SC_SUCCESS;
}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index afb891e..0dc33e7 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -18,8 +18,6 @@
#include "utils/list.h"
#include "p2p.h"
-/* TODO: add removal of expired P2P device entries */
-
enum p2p_go_state {
UNKNOWN_GO,
LOCAL_GO,
@@ -69,10 +67,18 @@
size_t oper_ssid_len;
/**
- * req_config_methods - Pending provisioning discovery methods
+ * req_config_methods - Pending provision discovery methods
*/
u16 req_config_methods;
+ /**
+ * wps_prov_info - Stored provisioning WPS config method
+ *
+ * This is used to store pending WPS config method between Provisioning
+ * Discovery and connection to a running group.
+ */
+ u16 wps_prov_info;
+
#define P2P_DEV_PROBE_REQ_ONLY BIT(0)
#define P2P_DEV_REPORTED BIT(1)
#define P2P_DEV_NOT_YET_READY BIT(2)
@@ -89,6 +95,7 @@
#define P2P_DEV_FORCE_FREQ BIT(13)
#define P2P_DEV_PD_FOR_JOIN BIT(14)
#define P2P_DEV_REPORTED_ONCE BIT(15)
+#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
unsigned int flags;
int status; /* enum p2p_status_code */
@@ -200,6 +207,11 @@
* P2P_INVITE_LISTEN - Listen during Invite
*/
P2P_INVITE_LISTEN,
+
+ /**
+ * P2P_SEARCH_WHEN_READY - Waiting to start Search
+ */
+ P2P_SEARCH_WHEN_READY,
} state;
/**
@@ -273,6 +285,11 @@
size_t ssid_len;
/**
+ * ssid_set - Whether SSID is already set for GO Negotiation
+ */
+ int ssid_set;
+
+ /**
* Regulatory class for own operational channel
*/
u8 op_reg_class;
@@ -349,6 +366,7 @@
int inv_persistent;
enum p2p_discovery_type find_type;
+ unsigned int last_p2p_find_timeout;
u8 last_prog_scan_class;
u8 last_prog_scan_chan;
int p2p_scan_running;
@@ -532,11 +550,6 @@
/* p2p_group.c */
const u8 * p2p_group_get_interface_addr(struct p2p_group *group);
-
-#ifdef ANDROID_BRCM_P2P_PATCH
-void p2p_get_group_noa(struct p2p_group *group, u8 *noa, size_t* noa_len);
-#endif
-
u8 p2p_group_presence_req(struct p2p_group *group,
const u8 *client_interface_addr,
const u8 *noa, size_t noa_len);
@@ -606,7 +619,7 @@
void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len);
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
- int join);
+ int join, int force_freq);
void p2p_reset_pending_pd(struct p2p_data *p2p);
/* p2p_invitation.c */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 42015ad..bb2767d 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -55,11 +55,7 @@
else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
dev_addr = peer->info.p2p_device_addr;
else
-#ifdef ANDROID_BRCM_P2P_PATCH
- dev_addr = p2p->cfg->p2p_dev_addr;
-#else
dev_addr = p2p->cfg->dev_addr;
-#endif
p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len);
p2p_buf_add_device_info(buf, p2p, peer);
p2p_buf_update_ie_hdr(buf, len);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 32d82f6..1ee59c5 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -112,7 +112,7 @@
MAC2STR(sa), msg.wps_config_methods, rx_freq);
dev = p2p_get_device(p2p, sa);
- if (dev == NULL || !(dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
+ if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request from "
"unknown peer " MACSTR, MAC2STR(sa));
@@ -191,8 +191,8 @@
msg.device_name, msg.config_methods,
msg.capability ? msg.capability[0] : 0,
msg.capability ? msg.capability[1] :
- 0);
-
+ 0,
+ msg.group_id, msg.group_id_len);
}
p2p_parse_free(&msg);
}
@@ -209,14 +209,14 @@
return;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Provisioning Discovery Response from " MACSTR
+ "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 Provisioning Discovery Response from "
+ "P2P: Ignore Provision Discovery Response from "
MACSTR " with no pending request", MAC2STR(sa));
p2p_parse_free(&msg);
return;
@@ -229,7 +229,7 @@
if (dev->dialog_token != msg.dialog_token) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore Provisioning Discovery Response with "
+ "P2P: Ignore Provision Discovery Response with "
"unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
@@ -246,7 +246,7 @@
if (msg.wps_config_methods != dev->req_config_methods) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
- "our Provisioning Discovery Request");
+ "our Provision Discovery Request");
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
P2P_PROV_DISC_REJECTED);
@@ -267,6 +267,10 @@
MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
}
+
+ /* Store the provisioning info */
+ dev->wps_prov_info = msg.wps_config_methods;
+
p2p_parse_free(&msg);
out:
@@ -279,25 +283,16 @@
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
- int join)
+ int join, int force_freq)
{
struct wpabuf *req;
int freq;
-#ifdef ANDROID_BRCM_P2P_PATCH
- if(dev->go_state == REMOTE_GO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Sending it to oper_freq %d", dev->oper_freq);
- freq= dev->oper_freq;
- }
- else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: NOT GO oper_freq %d listen_freq %d", dev->oper_freq, dev->listen_freq);
- freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
- }
-#else
- freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
-#endif
+ if (force_freq > 0)
+ freq = force_freq;
+ else
+ 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 "
@@ -345,7 +340,7 @@
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
- u16 config_methods, int join)
+ u16 config_methods, int join, int force_freq)
{
struct p2p_device *dev;
@@ -365,6 +360,9 @@
if (config_methods == 0)
return -1;
+ /* Reset provisioning info */
+ dev->wps_prov_info = 0;
+
dev->req_config_methods = config_methods;
if (join)
dev->flags |= P2P_DEV_PD_FOR_JOIN;
@@ -391,12 +389,26 @@
if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
- return p2p_send_prov_disc_req(p2p, dev, join);
+ return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
}
void p2p_reset_pending_pd(struct p2p_data *p2p)
{
+ struct p2p_device *dev;
+
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (os_memcmp(p2p->pending_pd_devaddr,
+ dev->info.p2p_device_addr, ETH_ALEN))
+ continue;
+ if (!dev->req_config_methods)
+ continue;
+ if (dev->flags & P2P_DEV_PD_FOR_JOIN)
+ continue;
+ /* Reset the config methods of the device */
+ dev->req_config_methods = 0;
+ }
+
p2p->user_initiated_pd = 0;
os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
p2p->pd_retries = 0;
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 9e26873..f53d4b5 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -16,6 +16,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -26,7 +27,7 @@
struct p2p_sd_query *q;
if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
- return 0; /* peer does not support SD */
+ return NULL; /* peer does not support SD */
for (q = p2p->sd_queries; q; q = q->next) {
if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
@@ -90,51 +91,21 @@
struct wpabuf *tlvs)
{
struct wpabuf *buf;
- u8 *len_pos, *len_pos2;
+ u8 *len_pos;
- buf = wpabuf_alloc(1000 + wpabuf_len(tlvs));
+ buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
if (buf == NULL)
return NULL;
- wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
- wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
- wpabuf_put_u8(buf, 0); /* Dialog Token */
-
- /* Advertisement Protocol IE */
- wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
- wpabuf_put_u8(buf, 2); /* Length */
- wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */
- wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
- /* Query Request */
- len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
- /* NQP Query Request Frame */
- wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
- len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+ /* 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_le16(buf, update_indic); /* Service Update Indicator */
wpabuf_put_buf(buf, tlvs);
+ gas_anqp_set_element_len(buf, len_pos);
- WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
- WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
-
- return buf;
-}
-
-
-static struct wpabuf * p2p_build_gas_comeback_req(u8 dialog_token)
-{
- struct wpabuf *buf;
-
- buf = wpabuf_alloc(3);
- if (buf == NULL)
- return NULL;
-
- wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
- wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_REQ);
- wpabuf_put_u8(buf, dialog_token);
+ gas_anqp_set_len(buf);
return buf;
}
@@ -145,7 +116,7 @@
{
struct wpabuf *req;
- req = p2p_build_gas_comeback_req(dialog_token);
+ req = gas_build_comeback_req(dialog_token);
if (req == NULL)
return;
@@ -165,42 +136,26 @@
const struct wpabuf *tlvs)
{
struct wpabuf *buf;
- u8 *len_pos, *len_pos2;
+ u8 *len_pos;
- buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0));
+ buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+ comeback_delay,
+ 100 + (tlvs ? wpabuf_len(tlvs) : 0));
if (buf == NULL)
return NULL;
- wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
- wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
- wpabuf_put_u8(buf, dialog_token);
- wpabuf_put_le16(buf, status_code);
- wpabuf_put_le16(buf, comeback_delay);
-
- /* Advertisement Protocol IE */
- wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
- wpabuf_put_u8(buf, 2); /* Length */
- wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
- wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
- /* Query Response */
- len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
if (tlvs) {
- /* NQP Query Response Frame */
- wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
- len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+ /* 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);
/* Service Update Indicator */
wpabuf_put_le16(buf, update_indic);
wpabuf_put_buf(buf, tlvs);
-
- WPA_PUT_LE16(len_pos2,
- (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
+ gas_anqp_set_element_len(buf, len_pos);
}
- WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+ gas_anqp_set_len(buf);
return buf;
}
@@ -214,31 +169,15 @@
u16 total_len)
{
struct wpabuf *buf;
- u8 *len_pos;
- buf = wpabuf_alloc(1000 + len);
+ buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+ more, 0, 100 + len);
if (buf == NULL)
return NULL;
- wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
- wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP);
- wpabuf_put_u8(buf, dialog_token);
- wpabuf_put_le16(buf, status_code);
- wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
- wpabuf_put_le16(buf, 0); /* Comeback Delay */
-
- /* Advertisement Protocol IE */
- wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
- wpabuf_put_u8(buf, 2); /* Length */
- wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
- wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
- /* Query Response */
- len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
if (frag_id == 0) {
- /* NQP Query Response Frame */
- wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
+ /* 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);
@@ -247,8 +186,7 @@
}
wpabuf_put_data(buf, data, len);
-
- WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+ gas_anqp_set_len(buf);
return buf;
}
@@ -349,7 +287,7 @@
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
- if (*pos != NATIVE_QUERY_PROTOCOL) {
+ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unsupported GAS advertisement protocol id %u",
*pos);
@@ -366,12 +304,12 @@
return;
end = pos + slen;
- /* NQP Query Request */
+ /* ANQP Query Request */
if (pos + 4 > end)
return;
- if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+ if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+ "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
@@ -380,20 +318,20 @@
pos += 2;
if (pos + slen > end || slen < 3 + 1) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid NQP Query Request length");
+ "P2P: Invalid ANQP Query Request length");
return;
}
if (WPA_GET_BE24(pos) != OUI_WFA) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+ "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
return;
}
pos += 3;
if (*pos != P2P_OUI_TYPE) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP vendor type %u", *pos);
+ "P2P: Unsupported ANQP vendor type %u", *pos);
return;
}
pos++;
@@ -451,11 +389,7 @@
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
- #ifdef ANDROID_BRCM_P2P_PATCH
- p2p->cfg->p2p_dev_addr,
- #else
p2p->cfg->dev_addr,
- #endif
wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Failed to send Action frame");
@@ -529,7 +463,7 @@
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
- if (*pos != NATIVE_QUERY_PROTOCOL) {
+ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unsupported GAS advertisement protocol id %u",
*pos);
@@ -567,12 +501,12 @@
return;
}
- /* NQP Query Response */
+ /* ANQP Query Response */
if (pos + 4 > end)
return;
- if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+ if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+ "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
@@ -581,20 +515,20 @@
pos += 2;
if (pos + slen > end || slen < 3 + 1) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid NQP Query Response length");
+ "P2P: Invalid ANQP Query Response length");
return;
}
if (WPA_GET_BE24(pos) != OUI_WFA) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+ "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
return;
}
pos += 3;
if (*pos != P2P_OUI_TYPE) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP vendor type %u", *pos);
+ "P2P: Unsupported ANQP vendor type %u", *pos);
return;
}
pos++;
@@ -776,7 +710,7 @@
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
- if (*pos != NATIVE_QUERY_PROTOCOL) {
+ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unsupported GAS advertisement protocol id %u",
*pos);
@@ -808,29 +742,29 @@
if (p2p->sd_rx_resp) {
/*
- * NQP header is only included in the first fragment; rest of
+ * ANQP header is only included in the first fragment; rest of
* the fragments start with continue TLVs.
*/
goto skip_nqp_header;
}
- /* NQP Query Response */
+ /* ANQP Query Response */
if (pos + 4 > end)
return;
- if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+ if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+ "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: NQP Query Response "
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: ANQP Query Response "
"length: %u", slen);
if (slen < 3 + 1) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid NQP Query Response length");
+ "P2P: Invalid ANQP Query Response length");
return;
}
if (pos + 4 > end)
@@ -838,14 +772,14 @@
if (WPA_GET_BE24(pos) != OUI_WFA) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+ "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
return;
}
pos += 3;
if (*pos != P2P_OUI_TYPE) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP vendor type %u", *pos);
+ "P2P: Unsupported ANQP vendor type %u", *pos);
return;
}
pos++;