diff options
Diffstat (limited to 'src/p2p/p2p.c')
-rw-r--r-- | src/p2p/p2p.c | 299 |
1 files changed, 287 insertions, 12 deletions
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index eb2821e..03380dc 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -172,6 +172,8 @@ static const char * p2p_state_txt(int state) return "INVITE_LISTEN"; case P2P_SEARCH_WHEN_READY: return "SEARCH_WHEN_READY"; + case P2P_CONTINUE_SEARCH_WHEN_READY: + return "CONTINUE_SEARCH_WHEN_READY"; default: return "?"; } @@ -725,6 +727,11 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level, break; } + if (msg.wfd_subelems) { + wpabuf_free(dev->info.wfd_subelems); + dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); + } + if (scan_res) { p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq, msg.group_info, msg.group_info_len); @@ -782,6 +789,8 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev) dev->info.wps_vendor_ext[i] = NULL; } + wpabuf_free(dev->info.wfd_subelems); + os_free(dev); } @@ -846,6 +855,7 @@ static void p2p_search(struct p2p_data *p2p) int freq = 0; enum p2p_scan_type type; u16 pw_id = DEV_PW_DEFAULT; + int res; if (p2p->drv_in_listen) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still " @@ -865,12 +875,18 @@ static void p2p_search(struct p2p_data *p2p) wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search"); } - if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq, - p2p->num_req_dev_types, p2p->req_dev_types, - p2p->find_dev_id, pw_id)) { + res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq, + p2p->num_req_dev_types, p2p->req_dev_types, + p2p->find_dev_id, pw_id); + if (res < 0) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scan request failed"); p2p_continue_find(p2p); + } 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"); + p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY); } else { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan"); p2p->p2p_scan_running = 1; @@ -975,7 +991,7 @@ static void p2p_free_req_dev_types(struct p2p_data *p2p) 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, - const u8 *dev_id) + const u8 *dev_id, unsigned int search_delay) { int res; @@ -1009,6 +1025,8 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, p2p->find_type = type; p2p_device_clear_reported(p2p); p2p_set_state(p2p, P2P_SEARCH); + p2p->search_delay = search_delay; + p2p->in_search_delay = 0; eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); p2p->last_p2p_find_timeout = timeout; if (timeout) @@ -1070,13 +1088,18 @@ int p2p_search_pending(struct p2p_data *p2p) int p2p_other_scan_completed(struct p2p_data *p2p) { + if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) { + p2p_set_state(p2p, P2P_SEARCH); + p2p_search(p2p); + return 1; + } 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) + p2p->find_dev_id, p2p->search_delay) < 0) return 0; return 1; } @@ -1442,6 +1465,11 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, } } + if (msg->wfd_subelems) { + wpabuf_free(dev->info.wfd_subelems); + dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems); + } + if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) { dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, @@ -1779,6 +1807,11 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr, p2p_copy_wps_info(dev, 1, &msg); + if (msg.wfd_subelems) { + wpabuf_free(dev->info.wfd_subelems); + dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); + } + p2p_parse_free(&msg); wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, @@ -1877,8 +1910,14 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p) struct wpabuf *buf; u8 *len; int pw_id = -1; + size_t extra = 0; + +#ifdef CONFIG_WIFI_DISPLAY + if (p2p->wfd_ie_probe_resp) + extra = wpabuf_len(p2p->wfd_ie_probe_resp); +#endif /* CONFIG_WIFI_DISPLAY */ - buf = wpabuf_alloc(1000); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -1889,6 +1928,11 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p) p2p_build_wps_ie(p2p, buf, pw_id, 1); +#ifdef CONFIG_WIFI_DISPLAY + if (p2p->wfd_ie_probe_resp) + wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp); +#endif /* CONFIG_WIFI_DISPLAY */ + /* P2P IE */ len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_capability(buf, p2p->dev_capab & @@ -2173,20 +2217,31 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, struct p2p_device *peer; size_t tmplen; int res; + size_t extra = 0; if (!p2p_group) return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie); +#ifdef CONFIG_WIFI_DISPLAY + if (p2p->wfd_ie_assoc_req) + extra = wpabuf_len(p2p->wfd_ie_assoc_req); +#endif /* CONFIG_WIFI_DISPLAY */ + /* * (Re)Association Request - P2P IE * P2P Capability attribute (shall be present) * Extended Listen Timing (may be present) * P2P Device Info attribute (shall be present) */ - tmp = wpabuf_alloc(200); + tmp = wpabuf_alloc(200 + extra); if (tmp == NULL) return -1; +#ifdef CONFIG_WIFI_DISPLAY + if (p2p->wfd_ie_assoc_req) + wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req); +#endif /* CONFIG_WIFI_DISPLAY */ + peer = bssid ? p2p_get_device(p2p, bssid) : NULL; lpos = p2p_buf_add_ie_hdr(tmp); @@ -2370,12 +2425,29 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0, p2p_expiration_timeout, p2p, NULL); + p2p->go_timeout = 100; + p2p->client_timeout = 20; + return p2p; } void p2p_deinit(struct p2p_data *p2p) { +#ifdef CONFIG_WIFI_DISPLAY + wpabuf_free(p2p->wfd_ie_beacon); + wpabuf_free(p2p->wfd_ie_probe_req); + wpabuf_free(p2p->wfd_ie_probe_resp); + wpabuf_free(p2p->wfd_ie_assoc_req); + wpabuf_free(p2p->wfd_ie_invitation); + wpabuf_free(p2p->wfd_ie_prov_disc_req); + wpabuf_free(p2p->wfd_ie_prov_disc_resp); + wpabuf_free(p2p->wfd_ie_go_neg); + wpabuf_free(p2p->wfd_dev_info); + wpabuf_free(p2p->wfd_assoc_bssid); + wpabuf_free(p2p->wfd_coupled_sink_info); +#endif /* CONFIG_WIFI_DISPLAY */ + eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL); eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL); eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); @@ -2723,7 +2795,13 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success) if (!success) { p2p->pending_action_state = P2P_NO_PENDING_ACTION; - if (p2p->state != P2P_IDLE) + if (p2p->user_initiated_pd && + (p2p->state == P2P_SEARCH || p2p->state == P2P_LISTEN_ONLY)) + { + /* Retry request from timeout to avoid busy loops */ + p2p->pending_action_state = P2P_PENDING_PD; + p2p_set_timeout(p2p, 0, 50000); + } else if (p2p->state != P2P_IDLE) p2p_continue_find(p2p); else if (p2p->user_initiated_pd) { p2p->pending_action_state = P2P_PENDING_PD; @@ -2775,7 +2853,14 @@ void p2p_scan_res_handled(struct p2p_data *p2p) void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id) { - u8 *len = p2p_buf_add_ie_hdr(ies); + u8 *len; + +#ifdef CONFIG_WIFI_DISPLAY + if (p2p->wfd_ie_probe_req) + wpabuf_put_buf(ies, p2p->wfd_ie_probe_req); +#endif /* CONFIG_WIFI_DISPLAY */ + + len = p2p_buf_add_ie_hdr(ies); p2p_buf_add_capability(ies, p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0); if (dev_id) @@ -2794,7 +2879,14 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id) size_t p2p_scan_ie_buf_len(struct p2p_data *p2p) { - return 100; + size_t len = 100; + +#ifdef CONFIG_WIFI_DISPLAY + if (p2p && p2p->wfd_ie_probe_req) + len += wpabuf_len(p2p->wfd_ie_probe_req); +#endif /* CONFIG_WIFI_DISPLAY */ + + return len; } @@ -2845,7 +2937,7 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success) * channel. */ p2p_set_state(p2p, P2P_CONNECT); - p2p_set_timeout(p2p, 0, 100000); + p2p_set_timeout(p2p, 0, success ? 200000 : 100000); } @@ -2861,7 +2953,7 @@ static void p2p_go_neg_resp_cb(struct p2p_data *p2p, int success) return; } p2p_set_state(p2p, P2P_CONNECT); - p2p_set_timeout(p2p, 0, 100000); + p2p_set_timeout(p2p, 0, 250000); } @@ -3056,6 +3148,14 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq) p2p_set_timeout(p2p, 0, 100000); return 1; } + if (p2p->search_delay) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay " + "search operation by %u ms", + p2p->search_delay); + p2p_set_timeout(p2p, p2p->search_delay / 1000, + (p2p->search_delay % 1000) * 1000); + return 1; + } p2p_search(p2p); return 1; } @@ -3250,6 +3350,16 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx) /* Check if we timed out waiting for PD req */ if (p2p->pending_action_state == P2P_PENDING_PD) p2p_timeout_prov_disc_req(p2p); + if (p2p->search_delay && !p2p->in_search_delay) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay " + "search operation by %u ms", + p2p->search_delay); + p2p->in_search_delay = 1; + p2p_set_timeout(p2p, p2p->search_delay / 1000, + (p2p->search_delay % 1000) * 1000); + break; + } + p2p->in_search_delay = 0; p2p_search(p2p); break; case P2P_CONNECT: @@ -3295,6 +3405,8 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx) break; case P2P_SEARCH_WHEN_READY: break; + case P2P_CONTINUE_SEARCH_WHEN_READY: + break; } } @@ -3478,6 +3590,24 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info, pos += res; } +#ifdef CONFIG_WIFI_DISPLAY + if (dev->info.wfd_subelems) { + res = os_snprintf(pos, end - pos, "wfd_subelems="); + if (res < 0 || res >= end - pos) + return pos - buf; + pos += res; + + pos += wpa_snprintf_hex(pos, end - pos, + wpabuf_head(dev->info.wfd_subelems), + wpabuf_len(dev->info.wfd_subelems)); + + res = os_snprintf(pos, end - pos, "\n"); + if (res < 0 || res >= end - pos) + return pos - buf; + pos += res; + } +#endif /* CONFIG_WIFI_DISPLAY */ + return pos - buf; } @@ -4085,5 +4215,150 @@ int p2p_in_progress(struct p2p_data *p2p) { if (p2p == NULL) return 0; + if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY || + p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) + return 2; return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING; } + + +void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout, + u8 client_timeout) +{ + if (p2p) { + p2p->go_timeout = go_timeout; + p2p->client_timeout = client_timeout; + } +} + + +void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay) +{ + if (p2p && p2p->search_delay < delay) + p2p->search_delay = delay; +} + + +#ifdef CONFIG_WIFI_DISPLAY + +static void p2p_update_wfd_ie_groups(struct p2p_data *p2p) +{ + size_t g; + struct p2p_group *group; + + for (g = 0; g < p2p->num_groups; g++) { + group = p2p->groups[g]; + p2p_group_update_ies(group); + } +} + + +int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie) +{ + wpabuf_free(p2p->wfd_ie_beacon); + p2p->wfd_ie_beacon = ie; + p2p_update_wfd_ie_groups(p2p); + return 0; +} + + +int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie) +{ + wpabuf_free(p2p->wfd_ie_probe_req); + p2p->wfd_ie_probe_req = ie; + return 0; +} + + +int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie) +{ + wpabuf_free(p2p->wfd_ie_probe_resp); + p2p->wfd_ie_probe_resp = ie; + p2p_update_wfd_ie_groups(p2p); + return 0; +} + + +int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie) +{ + wpabuf_free(p2p->wfd_ie_assoc_req); + p2p->wfd_ie_assoc_req = ie; + return 0; +} + + +int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie) +{ + wpabuf_free(p2p->wfd_ie_invitation); + p2p->wfd_ie_invitation = ie; + return 0; +} + + +int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie) +{ + wpabuf_free(p2p->wfd_ie_prov_disc_req); + p2p->wfd_ie_prov_disc_req = ie; + return 0; +} + + +int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie) +{ + wpabuf_free(p2p->wfd_ie_prov_disc_resp); + p2p->wfd_ie_prov_disc_resp = ie; + return 0; +} + + +int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie) +{ + wpabuf_free(p2p->wfd_ie_go_neg); + p2p->wfd_ie_go_neg = ie; + return 0; +} + + +int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem) +{ + wpabuf_free(p2p->wfd_dev_info); + if (elem) { + p2p->wfd_dev_info = wpabuf_dup(elem); + if (p2p->wfd_dev_info == NULL) + return -1; + } else + p2p->wfd_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); + if (elem) { + p2p->wfd_assoc_bssid = wpabuf_dup(elem); + if (p2p->wfd_assoc_bssid == NULL) + return -1; + } else + p2p->wfd_assoc_bssid = NULL; + + return 0; +} + + +int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p, + const struct wpabuf *elem) +{ + wpabuf_free(p2p->wfd_coupled_sink_info); + if (elem) { + p2p->wfd_coupled_sink_info = wpabuf_dup(elem); + if (p2p->wfd_coupled_sink_info == NULL) + return -1; + } else + p2p->wfd_coupled_sink_info = NULL; + + return 0; +} + +#endif /* CONFIG_WIFI_DISPLAY */ |