]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
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 6e7d11bcdc2fe8a56d83a130fa96c3fe4d5873a9..81c4c2709daab9d447eda524e77095e4388fc652 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 e9399fef5f476a4759b300290975a622d96c81fe..69e40302cd41a555e1aa95a1d869f7da28dfbe42 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 62d3b64e4f93d209f76f76991ab2d2db75a6fa48..c0e8651c0eaf38256441d036542d72a4c5d32e08 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 5c39a17b60ba385b26d078bda708a41caeac50e8..c718fba88f7674c13b7705bd26f345d2cbea7718 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 ac22c3195dd34c95eb8f11981c245ee31b3e982d..d69cd61c91ea63699822dc2c663948ccabd67938 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;