aboutsummaryrefslogtreecommitdiffstats
path: root/src/p2p
diff options
context:
space:
mode:
Diffstat (limited to 'src/p2p')
-rw-r--r--src/p2p/p2p.c244
-rw-r--r--src/p2p/p2p.h13
-rw-r--r--src/p2p/p2p_go_neg.c23
-rw-r--r--src/p2p/p2p_i.h16
-rw-r--r--src/p2p/p2p_invitation.c69
-rw-r--r--src/p2p/p2p_parse.c36
-rw-r--r--src/p2p/p2p_sd.c14
-rw-r--r--src/p2p/p2p_utils.c116
8 files changed, 347 insertions, 184 deletions
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 7d4a03c5..fc610819 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -211,29 +211,35 @@ void p2p_clear_timeout(struct p2p_data *p2p)
}
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
- int status)
+void p2p_go_neg_failed(struct p2p_data *p2p, int status)
{
struct p2p_go_neg_results res;
- p2p_clear_timeout(p2p);
- p2p_set_state(p2p, P2P_IDLE);
- if (p2p->go_neg_peer) {
- p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
- p2p->go_neg_peer->wps_method = WPS_NOT_READY;
- p2p->go_neg_peer->oob_pw_id = 0;
+ struct p2p_device *peer = p2p->go_neg_peer;
+
+ if (!peer)
+ return;
+
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+ if (p2p->state != P2P_SEARCH) {
+ /*
+ * Clear timeouts related to GO Negotiation if no new p2p_find
+ * has been started.
+ */
+ p2p_clear_timeout(p2p);
+ p2p_set_state(p2p, P2P_IDLE);
}
+
+ peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
+ peer->wps_method = WPS_NOT_READY;
+ peer->oob_pw_id = 0;
+ wpabuf_free(peer->go_neg_conf);
+ peer->go_neg_conf = NULL;
p2p->go_neg_peer = NULL;
os_memset(&res, 0, sizeof(res));
res.status = status;
- if (peer) {
- wpabuf_free(peer->go_neg_conf);
- peer->go_neg_conf = NULL;
- os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr,
- ETH_ALEN);
- os_memcpy(res.peer_interface_addr, peer->intended_addr,
- ETH_ALEN);
- }
+ os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
+ os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
}
@@ -348,8 +354,10 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
static void p2p_device_clear_reported(struct p2p_data *p2p)
{
struct p2p_device *dev;
- dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
dev->flags &= ~P2P_DEV_REPORTED;
+ dev->sd_reqs = 0;
+ }
}
@@ -650,6 +658,24 @@ static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
}
+static int p2p_compare_wfd_info(struct p2p_device *dev,
+ const struct p2p_message *msg)
+{
+ if (dev->info.wfd_subelems && msg->wfd_subelems) {
+ if (dev->info.wfd_subelems->used != msg->wfd_subelems->used)
+ return 1;
+
+ return os_memcmp(dev->info.wfd_subelems->buf,
+ msg->wfd_subelems->buf,
+ dev->info.wfd_subelems->used);
+ }
+ if (dev->info.wfd_subelems || msg->wfd_subelems)
+ return 1;
+
+ return 0;
+}
+
+
/**
* p2p_add_device - Add peer entries based on scan results or P2P frames
* @p2p: P2P module context from p2p_init()
@@ -675,6 +701,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
struct p2p_device *dev;
struct p2p_message msg;
const u8 *p2p_dev_addr;
+ int wfd_changed;
int i;
struct os_reltime time_now;
@@ -786,6 +813,8 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
break;
}
+ wfd_changed = p2p_compare_wfd_info(dev, &msg);
+
if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
@@ -800,7 +829,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)
+ if (dev->flags & P2P_DEV_REPORTED && !wfd_changed)
return 0;
p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
@@ -848,8 +877,7 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
/*
* If GO Negotiation is in progress, report that it has failed.
*/
- p2p_go_neg_failed(p2p, dev, -1);
- p2p->go_neg_peer = NULL;
+ p2p_go_neg_failed(p2p, -1);
}
if (p2p->invite_peer == dev)
p2p->invite_peer = NULL;
@@ -956,14 +984,8 @@ static void p2p_search(struct p2p_data *p2p)
p2p->num_req_dev_types, p2p->req_dev_types,
p2p->find_dev_id, pw_id);
if (res < 0) {
- p2p_dbg(p2p, "Scan request failed");
+ p2p_dbg(p2p, "Scan request schedule failed");
p2p_continue_find(p2p);
- } else {
- p2p_dbg(p2p, "Running p2p_scan");
- p2p->p2p_scan_running = 1;
- eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
- eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
- p2p, NULL);
}
}
@@ -976,6 +998,22 @@ static void p2p_find_timeout(void *eloop_ctx, void *timeout_ctx)
}
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status)
+{
+ if (status != 0) {
+ p2p_dbg(p2p, "Scan request failed");
+ /* Do continue find even for the first p2p_find_scan */
+ p2p_continue_find(p2p);
+ } else {
+ p2p_dbg(p2p, "Running p2p_scan");
+ p2p->p2p_scan_running = 1;
+ eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
+ eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
+ p2p, NULL);
+ }
+}
+
+
static int p2p_run_after_scan(struct p2p_data *p2p)
{
struct p2p_device *dev;
@@ -1106,17 +1144,11 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
return -1;
}
- if (res == 0) {
- p2p_dbg(p2p, "Running p2p_scan");
- p2p->p2p_scan_running = 1;
- eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
- eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
- p2p, NULL);
- } else if (p2p->p2p_scan_running) {
+ if (res != 0 && p2p->p2p_scan_running) {
p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
/* wait for the previous p2p_scan to complete */
res = 0; /* do not report failure */
- } else {
+ } else if (res != 0) {
p2p_dbg(p2p, "Failed to start p2p_scan");
p2p_set_state(p2p, P2P_IDLE);
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
@@ -1334,8 +1366,8 @@ int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
if (go)
p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
else if (!force_freq)
- p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
- &p2p->channels);
+ p2p_channels_union_inplace(&p2p->channels,
+ &p2p->cfg->cli_channels);
p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
@@ -1616,8 +1648,6 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
struct p2p_go_neg_results res;
int go = peer->go_state == LOCAL_GO;
struct p2p_channels intersection;
- int freqs;
- size_t i, j;
p2p_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)",
MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer");
@@ -1658,21 +1688,9 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
p2p_channels_dump(p2p, "intersection after no-GO removal",
&intersection);
}
- freqs = 0;
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c = &intersection.reg_class[i];
- if (freqs + 1 == P2P_MAX_CHANNELS)
- break;
- for (j = 0; j < c->channels; j++) {
- int freq;
- if (freqs + 1 == P2P_MAX_CHANNELS)
- break;
- freq = p2p_channel_to_freq(c->reg_class, c->channel[j]);
- if (freq < 0)
- continue;
- res.freq_list[freqs++] = freq;
- }
- }
+
+ p2p_channels_to_freqs(&intersection, res.freq_list,
+ P2P_MAX_CHANNELS);
res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
@@ -1713,7 +1731,6 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
rx_freq);
break;
case P2P_INVITATION_RESP:
- p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
break;
case P2P_PROV_DISC_REQ:
@@ -1992,11 +2009,12 @@ int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps)
attr.num_req_dev_type))
return 1; /* Own Primary Device Type matches */
- for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
+ for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) {
if (dev_type_list_match(p2p->cfg->sec_dev_type[i],
attr.req_dev_type,
attr.num_req_dev_type))
- return 1; /* Own Secondary Device Type matches */
+ return 1; /* Own Secondary Device Type matches */
+ }
/* No matching device type found */
return 0;
@@ -2541,6 +2559,7 @@ void p2p_deinit(struct p2p_data *p2p)
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
p2p_flush(p2p);
p2p_free_req_dev_types(p2p);
os_free(p2p->cfg->dev_name);
@@ -2583,8 +2602,10 @@ int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr)
p2p_dbg(p2p, "Unauthorizing " MACSTR, MAC2STR(addr));
- if (p2p->go_neg_peer == dev)
+ if (p2p->go_neg_peer == dev) {
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
p2p->go_neg_peer = NULL;
+ }
dev->wps_method = WPS_NOT_READY;
dev->oob_pw_id = 0;
@@ -2742,28 +2763,64 @@ int p2p_set_country(struct p2p_data *p2p, const char *country)
}
+static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
+{
+ if (dev->sd_pending_bcast_queries == 0) {
+ /* Initialize with total number of registered broadcast
+ * SD queries. */
+ dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
+ }
+
+ if (p2p_start_sd(p2p, dev) == 0)
+ return 1;
+
+ if (dev->req_config_methods &&
+ !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
+ p2p_dbg(p2p, "Send pending Provision Discovery Request to "
+ MACSTR " (config methods 0x%x)",
+ MAC2STR(dev->info.p2p_device_addr),
+ dev->req_config_methods);
+ if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
void p2p_continue_find(struct p2p_data *p2p)
{
struct p2p_device *dev;
+ int found;
+
p2p_set_state(p2p, P2P_SEARCH);
+
+ /* Continue from the device following the last iteration */
+ found = 0;
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
- if (dev->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 (dev == p2p->last_p2p_find_oper) {
+ found = 1;
+ continue;
+ }
+ if (!found)
+ continue;
+ if (p2p_pre_find_operation(p2p, dev) > 0) {
+ p2p->last_p2p_find_oper = dev;
+ return;
}
+ }
- if (p2p_start_sd(p2p, dev) == 0)
+ /*
+ * Wrap around to the beginning of the list and continue until the last
+ * iteration device.
+ */
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (p2p_pre_find_operation(p2p, dev) > 0) {
+ p2p->last_p2p_find_oper = dev;
return;
- if (dev->req_config_methods &&
- !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
- p2p_dbg(p2p, "Send pending Provision Discovery Request to "
- MACSTR " (config methods 0x%x)",
- MAC2STR(dev->info.p2p_device_addr),
- dev->req_config_methods);
- if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
- return;
}
+ if (dev == p2p->last_p2p_find_oper)
+ break;
}
p2p_listen_in_find(p2p, 1);
@@ -2777,6 +2834,8 @@ 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)
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p->sd_peer = NULL;
p2p_continue_find(p2p);
return;
@@ -3057,8 +3116,7 @@ static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success,
{
p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success);
if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
- p2p_go_neg_failed(p2p, p2p->go_neg_peer,
- p2p->go_neg_peer->status);
+ p2p_go_neg_failed(p2p, p2p->go_neg_peer->status);
} else if (success) {
struct p2p_device *dev;
dev = p2p_get_device(p2p, addr);
@@ -3086,7 +3144,7 @@ static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
if (result == P2P_SEND_ACTION_FAILED) {
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_go_neg_failed(p2p, -1);
return;
}
@@ -3257,7 +3315,7 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
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");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_go_neg_failed(p2p, -1);
return 0;
}
@@ -3308,7 +3366,7 @@ static void p2p_timeout_connect(struct p2p_data *p2p)
if (p2p->go_neg_peer &&
(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
p2p_dbg(p2p, "Wait for GO Negotiation Confirm timed out - assume GO Negotiation failed");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_go_neg_failed(p2p, -1);
return;
}
if (p2p->go_neg_peer &&
@@ -3339,7 +3397,7 @@ static void p2p_timeout_connect_listen(struct p2p_data *p2p)
if (p2p->go_neg_peer->connect_reqs >= 120) {
p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_go_neg_failed(p2p, -1);
return;
}
@@ -3365,20 +3423,12 @@ static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p)
static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
{
struct p2p_device *dev = p2p->go_neg_peer;
- struct os_reltime now;
if (dev == NULL) {
p2p_dbg(p2p, "Unknown GO Neg peer - stop GO Neg wait");
return;
}
- os_get_reltime(&now);
- if (os_reltime_expired(&now, &dev->go_neg_wait_started, 120)) {
- p2p_dbg(p2p, "Timeout on waiting peer to become ready for GO Negotiation");
- p2p_go_neg_failed(p2p, dev, -1);
- return;
- }
-
p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
p2p_listen_in_find(p2p, 0);
@@ -3489,6 +3539,10 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
p2p_dbg(p2p, "Timeout (state=%s)", p2p_state_txt(p2p->state));
p2p->in_listen = 0;
+ if (p2p->drv_in_listen) {
+ p2p_dbg(p2p, "Driver is still in listen state - stop it");
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ }
switch (p2p->state) {
case P2P_IDLE:
@@ -3704,7 +3758,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"[PD_FOR_JOIN]" : "",
dev->status,
dev->invitation_reqs);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -3714,7 +3768,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"ext_listen_interval=%u\n",
dev->ext_listen_period,
dev->ext_listen_interval);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -3724,7 +3778,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"oper_ssid=%s\n",
wpa_ssid_txt(dev->oper_ssid,
dev->oper_ssid_len));
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -3732,7 +3786,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
#ifdef CONFIG_WIFI_DISPLAY
if (dev->info.wfd_subelems) {
res = os_snprintf(pos, end - pos, "wfd_subelems=");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -3741,7 +3795,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
wpabuf_len(dev->info.wfd_subelems));
res = os_snprintf(pos, end - pos, "\n");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -4859,3 +4913,13 @@ void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem)
{
p2p->vendor_elem = vendor_elem;
}
+
+
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct p2p_data *p2p = eloop_ctx;
+
+ p2p_dbg(p2p,
+ "Timeout on waiting peer to become ready for GO Negotiation");
+ p2p_go_neg_failed(p2p, -1);
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 076a2ac1..fa886f74 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -949,6 +949,13 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
const u8 *dev_id, unsigned int search_delay);
/**
+ * p2p_notify_scan_trigger_status - Indicate scan trigger status
+ * @p2p: P2P module context from p2p_init()
+ * @status: 0 on success, -1 on failure
+ */
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status);
+
+/**
* p2p_stop_find - Stop P2P Find (Device Discovery)
* @p2p: P2P module context from p2p_init()
*/
@@ -1738,6 +1745,9 @@ void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
int p2p_channels_includes_freq(const struct p2p_channels *channels,
unsigned int freq);
+int p2p_channels_to_freqs(const struct p2p_channels *channels,
+ int *freq_list, unsigned int max_len);
+
/**
* p2p_supported_freq - Check whether channel is supported for P2P
* @p2p: P2P module context from p2p_init()
@@ -1912,7 +1922,8 @@ int p2p_set_no_go_freq(struct p2p_data *p2p,
/**
* p2p_in_progress - Check whether a P2P operation is progress
* @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ * Returns: 0 if P2P module is idle, 1 if an operation is in progress but not
+ * in search state, or 2 if search state operation is in progress
*/
int p2p_in_progress(struct p2p_data *p2p);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 21fae3f2..c654c5a8 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
@@ -240,6 +241,7 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
p2p_set_state(p2p, P2P_CONNECT);
p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;
p2p->go_neg_peer = dev;
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->connect_reqs++;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
@@ -621,7 +623,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
* Request frame.
*/
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- p2p_go_neg_failed(p2p, dev, *msg.status);
+ p2p_go_neg_failed(p2p, *msg.status);
p2p_parse_free(&msg);
return;
}
@@ -645,6 +647,9 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
p2p_add_dev_info(p2p, sa, dev, &msg);
}
+ if (p2p->go_neg_peer && p2p->go_neg_peer == dev)
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+
if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
p2p_dbg(p2p, "User has rejected this peer");
status = P2P_SC_FAIL_REJECTED_BY_USER;
@@ -789,6 +794,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
dev->dialog_token = msg.dialog_token;
os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
p2p->go_neg_peer = dev;
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
status = P2P_SC_SUCCESS;
}
@@ -957,7 +963,10 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
dev->flags |= P2P_DEV_NOT_YET_READY;
- os_get_reltime(&dev->go_neg_wait_started);
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p,
+ NULL);
+ eloop_register_timeout(120, 0, p2p_go_neg_wait_timeout,
+ p2p, NULL);
if (p2p->state == P2P_CONNECT_LISTEN)
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
else
@@ -965,7 +974,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p_set_timeout(p2p, 0, 0);
} else {
p2p_dbg(p2p, "Stop GO Negotiation attempt");
- p2p_go_neg_failed(p2p, dev, *msg.status);
+ p2p_go_neg_failed(p2p, *msg.status);
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_parse_free(&msg);
@@ -1147,13 +1156,13 @@ fail:
wpabuf_head(dev->go_neg_conf),
wpabuf_len(dev->go_neg_conf), 200) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
- p2p_go_neg_failed(p2p, dev, -1);
+ p2p_go_neg_failed(p2p, -1);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
} else
dev->go_neg_conf_sent++;
if (status != P2P_SC_SUCCESS) {
p2p_dbg(p2p, "GO Negotiation failed");
- p2p_go_neg_failed(p2p, dev, status);
+ p2p_go_neg_failed(p2p, status);
}
}
@@ -1204,7 +1213,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
}
if (*msg.status) {
p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
- p2p_go_neg_failed(p2p, dev, *msg.status);
+ p2p_go_neg_failed(p2p, *msg.status);
p2p_parse_free(&msg);
return;
}
@@ -1216,7 +1225,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
} else if (dev->go_state == REMOTE_GO) {
p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Confirmation");
p2p->ssid_len = 0;
- p2p_go_neg_failed(p2p, dev, P2P_SC_FAIL_INVALID_PARAMS);
+ p2p_go_neg_failed(p2p, P2P_SC_FAIL_INVALID_PARAMS);
p2p_parse_free(&msg);
return;
}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 3b60582b..62711e7c 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -101,10 +101,10 @@ struct p2p_device {
unsigned int flags;
int status; /* enum p2p_status_code */
- struct os_reltime go_neg_wait_started;
unsigned int wait_count;
unsigned int connect_reqs;
unsigned int invitation_reqs;
+ unsigned int sd_reqs;
u16 ext_listen_period;
u16 ext_listen_interval;
@@ -260,10 +260,18 @@ struct p2p_data {
*/
struct p2p_device *invite_peer;
+ /**
+ * last_p2p_find_oper - Pointer to last pre-find operation peer
+ */
+ struct p2p_device *last_p2p_find_oper;
+
const u8 *invite_go_dev_addr;
u8 invite_go_dev_addr_buf[ETH_ALEN];
int invite_dev_pw_id;
+ unsigned int retry_invite_req:1;
+ unsigned int retry_invite_req_sent:1;
+
/**
* sd_peer - Pointer to Service Discovery peer
*/
@@ -606,6 +614,8 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
void p2p_channels_intersect(const struct p2p_channels *a,
const struct p2p_channels *b,
struct p2p_channels *res);
+void p2p_channels_union_inplace(struct p2p_channels *res,
+ const struct p2p_channels *b);
void p2p_channels_union(const struct p2p_channels *a,
const struct p2p_channels *b,
struct p2p_channels *res);
@@ -768,8 +778,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
const u8 *addr);
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
- int status);
+void p2p_go_neg_failed(struct p2p_data *p2p, int status);
void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer);
int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps);
int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
@@ -783,6 +792,7 @@ void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
unsigned int force_freq, unsigned int pref_freq,
int go);
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx);
void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index ef01a668..558c6dd0 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -174,7 +174,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
u8 group_bssid[ETH_ALEN], *bssid;
int op_freq = 0;
u8 reg_class = 0, channel = 0;
- struct p2p_channels intersection, *channels = NULL;
+ struct p2p_channels all_channels, intersection, *channels = NULL;
int persistent;
os_memset(group_bssid, 0, sizeof(group_bssid));
@@ -226,7 +226,10 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
persistent = 1;
}
- if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev,
+ p2p_channels_union(&p2p->cfg->channels, &p2p->cfg->cli_channels,
+ &all_channels);
+
+ if (p2p_peer_channels_check(p2p, &all_channels, dev,
msg.channel_list, msg.channel_list_len) <
0) {
p2p_dbg(p2p, "No common channels found");
@@ -235,8 +238,9 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
}
p2p_channels_dump(p2p, "own channels", &p2p->cfg->channels);
+ p2p_channels_dump(p2p, "own client channels", &all_channels);
p2p_channels_dump(p2p, "peer channels", &dev->channels);
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+ p2p_channels_intersect(&all_channels, &dev->channels,
&intersection);
p2p_channels_dump(p2p, "intersection", &intersection);
@@ -248,6 +252,17 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
msg.dev_password_id_present ? msg.dev_password_id : -1);
}
+ if (go) {
+ p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+ &intersection);
+ p2p_channels_dump(p2p, "intersection(GO)", &intersection);
+ if (intersection.reg_classes == 0) {
+ p2p_dbg(p2p, "No common channels found (GO)");
+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ goto fail;
+ }
+ }
+
if (op_freq) {
p2p_dbg(p2p, "Invitation processing forced frequency %d MHz",
op_freq);
@@ -412,25 +427,68 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
if (dev == NULL) {
p2p_dbg(p2p, "Ignore Invitation Response from unknown peer "
MACSTR, MAC2STR(sa));
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
if (dev != p2p->invite_peer) {
p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer "
MACSTR, MAC2STR(sa));
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
- if (p2p_parse(data, len, &msg))
+ if (p2p_parse(data, len, &msg)) {
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
+ }
if (!msg.status) {
p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from "
MACSTR, MAC2STR(sa));
p2p_parse_free(&msg);
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ return;
+ }
+
+ /*
+ * We should not really receive a replayed response twice since
+ * duplicate frames are supposed to be dropped. However, not all drivers
+ * do that for pre-association frames. We did not use to verify dialog
+ * token matches for invitation response frames, but that check can be
+ * safely used to drop a replayed response to the previous Invitation
+ * Request in case the suggested operating channel was changed. This
+ * allows a duplicated reject frame to be dropped with the assumption
+ * that the real response follows after it.
+ */
+ if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+ p2p->retry_invite_req_sent &&
+ msg.dialog_token != dev->dialog_token) {
+ p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
+ msg.dialog_token, dev->dialog_token);
+ p2p_parse_free(&msg);
return;
}
+ if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+ p2p->retry_invite_req &&
+ p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class,
+ &p2p->op_channel) == 0) {
+ p2p->retry_invite_req = 0;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ p2p_set_state(p2p, P2P_INVITE);
+ p2p_dbg(p2p, "Resend Invitation Request setting op_class %u channel %u as operating channel",
+ p2p->op_reg_class, p2p->op_channel);
+ p2p->retry_invite_req_sent = 1;
+ p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
+ p2p->invite_dev_pw_id);
+ p2p_parse_free(&msg);
+ return;
+ }
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->retry_invite_req = 0;
+
if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) {
p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
MACSTR, MAC2STR(sa));
@@ -592,6 +650,9 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
dev_pw_id);
}
p2p->invite_dev_pw_id = dev_pw_id;
+ p2p->retry_invite_req = role == P2P_INVITE_ROLE_GO &&
+ persistent_group && !force_freq;
+ p2p->retry_invite_req_sent = 0;
dev = p2p_get_device(p2p, peer);
if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 &&
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index d6144a0e..52ba19e0 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -309,23 +309,27 @@ int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg)
while (pos < end) {
u16 attr_len;
- if (pos + 2 >= end) {
+ u8 id;
+
+ if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute");
return -1;
}
- attr_len = WPA_GET_LE16(pos + 1);
+ id = *pos++;
+ attr_len = WPA_GET_LE16(pos);
+ pos += 2;
wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u",
- pos[0], attr_len);
- if (pos + 3 + attr_len > end) {
+ id, attr_len);
+ if (attr_len > end - pos) {
wpa_printf(MSG_DEBUG, "P2P: Attribute underflow "
"(len=%u left=%d)",
- attr_len, (int) (end - pos - 3));
+ attr_len, (int) (end - pos));
wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos);
return -1;
}
- if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg))
+ if (p2p_parse_attribute(id, pos, attr_len, msg))
return -1;
- pos += 3 + attr_len;
+ pos += attr_len;
}
return 0;
@@ -603,7 +607,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
"dev=" MACSTR " iface=" MACSTR,
MAC2STR(cli->p2p_device_addr),
MAC2STR(cli->p2p_interface_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -614,7 +618,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
wps_dev_type_bin2str(cli->pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -623,7 +627,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
wps_dev_type_bin2str(
&cli->sec_dev_types[s * 8],
devtype, sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -638,7 +642,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
}
ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -672,7 +676,7 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
"p2p_dev_capab=0x%x\n"
"p2p_group_capab=0x%x\n",
msg.capability[0], msg.capability[1]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -684,14 +688,14 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
wps_dev_type_bin2str(msg.pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n",
msg.device_name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -699,14 +703,14 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR
"\n",
MAC2STR(msg.p2p_device_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n",
msg.config_methods);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 13119c20..1a2af04b 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -75,16 +75,25 @@ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
return NULL;
/* query number that needs to be send to the device */
if (count == dev->sd_pending_bcast_queries - 1)
- return q;
+ goto found;
count++;
}
if (!q->for_all_peers &&
os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) ==
0)
- return q;
+ goto found;
}
return NULL;
+
+found:
+ if (dev->sd_reqs > 100) {
+ p2p_dbg(p2p, "Too many SD request attempts to " MACSTR
+ " - skip remaining queries",
+ MAC2STR(dev->info.p2p_device_addr));
+ return NULL;
+ }
+ return q;
}
@@ -287,6 +296,7 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
if (req == NULL)
return -1;
+ dev->sd_reqs++;
p2p->sd_peer = dev;
p2p->sd_query = query;
p2p->pending_action_state = P2P_PENDING_SD;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 23acce76..f32751d7 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "common/ieee802_11_common.h"
#include "p2p_i.h"
@@ -54,56 +55,7 @@ int p2p_random(char *buf, size_t len)
*/
int p2p_channel_to_freq(int op_class, int channel)
{
- /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
- /* TODO: more operating classes */
- switch (op_class) {
- case 81:
- /* channels 1..13 */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 82:
- /* channel 14 */
- if (channel != 14)
- return -1;
- return 2414 + 5 * channel;
- case 83: /* channels 1..9; 40 MHz */
- case 84: /* channels 5..13; 40 MHz */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 115: /* channels 36,40,44,48; indoor only */
- case 118: /* channels 52,56,60,64; dfs */
- if (channel < 36 || channel > 64)
- return -1;
- return 5000 + 5 * channel;
- case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 116: /* channels 36,44; 40 MHz; indoor only */
- case 117: /* channels 40,48; 40 MHz; indoor only */
- case 119: /* channels 52,60; 40 MHz; dfs */
- case 120: /* channels 56,64; 40 MHz; dfs */
- if (channel < 36 || channel > 64)
- return -1;
- return 5000 + 5 * channel;
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
- if (channel < 36 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 180: /* 60 GHz band, channels 1..4 */
- if (channel < 1 || channel > 4)
- return -1;
- return 56160 + 2160 * channel;
- }
- return -1;
+ return ieee80211_chan_to_freq(NULL, op_class, channel);
}
@@ -241,20 +193,15 @@ static void p2p_op_class_union(struct p2p_reg_class *cl,
/**
- * p2p_channels_union - Union of channel lists
- * @a: First set of channels
+ * p2p_channels_union_inplace - Inplace union of channel lists
+ * @res: Input data and place for returning union of the channel sets
* @b: Second set of channels
- * @res: Data structure for returning the union of channels
*/
-void p2p_channels_union(const struct p2p_channels *a,
- const struct p2p_channels *b,
- struct p2p_channels *res)
+void p2p_channels_union_inplace(struct p2p_channels *res,
+ const struct p2p_channels *b)
{
size_t i, j;
- if (a != res)
- os_memcpy(res, a, sizeof(*res));
-
for (i = 0; i < res->reg_classes; i++) {
struct p2p_reg_class *cl = &res->reg_class[i];
for (j = 0; j < b->reg_classes; j++) {
@@ -284,6 +231,21 @@ void p2p_channels_union(const struct p2p_channels *a,
}
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res)
+{
+ os_memcpy(res, a, sizeof(*res));
+ p2p_channels_union_inplace(res, b);
+}
+
+
void p2p_channels_remove_freqs(struct p2p_channels *chan,
const struct wpa_freq_range_list *list)
{
@@ -428,7 +390,7 @@ void p2p_channels_dump(struct p2p_data *p2p, const char *title,
const struct p2p_reg_class *c;
c = &chan->reg_class[i];
ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
@@ -436,7 +398,7 @@ void p2p_channels_dump(struct p2p_data *p2p, const char *title,
ret = os_snprintf(pos, end - pos, "%s%u",
j == 0 ? "" : ",",
c->channel[j]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
}
@@ -517,3 +479,35 @@ int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
return 0;
}
+
+
+int p2p_channels_to_freqs(const struct p2p_channels *channels, int *freq_list,
+ unsigned int max_len)
+{
+ unsigned int i, idx;
+
+ if (!channels || max_len == 0)
+ return 0;
+
+ for (i = 0, idx = 0; i < channels->reg_classes; i++) {
+ const struct p2p_reg_class *c = &channels->reg_class[i];
+ unsigned int j;
+
+ if (idx + 1 == max_len)
+ break;
+ for (j = 0; j < c->channels; j++) {
+ int freq;
+ if (idx + 1 == max_len)
+ break;
+ freq = p2p_channel_to_freq(c->reg_class,
+ c->channel[j]);
+ if (freq < 0)
+ continue;
+ freq_list[idx++] = freq;
+ }
+ }
+
+ freq_list[idx] = 0;
+
+ return idx;
+}