From 5bf9a6c8595fa1aef20e3f45fcd7906fa216a002 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 1 Sep 2013 21:28:16 +0300 Subject: [PATCH] P2P: Add event messages for possible PSK failures on P2P groups 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=" event is used to indicate when this happens. This makes it easier for upper layers to remove the persistent group information with "REMOVE_NETWORK " 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 --- src/common/wpa_ctrl.h | 1 + wpa_supplicant/events.c | 2 ++ wpa_supplicant/p2p_supplicant.c | 49 ++++++++++++++++++++++++++++++- wpa_supplicant/p2p_supplicant.h | 6 ++++ wpa_supplicant/wpa_supplicant_i.h | 1 + 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 6e7d11bcd..81c4c2709 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -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: */ #define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT " diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index e9399fef5..69e40302c 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -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 && diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 62d3b64e4..c0e8651c0 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -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; +} diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 5c39a17b6..c718fba88 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -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 */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index ac22c3195..d69cd61c9 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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;