From a2354f88a6798a86676a6d62549dc86a44142b3f Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 25 Jan 2019 11:23:12 -0800 Subject: [PATCH] station/netdev: handle rekeying based on driver features A new driver extended feature bit was added signifying if the driver supports PTK replacement/rekeying. During a connect, netdev checks for the driver feature and sets the handshakes 'no_rekey' flag accordingly. At some point the AP will decide to rekey which is handled inside eapol. If no_rekey is unset we rekey as normal and the connection remains open. If we have set no_rekey eapol will emit HANDSHAKE_EVENT_REKEY_FAILED, which is now caught inside station. If this happens our only choice is to fully disconnect and reconnect. --- src/netdev.c | 4 ++++ src/station.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) 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) {