P2P: Add event messages for possible PSK failures on P2P groups
authorJouni Malinen <j@w1.fi>
Sun, 1 Sep 2013 18:28:16 +0000 (21:28 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 1 Sep 2013 18:35:10 +0000 (21:35 +0300)
It is possible for the GO of a persistent group to change the PSK or
remove a client when per-client PSKs are used and this can happen
without the SSID changing (i.e., the group is still valid, but just not
for a specific client). If the client side of such persistent group ends
up trying to use an invalidated persistent group information, the
connection will fail in 4-way handshake. A new WPS provisioning step is
needed to recover from this.

Detect this type of case based on two 4-way handshake failures when
acting as a P2P client in a persistent group. A new
"P2P-PERSISTENT-PSK-FAIL id=<persistent group id>" event is used to
indicate when this happens. This makes it easier for upper layers to
remove the persistent group information with "REMOVE_NETWORK <persistent
group id>" if desired (e.g., based on user confirmation).

In addition to indicating the error cases for persistent groups, all
this type of PSK failures end up in the client removing the group with
the new reason=PSK_FAILURE information in the P2P-GROUP-REMOVED event.

Signed-hostap: Jouni Malinen <j@w1.fi>

src/common/wpa_ctrl.h
wpa_supplicant/events.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/wpa_supplicant_i.h

index 6e7d11b..81c4c27 100644 (file)
@@ -138,6 +138,7 @@ extern "C" {
 #define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
 #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
 #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
+#define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id="
 
 /* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
 #define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
index e9399fe..69e4030 100644 (file)
@@ -2017,6 +2017,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
        if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
                        "pre-shared key may be incorrect");
+               if (wpas_p2p_4way_hs_failed(wpa_s) > 0)
+                       return; /* P2P group removed */
                wpas_auth_failed(wpa_s);
        }
        if (!wpa_s->disconnected &&
index 62d3b64..c0e8651 100644 (file)
@@ -82,7 +82,8 @@ enum p2p_group_removal_reason {
        P2P_GROUP_REMOVAL_REQUESTED,
        P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
        P2P_GROUP_REMOVAL_UNAVAILABLE,
-       P2P_GROUP_REMOVAL_GO_ENDING_SESSION
+       P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
+       P2P_GROUP_REMOVAL_PSK_FAILURE
 };
 
 
@@ -391,6 +392,9 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
        case P2P_GROUP_REMOVAL_GO_ENDING_SESSION:
                reason = " reason=GO_ENDING_SESSION";
                break;
+       case P2P_GROUP_REMOVAL_PSK_FAILURE:
+               reason = " reason=PSK_FAILURE";
+               break;
        default:
                reason = "";
                break;
@@ -4519,6 +4523,7 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
        wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0);
        if (wpa_s == NULL)
                return -1;
+       wpa_s->p2p_last_4way_hs_fail = NULL;
 
        wpa_supplicant_ap_deinit(wpa_s);
 
@@ -6248,3 +6253,45 @@ void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
        for (w = wpa_s->global->ifaces; w; w = w->next)
                wpas_p2p_remove_client_go(w, peer, iface_addr);
 }
+
+
+int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+       if (ssid == NULL || !ssid->p2p_group)
+               return 0;
+
+       if (wpa_s->p2p_last_4way_hs_fail &&
+           wpa_s->p2p_last_4way_hs_fail == ssid) {
+               u8 go_dev_addr[ETH_ALEN];
+               struct wpa_ssid *persistent;
+
+               if (wpas_p2p_persistent_group(wpa_s, go_dev_addr,
+                                             ssid->ssid,
+                                             ssid->ssid_len) <= 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not determine whether 4-way handshake failures were for a persistent group");
+                       goto disconnect;
+               }
+
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Two 4-way handshake failures for a P2P group - go_dev_addr="
+                       MACSTR, MAC2STR(go_dev_addr));
+               persistent = wpas_p2p_get_persistent(wpa_s->parent, go_dev_addr,
+                                                    ssid->ssid,
+                                                    ssid->ssid_len);
+               if (persistent == NULL || persistent->mode != WPAS_MODE_INFRA) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No matching persistent group stored");
+                       goto disconnect;
+               }
+               wpa_msg_global(wpa_s->parent, MSG_INFO,
+                              P2P_EVENT_PERSISTENT_PSK_FAIL "%d",
+                              persistent->id);
+       disconnect:
+               wpa_s->p2p_last_4way_hs_fail = NULL;
+               wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_PSK_FAILURE);
+               return 1;
+       }
+
+       wpa_s->p2p_last_4way_hs_fail = ssid;
+       return 0;
+}
index 5c39a17..c718fba 100644 (file)
@@ -160,10 +160,16 @@ void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
 
 #ifdef CONFIG_P2P
 void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s);
+int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
 #else /* CONFIG_P2P */
 static inline void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
 {
 }
+
+static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
+{
+       return 0;
+}
 #endif /* CONFIG_P2P */
 
 #endif /* P2P_SUPPLICANT_H */
index ac22c31..d69cd61 100644 (file)
@@ -652,6 +652,7 @@ struct wpa_supplicant {
        int p2p_go_intent;
        int p2p_connect_freq;
        struct os_time p2p_auto_started;
+       struct wpa_ssid *p2p_last_4way_hs_fail;
 #endif /* CONFIG_P2P */
 
        struct wpa_ssid *bgscan_ssid;