Accumulative patch from commit dc013f1e37df3462085cf01a13f0c432f146ad7a
Author: Jouni Malinen <jouni@qca.qualcomm.com>
Date: Tue Jan 15 12:03:29 2013 +0200
eapol_test: Remove unnecessary header file inclusion
- P2P: Send P2P-FIND-STOPPED event in the new continue-search states
- P2P: Add some more details on Service Query TLV format
- P2P: Use the same Dialog Token value for every GO Negotiation retry
- P2P: Publish more connected clients info in Probe Response frames
- P2P: Fix some memory leaks in p2p_add_device()
- P2P: Use the same Dialog Token value for every PD retry
- P2P: Document operating channel selection functions
- P2P: Always re-select operating channel if not hard coded
- P2P: Do not allow re-selection of GO channel if forced_freq in use
- P2P: Set FORCE_FREQ flag as part of p2p_prepare_channel()
- P2P: Share a single function for GO channel selection
- P2P: Prefer operating channels where HT40 is possible
- P2P: Be more careful with wpa_config_update_psk() call
- P2P: Allow PSK to be used instead of passphrase for persistent GO
- P2P: Consider age for the P2P scan results
- Move some P2P offchannel operations to offchannel.c
- P2P: Add more complete description of p2p_cancel
- P2P: Allow p2p_cancel to be used to stop p2p_connect-join operation
- Interworking changes
- WNM changes
- WPS changes
- SAE changes
Change-Id: I38b847d3460066cc58aecbcf67266bfcff1d344e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index b122f7c..aaacc9a 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -630,6 +630,7 @@
* P2P Device Address or P2P Interface Address)
* @level: Signal level (signal strength of the received frame from the peer)
* @freq: Frequency on which the Beacon or Probe Response frame was received
+ * @age_ms: Age of the information in milliseconds
* @ies: IEs from the Beacon or Probe Response frame
* @ies_len: Length of ies buffer in octets
* @scan_res: Whether this was based on scan results
@@ -640,13 +641,15 @@
* like Provision Discovery Request that contains P2P Capability and P2P Device
* Info attributes.
*/
-int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
- const u8 *ies, size_t ies_len, int scan_res)
+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
+ unsigned int age_ms, int level, const u8 *ies,
+ size_t ies_len, int scan_res)
{
struct p2p_device *dev;
struct p2p_message msg;
const u8 *p2p_dev_addr;
int i;
+ struct os_time time_now, time_tmp_age, entry_ts;
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ies, ies_len, &msg)) {
@@ -673,6 +676,7 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not add peer "
"filter for " MACSTR " due to peer filter",
MAC2STR(p2p_dev_addr));
+ p2p_parse_free(&msg);
return 0;
}
@@ -681,7 +685,24 @@
p2p_parse_free(&msg);
return -1;
}
- os_get_time(&dev->last_seen);
+
+ os_get_time(&time_now);
+ time_tmp_age.sec = age_ms / 1000;
+ time_tmp_age.usec = (age_ms % 1000) * 1000;
+ os_time_sub(&time_now, &time_tmp_age, &entry_ts);
+
+ /*
+ * Update the device entry only if the new peer
+ * entry is newer than the one previously stored.
+ */
+ if (dev->last_seen.usec > 0 &&
+ os_time_before(&entry_ts, &dev->last_seen)) {
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ os_memcpy(&dev->last_seen, &entry_ts, sizeof(struct os_time));
+
dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
@@ -1123,7 +1144,9 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p_clear_timeout(p2p);
- if (p2p->state == P2P_SEARCH)
+ if (p2p->state == P2P_SEARCH ||
+ p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY ||
+ p2p->state == P2P_SEARCH_WHEN_READY)
wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
p2p_set_state(p2p, P2P_IDLE);
p2p_free_req_dev_types(p2p);
@@ -1166,89 +1189,115 @@
}
-static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq,
- unsigned int pref_freq)
+static int p2p_prepare_channel_pref(struct p2p_data *p2p,
+ unsigned int force_freq,
+ unsigned int pref_freq)
{
- if (force_freq || pref_freq) {
- u8 op_reg_class, op_channel;
- unsigned int freq = force_freq ? force_freq : pref_freq;
- if (p2p_freq_to_channel(p2p->cfg->country, freq,
- &op_reg_class, &op_channel) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported frequency %u MHz",
- freq);
- return -1;
- }
- if (!p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
- op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Frequency %u MHz (oper_class %u "
- "channel %u) not allowed for P2P",
- freq, op_reg_class, op_channel);
- return -1;
- }
- p2p->op_reg_class = op_reg_class;
- p2p->op_channel = op_channel;
- if (force_freq) {
- p2p->channels.reg_classes = 1;
- p2p->channels.reg_class[0].channels = 1;
- p2p->channels.reg_class[0].reg_class =
- p2p->op_reg_class;
- p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
- } else {
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- }
+ u8 op_class, op_channel;
+ unsigned int freq = force_freq ? force_freq : pref_freq;
+
+ if (p2p_freq_to_channel(p2p->cfg->country, freq,
+ &op_class, &op_channel) < 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Unsupported frequency %u MHz", freq);
+ return -1;
+ }
+
+ if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Frequency %u MHz (oper_class %u channel %u) not "
+ "allowed for P2P", freq, op_class, op_channel);
+ return -1;
+ }
+
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+
+ if (force_freq) {
+ p2p->channels.reg_classes = 1;
+ p2p->channels.reg_class[0].channels = 1;
+ p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
+ p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
} else {
- u8 op_reg_class, op_channel;
-
- if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
- p2p_supported_freq(p2p, p2p->best_freq_overall) &&
- p2p_freq_to_channel(p2p->cfg->country,
- p2p->best_freq_overall,
- &op_reg_class, &op_channel) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Select best overall channel as "
- "operating channel preference");
- p2p->op_reg_class = op_reg_class;
- p2p->op_channel = op_channel;
- } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
- p2p_supported_freq(p2p, p2p->best_freq_5) &&
- p2p_freq_to_channel(p2p->cfg->country,
- p2p->best_freq_5,
- &op_reg_class, &op_channel) ==
- 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Select best 5 GHz channel as "
- "operating channel preference");
- p2p->op_reg_class = op_reg_class;
- p2p->op_channel = op_channel;
- } else if (!p2p->cfg->cfg_op_channel &&
- p2p->best_freq_24 > 0 &&
- p2p_supported_freq(p2p, p2p->best_freq_24) &&
- p2p_freq_to_channel(p2p->cfg->country,
- p2p->best_freq_24,
- &op_reg_class, &op_channel) ==
- 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Select best 2.4 GHz channel as "
- "operating channel preference");
- p2p->op_reg_class = op_reg_class;
- p2p->op_channel = op_channel;
- } else {
- p2p->op_reg_class = p2p->cfg->op_reg_class;
- p2p->op_channel = p2p->cfg->op_channel;
- }
-
os_memcpy(&p2p->channels, &p2p->cfg->channels,
sizeof(struct p2p_channels));
}
+
+ return 0;
+}
+
+
+static void p2p_prepare_channel_best(struct p2p_data *p2p)
+{
+ u8 op_class, op_channel;
+
+ if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
+ p2p_supported_freq(p2p, p2p->best_freq_overall) &&
+ p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
+ &op_class, &op_channel) == 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best "
+ "overall channel as operating channel preference");
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
+ p2p_supported_freq(p2p, p2p->best_freq_5) &&
+ p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
+ &op_class, &op_channel) == 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 5 GHz "
+ "channel as operating channel preference");
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
+ p2p_supported_freq(p2p, p2p->best_freq_24) &&
+ p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
+ &op_class, &op_channel) == 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 2.4 "
+ "GHz channel as operating channel preference");
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ } else {
+ p2p->op_reg_class = p2p->cfg->op_reg_class;
+ p2p->op_channel = p2p->cfg->op_channel;
+ }
+
+ os_memcpy(&p2p->channels, &p2p->cfg->channels,
+ sizeof(struct p2p_channels));
+}
+
+
+/**
+ * p2p_prepare_channel - Select operating channel for GO Negotiation
+ * @p2p: P2P module context from p2p_init()
+ * @dev: Selected peer device
+ * @force_freq: Forced frequency in MHz or 0 if not forced
+ * @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * 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.
+ */
+static int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ unsigned int force_freq, unsigned int pref_freq)
+{
+ if (force_freq || pref_freq) {
+ if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+ return -1;
+ } else {
+ p2p_prepare_channel_best(p2p);
+ }
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Own preference for operation channel: "
"Operating Class %u Channel %u%s",
p2p->op_reg_class, p2p->op_channel,
force_freq ? " (forced)" : "");
+ if (force_freq)
+ dev->flags |= P2P_DEV_FORCE_FREQ;
+ else
+ dev->flags &= ~P2P_DEV_FORCE_FREQ;
+
return 0;
}
@@ -1289,9 +1338,6 @@
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
wps_method, persistent_group, pd_before_go_neg);
- if (p2p_prepare_channel(p2p, force_freq, pref_freq) < 0)
- return -1;
-
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1300,6 +1346,9 @@
return -1;
}
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ return -1;
+
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
@@ -1339,8 +1388,16 @@
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
if (pd_before_go_neg)
dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
- else
+ else {
dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+ /*
+ * Assign dialog token here to use the same value in each
+ * retry within the same GO Negotiation exchange.
+ */
+ dev->dialog_token++;
+ if (dev->dialog_token == 0)
+ dev->dialog_token = 1;
+ }
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
@@ -1367,11 +1424,6 @@
dev->wps_method = wps_method;
dev->status = P2P_SC_SUCCESS;
- if (force_freq)
- dev->flags |= P2P_DEV_FORCE_FREQ;
- else
- dev->flags &= ~P2P_DEV_FORCE_FREQ;
-
if (p2p->p2p_scan_running) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: p2p_scan running - delay connect send");
@@ -1401,9 +1453,6 @@
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
wps_method, persistent_group);
- if (p2p_prepare_channel(p2p, force_freq, pref_freq) < 0)
- return -1;
-
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1412,6 +1461,9 @@
return -1;
}
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ return -1;
+
p2p->ssid_set = 0;
if (force_ssid) {
wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
@@ -1432,11 +1484,6 @@
dev->wps_method = wps_method;
dev->status = P2P_SC_SUCCESS;
- if (force_freq)
- dev->flags |= P2P_DEV_FORCE_FREQ;
- else
- dev->flags &= ~P2P_DEV_FORCE_FREQ;
-
return 0;
}
@@ -2840,9 +2887,10 @@
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- int level, const u8 *ies, size_t ies_len)
+ unsigned int age, int level, const u8 *ies,
+ size_t ies_len)
{
- p2p_add_device(p2p, bssid, freq, level, ies, ies_len, 1);
+ p2p_add_device(p2p, bssid, freq, age, level, ies, ies_len, 1);
return 0;
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 045e6f7..18e733b 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1200,6 +1200,7 @@
* @p2p: P2P module context from p2p_init()
* @bssid: BSSID of the scan result
* @freq: Frequency of the channel on which the device was found in MHz
+ * @age: Age of the scan result in milliseconds
* @level: Signal level (signal strength of the received Beacon/Probe Response
* frame)
* @ies: Pointer to IEs from the scan result
@@ -1221,7 +1222,8 @@
* start of a pending operation, e.g., to start a pending GO negotiation.
*/
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- int level, const u8 *ies, size_t ies_len);
+ unsigned int age, int level, const u8 *ies,
+ size_t ies_len);
/**
* p2p_scan_res_handled - Indicate end of scan results
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index fe4b560..37d43bb 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -145,9 +145,6 @@
if (buf == NULL)
return NULL;
- peer->dialog_token++;
- if (peer->dialog_token == 0)
- peer->dialog_token = 1;
p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token);
len = p2p_buf_add_ie_hdr(buf);
@@ -336,6 +333,17 @@
}
+/**
+ * p2p_reselect_channel - Re-select operating channel based on peer information
+ * @p2p: P2P module context from p2p_init()
+ * @intersection: Support channel list intersection from local and peer
+ *
+ * This function is used to re-select the best channel after having received
+ * information from the peer to allow supported channel lists to be intersected.
+ * This can be used to improve initial channel selection done in
+ * p2p_prepare_channel() prior to the start of GO Negotiation. In addition, this
+ * can be used for Invitation case.
+ */
void p2p_reselect_channel(struct p2p_data *p2p,
struct p2p_channels *intersection)
{
@@ -390,6 +398,35 @@
}
}
+ /* Try a channel where we might be able to use HT40 */
+ for (i = 0; i < intersection->reg_classes; i++) {
+ struct p2p_reg_class *c = &intersection->reg_class[i];
+ if (c->reg_class == 116 || c->reg_class == 117 ||
+ c->reg_class == 126 || c->reg_class == 127) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Pick possible HT40 channel (reg_class "
+ "%u channel %u) from intersection",
+ c->reg_class, c->channel[0]);
+ p2p->op_reg_class = c->reg_class;
+ p2p->op_channel = c->channel[0];
+ return;
+ }
+ }
+
+ /*
+ * Try to see if the original channel is in the intersection. If
+ * so, no need to change anything, as it already contains some
+ * randomness.
+ */
+ if (p2p_channels_includes(intersection, p2p->op_reg_class,
+ p2p->op_channel)) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Using original operating class and channel "
+ "(op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+
/*
* Fall back to whatever is included in the channel intersection since
* no better options seems to be available.
@@ -403,6 +440,60 @@
}
+static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ u8 *status)
+{
+ struct p2p_channels intersection;
+ size_t i;
+
+ p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
+ if (intersection.reg_classes == 0 ||
+ intersection.reg_class[0].channels == 0) {
+ *status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: No common channels found");
+ return -1;
+ }
+
+ for (i = 0; i < intersection.reg_classes; i++) {
+ struct p2p_reg_class *c;
+ c = &intersection.reg_class[i];
+ wpa_printf(MSG_DEBUG, "P2P: reg_class %u", c->reg_class);
+ wpa_hexdump(MSG_DEBUG, "P2P: channels",
+ c->channel, c->channels);
+ }
+
+ if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
+ p2p->op_channel)) {
+ if (dev->flags & P2P_DEV_FORCE_FREQ) {
+ *status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer does "
+ "not support the forced channel");
+ return -1;
+ }
+
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
+ "channel (op_class %u channel %u) not acceptable to "
+ "the peer", p2p->op_reg_class, p2p->op_channel);
+ p2p_reselect_channel(p2p, &intersection);
+ } else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
+ !p2p->cfg->cfg_op_channel) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Try to optimize "
+ "channel selection with peer information received; "
+ "previously selected op_class %u channel %u",
+ p2p->op_reg_class, p2p->op_channel);
+ p2p_reselect_channel(p2p, &intersection);
+ }
+
+ if (!p2p->ssid_set) {
+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ p2p->ssid_set = 1;
+ }
+
+ return 0;
+}
+
+
void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
@@ -619,36 +710,8 @@
goto fail;
}
- if (go) {
- struct p2p_channels intersection;
- size_t i;
- p2p_channels_intersect(&p2p->channels, &dev->channels,
- &intersection);
- if (intersection.reg_classes == 0 ||
- intersection.reg_class[0].channels == 0) {
- status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
- goto fail;
- }
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c;
- c = &intersection.reg_class[i];
- wpa_printf(MSG_DEBUG, "P2P: reg_class %u",
- c->reg_class);
- wpa_hexdump(MSG_DEBUG, "P2P: channels",
- c->channel, c->channels);
- }
- if (!p2p_channels_includes(&intersection,
- p2p->op_reg_class,
- p2p->op_channel))
- p2p_reselect_channel(p2p, &intersection);
-
- if (!p2p->ssid_set) {
- p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
- p2p->ssid_set = 1;
- }
- }
+ if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
+ goto fail;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
dev->oper_freq = p2p_channel_to_freq((const char *)
@@ -1021,35 +1084,8 @@
goto fail;
}
- if (go) {
- struct p2p_channels intersection;
- size_t i;
- p2p_channels_intersect(&p2p->channels, &dev->channels,
- &intersection);
- if (intersection.reg_classes == 0 ||
- intersection.reg_class[0].channels == 0) {
- status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
- goto fail;
- }
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c;
- c = &intersection.reg_class[i];
- wpa_printf(MSG_DEBUG, "P2P: reg_class %u",
- c->reg_class);
- wpa_hexdump(MSG_DEBUG, "P2P: channels",
- c->channel, c->channels);
- }
- if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
- p2p->op_channel))
- p2p_reselect_channel(p2p, &intersection);
-
- if (!p2p->ssid_set) {
- p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
- p2p->ssid_set = 1;
- }
- }
+ if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
+ goto fail;
p2p_set_state(p2p, P2P_GO_NEG);
p2p_clear_timeout(p2p);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 8687320..633dd5c 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -169,6 +169,39 @@
}
+static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems)
+{
+ struct wpabuf *ie;
+ const u8 *pos, *end;
+ size_t len;
+
+ if (subelems == NULL)
+ return NULL;
+
+ len = wpabuf_len(subelems) + 100;
+
+ ie = wpabuf_alloc(len);
+ if (ie == NULL)
+ return NULL;
+
+ pos = wpabuf_head(subelems);
+ end = pos + wpabuf_len(subelems);
+
+ while (end > pos) {
+ size_t frag_len = end - pos;
+ if (frag_len > 251)
+ frag_len = 251;
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(ie, 4 + frag_len);
+ wpabuf_put_be32(ie, P2P_IE_VENDOR_TYPE);
+ wpabuf_put_data(ie, pos, frag_len);
+ pos += frag_len;
+ }
+
+ return ie;
+}
+
+
static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
{
struct wpabuf *ie;
@@ -367,9 +400,8 @@
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
{
u8 *group_info;
- struct wpabuf *ie;
+ struct wpabuf *p2p_subelems, *ie;
struct p2p_group_member *m;
- u8 *len;
size_t extra = 0;
#ifdef CONFIG_WIFI_DISPLAY
@@ -377,33 +409,32 @@
extra += wpabuf_len(group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
- ie = wpabuf_alloc(257 + extra);
- if (ie == NULL)
+ p2p_subelems = wpabuf_alloc(500 + extra);
+ if (p2p_subelems == NULL)
return NULL;
#ifdef CONFIG_WIFI_DISPLAY
if (group->wfd_ie)
- wpabuf_put_buf(ie, group->wfd_ie);
+ wpabuf_put_buf(p2p_subelems, group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
- len = p2p_buf_add_ie_hdr(ie);
-
- p2p_group_add_common_ies(group, ie);
- p2p_group_add_noa(ie, group->noa);
+ p2p_group_add_common_ies(group, p2p_subelems);
+ p2p_group_add_noa(p2p_subelems, group->noa);
/* P2P Device Info */
- p2p_buf_add_device_info(ie, group->p2p, NULL);
+ p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
/* P2P Group Info */
- group_info = wpabuf_put(ie, 0);
- wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO);
- wpabuf_put_le16(ie, 0); /* Length to be filled */
+ group_info = wpabuf_put(p2p_subelems, 0);
+ wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
+ wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
for (m = group->members; m; m = m->next)
- p2p_client_info(ie, m);
+ p2p_client_info(p2p_subelems, m);
WPA_PUT_LE16(group_info + 1,
- (u8 *) wpabuf_put(ie, 0) - group_info - 3);
+ (u8 *) wpabuf_put(p2p_subelems, 0) - group_info - 3);
- p2p_buf_update_ie_hdr(ie, len);
+ ie = p2p_group_encaps_probe_resp(p2p_subelems);
+ wpabuf_free(p2p_subelems);
return ie;
}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index d2868fb..712544b 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -705,8 +705,9 @@
struct p2p_message *msg);
void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
struct p2p_device *dev, struct p2p_message *msg);
-int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
- const u8 *ies, size_t ies_len, int scan_res);
+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
+ unsigned int age_ms, int level, const u8 *ies,
+ size_t ies_len, int scan_res);
struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
const u8 *addr);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 7bf6600..ac67932 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -176,8 +176,8 @@
"P2P: Invitation Request from unknown peer "
MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
- {
+ if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+ 0)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Invitation Request add device failed "
MACSTR, MAC2STR(sa));
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e40f2b7..ca33f17 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -151,8 +151,9 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request from "
"unknown peer " MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
- {
+
+ if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+ 0)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request add device "
"failed " MACSTR, MAC2STR(sa));
@@ -379,9 +380,6 @@
/* TODO: use device discoverability request through GO */
}
- dev->dialog_token++;
- if (dev->dialog_token == 0)
- dev->dialog_token = 1;
req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
dev->req_config_methods,
join ? dev : NULL);
@@ -452,6 +450,14 @@
if (p2p->user_initiated_pd)
p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
+ /*
+ * Assign dialog token here to use the same value in each retry within
+ * the same PD exchange.
+ */
+ dev->dialog_token++;
+ if (dev->dialog_token == 0)
+ dev->dialog_token = 1;
+
return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
}