summaryrefslogtreecommitdiffstats
path: root/contrib/wpa/src/p2p
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa/src/p2p')
-rw-r--r--contrib/wpa/src/p2p/p2p.c387
-rw-r--r--contrib/wpa/src/p2p/p2p.h89
-rw-r--r--contrib/wpa/src/p2p/p2p_build.c8
-rw-r--r--contrib/wpa/src/p2p/p2p_go_neg.c141
-rw-r--r--contrib/wpa/src/p2p/p2p_group.c28
-rw-r--r--contrib/wpa/src/p2p/p2p_i.h25
-rw-r--r--contrib/wpa/src/p2p/p2p_invitation.c6
-rw-r--r--contrib/wpa/src/p2p/p2p_parse.c98
-rw-r--r--contrib/wpa/src/p2p/p2p_pd.c893
-rw-r--r--contrib/wpa/src/p2p/p2p_sd.c82
-rw-r--r--contrib/wpa/src/p2p/p2p_utils.c23
11 files changed, 1244 insertions, 536 deletions
diff --git a/contrib/wpa/src/p2p/p2p.c b/contrib/wpa/src/p2p/p2p.c
index 767706c..157bf89 100644
--- a/contrib/wpa/src/p2p/p2p.c
+++ b/contrib/wpa/src/p2p/p2p.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "eloop.h"
+#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
@@ -445,8 +446,9 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p,
static void p2p_copy_client_info(struct p2p_device *dev,
struct p2p_client_info *cli)
{
- os_memcpy(dev->info.device_name, cli->dev_name, cli->dev_name_len);
- dev->info.device_name[cli->dev_name_len] = '\0';
+ p2p_copy_filter_devname(dev->info.device_name,
+ sizeof(dev->info.device_name),
+ cli->dev_name, cli->dev_name_len);
dev->info.dev_capab = cli->dev_capab;
dev->info.config_methods = cli->config_methods;
os_memcpy(dev->info.pri_dev_type, cli->pri_dev_type, 8);
@@ -636,11 +638,11 @@ static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
end = ies + ies_len;
- for (pos = ies; pos + 1 < end; pos += len) {
+ for (pos = ies; end - pos > 1; pos += len) {
id = *pos++;
len = *pos++;
- if (pos + len > end)
+ if (len > end - pos)
break;
if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3)
@@ -709,6 +711,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
struct p2p_message msg;
const u8 *p2p_dev_addr;
int wfd_changed;
+ int dev_name_changed;
int i;
struct os_reltime time_now;
@@ -786,11 +789,11 @@ 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);
+ wpabuf_free(dev->info.p2ps_instance);
+ dev->info.p2ps_instance = NULL;
+ if (msg.adv_service_instance && msg.adv_service_instance_len)
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) {
@@ -819,6 +822,9 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
}
dev->info.level = level;
+ dev_name_changed = os_strncmp(dev->info.device_name, msg.device_name,
+ WPS_DEV_NAME_MAX_LEN) != 0;
+
p2p_copy_wps_info(p2p, dev, 0, &msg);
for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
@@ -837,9 +843,12 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
wfd_changed = p2p_compare_wfd_info(dev, &msg);
- if (msg.wfd_subelems) {
+ if (wfd_changed) {
wpabuf_free(dev->info.wfd_subelems);
- dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ if (msg.wfd_subelems)
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ else
+ dev->info.wfd_subelems = NULL;
}
if (scan_res) {
@@ -853,6 +862,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
p2p_update_peer_vendor_elems(dev, ies, ies_len);
if (dev->flags & P2P_DEV_REPORTED && !wfd_changed &&
+ !dev_name_changed &&
(!msg.adv_service_instance ||
(dev->flags & P2P_DEV_P2PS_REPORTED)))
return 0;
@@ -1000,8 +1010,16 @@ static void p2p_search(struct p2p_data *p2p)
}
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
- if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
- (freq = p2p_get_next_prog_freq(p2p)) > 0) {
+ if (p2p->find_pending_full &&
+ (p2p->find_type == P2P_FIND_PROGRESSIVE ||
+ p2p->find_type == P2P_FIND_START_WITH_FULL)) {
+ type = P2P_SCAN_FULL;
+ p2p_dbg(p2p, "Starting search (pending full scan)");
+ p2p->find_pending_full = 0;
+ } else if ((p2p->find_type == P2P_FIND_PROGRESSIVE &&
+ (freq = p2p_get_next_prog_freq(p2p)) > 0) ||
+ (p2p->find_type == P2P_FIND_START_WITH_FULL &&
+ (freq = p2p->find_specified_freq) > 0)) {
type = P2P_SCAN_SOCIAL_PLUS_ONE;
p2p_dbg(p2p, "Starting search (+ freq %u)", freq);
} else {
@@ -1058,7 +1076,7 @@ static int p2p_run_after_scan(struct p2p_data *p2p)
p2p->after_scan_tx->bssid,
(u8 *) (p2p->after_scan_tx + 1),
p2p->after_scan_tx->len,
- p2p->after_scan_tx->wait_time);
+ p2p->after_scan_tx->wait_time, NULL);
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
return 1;
@@ -1154,21 +1172,20 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
u8 seek_count, const char **seek, int freq)
{
int res;
+ struct os_reltime start;
p2p_dbg(p2p, "Starting find (type=%d)", type);
- os_get_reltime(&p2p->find_start);
if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "p2p_scan is already running");
}
p2p_free_req_dev_types(p2p);
if (req_dev_types && num_req_dev_types) {
- p2p->req_dev_types = os_malloc(num_req_dev_types *
+ p2p->req_dev_types = os_memdup(req_dev_types,
+ num_req_dev_types *
WPS_DEV_TYPE_LEN);
if (p2p->req_dev_types == NULL)
return -1;
- os_memcpy(p2p->req_dev_types, req_dev_types,
- num_req_dev_types * WPS_DEV_TYPE_LEN);
p2p->num_req_dev_types = num_req_dev_types;
}
@@ -1220,9 +1237,19 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
p2p_clear_timeout(p2p);
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_find");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ p2p->find_pending_full = 0;
p2p->find_type = type;
+ if (freq != 2412 && freq != 2437 && freq != 2462 && freq != 60480)
+ p2p->find_specified_freq = freq;
+ else
+ p2p->find_specified_freq = 0;
p2p_device_clear_reported(p2p);
+ os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
p2p_set_state(p2p, P2P_SEARCH);
p2p->search_delay = search_delay;
p2p->in_search_delay = 0;
@@ -1231,12 +1258,13 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
if (timeout)
eloop_register_timeout(timeout, 0, p2p_find_timeout,
p2p, NULL);
+ os_get_reltime(&start);
switch (type) {
case P2P_FIND_START_WITH_FULL:
if (freq > 0) {
/*
* Start with the specified channel and then move to
- * social channels only scans.
+ * scans for social channels and this specific channel.
*/
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx,
P2P_SCAN_SPECIFIC, freq,
@@ -1262,9 +1290,15 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
return -1;
}
+ if (!res)
+ p2p->find_start = start;
+
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 */
+ if (type == P2P_FIND_PROGRESSIVE ||
+ (type == P2P_FIND_START_WITH_FULL && freq == 0))
+ p2p->find_pending_full = 1;
res = 0; /* do not report failure */
} else if (res != 0) {
p2p_dbg(p2p, "Failed to start p2p_scan");
@@ -1440,7 +1474,8 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
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->op_channel,
+ NULL, NULL) == 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 {
@@ -1459,7 +1494,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
/**
- * p2p_prepare_channel - Select operating channel for GO Negotiation
+ * p2p_prepare_channel - Select operating channel for GO Negotiation or P2PS PD
* @p2p: P2P module context from p2p_init()
* @dev: Selected peer device
* @force_freq: Forced frequency in MHz or 0 if not forced
@@ -1468,9 +1503,9 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* Returns: 0 on success, -1 on failure (channel not supported for P2P)
*
* This function is used to do initial operating channel selection for GO
- * Negotiation prior to having received peer information. The selected channel
- * may be further optimized in p2p_reselect_channel() once the peer information
- * is available.
+ * Negotiation prior to having received peer information or for P2PS PD
+ * signalling. The selected channel may be further optimized in
+ * p2p_reselect_channel() once the peer information is available.
*/
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
unsigned int force_freq, unsigned int pref_freq, int go)
@@ -1826,6 +1861,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
p2p_clear_timeout(p2p);
p2p->ssid_set = 0;
peer->go_neg_req_sent = 0;
+ peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
peer->wps_method = WPS_NOT_READY;
peer->oob_pw_id = 0;
wpabuf_free(peer->go_neg_conf);
@@ -2028,8 +2064,23 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
dev = p2p_get_device(p2p, addr);
if (dev) {
- if (dev->country[0] == 0 && msg.listen_channel)
- os_memcpy(dev->country, msg.listen_channel, 3);
+ if (msg.listen_channel) {
+ int freq;
+
+ if (dev->country[0] == 0)
+ os_memcpy(dev->country, msg.listen_channel, 3);
+
+ freq = p2p_channel_to_freq(msg.listen_channel[3],
+ msg.listen_channel[4]);
+
+ if (freq > 0 && dev->listen_freq != freq) {
+ p2p_dbg(p2p,
+ "Updated peer " MACSTR " Listen channel (Probe Request): %d -> %d MHz",
+ MAC2STR(addr), dev->listen_freq, freq);
+ dev->listen_freq = freq;
+ }
+ }
+
os_get_reltime(&dev->last_seen);
p2p_parse_free(&msg);
return; /* already known */
@@ -2212,6 +2263,58 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
return buf;
}
+static int p2p_build_probe_resp_buf(struct p2p_data *p2p, struct wpabuf *buf,
+ struct wpabuf *ies,
+ const u8 *addr, int rx_freq)
+{
+ struct ieee80211_mgmt *resp;
+ u8 channel, op_class;
+
+ resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.probe_resp.variable));
+
+ resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_PROBE_RESP << 4));
+ os_memcpy(resp->da, addr, ETH_ALEN);
+ os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
+ os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
+ resp->u.probe_resp.beacon_int = host_to_le16(100);
+ /* hardware or low-level driver will setup seq_ctrl and timestamp */
+ resp->u.probe_resp.capab_info =
+ host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
+ WLAN_CAPABILITY_PRIVACY |
+ WLAN_CAPABILITY_SHORT_SLOT_TIME);
+
+ wpabuf_put_u8(buf, WLAN_EID_SSID);
+ wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
+ wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+
+ wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
+ wpabuf_put_u8(buf, 8);
+ wpabuf_put_u8(buf, (60 / 5) | 0x80);
+ wpabuf_put_u8(buf, 90 / 5);
+ wpabuf_put_u8(buf, (120 / 5) | 0x80);
+ wpabuf_put_u8(buf, 180 / 5);
+ wpabuf_put_u8(buf, (240 / 5) | 0x80);
+ wpabuf_put_u8(buf, 360 / 5);
+ wpabuf_put_u8(buf, 480 / 5);
+ wpabuf_put_u8(buf, 540 / 5);
+
+ if (!rx_freq) {
+ channel = p2p->cfg->channel;
+ } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+ p2p_err(p2p, "Failed to convert freq to channel");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
+ wpabuf_put_u8(buf, 1);
+ wpabuf_put_u8(buf, channel);
+
+ wpabuf_put_buf(buf, ies);
+
+ return 0;
+}
static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
{
@@ -2245,10 +2348,8 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
{
struct ieee802_11_elems elems;
struct wpabuf *buf;
- struct ieee80211_mgmt *resp;
struct p2p_message msg;
struct wpabuf *ies;
- u8 channel, op_class;
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
ParseFailed) {
@@ -2360,7 +2461,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_dbg(p2p, "Probe Req requested Device Type did not match - ignore it");
p2p_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
@@ -2392,49 +2493,12 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
return P2P_PREQ_NOT_PROCESSED;
}
- resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
- u.probe_resp.variable));
-
- resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
- (WLAN_FC_STYPE_PROBE_RESP << 4));
- os_memcpy(resp->da, addr, ETH_ALEN);
- os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
- os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
- resp->u.probe_resp.beacon_int = host_to_le16(100);
- /* hardware or low-level driver will setup seq_ctrl and timestamp */
- resp->u.probe_resp.capab_info =
- host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
- WLAN_CAPABILITY_PRIVACY |
- WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
- wpabuf_put_u8(buf, WLAN_EID_SSID);
- wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
- wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
-
- wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
- wpabuf_put_u8(buf, 8);
- wpabuf_put_u8(buf, (60 / 5) | 0x80);
- wpabuf_put_u8(buf, 90 / 5);
- wpabuf_put_u8(buf, (120 / 5) | 0x80);
- wpabuf_put_u8(buf, 180 / 5);
- wpabuf_put_u8(buf, (240 / 5) | 0x80);
- wpabuf_put_u8(buf, 360 / 5);
- wpabuf_put_u8(buf, 480 / 5);
- wpabuf_put_u8(buf, 540 / 5);
-
- if (!rx_freq) {
- channel = p2p->cfg->channel;
- } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+ if (p2p_build_probe_resp_buf(p2p, buf, ies, addr, rx_freq)) {
wpabuf_free(ies);
wpabuf_free(buf);
return P2P_PREQ_NOT_PROCESSED;
}
- wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
- wpabuf_put_u8(buf, 1);
- wpabuf_put_u8(buf, channel);
-
- wpabuf_put_buf(buf, ies);
wpabuf_free(ies);
p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
@@ -2448,12 +2512,18 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
const u8 *bssid, const u8 *ie, size_t ie_len,
- unsigned int rx_freq)
+ unsigned int rx_freq, int p2p_lo_started)
{
enum p2p_probe_req_status res;
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
+ if (p2p_lo_started) {
+ p2p_dbg(p2p,
+ "Probe Response is offloaded, do not reply Probe Request");
+ return P2P_PREQ_PROCESSED;
+ }
+
res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
return res;
@@ -2781,6 +2851,7 @@ void p2p_service_flush_asp(struct p2p_data *p2p)
}
p2p->p2ps_adv_list = NULL;
+ p2ps_prov_free(p2p);
p2p_dbg(p2p, "All ASP advertisements flushed");
}
@@ -2942,9 +3013,9 @@ void p2p_deinit(struct p2p_data *p2p)
wpabuf_free(p2p->wfd_dev_info);
wpabuf_free(p2p->wfd_assoc_bssid);
wpabuf_free(p2p->wfd_coupled_sink_info);
+ wpabuf_free(p2p->wfd_r2_dev_info);
#endif /* CONFIG_WIFI_DISPLAY */
- 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);
@@ -2959,7 +3030,6 @@ void p2p_deinit(struct p2p_data *p2p)
os_free(p2p->groups);
p2ps_prov_free(p2p);
wpabuf_free(p2p->sd_resp);
- os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
os_free(p2p->no_go_freq.range);
p2p_service_flush_asp(p2p);
@@ -2971,6 +3041,8 @@ void p2p_deinit(struct p2p_data *p2p)
void p2p_flush(struct p2p_data *p2p)
{
struct p2p_device *dev, *prev;
+
+ p2p_ext_listen(p2p, 0, 0);
p2p_stop_find(p2p);
dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device,
list) {
@@ -2981,6 +3053,10 @@ void p2p_flush(struct p2p_data *p2p)
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
p2p->ssid_set = 0;
+ p2ps_prov_free(p2p);
+ p2p_reset_pending_pd(p2p);
+ p2p->override_pref_op_class = 0;
+ p2p->override_pref_channel = 0;
}
@@ -3157,13 +3233,18 @@ 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)
{
+ int res;
+
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)
+ res = p2p_start_sd(p2p, dev);
+ if (res == -2)
+ return -2;
+ if (res == 0)
return 1;
if (dev->req_config_methods &&
@@ -3183,7 +3264,7 @@ static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
void p2p_continue_find(struct p2p_data *p2p)
{
struct p2p_device *dev;
- int found;
+ int found, res;
p2p_set_state(p2p, P2P_SEARCH);
@@ -3196,10 +3277,13 @@ void p2p_continue_find(struct p2p_data *p2p)
}
if (!found)
continue;
- if (p2p_pre_find_operation(p2p, dev) > 0) {
+ res = p2p_pre_find_operation(p2p, dev);
+ if (res > 0) {
p2p->last_p2p_find_oper = dev;
return;
}
+ if (res == -2)
+ goto skip_sd;
}
/*
@@ -3207,14 +3291,19 @@ void p2p_continue_find(struct p2p_data *p2p)
* iteration device.
*/
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
- if (p2p_pre_find_operation(p2p, dev) > 0) {
+ res = p2p_pre_find_operation(p2p, dev);
+ if (res > 0) {
p2p->last_p2p_find_oper = dev;
return;
}
+ if (res == -2)
+ goto skip_sd;
if (dev == p2p->last_p2p_find_oper)
break;
}
+skip_sd:
+ os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
p2p_listen_in_find(p2p, 1);
}
@@ -3226,8 +3315,17 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success)
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (!success) {
- if (p2p->sd_peer)
+ if (p2p->sd_peer) {
+ if (is_zero_ether_addr(p2p->sd_query_no_ack)) {
+ os_memcpy(p2p->sd_query_no_ack,
+ p2p->sd_peer->info.p2p_device_addr,
+ ETH_ALEN);
+ p2p_dbg(p2p,
+ "First SD Query no-ACK in this search iteration: "
+ MACSTR, MAC2STR(p2p->sd_query_no_ack));
+ }
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ }
p2p->sd_peer = NULL;
if (p2p->state != P2P_IDLE)
p2p_continue_find(p2p);
@@ -3326,6 +3424,43 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
}
/*
+ * If after PD Request the peer doesn't expect to receive PD Response
+ * the PD Request ACK indicates a completion of the current PD. This
+ * happens only on the advertiser side sending the follow-on PD Request
+ * with the status different than 12 (Success: accepted by user).
+ */
+ if (p2p->p2ps_prov && !p2p->p2ps_prov->pd_seeker &&
+ p2p->p2ps_prov->status != P2P_SC_SUCCESS_DEFERRED) {
+ p2p_dbg(p2p, "P2PS PD completion on Follow-on PD Request ACK");
+
+ 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 (p2p->cfg->p2ps_prov_complete) {
+ p2p->cfg->p2ps_prov_complete(
+ p2p->cfg->cb_ctx,
+ p2p->p2ps_prov->status,
+ p2p->p2ps_prov->adv_mac,
+ p2p->p2ps_prov->adv_mac,
+ p2p->p2ps_prov->session_mac,
+ NULL, p2p->p2ps_prov->adv_id,
+ p2p->p2ps_prov->session_id,
+ 0, 0, NULL, 0, 0, 0,
+ NULL, NULL, 0, 0, NULL, 0);
+ }
+
+ if (p2p->user_initiated_pd)
+ p2p_reset_pending_pd(p2p);
+
+ p2ps_prov_free(p2p);
+ return;
+ }
+
+ /*
* This postponing, of resetting pending_action_state, needs to be
* done only for user initiated PD requests and not internal ones.
*/
@@ -3399,9 +3534,11 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
* operation was started.
*/
p2p_dbg(p2p, "Ignore old scan result for " MACSTR
- " (rx_time=%u.%06u)",
+ " (rx_time=%u.%06u find_start=%u.%06u)",
MAC2STR(bssid), (unsigned int) rx_time->sec,
- (unsigned int) rx_time->usec);
+ (unsigned int) rx_time->usec,
+ (unsigned int) p2p->find_start.sec,
+ (unsigned int) p2p->find_start.usec);
return 0;
}
@@ -3426,7 +3563,8 @@ void p2p_scan_res_handled(struct p2p_data *p2p)
}
-void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id,
+ unsigned int bands)
{
u8 dev_capab;
u8 *len;
@@ -3460,6 +3598,9 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period,
p2p->ext_listen_interval);
+ if (bands & BAND_60_GHZ)
+ p2p_buf_add_device_info(ies, p2p, NULL);
+
if (p2p->p2ps_seek && p2p->p2ps_seek_count)
p2p_buf_add_service_hash(ies, p2p);
@@ -3694,6 +3835,8 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
break;
case P2P_PENDING_INVITATION_RESPONSE:
p2p_invitation_resp_cb(p2p, success);
+ if (p2p->inv_status != P2P_SC_SUCCESS)
+ p2p_check_after_scan_tx_continuation(p2p);
break;
case P2P_PENDING_DEV_DISC_REQUEST:
p2p_dev_disc_req_cb(p2p, success);
@@ -3751,6 +3894,19 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
if (p2p->in_listen)
return 0; /* Internal timeout will trigger the next step */
+ if (p2p->state == P2P_WAIT_PEER_CONNECT && p2p->go_neg_peer &&
+ p2p->pending_listen_freq) {
+ /*
+ * Better wait a bit if the driver is unable to start
+ * offchannel operation for some reason to continue with
+ * P2P_WAIT_PEER_(IDLE/CONNECT) state transitions.
+ */
+ p2p_dbg(p2p,
+ "Listen operation did not seem to start - delay idle phase to avoid busy loop");
+ p2p_set_timeout(p2p, 0, 100000);
+ return 1;
+ }
+
if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
if (p2p->go_neg_peer->connect_reqs >= 120) {
p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
@@ -4613,9 +4769,12 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
- u8 *op_channel)
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list)
{
- return p2p_channel_random_social(&p2p->channels, op_class, op_channel);
+ return p2p_channel_random_social(&p2p->channels, op_class, op_channel,
+ avoid_list, disallow_list);
}
@@ -4695,11 +4854,10 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
struct p2p_channel *n;
if (pref_chan) {
- n = os_malloc(num_pref_chan * sizeof(struct p2p_channel));
+ n = os_memdup(pref_chan,
+ num_pref_chan * sizeof(struct p2p_channel));
if (n == NULL)
return -1;
- os_memcpy(n, pref_chan,
- num_pref_chan * sizeof(struct p2p_channel));
} else
n = NULL;
@@ -4815,6 +4973,8 @@ 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)
{
+ int res, scheduled;
+
if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes");
if (p2p->after_scan_tx) {
@@ -4835,8 +4995,16 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
return 0;
}
- return p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
- buf, len, wait_time);
+ res = p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
+ buf, len, wait_time, &scheduled);
+ if (res == 0 && scheduled && p2p->in_listen && freq > 0 &&
+ (unsigned int) p2p->drv_in_listen != freq) {
+ p2p_dbg(p2p,
+ "Stop listen on %d MHz to allow a frame to be sent immediately on %d MHz",
+ p2p->drv_in_listen, freq);
+ p2p_stop_listen_for_freq(p2p, freq);
+ }
+ return res;
}
@@ -5021,6 +5189,20 @@ int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
}
+int p2p_set_wfd_r2_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
+{
+ wpabuf_free(p2p->wfd_r2_dev_info);
+ if (elem) {
+ p2p->wfd_r2_dev_info = wpabuf_dup(elem);
+ if (p2p->wfd_r2_dev_info == NULL)
+ return -1;
+ } else
+ p2p->wfd_r2_dev_info = NULL;
+
+ return 0;
+}
+
+
int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem)
{
wpabuf_free(p2p->wfd_assoc_bssid);
@@ -5400,3 +5582,42 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
i, p2p->pref_freq_list[i]);
}
}
+
+
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+ u8 chan)
+{
+ p2p->override_pref_op_class = op_class;
+ p2p->override_pref_channel = chan;
+}
+
+
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+ unsigned int freq)
+{
+ struct wpabuf *ies, *buf;
+ u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ int ret;
+
+ ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
+ if (!ies) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: Failed to build Probe Response IEs");
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(200 + wpabuf_len(ies));
+ if (!buf) {
+ wpabuf_free(ies);
+ return NULL;
+ }
+
+ ret = p2p_build_probe_resp_buf(p2p, buf, ies, addr, freq);
+ wpabuf_free(ies);
+ if (ret) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/contrib/wpa/src/p2p/p2p.h b/contrib/wpa/src/p2p/p2p.h
index b4060be..425b037 100644
--- a/contrib/wpa/src/p2p/p2p.h
+++ b/contrib/wpa/src/p2p/p2p.h
@@ -31,7 +31,7 @@
/**
* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
*/
-#define P2P_MAX_REG_CLASSES 10
+#define P2P_MAX_REG_CLASSES 15
/**
* P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class
@@ -99,6 +99,15 @@ struct p2p_go_neg_results {
int vht;
+ u8 max_oper_chwidth;
+
+ unsigned int vht_center_freq2;
+
+ /**
+ * he - Indicates if IEEE 802.11ax HE is enabled
+ */
+ int he;
+
/**
* ssid - SSID of the group
*/
@@ -224,6 +233,16 @@ struct p2ps_provision {
u8 cpt_priority[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
/**
+ * force_freq - The only allowed channel frequency in MHz or 0.
+ */
+ unsigned int force_freq;
+
+ /**
+ * pref_freq - Preferred operating frequency in MHz or 0.
+ */
+ unsigned int pref_freq;
+
+ /**
* info - Vendor defined extra Provisioning information
*/
char info[0];
@@ -646,6 +665,8 @@ struct p2p_config {
* @buf: Frame body (starting from Category field)
* @len: Length of buf in octets
* @wait_time: How many msec to wait for a response frame
+ * @scheduled: Return value indicating whether the transmissions was
+ * scheduled to happen once the radio is available
* Returns: 0 on success, -1 on failure
*
* The Action frame may not be transmitted immediately and the status
@@ -656,7 +677,7 @@ struct p2p_config {
*/
int (*send_action)(void *ctx, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
- size_t len, unsigned int wait_time);
+ size_t len, unsigned int wait_time, int *scheduled);
/**
* send_action_done - Notify that Action frame sequence was completed
@@ -1024,6 +1045,8 @@ struct p2p_config {
* @ssid_len: Buffer for returning length of @ssid
* @group_iface: Buffer for returning whether a separate group interface
* would be used
+ * @freq: Variable for returning the current operating frequency of a
+ * currently running P2P GO.
* Returns: 1 if GO info found, 0 otherwise
*
* This is used to compose New Group settings (SSID, and intended
@@ -1031,7 +1054,8 @@ struct p2p_config {
* 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);
+ u8 *ssid, size_t *ssid_len, int *group_iface,
+ unsigned int *freq);
/**
* remove_stale_groups - Remove stale P2PS groups
@@ -1056,7 +1080,9 @@ struct p2p_config {
const u8 *persist_ssid,
size_t persist_ssid_size, int response_done,
int prov_start, const char *session_info,
- const u8 *feat_cap, size_t feat_cap_len);
+ const u8 *feat_cap, size_t feat_cap_len,
+ unsigned int freq, const u8 *group_ssid,
+ size_t group_ssid_len);
/**
* prov_disc_resp_cb - Callback for indicating completion of PD Response
@@ -1070,14 +1096,20 @@ struct p2p_config {
/**
* p2ps_group_capability - Determine group capability
+ * @ctx: Callback context from cb_ctx
+ * @incoming: Peer requested roles, expressed with P2PS_SETUP_* bitmap.
+ * @role: Local roles, expressed with P2PS_SETUP_* bitmap.
+ * @force_freq: Variable for returning forced frequency for the group.
+ * @pref_freq: Variable for returning preferred frequency for the group.
+ * Returns: P2PS_SETUP_* bitmap of group capability result.
*
- * 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.
+ * This function can be used to determine group capability and
+ * frequencies based on information from P2PS PD exchange and the
+ * current state of ongoing groups and driver capabilities.
*/
- u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role);
+ u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role,
+ unsigned int *force_freq,
+ unsigned int *pref_freq);
/**
* get_pref_freq_list - Get preferred frequency list for an interface
@@ -1530,12 +1562,13 @@ enum p2p_probe_req_status {
* @ie: Information elements from the Probe Request frame body
* @ie_len: Length of ie buffer in octets
* @rx_freq: Probe Request frame RX frequency
+ * @p2p_lo_started: Whether P2P Listen Offload is started
* Returns: value indicating the type and status of the probe request
*/
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
const u8 *bssid, const u8 *ie, size_t ie_len,
- unsigned int rx_freq);
+ unsigned int rx_freq, int p2p_lo_started);
/**
* p2p_rx_action - Report received Action frame
@@ -1691,6 +1724,12 @@ struct p2p_group_config {
int freq;
/**
+ * ip_addr_alloc - Whether IP address allocation within 4-way handshake
+ * is supported
+ */
+ int ip_addr_alloc;
+
+ /**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
@@ -1877,8 +1916,10 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
* @p2p: P2P module context from p2p_init()
* @ies: Buffer for writing P2P IE
* @dev_id: Device ID to search for or %NULL for any
+ * @bands: Frequency bands used in the scan (enum wpa_radio_work_band bitmap)
*/
-void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id);
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id,
+ unsigned int bands);
/**
* p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
@@ -1971,6 +2012,8 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
* @p2p: P2P config
* @op_class: Selected operating class
* @op_channel: Selected social channel
+ * @avoid_list: Channel ranges to try to avoid or %NULL
+ * @disallow_list: Channel ranges to discard or %NULL
* Returns: 0 on success, -1 on failure
*
* This function is used before p2p_init is called. A random social channel
@@ -1978,7 +2021,9 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
* returned on success.
*/
int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
- u8 *op_channel);
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list);
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
u8 forced);
@@ -2100,6 +2145,16 @@ int p2p_client_limit_reached(struct p2p_group *group);
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
/**
+ * p2p_group_get_client_interface_addr - Get P2P Interface Address of a client in a group
+ * @group: P2P group context from p2p_group_init()
+ * @dev_addr: P2P Device Address of the client
+ * Returns: P2P Interface Address of the client if found or %NULL if no match
+ * found
+ */
+const u8 * p2p_group_get_client_interface_addr(struct p2p_group *group,
+ const u8 *dev_addr);
+
+/**
* 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
@@ -2222,6 +2277,7 @@ int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_r2_dev_info(struct p2p_data *p2p, const struct wpabuf *elem);
int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem);
int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
const struct wpabuf *elem);
@@ -2241,7 +2297,7 @@ struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
* discovery (p2p_find). A random number of 100 TU units is picked for each
* Listen state iteration from [min_disc_int,max_disc_int] range.
*
- * max_disc_tu can be used to futher limit the discoverable duration. However,
+ * max_disc_tu can be used to further limit the discoverable duration. However,
* it should be noted that use of this parameter is not recommended since it
* would not be compliant with the P2P specification.
*/
@@ -2329,6 +2385,8 @@ void p2p_expire_peers(struct p2p_data *p2p);
void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
const unsigned int *pref_freq_list,
unsigned int size);
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+ u8 chan);
/**
* p2p_group_get_common_freqs - Get the group common frequencies
@@ -2340,4 +2398,7 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
unsigned int *num);
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+ unsigned int freq);
+
#endif /* P2P_H */
diff --git a/contrib/wpa/src/p2p/p2p_build.c b/contrib/wpa/src/p2p/p2p_build.c
index 793d28b..63eb2e8 100644
--- a/contrib/wpa/src/p2p/p2p_build.c
+++ b/contrib/wpa/src/p2p/p2p_build.c
@@ -202,11 +202,11 @@ void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
if (peer && peer->wps_method != WPS_NOT_READY) {
if (peer->wps_method == WPS_PBC)
methods |= WPS_CONFIG_PUSHBUTTON;
+ else if (peer->wps_method == WPS_P2PS)
+ methods |= WPS_CONFIG_P2PS;
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 |
@@ -802,7 +802,7 @@ int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
wpabuf_put_be16(buf, p2p->cfg->config_methods);
}
- if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
+ if (wps_build_wfa_ext(buf, 0, NULL, 0, 0) < 0)
return -1;
if (all_attr && p2p->cfg->num_sec_dev_types) {
diff --git a/contrib/wpa/src/p2p/p2p_go_neg.c b/contrib/wpa/src/p2p/p2p_go_neg.c
index 83b4356..65ab4b8 100644
--- a/contrib/wpa/src/p2p/p2p_go_neg.c
+++ b/contrib/wpa/src/p2p/p2p_go_neg.c
@@ -38,7 +38,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
{
const u8 *pos, *end;
struct p2p_channels *ch;
- size_t channels;
+ u8 channels;
struct p2p_channels intersection;
ch = &dev->channels;
@@ -58,14 +58,14 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
}
pos += 3;
- while (pos + 2 < end) {
+ while (end - pos > 2) {
struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes];
cl->reg_class = *pos++;
- if (pos + 1 + pos[0] > end) {
+ channels = *pos++;
+ if (channels > end - pos) {
p2p_info(p2p, "Invalid peer Channel List");
return -1;
}
- channels = *pos++;
cl->channels = channels > P2P_MAX_REG_CLASS_CHANNELS ?
P2P_MAX_REG_CLASS_CHANNELS : channels;
os_memcpy(cl->channel, pos, cl->channels);
@@ -315,7 +315,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
group_capab);
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 && !p2p->num_pref_freq) {
+ if (p2p->override_pref_op_class) {
+ p2p_dbg(p2p, "Override operating channel preference");
+ p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p->override_pref_op_class,
+ p2p->override_pref_channel);
+ } else if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
p2p_dbg(p2p, "Omit Operating Channel attribute");
} else {
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
@@ -384,7 +389,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
unsigned int i;
const int op_classes_5ghz[] = { 124, 125, 115, 0 };
const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
- const int op_classes_vht[] = { 128, 0 };
+ const int op_classes_vht[] = { 128, 129, 130, 0 };
if (p2p->own_freq_preference > 0 &&
p2p_freq_to_channel(p2p->own_freq_preference,
@@ -562,26 +567,11 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go,
* also supported by the peer device.
*/
for (i = 0; i < size && !found; i++) {
- /*
- * Make sure that the common frequency is:
- * 1. Supported by peer
- * 2. Allowed for P2P use.
- */
+ /* Make sure that the common frequency is supported by peer. */
oper_freq = freq_list[i];
if (p2p_freq_to_channel(oper_freq, &op_class,
- &op_channel) < 0) {
- p2p_dbg(p2p, "Unsupported frequency %u MHz", oper_freq);
- continue;
- }
- 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,
- "Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
- oper_freq, op_class, op_channel);
- break;
- }
+ &op_channel) < 0)
+ continue; /* cannot happen due to earlier check */
for (j = 0; j < msg->channel_list_len; j++) {
if (op_channel != msg->channel_list[j])
@@ -602,8 +592,7 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go,
oper_freq);
} else {
p2p_dbg(p2p,
- "None of our preferred channels are supported by peer!. Use: %d MHz for oper_channel",
- dev->oper_freq);
+ "None of our preferred channels are supported by peer!");
}
}
@@ -629,29 +618,9 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go,
msg->pref_freq_list[2 * j + 1]);
if (freq_list[i] != oper_freq)
continue;
-
- /*
- * Make sure that the found frequency is:
- * 1. Supported
- * 2. Allowed for P2P use.
- */
if (p2p_freq_to_channel(oper_freq, &op_class,
- &op_channel) < 0) {
- p2p_dbg(p2p, "Unsupported frequency %u MHz",
- oper_freq);
- continue;
- }
-
- 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,
- "Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
- oper_freq, op_class, op_channel);
- break;
- }
+ &op_channel) < 0)
+ continue; /* cannot happen */
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
os_memcpy(&p2p->channels, &p2p->cfg->channels,
@@ -666,9 +635,7 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go,
"Freq %d MHz is a common preferred channel for both peer and local, use it as operating channel",
oper_freq);
} else {
- p2p_dbg(p2p,
- "No common preferred channels found! Use: %d MHz for oper_channel",
- dev->oper_freq);
+ p2p_dbg(p2p, "No common preferred channels found!");
}
}
@@ -679,6 +646,8 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size;
unsigned int i;
u8 op_class, op_channel;
+ char txt[100], *pos, *end;
+ int res;
/*
* Use the preferred channel list from the driver only if there is no
@@ -694,6 +663,39 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size,
freq_list))
return;
+ /* Filter out frequencies that are not acceptable for P2P use */
+ i = 0;
+ while (i < size) {
+ if (p2p_freq_to_channel(freq_list[i], &op_class,
+ &op_channel) < 0 ||
+ (!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,
+ "Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
+ freq_list[i], go);
+ if (size - i - 1 > 0)
+ os_memmove(&freq_list[i], &freq_list[i + 1], size - i - 1);
+ size--;
+ continue;
+ }
+
+ /* Preferred frequency is acceptable for P2P use */
+ i++;
+ }
+
+ pos = txt;
+ end = pos + sizeof(txt);
+ for (i = 0; i < size; i++) {
+ res = os_snprintf(pos, end - pos, " %u", freq_list[i]);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
+ p2p_dbg(p2p, "Local driver frequency preference (size=%u):%s",
+ size, txt);
/*
* Check if peer's preference of operating channel is in
@@ -703,20 +705,14 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
if (freq_list[i] == (unsigned int) dev->oper_freq)
break;
}
- if (i != size) {
+ if (i != size &&
+ p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) {
/* Peer operating channel preference matches our preference */
- if (p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) <
- 0) {
- p2p_dbg(p2p,
- "Peer operating channel preference is unsupported frequency %u MHz",
- freq_list[i]);
- } else {
- p2p->op_reg_class = op_class;
- p2p->op_channel = op_channel;
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- return;
- }
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ os_memcpy(&p2p->channels, &p2p->cfg->channels,
+ sizeof(struct p2p_channels));
+ return;
}
p2p_dbg(p2p,
@@ -901,6 +897,14 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
return;
}
+ if (dev->go_neg_req_sent &&
+ (dev->flags & P2P_DEV_PEER_WAITING_RESPONSE)) {
+ p2p_dbg(p2p,
+ "Do not reply since peer is waiting for us to start a new GO Negotiation and GO Neg Request already sent");
+ p2p_parse_free(&msg);
+ return;
+ }
+
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
if (go < 0) {
p2p_dbg(p2p, "Incompatible GO Intent");
@@ -1052,7 +1056,7 @@ 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), 500) < 0) {
+ wpabuf_head(resp), wpabuf_len(resp), 100) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
}
@@ -1260,6 +1264,11 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
dev->client_timeout = msg.config_timeout[1];
}
+ if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ }
+
if (!msg.operating_channel && !go) {
/*
* Note: P2P Client may omit Operating Channel attribute to
@@ -1386,7 +1395,7 @@ fail:
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
wpabuf_head(dev->go_neg_conf),
- wpabuf_len(dev->go_neg_conf), 200) < 0) {
+ wpabuf_len(dev->go_neg_conf), 50) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
p2p_go_neg_failed(p2p, -1);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
diff --git a/contrib/wpa/src/p2p/p2p_group.c b/contrib/wpa/src/p2p/p2p_group.c
index 0d66993..aa18af6 100644
--- a/contrib/wpa/src/p2p/p2p_group.c
+++ b/contrib/wpa/src/p2p/p2p_group.c
@@ -155,7 +155,8 @@ 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;
+ if (group->cfg->ip_addr_alloc)
+ group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
p2p_buf_add_capability(ie, dev_capab, group_capab);
}
@@ -296,14 +297,14 @@ static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
os_memset(zero_addr, 0, ETH_ALEN);
pos = wpabuf_head_u8(m->wfd_ie);
end = pos + wpabuf_len(m->wfd_ie);
- while (pos + 1 < end) {
+ while (end - pos >= 3) {
u8 id;
u16 len;
id = *pos++;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end)
+ if (len > end - pos)
break;
switch (id) {
@@ -366,6 +367,8 @@ wifi_display_build_go_ie(struct p2p_group *group)
return NULL;
if (group->p2p->wfd_dev_info)
wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info);
+ if (group->p2p->wfd_r2_dev_info)
+ wpabuf_put_buf(wfd_subelems, group->p2p->wfd_r2_dev_info);
if (group->p2p->wfd_assoc_bssid)
wpabuf_put_buf(wfd_subelems,
group->p2p->wfd_assoc_bssid);
@@ -849,6 +852,20 @@ static struct p2p_group_member * p2p_group_get_client(struct p2p_group *group,
}
+const u8 * p2p_group_get_client_interface_addr(struct p2p_group *group,
+ const u8 *dev_addr)
+{
+ struct p2p_group_member *m;
+
+ if (!group)
+ return NULL;
+ m = p2p_group_get_client(group, dev_addr);
+ if (m)
+ return m->addr;
+ return NULL;
+}
+
+
static struct p2p_group_member * p2p_group_get_client_iface(
struct p2p_group *group, const u8 *interface_addr)
{
@@ -924,7 +941,8 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr,
group->cfg->interface_addr,
group->cfg->interface_addr,
- wpabuf_head(req), wpabuf_len(req), 200) < 0)
+ wpabuf_head(req), wpabuf_len(req), 200, NULL)
+ < 0)
{
p2p_dbg(p2p, "Failed to send Action frame");
}
@@ -1097,7 +1115,7 @@ int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
struct p2p_device *dev;
dev = p2p_get_device(group->p2p, m->dev_addr);
- if (!dev)
+ if (!dev || dev->channels.reg_classes == 0)
continue;
p2p_channels_intersect(&intersect, &dev->channels, &res);
diff --git a/contrib/wpa/src/p2p/p2p_i.h b/contrib/wpa/src/p2p/p2p_i.h
index 0ce4058..d2c55c9 100644
--- a/contrib/wpa/src/p2p/p2p_i.h
+++ b/contrib/wpa/src/p2p/p2p_i.h
@@ -308,6 +308,18 @@ struct p2p_data {
*/
int num_p2p_sd_queries;
+ /**
+ * sd_query_no_ack - The first peer (Dev Addr) that did not ACK SD Query
+ *
+ * This is used to track the first peer that did not ACK an SD Query
+ * within a single P2P Search iteration. All zeros address means no such
+ * peer was yet seen. This information is used to allow a new Listen and
+ * Search phases to be once every pending SD Query has been sent once to
+ * each peer instead of looping all pending attempts continuously until
+ * running out of retry maximums.
+ */
+ u8 sd_query_no_ack[ETH_ALEN];
+
/* GO Negotiation data */
/**
@@ -425,9 +437,11 @@ struct p2p_data {
int inv_persistent;
enum p2p_discovery_type find_type;
+ int find_specified_freq;
unsigned int last_p2p_find_timeout;
u8 last_prog_scan_class;
u8 last_prog_scan_chan;
+ unsigned int find_pending_full:1;
int p2p_scan_running;
enum p2p_after_scan {
P2P_AFTER_SCAN_NOTHING,
@@ -533,6 +547,7 @@ struct p2p_data {
struct wpabuf *wfd_dev_info;
struct wpabuf *wfd_assoc_bssid;
struct wpabuf *wfd_coupled_sink_info;
+ struct wpabuf *wfd_r2_dev_info;
#endif /* CONFIG_WIFI_DISPLAY */
u16 authorized_oob_dev_pw_id;
@@ -541,6 +556,10 @@ struct p2p_data {
unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS];
unsigned int num_pref_freq;
+
+ /* Override option for preferred operating channel in GO Negotiation */
+ u8 override_pref_op_class;
+ u8 override_pref_channel;
};
/**
@@ -688,9 +707,13 @@ void p2p_channels_dump(struct p2p_data *p2p, const char *title,
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);
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list);
/* p2p_parse.c */
+void p2p_copy_filter_devname(char *dst, size_t dst_len,
+ const void *src, size_t src_len);
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);
diff --git a/contrib/wpa/src/p2p/p2p_invitation.c b/contrib/wpa/src/p2p/p2p_invitation.c
index 108e5b7..77d662a 100644
--- a/contrib/wpa/src/p2p/p2p_invitation.c
+++ b/contrib/wpa/src/p2p/p2p_invitation.c
@@ -284,7 +284,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
if (!p2p_channels_includes(&intersection, reg_class, channel))
{
- p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
+ p2p_dbg(p2p, "forced freq %d MHz not in the supported channels intersection",
op_freq);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
@@ -418,7 +418,7 @@ fail:
p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
+ wpabuf_head(resp), wpabuf_len(resp), 50) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
}
@@ -488,7 +488,7 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
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->op_channel, NULL, NULL) == 0) {
p2p->retry_invite_req = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
diff --git a/contrib/wpa/src/p2p/p2p_parse.c b/contrib/wpa/src/p2p/p2p_parse.c
index bd1e68b..5d2299c 100644
--- a/contrib/wpa/src/p2p/p2p_parse.c
+++ b/contrib/wpa/src/p2p/p2p_parse.c
@@ -15,11 +15,29 @@
#include "p2p_i.h"
+void p2p_copy_filter_devname(char *dst, size_t dst_len,
+ const void *src, size_t src_len)
+{
+ size_t i;
+
+ if (src_len >= dst_len)
+ src_len = dst_len - 1;
+ os_memcpy(dst, src, src_len);
+ dst[src_len] = '\0';
+ for (i = 0; i < src_len; i++) {
+ if (dst[i] == '\0')
+ break;
+ if (is_ctrl_char(dst[i]))
+ dst[i] = '_';
+ }
+}
+
+
static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
struct p2p_message *msg)
{
const u8 *pos;
- size_t i, nlen;
+ u16 nlen;
char devtype[WPS_DEV_TYPE_BUFSIZE];
switch (id) {
@@ -149,21 +167,14 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
pos += 2;
nlen = WPA_GET_BE16(pos);
pos += 2;
- if (data + len - pos < (int) nlen ||
- nlen > WPS_DEV_NAME_MAX_LEN) {
+ if (nlen > data + len - pos || nlen > WPS_DEV_NAME_MAX_LEN) {
wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
- "length %d (buf len %d)", (int) nlen,
+ "length %u (buf len %d)", nlen,
(int) (data + len - pos));
return -1;
}
- os_memcpy(msg->device_name, pos, nlen);
- msg->device_name[nlen] = '\0';
- for (i = 0; i < nlen; i++) {
- if (msg->device_name[i] == '\0')
- break;
- if (is_ctrl_char(msg->device_name[i]))
- msg->device_name[i] = '_';
- }
+ p2p_copy_filter_devname(msg->device_name,
+ sizeof(msg->device_name), pos, nlen);
wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR
" primary device type %s device name '%s' "
"config methods 0x%x",
@@ -637,49 +648,48 @@ int p2p_group_info_parse(const u8 *gi, size_t gi_len,
gend = gi + gi_len;
while (g < gend) {
struct p2p_client_info *cli;
- const u8 *t, *cend;
- int count;
+ const u8 *cend;
+ u16 count;
+ u8 len;
cli = &info->client[info->num_clients];
- cend = g + 1 + g[0];
- if (cend > gend)
+ len = *g++;
+ if (len > gend - g || len < 2 * ETH_ALEN + 1 + 2 + 8 + 1)
return -1; /* invalid data */
+ cend = g + len;
/* g at start of P2P Client Info Descriptor */
- /* t at Device Capability Bitmap */
- t = g + 1 + 2 * ETH_ALEN;
- if (t > cend)
- return -1; /* invalid data */
- cli->p2p_device_addr = g + 1;
- cli->p2p_interface_addr = g + 1 + ETH_ALEN;
- cli->dev_capab = t[0];
-
- if (t + 1 + 2 + 8 + 1 > cend)
- return -1; /* invalid data */
-
- cli->config_methods = WPA_GET_BE16(&t[1]);
- cli->pri_dev_type = &t[3];
-
- t += 1 + 2 + 8;
- /* t at Number of Secondary Device Types */
- cli->num_sec_dev_types = *t++;
- if (t + 8 * cli->num_sec_dev_types > cend)
+ cli->p2p_device_addr = g;
+ g += ETH_ALEN;
+ cli->p2p_interface_addr = g;
+ g += ETH_ALEN;
+ cli->dev_capab = *g++;
+
+ cli->config_methods = WPA_GET_BE16(g);
+ g += 2;
+ cli->pri_dev_type = g;
+ g += 8;
+
+ /* g at Number of Secondary Device Types */
+ len = *g++;
+ if (8 * len > cend - g)
return -1; /* invalid data */
- cli->sec_dev_types = t;
- t += 8 * cli->num_sec_dev_types;
+ cli->num_sec_dev_types = len;
+ cli->sec_dev_types = g;
+ g += 8 * len;
- /* t at Device Name in WPS TLV format */
- if (t + 2 + 2 > cend)
+ /* g at Device Name in WPS TLV format */
+ if (cend - g < 2 + 2)
return -1; /* invalid data */
- if (WPA_GET_BE16(t) != ATTR_DEV_NAME)
+ if (WPA_GET_BE16(g) != ATTR_DEV_NAME)
return -1; /* invalid Device Name TLV */
- t += 2;
- count = WPA_GET_BE16(t);
- t += 2;
- if (count > cend - t)
+ g += 2;
+ count = WPA_GET_BE16(g);
+ g += 2;
+ if (count > cend - g)
return -1; /* invalid Device Name TLV */
if (count >= WPS_DEV_NAME_MAX_LEN)
count = WPS_DEV_NAME_MAX_LEN;
- cli->dev_name = (const char *) t;
+ cli->dev_name = (const char *) g;
cli->dev_name_len = count;
g = cend;
diff --git a/contrib/wpa/src/p2p/p2p_pd.c b/contrib/wpa/src/p2p/p2p_pd.c
index 8900945..3994ec0 100644
--- a/contrib/wpa/src/p2p/p2p_pd.c
+++ b/contrib/wpa/src/p2p/p2p_pd.c
@@ -40,21 +40,31 @@ 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)
+static void p2ps_add_new_group_info(struct p2p_data *p2p,
+ struct p2p_device *dev,
+ struct wpabuf *buf)
{
int found;
u8 intended_addr[ETH_ALEN];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int group_iface;
+ unsigned int force_freq;
if (!p2p->cfg->get_go_info)
return;
found = p2p->cfg->get_go_info(
p2p->cfg->cb_ctx, intended_addr, ssid,
- &ssid_len, &group_iface);
+ &ssid_len, &group_iface, &force_freq);
if (found) {
+ if (force_freq > 0) {
+ p2p->p2ps_prov->force_freq = force_freq;
+ p2p->p2ps_prov->pref_freq = 0;
+
+ if (dev)
+ p2p_prepare_channel(p2p, dev, force_freq, 0, 0);
+ }
p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
ssid, ssid_len);
@@ -92,62 +102,62 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
size_t ssid_len;
u8 go_dev_addr[ETH_ALEN];
u8 intended_addr[ETH_ALEN];
+ int follow_on_req_fail = prov->status >= 0 &&
+ prov->status != P2P_SC_SUCCESS_DEFERRED;
/* 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 (!follow_on_req_fail &&
+ (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
+ p2ps_add_new_group_info(p2p, dev, 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, intended_addr);
- }
-
- /* Add Operating Channel if conncap includes GO */
- if (shared_group ||
- (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
- P2PS_SETUP_NEW))) {
- u8 tmp;
+ if (!follow_on_req_fail) {
+ 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,
+ intended_addr);
+ }
- p2p_go_select_channel(p2p, dev, &tmp);
+ if (shared_group ||
+ (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW)))
+ p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ &p2p->channels);
- if (p2p->op_reg_class && p2p->op_channel)
+ if ((shared_group && !is_zero_ether_addr(intended_addr)) ||
+ (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
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])
+ if (prov->status < 0 && prov->info[0])
p2p_buf_add_session_info(buf, prov->info);
- p2p_buf_add_connection_capability(buf, prov->conncap);
+ if (!follow_on_req_fail)
+ 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);
- }
+ if (!follow_on_req_fail) {
+ 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_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);
@@ -285,6 +295,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
u8 *len = p2p_buf_add_ie_hdr(buf);
struct p2ps_provision *prov = p2p->p2ps_prov;
u8 group_capab;
+ u8 conncap = 0;
+
+ if (status == P2P_SC_SUCCESS ||
+ status == P2P_SC_SUCCESS_DEFERRED)
+ conncap = prov->conncap;
if (!status && prov->status != -1)
status = prov->status;
@@ -301,7 +316,7 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
group_capab);
p2p_buf_add_device_info(buf, p2p, NULL);
- if (persist_ssid && p2p->cfg->get_persistent_group &&
+ if (persist_ssid && p2p->cfg->get_persistent_group && dev &&
(status == P2P_SC_SUCCESS ||
status == P2P_SC_SUCCESS_DEFERRED)) {
u8 ssid[SSID_MAX_LEN];
@@ -323,16 +338,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
}
}
- if (!persist && (prov->conncap & P2PS_SETUP_GROUP_OWNER))
- p2ps_add_new_group_info(p2p, buf);
+ if (!persist && (conncap & P2PS_SETUP_GROUP_OWNER))
+ p2ps_add_new_group_info(p2p, dev, 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 (persist || (conncap & P2PS_SETUP_GROUP_OWNER)) {
if (p2p->op_reg_class && p2p->op_channel)
p2p_buf_add_operating_channel(
buf, p2p->cfg->country,
@@ -345,17 +355,20 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
p2p->cfg->op_channel);
}
- p2p_buf_add_channel_list(buf, p2p->cfg->country,
- &p2p->cfg->channels);
+ if (persist ||
+ (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
+ p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ &p2p->channels);
- if (!persist && (status == P2P_SC_SUCCESS ||
- status == P2P_SC_SUCCESS_DEFERRED))
- p2p_buf_add_connection_capability(buf, prov->conncap);
+ if (!persist && conncap)
+ p2p_buf_add_connection_capability(buf, conncap);
p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac);
- p2p_buf_add_config_timeout(buf, p2p->go_timeout,
- p2p->client_timeout);
+ if (persist ||
+ (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+ p2p->client_timeout);
p2p_buf_add_session_id(buf, prov->session_id,
prov->session_mac);
@@ -427,6 +440,117 @@ static u8 p2ps_own_preferred_cpt(const u8 *cpt_priority, u8 req_cpt_mask)
}
+/* Check if the message contains a valid P2PS PD Request */
+static int p2ps_validate_pd_req(struct p2p_data *p2p, struct p2p_message *msg,
+ const u8 *addr)
+{
+ u8 group_id = 0;
+ u8 intended_addr = 0;
+ u8 operating_channel = 0;
+ u8 channel_list = 0;
+ u8 config_timeout = 0;
+ u8 listen_channel = 0;
+
+#define P2PS_PD_REQ_CHECK(_val, _attr) \
+do { \
+ if ((_val) && !msg->_attr) { \
+ p2p_dbg(p2p, "Not P2PS PD Request. Missing %s", #_attr); \
+ return -1; \
+ } \
+} while (0)
+
+ P2PS_PD_REQ_CHECK(1, adv_id);
+ P2PS_PD_REQ_CHECK(1, session_id);
+ P2PS_PD_REQ_CHECK(1, session_mac);
+ P2PS_PD_REQ_CHECK(1, adv_mac);
+ P2PS_PD_REQ_CHECK(1, capability);
+ P2PS_PD_REQ_CHECK(1, p2p_device_info);
+ P2PS_PD_REQ_CHECK(1, feature_cap);
+
+ /*
+ * We don't need to check Connection Capability, Persistent Group,
+ * and related attributes for follow-on PD Request with a status
+ * other than SUCCESS_DEFERRED.
+ */
+ if (msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED)
+ return 0;
+
+ P2PS_PD_REQ_CHECK(1, conn_cap);
+
+ /*
+ * Note 1: A feature capability attribute structure can be changed
+ * in the future. The assumption is that such modifications are
+ * backward compatible, therefore we allow processing of msg.feature_cap
+ * exceeding the size of the p2ps_feature_capab structure.
+ * Note 2: Verification of msg.feature_cap_len below has to be changed
+ * to allow 2 byte feature capability processing if
+ * struct p2ps_feature_capab is extended to include additional fields
+ * and it affects the structure size.
+ */
+ if (msg->feature_cap_len < sizeof(struct p2ps_feature_capab)) {
+ p2p_dbg(p2p, "P2PS: Invalid feature capability len");
+ return -1;
+ }
+
+ switch (*msg->conn_cap) {
+ case P2PS_SETUP_NEW:
+ group_id = 1;
+ intended_addr = 1;
+ operating_channel = 1;
+ channel_list = 1;
+ config_timeout = 1;
+ listen_channel = 1;
+ break;
+ case P2PS_SETUP_CLIENT:
+ channel_list = 1;
+ listen_channel = 1;
+ break;
+ case P2PS_SETUP_GROUP_OWNER:
+ group_id = 1;
+ intended_addr = 1;
+ operating_channel = 1;
+ break;
+ case P2PS_SETUP_NEW | P2PS_SETUP_GROUP_OWNER:
+ group_id = 1;
+ operating_channel = 1;
+ intended_addr = 1;
+ channel_list = 1;
+ config_timeout = 1;
+ break;
+ case P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER:
+ group_id = 1;
+ intended_addr = 1;
+ operating_channel = 1;
+ channel_list = 1;
+ config_timeout = 1;
+ break;
+ default:
+ p2p_dbg(p2p, "Invalid P2PS PD connection capability");
+ return -1;
+ }
+
+ if (msg->persistent_dev) {
+ channel_list = 1;
+ config_timeout = 1;
+ if (os_memcmp(msg->persistent_dev, addr, ETH_ALEN) == 0) {
+ intended_addr = 1;
+ operating_channel = 1;
+ }
+ }
+
+ P2PS_PD_REQ_CHECK(group_id, group_id);
+ P2PS_PD_REQ_CHECK(intended_addr, intended_addr);
+ P2PS_PD_REQ_CHECK(operating_channel, operating_channel);
+ P2PS_PD_REQ_CHECK(channel_list, channel_list);
+ P2PS_PD_REQ_CHECK(config_timeout, config_timeout);
+ P2PS_PD_REQ_CHECK(listen_channel, listen_channel);
+
+#undef P2PS_PD_REQ_CHECK
+
+ return 0;
+}
+
+
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
@@ -440,14 +564,16 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
u8 conncap = P2PS_SETUP_NEW;
u8 auto_accept = 0;
u32 session_id = 0;
- u8 session_mac[ETH_ALEN];
- u8 adv_mac[ETH_ALEN];
+ u8 session_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ u8 adv_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
const u8 *group_mac;
int passwd_id = DEV_PW_DEFAULT;
u16 config_methods;
u16 allowed_config_methods = WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
struct p2ps_feature_capab resp_fcap = { 0, 0 };
- struct p2ps_feature_capab *req_fcap;
+ struct p2ps_feature_capab *req_fcap = NULL;
+ u8 remote_conncap;
+ u16 method;
if (p2p_parse(data, len, &msg))
return;
@@ -466,300 +592,431 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
0)) {
p2p_dbg(p2p, "Provision Discovery Request add device failed "
MACSTR, MAC2STR(sa));
+ goto out;
+ }
+
+ if (!dev) {
+ dev = p2p_get_device(p2p, sa);
+ if (!dev) {
+ p2p_dbg(p2p,
+ "Provision Discovery device not found "
+ MACSTR, MAC2STR(sa));
+ goto out;
+ }
}
} else if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
}
- if (msg.adv_id)
- allowed_config_methods |= WPS_CONFIG_P2PS;
- else
+ if (!msg.adv_id) {
allowed_config_methods |= WPS_CONFIG_PUSHBUTTON;
+ if (!(msg.wps_config_methods & allowed_config_methods)) {
+ p2p_dbg(p2p,
+ "Unsupported Config Methods in Provision Discovery Request");
+ goto out;
+ }
- if (!(msg.wps_config_methods & allowed_config_methods)) {
- p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
- goto out;
- }
+ /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
+ if (msg.group_id) {
+ size_t i;
- /* 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],
- msg.group_id,
- msg.group_id_len))
- break;
+ for (i = 0; i < p2p->num_groups; i++) {
+ if (p2p_group_is_group_id_match(
+ p2p->groups[i],
+ msg.group_id, msg.group_id_len))
+ break;
+ }
+ if (i == p2p->num_groups) {
+ p2p_dbg(p2p,
+ "PD request for unknown P2P Group ID - reject");
+ goto out;
+ }
}
- if (i == p2p->num_groups) {
- p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
+ } else {
+ allowed_config_methods |= WPS_CONFIG_P2PS;
+
+ /*
+ * Set adv_id here, so in case of an error, a P2PS PD Response
+ * will be sent.
+ */
+ adv_id = WPA_GET_LE32(msg.adv_id);
+ if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) {
+ reject = P2P_SC_FAIL_INVALID_PARAMS;
goto out;
}
- }
- if (dev) {
- dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
- P2P_DEV_PD_PEER_KEYPAD |
- P2P_DEV_PD_PEER_P2PS);
+ req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
- /* 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);
+ 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);
+
+ if (msg.conn_cap)
+ conncap = *msg.conn_cap;
+
+ /*
+ * We need to verify a P2PS config methog in an initial PD
+ * request or in a follow-on PD request with the status
+ * SUCCESS_DEFERRED.
+ */
+ if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) &&
+ !(msg.wps_config_methods & allowed_config_methods)) {
+ p2p_dbg(p2p,
+ "Unsupported Config Methods in Provision Discovery Request");
+ goto out;
}
+
+ /*
+ * TODO: since we don't support multiple PD, reject PD request
+ * if we are in the middle of P2PS PD with some other peer
+ */
}
+
+ dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
+ P2P_DEV_PD_PEER_KEYPAD |
+ P2P_DEV_PD_PEER_P2PS);
+
if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
p2p_dbg(p2p, "Peer " MACSTR
" requested us to show a PIN on display", MAC2STR(sa));
- if (dev)
- dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+ dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
passwd_id = DEV_PW_USER_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
p2p_dbg(p2p, "Peer " MACSTR
" requested us to write its PIN using keypad",
MAC2STR(sa));
- if (dev)
- dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
+ 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;
+ dev->flags |= P2P_DEV_PD_PEER_P2PS;
passwd_id = DEV_PW_P2PS_DEFAULT;
}
- reject = P2P_SC_SUCCESS;
+ /* 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);
+ }
- os_memset(session_mac, 0, ETH_ALEN);
- os_memset(adv_mac, 0, ETH_ALEN);
+ reject = P2P_SC_SUCCESS;
- /* Note 1: A feature capability attribute structure can be changed
- * in the future. The assumption is that such modifications are
- * backwards compatible, therefore we allow processing of
- * msg.feature_cap exceeding the size of the p2ps_feature_capab
- * structure.
- * Note 2: Vverification of msg.feature_cap_len below has to be changed
- * to allow 2 byte feature capability processing if struct
- * p2ps_feature_capab is extended to include additional fields and it
- * affects the structure size.
+ /*
+ * End of a legacy P2P PD Request processing, from this point continue
+ * with P2PS one.
*/
- if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac &&
- msg.feature_cap && msg.feature_cap_len >= sizeof(*req_fcap) &&
- (msg.status || msg.conn_cap)) {
- u8 remote_conncap;
+ if (!msg.adv_id)
+ goto out;
- req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
+ remote_conncap = conncap;
- os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
- os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+ if (!msg.status) {
+ unsigned int forced_freq, pref_freq;
- 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);
+ if (os_memcmp(p2p->cfg->dev_addr, msg.adv_mac, ETH_ALEN)) {
+ p2p_dbg(p2p,
+ "P2PS PD adv mac does not match the local one");
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ goto out;
+ }
- p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv);
+ p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
+ if (!p2ps_adv) {
+ p2p_dbg(p2p, "P2PS PD invalid adv_id=0x%X", adv_id);
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ goto out;
+ }
+ p2p_dbg(p2p, "adv_id: 0x%X, p2ps_adv: %p", adv_id, p2ps_adv);
- if (msg.conn_cap)
- conncap = *msg.conn_cap;
- remote_conncap = conncap;
+ auto_accept = p2ps_adv->auto_accept;
+ conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
+ conncap, auto_accept,
+ &forced_freq,
+ &pref_freq);
- 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);
- p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
- auto_accept, remote_conncap, conncap);
+ p2p_prepare_channel(p2p, dev, forced_freq, pref_freq, 0);
- resp_fcap.cpt =
- p2ps_own_preferred_cpt(p2ps_adv->cpt_priority,
+ resp_fcap.cpt = p2ps_own_preferred_cpt(p2ps_adv->cpt_priority,
req_fcap->cpt);
+ p2p_dbg(p2p, "cpt: service:0x%x remote:0x%x result:0x%x",
+ p2ps_adv->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
+
+ if (!resp_fcap.cpt) {
+ p2p_dbg(p2p,
+ "Incompatible P2PS feature capability CPT bitmask");
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ } else if (p2ps_adv->config_methods &&
+ !(msg.wps_config_methods &
+ p2ps_adv->config_methods)) {
p2p_dbg(p2p,
- "cpt: service:0x%x remote:0x%x result:0x%x",
- p2ps_adv->cpt_mask, req_fcap->cpt,
- resp_fcap.cpt);
+ "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 (!resp_fcap.cpt) {
- p2p_dbg(p2p,
- "Incompatible P2PS feature capability CPT bitmask");
- reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- } else 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 (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
- p2p_dbg(p2p, "Keypad - always defer");
- auto_accept = 0;
+ if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
+ msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
+ msg.channel_list && msg.channel_list_len &&
+ p2p_peer_channels_check(p2p, &p2p->channels, dev,
+ msg.channel_list,
+ msg.channel_list_len) < 0) {
+ p2p_dbg(p2p,
+ "No common channels - force deferred flow");
+ auto_accept = 0;
+ }
+
+ if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) ||
+ msg.persistent_dev) && msg.operating_channel) {
+ struct p2p_channels intersect;
+
+ /*
+ * There are cases where only the operating channel is
+ * provided. This requires saving the channel as the
+ * supported channel list, and verifying that it is
+ * supported.
+ */
+ if (dev->channels.reg_classes == 0 ||
+ !p2p_channels_includes(&dev->channels,
+ msg.operating_channel[3],
+ msg.operating_channel[4])) {
+ struct p2p_channels *ch = &dev->channels;
+
+ os_memset(ch, 0, sizeof(*ch));
+ ch->reg_class[0].reg_class =
+ msg.operating_channel[3];
+ ch->reg_class[0].channel[0] =
+ msg.operating_channel[4];
+ ch->reg_class[0].channels = 1;
+ ch->reg_classes = 1;
}
- 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;
+ p2p_channels_intersect(&p2p->channels, &dev->channels,
+ &intersect);
+
+ if (intersect.reg_classes == 0) {
+ p2p_dbg(p2p,
+ "No common channels - force deferred flow");
+ auto_accept = 0;
}
- } 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)) {
+ if (auto_accept || reject != P2P_SC_SUCCESS) {
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;
+ tmp->force_freq = forced_freq;
+ tmp->pref_freq = pref_freq;
+ 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;
}
+ }
- 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;
+ if (!msg.status && !auto_accept &&
+ (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
+ struct p2ps_provision *tmp;
- conncap = p2p->cfg->p2ps_group_capability(
- p2p->cfg->cb_ctx, remote_conncap,
- p2p->p2ps_prov->conncap);
+ if (!conncap) {
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ goto out;
+ }
- p2p_dbg(p2p,
- "Conncap: local:%d remote:%d result:%d",
- p2p->p2ps_prov->conncap,
- remote_conncap, conncap);
+ 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;
+ }
- resp_fcap.cpt = p2ps_own_preferred_cpt(
- p2p->p2ps_prov->cpt_priority,
- req_fcap->cpt);
+ /* Not a P2PS Follow-on PD */
+ if (!msg.status)
+ goto out;
- p2p_dbg(p2p,
- "cpt: local:0x%x remote:0x%x result:0x%x",
- p2p->p2ps_prov->cpt_mask,
- req_fcap->cpt, resp_fcap.cpt);
+ if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) {
+ reject = *msg.status;
+ goto out;
+ }
- /*
- * 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;
-
- if (!conncap ||
- !(msg.wps_config_methods & method)) {
- /*
- * Reject this "Deferred Accept*
- * if incompatible conncap or method
- */
- reject =
- P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- } else if (!resp_fcap.cpt) {
- p2p_dbg(p2p,
- "Incompatible P2PS feature capability CPT bitmask");
- reject =
- P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- } else {
- reject = P2P_SC_SUCCESS;
- }
-
- p2p->p2ps_prov->status = reject;
- p2p->p2ps_prov->conncap = conncap;
- }
- }
+ if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
+ goto out;
+
+ if (p2p->p2ps_prov->adv_id != adv_id ||
+ os_memcmp(p2p->p2ps_prov->adv_mac, msg.adv_mac, ETH_ALEN)) {
+ p2p_dbg(p2p,
+ "P2PS Follow-on PD with mismatch Advertisement ID/MAC");
+ goto out;
+ }
+
+ if (p2p->p2ps_prov->session_id != session_id ||
+ os_memcmp(p2p->p2ps_prov->session_mac, msg.session_mac, ETH_ALEN)) {
+ p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC");
+ goto out;
+ }
+
+ method = p2p->p2ps_prov->method;
+
+ conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
+ remote_conncap,
+ p2p->p2ps_prov->conncap,
+ &p2p->p2ps_prov->force_freq,
+ &p2p->p2ps_prov->pref_freq);
+
+ resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority,
+ req_fcap->cpt);
+
+ p2p_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x",
+ p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
+
+ p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
+ p2p->p2ps_prov->pref_freq, 0);
+
+ /*
+ * 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;
+
+ if (!conncap || !(msg.wps_config_methods & method)) {
+ /*
+ * Reject this "Deferred Accept*
+ * if incompatible conncap or method
+ */
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ } else if (!resp_fcap.cpt) {
+ p2p_dbg(p2p,
+ "Incompatible P2PS feature capability CPT bitmask");
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
+ msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
+ msg.channel_list && msg.channel_list_len &&
+ p2p_peer_channels_check(p2p, &p2p->channels, dev,
+ msg.channel_list,
+ msg.channel_list_len) < 0) {
+ p2p_dbg(p2p,
+ "No common channels in Follow-On Provision Discovery Request");
+ reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ } else {
+ reject = P2P_SC_SUCCESS;
+ }
+
+ dev->oper_freq = 0;
+ if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) {
+ u8 tmp;
+
+ if (msg.operating_channel)
+ dev->oper_freq =
+ p2p_channel_to_freq(msg.operating_channel[3],
+ msg.operating_channel[4]);
+
+ if ((conncap & P2PS_SETUP_GROUP_OWNER) &&
+ p2p_go_select_channel(p2p, dev, &tmp) < 0)
+ reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
}
+ p2p->p2ps_prov->status = reject;
+ p2p->p2ps_prov->conncap = conncap;
+
out:
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,
- (const u8 *) &resp_fcap,
- sizeof(resp_fcap));
- if (resp == NULL) {
- p2p_parse_free(&msg);
- return;
- }
- p2p_dbg(p2p, "Sending Provision Discovery Response");
- if (rx_freq > 0)
- freq = rx_freq;
- else
- freq = p2p_channel_to_freq(p2p->cfg->reg_class,
- p2p->cfg->channel);
- if (freq < 0) {
- p2p_dbg(p2p, "Unknown regulatory class/channel");
+
+ /*
+ * Send PD Response for an initial PD Request or for follow-on
+ * PD Request with P2P_SC_SUCCESS_DEFERRED status.
+ */
+ if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) {
+ 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,
+ (const u8 *) &resp_fcap,
+ sizeof(resp_fcap));
+ if (!resp) {
+ p2p_parse_free(&msg);
+ return;
+ }
+ p2p_dbg(p2p, "Sending Provision Discovery Response");
+ if (rx_freq > 0)
+ freq = rx_freq;
+ else
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
+ wpabuf_free(resp);
+ p2p_parse_free(&msg);
+ return;
+ }
+ 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),
+ 50) < 0)
+ p2p_dbg(p2p, "Failed to send Action frame");
+ else
+ p2p->send_action_in_progress = 1;
+
wpabuf_free(resp);
+ }
+
+ if (!dev) {
p2p_parse_free(&msg);
return;
}
- 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) {
- p2p_dbg(p2p, "Failed to send Action frame");
- } else
- p2p->send_action_in_progress = 1;
- wpabuf_free(resp);
+ freq = 0;
+ if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) {
+ freq = p2p_channel_to_freq(p2p->op_reg_class,
+ p2p->op_channel);
+ if (freq < 0)
+ freq = 0;
+ }
if (!p2p->cfg->p2ps_prov_complete) {
/* Don't emit anything */
@@ -771,7 +1028,8 @@ out:
NULL, adv_id, session_id,
0, 0, msg.persistent_ssid,
msg.persistent_ssid_len,
- 0, 0, NULL, NULL, 0);
+ 0, 0, NULL, NULL, 0, freq,
+ NULL, 0);
} else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
p2p->p2ps_prov) {
p2p->p2ps_prov->status = reject;
@@ -784,7 +1042,8 @@ out:
session_id, conncap, 0,
msg.persistent_ssid,
msg.persistent_ssid_len, 0,
- 0, NULL, NULL, 0);
+ 0, NULL, NULL, 0, freq,
+ NULL, 0);
else
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
*msg.status,
@@ -796,7 +1055,8 @@ out:
msg.persistent_ssid_len, 0,
0, NULL,
(const u8 *) &resp_fcap,
- sizeof(resp_fcap));
+ sizeof(resp_fcap), freq,
+ NULL, 0);
} 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,
@@ -807,7 +1067,7 @@ out:
msg.persistent_ssid_len,
0, 0, NULL,
(const u8 *) &resp_fcap,
- sizeof(resp_fcap));
+ sizeof(resp_fcap), freq, NULL, 0);
} else if (msg.status) {
} else if (auto_accept && reject == P2P_SC_SUCCESS) {
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
@@ -818,7 +1078,11 @@ out:
msg.persistent_ssid_len,
0, 0, NULL,
(const u8 *) &resp_fcap,
- sizeof(resp_fcap));
+ sizeof(resp_fcap), freq,
+ msg.group_id ?
+ msg.group_id + ETH_ALEN : NULL,
+ msg.group_id ?
+ msg.group_id_len - ETH_ALEN : 0);
} else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
(!msg.session_info || !msg.session_info_len)) {
p2p->p2ps_prov->method = msg.wps_config_methods;
@@ -831,7 +1095,7 @@ out:
msg.persistent_ssid_len,
0, 1, NULL,
(const u8 *) &resp_fcap,
- sizeof(resp_fcap));
+ sizeof(resp_fcap), freq, NULL, 0);
} 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);
@@ -848,7 +1112,8 @@ out:
session_id, conncap, passwd_id,
msg.persistent_ssid, msg.persistent_ssid_len,
0, 1, buf,
- (const u8 *) &resp_fcap, sizeof(resp_fcap));
+ (const u8 *) &resp_fcap, sizeof(resp_fcap),
+ freq, NULL, 0);
os_free(buf);
}
@@ -898,7 +1163,10 @@ out:
msg.group_id, msg.group_id_len);
}
- if (dev && reject == P2P_SC_SUCCESS) {
+ if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
+ p2ps_prov_free(p2p);
+
+ if (reject == P2P_SC_SUCCESS) {
switch (config_methods) {
case WPS_CONFIG_DISPLAY:
dev->wps_prov_info = WPS_CONFIG_KEYPAD;
@@ -1084,6 +1352,9 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
" with no pending request", MAC2STR(sa));
p2p_parse_free(&msg);
return;
+ } else if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
}
if (dev->dialog_token != msg.dialog_token) {
@@ -1148,17 +1419,71 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
passwd_id = DEV_PW_P2PS_DEFAULT;
}
- if ((msg.conn_cap || msg.persistent_dev) &&
- (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
+ if ((status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
p2p->p2ps_prov) {
+ dev->oper_freq = 0;
+
+ /*
+ * Save the reported channel list and operating frequency.
+ * Note that the specification mandates that the responder
+ * should include in the channel list only channels reported by
+ * the initiator, so this is only a sanity check, and if this
+ * fails the flow would continue, although it would probably
+ * fail. Same is true for the operating channel.
+ */
+ if (msg.channel_list && msg.channel_list_len &&
+ p2p_peer_channels_check(p2p, &p2p->channels, dev,
+ msg.channel_list,
+ msg.channel_list_len) < 0)
+ p2p_dbg(p2p, "P2PS PD Response - no common channels");
+
+ if (msg.operating_channel) {
+ if (p2p_channels_includes(&p2p->channels,
+ msg.operating_channel[3],
+ msg.operating_channel[4]) &&
+ p2p_channels_includes(&dev->channels,
+ msg.operating_channel[3],
+ msg.operating_channel[4])) {
+ dev->oper_freq =
+ p2p_channel_to_freq(
+ msg.operating_channel[3],
+ msg.operating_channel[4]);
+ } else {
+ p2p_dbg(p2p,
+ "P2PS PD Response - invalid operating channel");
+ }
+ }
+
if (p2p->cfg->p2ps_prov_complete) {
+ int freq = 0;
+
+ if (conncap == P2PS_SETUP_GROUP_OWNER) {
+ u8 tmp;
+
+ /*
+ * Re-select the operating channel as it is
+ * possible that original channel is no longer
+ * valid. This should not really fail.
+ */
+ if (p2p_go_select_channel(p2p, dev, &tmp) < 0)
+ p2p_dbg(p2p,
+ "P2PS PD channel selection failed");
+
+ freq = p2p_channel_to_freq(p2p->op_reg_class,
+ p2p->op_channel);
+ if (freq < 0)
+ freq = 0;
+ }
+
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,
- msg.feature_cap, msg.feature_cap_len);
+ msg.feature_cap, msg.feature_cap_len, freq,
+ msg.group_id ? msg.group_id + ETH_ALEN : NULL,
+ msg.group_id ? msg.group_id_len - ETH_ALEN : 0);
}
p2ps_prov_free(p2p);
} else if (status != P2P_SC_SUCCESS &&
@@ -1169,7 +1494,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
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, NULL, 0);
+ 0, 0, NULL, 0, 1, 0, NULL, NULL, 0, 0, NULL, 0);
p2ps_prov_free(p2p);
}
@@ -1259,7 +1584,7 @@ out:
report_config_methods);
if (p2p->state == P2P_PD_DURING_FIND) {
- p2p_clear_timeout(p2p);
+ p2p_stop_listen_for_freq(p2p, 0);
p2p_continue_find(p2p);
}
}
@@ -1318,6 +1643,10 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
"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);
+
+ if (p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
+ p2p->p2ps_prov->pref_freq, 1) < 0)
+ return -1;
}
req = p2p_build_prov_disc_req(p2p, dev, join);
diff --git a/contrib/wpa/src/p2p/p2p_sd.c b/contrib/wpa/src/p2p/p2p_sd.c
index 1a2af04..b9e753f 100644
--- a/contrib/wpa/src/p2p/p2p_sd.c
+++ b/contrib/wpa/src/p2p/p2p_sd.c
@@ -28,11 +28,11 @@ static int wfd_wsd_supported(struct wpabuf *wfd)
pos = wpabuf_head(wfd);
end = pos + wpabuf_len(wfd);
- while (pos + 3 <= end) {
+ while (end - pos >= 3) {
subelem = *pos++;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end)
+ if (len > end - pos)
break;
if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
@@ -288,6 +288,14 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
query = p2p_pending_sd_req(p2p, dev);
if (query == NULL)
return -1;
+ if (p2p->state == P2P_SEARCH &&
+ os_memcmp(p2p->sd_query_no_ack, dev->info.p2p_device_addr,
+ ETH_ALEN) == 0) {
+ p2p_dbg(p2p, "Do not start Service Discovery with " MACSTR
+ " due to it being the first no-ACK peer in this search iteration",
+ MAC2STR(dev->info.p2p_device_addr));
+ return -2;
+ }
p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
MAC2STR(dev->info.p2p_device_addr));
@@ -355,11 +363,11 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
pos++;
slen = *pos++;
- next = pos + slen;
- if (next > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
return;
}
+ next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -370,16 +378,16 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Request */
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end)
+ if (slen > end - pos)
return;
end = pos + slen;
/* ANQP Query Request */
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@@ -389,7 +397,7 @@ 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) {
+ if (slen > end - pos || slen < 3 + 1) {
p2p_dbg(p2p, "Invalid ANQP Query Request length");
return;
}
@@ -401,7 +409,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
}
pos += 4;
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
update_indic = WPA_GET_LE16(pos);
p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
@@ -417,9 +425,17 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
u8 dialog_token, const struct wpabuf *resp_tlvs)
{
struct wpabuf *resp;
+ size_t max_len;
+ unsigned int wait_time = 200;
+
+ /*
+ * In the 60 GHz, we have a smaller maximum frame length for management
+ * frames.
+ */
+ max_len = (freq > 56160) ? 928 : 1400;
/* TODO: fix the length limit to match with the maximum frame length */
- if (wpabuf_len(resp_tlvs) > 1400) {
+ if (wpabuf_len(resp_tlvs) > max_len) {
p2p_dbg(p2p, "SD response long enough to require fragmentation");
if (p2p->sd_resp) {
/*
@@ -445,6 +461,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
1, p2p->srv_update_indic, NULL);
} else {
p2p_dbg(p2p, "SD response fits in initial response");
+ wait_time = 0; /* no more SD frames in the sequence */
resp = p2p_build_sd_response(dialog_token,
WLAN_STATUS_SUCCESS, 0,
p2p->srv_update_indic, resp_tlvs);
@@ -455,7 +472,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
+ wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(resp);
@@ -512,11 +529,11 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos++;
slen = *pos++;
- next = pos + slen;
- if (next > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
return;
}
+ next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -527,14 +544,14 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Response */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
p2p_dbg(p2p, "Too short Query Response");
return;
}
slen = WPA_GET_LE16(pos);
pos += 2;
p2p_dbg(p2p, "Query Response Length: %d", slen);
- if (pos + slen > end) {
+ if (slen > end - pos) {
p2p_dbg(p2p, "Not enough Query Response data");
return;
}
@@ -552,7 +569,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
}
/* ANQP Query Response */
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@@ -562,7 +579,7 @@ 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) {
+ if (slen > end - pos || slen < 3 + 1) {
p2p_dbg(p2p, "Invalid ANQP Query Response length");
return;
}
@@ -574,7 +591,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
}
pos += 4;
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
update_indic = WPA_GET_LE16(pos);
p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
@@ -606,8 +623,9 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
{
struct wpabuf *resp;
u8 dialog_token;
- size_t frag_len;
+ size_t frag_len, max_len;
int more = 0;
+ unsigned int wait_time = 200;
wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len);
if (len < 1)
@@ -630,9 +648,14 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
return;
}
+ /*
+ * In the 60 GHz, we have a smaller maximum frame length for management
+ * frames.
+ */
+ max_len = (rx_freq > 56160) ? 928 : 1400;
frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos;
- if (frag_len > 1400) {
- frag_len = 1400;
+ if (frag_len > max_len) {
+ frag_len = max_len;
more = 1;
}
resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS,
@@ -655,12 +678,13 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "All fragments of SD response sent");
wpabuf_free(p2p->sd_resp);
p2p->sd_resp = NULL;
+ wait_time = 0; /* no more SD frames in the sequence */
}
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
+ wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(resp);
@@ -727,11 +751,11 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos++;
slen = *pos++;
- next = pos + slen;
- if (next > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
return;
}
+ next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -742,14 +766,14 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Response */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
p2p_dbg(p2p, "Too short Query Response");
return;
}
slen = WPA_GET_LE16(pos);
pos += 2;
p2p_dbg(p2p, "Query Response Length: %d", slen);
- if (pos + slen > end) {
+ if (slen > end - pos) {
p2p_dbg(p2p, "Not enough Query Response data");
return;
}
@@ -768,7 +792,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
}
/* ANQP Query Response */
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@@ -783,7 +807,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "Invalid ANQP Query Response length");
return;
}
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
@@ -793,7 +817,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
}
pos += 4;
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
diff --git a/contrib/wpa/src/p2p/p2p_utils.c b/contrib/wpa/src/p2p/p2p_utils.c
index 2e2aa8a..1a62a44 100644
--- a/contrib/wpa/src/p2p/p2p_utils.c
+++ b/contrib/wpa/src/p2p/p2p_utils.c
@@ -413,17 +413,30 @@ int p2p_channel_select(struct p2p_channels *chans, const int *classes,
int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
- u8 *op_channel)
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list)
{
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))
+ /* Try to find available social channels from 2.4 GHz.
+ * If the avoid_list includes any of the 2.4 GHz social channels, that
+ * channel is not allowed by p2p_channels_includes() rules. However, it
+ * is assumed to allow minimal traffic for P2P negotiation, so allow it
+ * here for social channel selection unless explicitly disallowed in the
+ * disallow_list. */
+ if (p2p_channels_includes(chans, 81, 1) ||
+ (freq_range_list_includes(avoid_list, 2412) &&
+ !freq_range_list_includes(disallow_list, 2412)))
chan[num_channels++] = 1;
- if (p2p_channels_includes(chans, 81, 6))
+ if (p2p_channels_includes(chans, 81, 6) ||
+ (freq_range_list_includes(avoid_list, 2437) &&
+ !freq_range_list_includes(disallow_list, 2437)))
chan[num_channels++] = 6;
- if (p2p_channels_includes(chans, 81, 11))
+ if (p2p_channels_includes(chans, 81, 11) ||
+ (freq_range_list_includes(avoid_list, 2462) &&
+ !freq_range_list_includes(disallow_list, 2462)))
chan[num_channels++] = 11;
/* Try to find available social channels from 60 GHz */
OpenPOWER on IntegriCloud