P2P: Allow older scan results to improve p2p_connect-auto robustness
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 8 May 2012 14:13:56 +0000 (17:13 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 8 May 2012 14:38:57 +0000 (17:38 +0300)
Previusly the peer was assumed to not be operating a GO if the BSS entry
for it was not updated in the single scan run started by
p2p_connect-auto. This is not very robust since a scan may miss the peer
if either a Probe Request or Probe Response frame is lost. Improve
robustness by assuming the peer is still operating the GO and starting
the join operation. If the GO is not found during PD-for-join or the
single-channel scans during the join, fall back to GO Negotiation.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

wpa_supplicant/events.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/wpa_supplicant_i.h

index 8031936..e8cf326 100644 (file)
@@ -1131,6 +1131,9 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                        int timeout_sec = wpa_s->scan_interval;
                        int timeout_usec = 0;
 #ifdef CONFIG_P2P
+                       if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
+                               return 0;
+
                        if (wpa_s->p2p_in_provisioning) {
                                /*
                                 * Use shorter wait during P2P Provisioning
index 007d8a3..79c7b65 100644 (file)
@@ -71,6 +71,8 @@ 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);
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+                                       int group_added);
 
 
 static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
@@ -216,7 +218,7 @@ static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
 {
        struct wpa_ssid *ssid;
        char *gtype;
@@ -271,13 +273,16 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
                reason = "";
                break;
        }
-       wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s",
-               wpa_s->ifname, gtype, reason);
+       if (!silent) {
+               wpa_msg(wpa_s->parent, MSG_INFO,
+                       P2P_EVENT_GROUP_REMOVED "%s %s%s",
+                       wpa_s->ifname, gtype, reason);
+       }
 
        if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
                wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
 
-       if (ssid)
+       if (!silent && ssid)
                wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
 
        if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
@@ -547,7 +552,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        if (!success) {
                wpa_msg(wpa_s->parent, MSG_INFO,
                        P2P_EVENT_GROUP_FORMATION_FAILURE);
-               wpas_p2p_group_delete(wpa_s);
+               wpas_p2p_group_delete(wpa_s, 0);
                return;
        }
 
@@ -655,6 +660,13 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
            (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;
+               if (wpa_s->p2p_fallback_to_go_neg) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+                               "during p2p_connect-auto");
+                       wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+                       return;
+               }
+
                wpa_printf(MSG_DEBUG, "P2P: Starting pending "
                           "join-existing-group operation (no ACK for PD "
                           "Req)");
@@ -1877,6 +1889,13 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
 {
        struct wpa_supplicant *wpa_s = ctx;
 
+       if (wpa_s->p2p_fallback_to_go_neg) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto "
+                       "failed - fall back to GO Negotiation");
+               wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+               return;
+       }
+
        wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
                " p2p_dev_addr=" MACSTR " status=%d",
                MAC2STR(peer), status);
@@ -2702,7 +2721,7 @@ static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
 
        bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr);
        if (bss == NULL)
-               return 0;
+               return -1;
        if (bss->last_update_idx < wpa_s->bss_update_idx) {
                wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the "
                           "last scan");
@@ -2741,6 +2760,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
        if (wpa_s->p2p_auto_pd) {
                int join = wpas_p2p_peer_go(wpa_s,
                                            wpa_s->pending_join_dev_addr);
+               if (join < 0)
+                       join = 0;
                wpa_s->p2p_auto_pd = 0;
                wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG;
                wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
@@ -2758,7 +2779,9 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
        }
 
        if (wpa_s->p2p_auto_join) {
-               if (!wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr)) {
+               int join = wpas_p2p_peer_go(wpa_s,
+                                           wpa_s->pending_join_dev_addr);
+               if (join < 0) {
                        wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
                                   "running a GO -> use GO Negotiation");
                        wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
@@ -2770,8 +2793,11 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                        return;
                }
 
-               wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO -> try "
-                          "to join the group");
+               wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> "
+                          "try to join the group", join ? "" :
+                          " in older scan");
+               if (!join)
+                       wpa_s->p2p_fallback_to_go_neg = 1;
        }
 
        freq = p2p_get_oper_freq(wpa_s->global->p2p,
@@ -2986,6 +3012,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
        }
 
        group->p2p_in_provisioning = 1;
+       group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
 
        os_memset(&res, 0, sizeof(res));
        os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
@@ -3072,6 +3099,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        wpa_s->p2p_persistent_id = persistent_id;
        wpa_s->p2p_go_intent = go_intent;
        wpa_s->p2p_connect_freq = freq;
+       wpa_s->p2p_fallback_to_go_neg = 0;
 
        if (pin)
                os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -3564,6 +3592,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
        /* Make sure we are not running find during connection establishment */
        wpas_p2p_stop_find(wpa_s);
 
+       wpa_s->p2p_fallback_to_go_neg = 0;
+
        if (ssid->mode == WPAS_MODE_INFRA)
                return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
 
@@ -3740,6 +3770,7 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 {
        u16 config_methods;
 
+       wpa_s->p2p_fallback_to_go_neg = 0;
        wpa_s->pending_pd_use = NORMAL_PD;
        if (os_strncmp(config_method, "display", 7) == 0)
                config_methods = WPS_CONFIG_DISPLAY;
@@ -4205,7 +4236,7 @@ static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
        wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
                   "group");
        wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
-       wpas_p2p_group_delete(wpa_s);
+       wpas_p2p_group_delete(wpa_s, 0);
 }
 
 
@@ -4285,7 +4316,7 @@ void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
                wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group "
                           "session is ending");
                wpa_s->removal_reason = P2P_GROUP_REMOVAL_GO_ENDING_SESSION;
-               wpas_p2p_group_delete(wpa_s);
+               wpas_p2p_group_delete(wpa_s, 0);
        }
 }
 
@@ -4653,7 +4684,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                        found = 1;
                        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
                                             wpa_s->parent, NULL);
-                       wpas_p2p_group_delete(wpa_s);
+                       wpas_p2p_group_delete(wpa_s, 0);
                        break;
                }
        }
@@ -4675,7 +4706,7 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
        wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
                   "being available anymore");
        wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
-       wpas_p2p_group_delete(wpa_s);
+       wpas_p2p_group_delete(wpa_s, 0);
 }
 
 
@@ -4722,7 +4753,7 @@ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
                return -1;
 
        wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
-       wpas_p2p_group_delete(wpa_s);
+       wpas_p2p_group_delete(wpa_s, 0);
 
        return 0;
 }
@@ -4796,3 +4827,34 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
                return;
        wpas_p2p_add_persistent_group_client(wpa_s, addr);
 }
+
+
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+                                       int group_added)
+{
+       struct wpa_supplicant *group = wpa_s;
+       if (wpa_s->global->p2p_group_formation)
+               group = wpa_s->global->p2p_group_formation;
+       wpa_s = wpa_s->parent;
+       if (group_added)
+               wpas_p2p_group_delete(group, 1);
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
+       wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
+                        wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
+                        0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+                        wpa_s->p2p_persistent_id);
+}
+
+
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->p2p_fallback_to_go_neg ||
+           wpa_s->p2p_in_provisioning <= 5)
+               return 0;
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
+               "fallback to GO Negotiation");
+       wpas_p2p_fallback_to_go_neg(wpa_s, 1);
+
+       return 1;
+}
index 9779aaa..a0d94b6 100644 (file)
@@ -140,5 +140,6 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
                                          size_t ssid_len);
 void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
                                       const u8 *addr);
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
 
 #endif /* P2P_SUPPLICANT_H */
index 7067eec..248c541 100644 (file)
@@ -517,6 +517,7 @@ struct wpa_supplicant {
        unsigned int p2p_auto_join:1;
        unsigned int p2p_auto_pd:1;
        unsigned int p2p_persistent_group:1;
+       unsigned int p2p_fallback_to_go_neg:1;
        int p2p_persistent_id;
        int p2p_go_intent;
        int p2p_connect_freq;