diff --git a/src/handshake.c b/src/handshake.c index 60ec0969..734e997c 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -107,6 +107,11 @@ void handshake_state_free(struct handshake_state *s) { __typeof__(s->free) destroy = s->free; + if (s->in_event) { + s->in_event = false; + return; + } + l_free(s->authenticator_ie); l_free(s->supplicant_ie); l_free(s->authenticator_rsnxe); diff --git a/src/handshake.h b/src/handshake.h index 6d56dadd..34d4829d 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -159,17 +159,29 @@ struct handshake_state { void *user_data; void (*free)(struct handshake_state *s); + bool in_event; handshake_event_func_t event_func; }; -#define handshake_event(hs, event, ...) \ - do { \ - if (!(hs)->event_func) \ - break; \ +#define handshake_event(_hs, event, ...) \ + (__extension__ ({ \ + struct handshake_state *hs = (_hs); \ + bool freed = false; \ \ - (hs)->event_func((hs), event, (hs)->user_data, ##__VA_ARGS__); \ - } while (0) + if (hs->event_func && !hs->in_event) { \ + hs->in_event = true; \ + hs->event_func(hs, event, hs->user_data, \ + ##__VA_ARGS__); \ + \ + if (!hs->in_event) { \ + handshake_state_free(hs); \ + freed = true; \ + } else \ + hs->in_event = false; \ + } \ + freed; \ + })) void handshake_state_free(struct handshake_state *s); diff --git a/src/netdev.c b/src/netdev.c index b311c0ee..4dc9ce94 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -1482,7 +1482,9 @@ static void try_handshake_complete(struct netdev_handshake_state *nhs) if (nhs->ptk_installed && nhs->gtk_installed && nhs->igtk_installed && !nhs->complete) { nhs->complete = true; - handshake_event(&nhs->super, HANDSHAKE_EVENT_COMPLETE); + + if (handshake_event(&nhs->super, HANDSHAKE_EVENT_COMPLETE)) + return; if (nhs->netdev->type == NL80211_IFTYPE_STATION || nhs->netdev->type == NL80211_IFTYPE_P2P_CLIENT) @@ -2006,7 +2008,9 @@ static void netdev_group_timeout_cb(struct l_timeout *timeout, void *user_data) nhs->netdev->index); nhs->complete = true; - handshake_event(&nhs->super, HANDSHAKE_EVENT_COMPLETE); + + if (handshake_event(&nhs->super, HANDSHAKE_EVENT_COMPLETE)) + return; netdev_connect_ok(nhs->netdev); } @@ -2155,7 +2159,9 @@ static void netdev_set_pmk_cb(struct l_genl_msg *msg, void *user_data) return; } - handshake_event(netdev->handshake, HANDSHAKE_EVENT_SETTING_KEYS); + if (handshake_event(netdev->handshake, HANDSHAKE_EVENT_SETTING_KEYS)) + return; + netdev_connect_ok(netdev); } @@ -2906,8 +2912,8 @@ process_resp_ies: } /* Allow station to sync the PSK to disk */ - if (is_offload(hs)) - handshake_event(hs, HANDSHAKE_EVENT_SETTING_KEYS); + if (is_offload(hs) && handshake_event(hs, HANDSHAKE_EVENT_SETTING_KEYS)) + return; netdev_connect_ok(netdev); return;