diff --git a/src/netdev.c b/src/netdev.c index e2998284..082bcbbf 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -2748,6 +2748,10 @@ static int netdev_connect_common(struct netdev *netdev, handshake_state_set_authenticator_address(hs, bss->addr); handshake_state_set_supplicant_address(hs, netdev->addr); + if (!wiphy_has_ext_feature(netdev->wiphy, + NL80211_EXT_FEATURE_CAN_REPLACE_PTK0)) + handshake_state_set_no_rekey(hs, true); + if (netdev->sae_sm) sae_start(netdev->sae_sm); else if (netdev->owe) diff --git a/src/station.c b/src/station.c index 2778b8e9..2a2e0921 100644 --- a/src/station.c +++ b/src/station.c @@ -377,6 +377,8 @@ void station_set_scan_results(struct station *station, struct l_queue *bss_list, l_queue_destroy(old_bss_list, bss_free); } +static void station_reconnect(struct station *station); + static void station_handshake_event(struct handshake_state *hs, enum handshake_event event, void *event_data, void *user_data) @@ -397,8 +399,11 @@ static void station_handshake_event(struct handshake_state *hs, case HANDSHAKE_EVENT_FAILED: netdev_handshake_failed(hs, l_get_u16(event_data)); break; - case HANDSHAKE_EVENT_SETTING_KEYS_FAILED: + case HANDSHAKE_EVENT_REKEY_FAILED: + station_reconnect(station); + break; case HANDSHAKE_EVENT_COMPLETE: + case HANDSHAKE_EVENT_SETTING_KEYS_FAILED: /* * currently we dont care about any other events. The * netdev_connect_cb will notify us when the connection is @@ -1811,6 +1816,42 @@ static struct l_dbus_message *station_dbus_connect_hidden_network( return NULL; } +static void station_disconnect_reconnect_cb(struct netdev *netdev, bool success, + void *user_data) +{ + struct station *station = user_data; + struct handshake_state *hs; + int r; + + hs = station_handshake_setup(station, station->connected_network, + station->connected_bss); + if (!hs) + goto error; + + r = netdev_connect(station->netdev, station->connected_bss, hs, + station_netdev_event, station_connect_cb, + station); + if (r < 0) + goto error; + + return; + +error: + station_disconnect(station); +} + +static void station_reconnect(struct station *station) +{ + /* + * Rather than doing 4 or so state changes, lets just go into + * roaming for the duration of this reconnect. + */ + station_enter_state(station, STATION_STATE_ROAMING); + + netdev_disconnect(station->netdev, station_disconnect_reconnect_cb, + station); +} + static void station_disconnect_cb(struct netdev *netdev, bool success, void *user_data) {