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=<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>
This commit is contained in:
Jouni Malinen 2013-09-01 21:28:16 +03:00
parent eac8dab87c
commit 5bf9a6c859
5 changed files with 58 additions and 1 deletions

View 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 "

View 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 &&

View 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;
}

View 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 */

View 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;