diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index ffda3bb6f..5cfa9720d 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -62,6 +62,8 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s); static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx); static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr, const u8 *dev_addr, enum p2p_wps_method wps_method); +static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, + void *timeout_ctx); static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s); static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s); static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx); @@ -638,12 +640,14 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res); - if (wpa_s->pending_pd_before_join && + if (result != OFFCHANNEL_SEND_ACTION_SUCCESS && + wpa_s->pending_pd_before_join && (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 || os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) { wpa_s->pending_pd_before_join = 0; wpa_printf(MSG_DEBUG, "P2P: Starting pending " - "join-existing-group operation"); + "join-existing-group operation (no ACK for PD " + "Req)"); wpas_p2p_join_start(wpa_s); } } @@ -2408,6 +2412,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s) wpa_s->go_params = NULL; eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); + eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL); wpa_s->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); @@ -2542,6 +2547,21 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s) } +static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + if (!wpa_s->pending_pd_before_join) + return; + /* + * Provision Discovery Response may have been lost - try to connect + * anyway since we do not need any information from this PD. + */ + wpa_printf(MSG_DEBUG, "P2P: PD timeout for join-existing-group - " + "try to connect anyway"); + wpas_p2p_join_start(wpa_s); +} + + static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { @@ -2640,8 +2660,15 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, /* * Actual join operation will be started from the Action frame - * TX status callback. + * TX status callback (if no ACK is received) or when the + * Provision Discovery Response is received. Use a short + * timeout as a backup mechanism should the Provision Discovery + * Response be lost for any reason. */ + eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, + NULL); + eloop_register_timeout(2, 0, wpas_p2p_pd_before_join_timeout, + wpa_s, NULL); return; } @@ -2740,6 +2767,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) struct wpa_supplicant *group; struct p2p_go_neg_results res; + eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL); group = wpas_p2p_get_group_iface(wpa_s, 0, 0); if (group == NULL) return -1;