return "INVITE";
case P2P_INVITE_LISTEN:
return "INVITE_LISTEN";
+ case P2P_SEARCH_WHEN_READY:
+ return "SEARCH_WHEN_READY";
default:
return "?";
}
}
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
+{
+ struct p2p_device *dev = NULL;
+
+ if (!addr || !p2p)
+ return 0;
+
+ dev = p2p_get_device(p2p, addr);
+ if (dev)
+ return dev->wps_prov_info;
+ else
+ return 0;
+}
+
+
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+{
+ struct p2p_device *dev = NULL;
+
+ if (!iface_addr || !p2p)
+ return;
+
+ dev = p2p_get_device_interface(p2p, iface_addr);
+ if (dev)
+ dev->wps_prov_info = 0;
+}
+
+
void p2p_set_state(struct p2p_data *p2p, int new_state)
{
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
struct p2p_go_neg_results res;
p2p_clear_timeout(p2p);
p2p_set_state(p2p, P2P_IDLE);
+ if (p2p->go_neg_peer)
+ p2p->go_neg_peer->wps_method = WPS_NOT_READY;
p2p->go_neg_peer = NULL;
os_memset(&res, 0, sizeof(res));
p2p->pending_listen_usec = (timeout % 1000) * 1000;
if (p2p->p2p_scan_running) {
+ if (p2p->start_after_scan == P2P_AFTER_SCAN_NOTHING) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: p2p_scan running - connect is already "
+ "pending - skip listen");
+ return 0;
+ }
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: p2p_scan running - delay start of listen state");
p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
* group, the information will be restored in the loop following this.
*/
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
- if (os_memcpy(dev->member_in_go_iface, go_interface_addr,
+ if (os_memcmp(dev->member_in_go_iface, go_interface_addr,
ETH_ALEN) == 0) {
os_memset(dev->member_in_go_iface, 0, ETH_ALEN);
os_memset(dev->member_in_go_dev, 0, ETH_ALEN);
for (c = 0; c < info.num_clients; c++) {
struct p2p_client_info *cli = &info.client[c];
+ if (os_memcmp(cli->p2p_device_addr, p2p->cfg->dev_addr,
+ ETH_ALEN) == 0)
+ continue; /* ignore our own entry */
dev = p2p_get_device(p2p, cli->p2p_device_addr);
if (dev) {
/*
{
int i;
- if (p2p->go_neg_peer == dev)
+ if (p2p->go_neg_peer == dev) {
+ /*
+ * If GO Negotiation is in progress, report that it has failed.
+ */
+ p2p_go_neg_failed(p2p, dev, -1);
p2p->go_neg_peer = NULL;
+ }
if (p2p->invite_peer == dev)
p2p->invite_peer = NULL;
if (p2p->sd_peer == dev)
}
if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
- p2p->num_req_dev_types, p2p->req_dev_types) < 0)
- {
+ p2p->num_req_dev_types, p2p->req_dev_types,
+ p2p->find_dev_id) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Scan request failed");
p2p_continue_find(p2p);
enum p2p_after_scan op;
if (p2p->after_scan_tx) {
- int ret;
/* TODO: schedule p2p_run_after_scan to be called from TX
* status callback(?) */
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending "
"Action frame at p2p_scan completion");
- ret = p2p->cfg->send_action(p2p->cfg->cb_ctx,
- p2p->after_scan_tx->freq,
- p2p->after_scan_tx->dst,
- p2p->after_scan_tx->src,
- p2p->after_scan_tx->bssid,
- (u8 *) (p2p->after_scan_tx + 1),
- p2p->after_scan_tx->len,
- p2p->after_scan_tx->wait_time);
+ p2p->cfg->send_action(p2p->cfg->cb_ctx,
+ p2p->after_scan_tx->freq,
+ p2p->after_scan_tx->dst,
+ p2p->after_scan_tx->src,
+ p2p->after_scan_tx->bssid,
+ (u8 *) (p2p->after_scan_tx + 1),
+ p2p->after_scan_tx->len,
+ p2p->after_scan_tx->wait_time);
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
return 1;
int p2p_find(struct p2p_data *p2p, unsigned int timeout,
enum p2p_discovery_type type,
- unsigned int num_req_dev_types, const u8 *req_dev_types)
+ unsigned int num_req_dev_types, const u8 *req_dev_types,
+ const u8 *dev_id)
{
int res;
p2p->num_req_dev_types = num_req_dev_types;
}
+ if (dev_id) {
+ os_memcpy(p2p->find_dev_id_buf, dev_id, ETH_ALEN);
+ p2p->find_dev_id = p2p->find_dev_id_buf;
+ } else
+ p2p->find_dev_id = NULL;
+
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
p2p_clear_timeout(p2p);
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p_device_clear_reported(p2p);
p2p_set_state(p2p, P2P_SEARCH);
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+ p2p->last_p2p_find_timeout = timeout;
if (timeout)
eloop_register_timeout(timeout, 0, p2p_find_timeout,
p2p, NULL);
case P2P_FIND_PROGRESSIVE:
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
p2p->num_req_dev_types,
- p2p->req_dev_types);
+ p2p->req_dev_types, dev_id);
break;
case P2P_FIND_ONLY_SOCIAL:
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,
p2p->num_req_dev_types,
- p2p->req_dev_types);
+ p2p->req_dev_types, dev_id);
break;
default:
return -1;
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
p2p, NULL);
+ } else if (res == 1) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
+ "p2p_scan at this point - will try again after "
+ "previous scan completes");
+ res = 0;
+ p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
+ eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
} else {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
"p2p_scan");
}
+int p2p_other_scan_completed(struct p2p_data *p2p)
+{
+ if (p2p->state != P2P_SEARCH_WHEN_READY)
+ return 0;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
+ "now that previous scan was completed");
+ if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
+ p2p->num_req_dev_types, p2p->req_dev_types,
+ p2p->find_dev_id) < 0)
+ return 0;
+ return 1;
+}
+
+
void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
{
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
}
+static void p2p_set_dev_persistent(struct p2p_device *dev,
+ int persistent_group)
+{
+ switch (persistent_group) {
+ case 0:
+ dev->flags &= ~(P2P_DEV_PREFER_PERSISTENT_GROUP |
+ P2P_DEV_PREFER_PERSISTENT_RECONN);
+ break;
+ case 1:
+ dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
+ dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_RECONN;
+ break;
+ case 2:
+ dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP |
+ P2P_DEV_PREFER_PERSISTENT_RECONN;
+ break;
+ }
+}
+
+
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
if (p2p_prepare_channel(p2p, force_freq) < 0)
return -1;
+ p2p->ssid_set = 0;
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
- if (persistent_group)
- dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
- else
- dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+ p2p_set_dev_persistent(dev, persistent_group);
p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
dev->flags &= ~P2P_DEV_USER_REJECTED;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
- if (persistent_group)
- dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
- else
- dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+ p2p_set_dev_persistent(dev, persistent_group);
p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
res.wps_method = peer->wps_method;
- if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
- res.persistent_group = 1;
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+ res.persistent_group = 2;
+ else
+ res.persistent_group = 1;
+ }
if (go) {
/* Setup AP mode for WPS provisioning */
res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
p2p_clear_timeout(p2p);
+ p2p->ssid_set = 0;
peer->go_neg_req_sent = 0;
peer->wps_method = WPS_NOT_READY;
}
-void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da, const u8 *sa,
- const u8 *bssid, const u8 *data, size_t len,
- int freq)
+static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da,
+ const u8 *sa, const u8 *bssid, const u8 *data,
+ size_t len, int freq)
{
if (len < 1)
return;
if (dev) {
if (dev->country[0] == 0 && msg.listen_channel)
os_memcpy(dev->country, msg.listen_channel, 3);
+ os_get_time(&dev->last_seen);
p2p_parse_free(&msg);
return; /* already known */
}
} else if (dev->req_config_methods &&
!(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provisioning Discovery Request to "
+ "pending Provision Discovery Request to "
MACSTR " (config methods 0x%x)",
MAC2STR(dev->info.p2p_device_addr),
dev->req_config_methods);
- if (p2p_send_prov_disc_req(p2p, dev, 0) == 0)
+ if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
return;
}
}
* p2p_retry_pd - Retry any pending provision disc requests in IDLE state
* @p2p: P2P module context from p2p_init()
*/
-void p2p_retry_pd(struct p2p_data *p2p)
+static void p2p_retry_pd(struct p2p_data *p2p)
{
struct p2p_device *dev;
continue;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provisioning Discovery Request to "
+ "pending Provision Discovery Request to "
MACSTR " (config methods 0x%x)",
MAC2STR(dev->info.p2p_device_addr),
dev->req_config_methods);
- p2p_send_prov_disc_req(p2p, dev, 0);
+ p2p_send_prov_disc_req(p2p, dev, 0, 0);
return;
}
}
}
-void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies)
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
{
u8 *len = p2p_buf_add_ie_hdr(ies);
p2p_buf_add_capability(ies, p2p->dev_capab, 0);
+ if (dev_id)
+ p2p_buf_add_device_id(ies, dev_id);
if (p2p->cfg->reg_class && p2p->cfg->channel)
p2p_buf_add_listen_channel(ies, p2p->cfg->country,
p2p->cfg->reg_class,
}
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
+{
+ return 100;
+}
+
+
int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
{
return p2p_attr_text(p2p_ie, buf, end);
* state once per second to give other uses a chance to use the radio.
*/
p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
- p2p_set_timeout(p2p, 1, 0);
+ p2p_set_timeout(p2p, 0, 500000);
}
case P2P_INVITE_LISTEN:
p2p_timeout_invite_listen(p2p);
break;
+ case P2P_SEARCH_WHEN_READY:
+ break;
}
}
}
-static const char * p2p_wps_method_text(enum p2p_wps_method method)
+const char * p2p_wps_method_text(enum p2p_wps_method method)
{
switch (method) {
case WPS_NOT_READY:
}
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
- char *buf, size_t buflen)
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+ const u8 *addr, int next)
{
struct p2p_device *dev;
- int res;
- char *pos, *end;
- struct os_time now;
- char devtype[WPS_DEV_TYPE_BUFSIZE];
if (addr)
dev = p2p_get_device(p2p, addr);
}
if (dev == NULL)
+ return NULL;
+
+ return &dev->info;
+}
+
+
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+ char *buf, size_t buflen)
+{
+ struct p2p_device *dev;
+ int res;
+ char *pos, *end;
+ struct os_time now;
+
+ if (info == NULL)
return -1;
+ dev = (struct p2p_device *) (((u8 *) info) -
+ offsetof(struct p2p_device, info));
+
pos = buf;
end = buf + buflen;
- res = os_snprintf(pos, end - pos, MACSTR "\n",
- MAC2STR(dev->info.p2p_device_addr));
- if (res < 0 || res >= end - pos)
- return pos - buf;
- pos += res;
-
os_get_time(&now);
res = os_snprintf(pos, end - pos,
"age=%d\n"
"listen_freq=%d\n"
- "level=%d\n"
"wps_method=%s\n"
"interface_addr=" MACSTR "\n"
"member_in_go_dev=" MACSTR "\n"
"member_in_go_iface=" MACSTR "\n"
- "pri_dev_type=%s\n"
- "device_name=%s\n"
- "manufacturer=%s\n"
- "model_name=%s\n"
- "model_number=%s\n"
- "serial_number=%s\n"
- "config_methods=0x%x\n"
- "dev_capab=0x%x\n"
- "group_capab=0x%x\n"
"go_neg_req_sent=%d\n"
"go_state=%s\n"
"dialog_token=%u\n"
"invitation_reqs=%u\n",
(int) (now.sec - dev->last_seen.sec),
dev->listen_freq,
- dev->info.level,
p2p_wps_method_text(dev->wps_method),
MAC2STR(dev->interface_addr),
MAC2STR(dev->member_in_go_dev),
MAC2STR(dev->member_in_go_iface),
- wps_dev_type_bin2str(dev->info.pri_dev_type,
- devtype, sizeof(devtype)),
- dev->info.device_name,
- dev->info.manufacturer,
- dev->info.model_name,
- dev->info.model_number,
- dev->info.serial_number,
- dev->info.config_methods,
- dev->info.dev_capab,
- dev->info.group_capab,
dev->go_neg_req_sent,
p2p_go_state_text(dev->go_state),
dev->dialog_token,
}
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr)
+{
+ return p2p_get_device(p2p, addr) != NULL;
+}
+
+
void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
{
if (enabled) {
return &dev->info;
}
+
+
+int p2p_in_progress(struct p2p_data *p2p)
+{
+ if (p2p == NULL)
+ return 0;
+ return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
+}