From 755d4e55c2253dc342a232aff725843fcfa727df Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Mon, 22 Jan 2018 15:55:08 +0100 Subject: [PATCH] iwd: simple periodic scanning Add very simple periodic scanning because IWD itself only does periodic scanning when it is in charge of autoconnecting (by policy). Since we keep IWD out of the autoconnect state in order to use NM's autoconnect logic, we need to request the scanning. The policy in this patch is to use a simple 10s period between the end of one scan the requesting of another while not connected, and 20s when connected. This is so that users can expect similar results from both wifi backends but without duplicating the more elaborate code in the wpa_supplicant backend which can potentially be moved to a common superclass. --- src/devices/wifi/nm-device-iwd.c | 98 ++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index eaf504cc44..6c54120391 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -75,10 +75,12 @@ typedef struct { GCancellable * cancellable; NMDeviceWifiCapabilities capabilities; NMActRequestGetSecretsCallId *wifi_secrets_id; + guint periodic_scan_id; bool enabled:1; bool can_scan:1; bool can_connect:1; bool scanning:1; + bool scan_requested:1; } NMDeviceIwdPrivate; struct _NMDeviceIwd { @@ -101,6 +103,9 @@ G_DEFINE_TYPE (NMDeviceIwd, nm_device_iwd, NM_TYPE_DEVICE) /*****************************************************************************/ +static void schedule_periodic_scan (NMDeviceIwd *self, + NMDeviceState current_state); + static void _ap_dump (NMDeviceIwd *self, NMLogLevel log_level, @@ -863,6 +868,33 @@ check_scanning_prohibited (NMDeviceIwd *self, gboolean periodic) return prohibited; } +static void +scan_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + NMDeviceIwd *self = user_data; + NMDeviceIwdPrivate *priv; + gs_free_error GError *error = NULL; + + if ( !_nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, + G_VARIANT_TYPE ("()"), &error) + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + priv = NM_DEVICE_IWD_GET_PRIVATE (self); + priv->scan_requested = FALSE; + + /* On success, priv->scanning becomes true right before or right + * after this callback, so the next automatic scan will be + * scheduled when priv->scanning goes back to false. On error, + * schedule a retry now. + */ + if (error && !priv->scanning) { + NMDeviceState state = nm_device_get_state (NM_DEVICE (self)); + + schedule_periodic_scan (self, state); + } +} + static void dbus_request_scan_cb (NMDevice *device, GDBusMethodInvocation *context, @@ -912,8 +944,14 @@ dbus_request_scan_cb (NMDevice *device, } } - g_dbus_proxy_call (priv->dbus_proxy, "Scan", g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + if (!priv->scanning && !priv->scan_requested) { + g_dbus_proxy_call (priv->dbus_proxy, "Scan", + g_variant_new ("()"), + G_DBUS_CALL_FLAGS_NONE, -1, + priv->cancellable, scan_cb, self); + priv->scan_requested = TRUE; + } + g_dbus_method_invocation_return_value (context, NULL); } @@ -1461,6 +1499,45 @@ get_configured_mtu (NMDevice *device, gboolean *out_is_user_config) return mtu; } +static gboolean +periodic_scan_timeout_cb (gpointer user_data) +{ + NMDeviceIwd *self = user_data; + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + + priv->periodic_scan_id = 0; + + if (priv->scanning || priv->scan_requested) + return FALSE; + + g_dbus_proxy_call (priv->dbus_proxy, "Scan", g_variant_new ("()"), + G_DBUS_CALL_FLAGS_NONE, -1, + priv->cancellable, scan_cb, self); + priv->scan_requested = TRUE; + + return FALSE; +} + +static void +schedule_periodic_scan (NMDeviceIwd *self, NMDeviceState current_state) +{ + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + guint interval; + + if (current_state <= NM_DEVICE_STATE_UNAVAILABLE) + return; + + if (current_state == NM_DEVICE_STATE_DISCONNECTED) + interval = 10; + else + interval = 20; + + nm_clear_g_source (&priv->periodic_scan_id); + priv->periodic_scan_id = g_timeout_add_seconds (interval, + periodic_scan_timeout_cb, + self); +} + static void device_state_changed (NMDevice *device, NMDeviceState new_state, @@ -1470,10 +1547,13 @@ device_state_changed (NMDevice *device, NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - if (new_state <= NM_DEVICE_STATE_UNAVAILABLE) + if (new_state <= NM_DEVICE_STATE_UNAVAILABLE) { remove_all_aps (self); - else if (old_state <= NM_DEVICE_STATE_UNAVAILABLE) + nm_clear_g_source (&priv->periodic_scan_id); + } else if (old_state <= NM_DEVICE_STATE_UNAVAILABLE) { update_aps (self); + schedule_periodic_scan (self, new_state); + } switch (new_state) { case NM_DEVICE_STATE_UNMANAGED: @@ -1710,6 +1790,7 @@ static void scanning_changed (NMDeviceIwd *self, gboolean new_scanning) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + NMDeviceState state = nm_device_get_state (NM_DEVICE (self)); if (new_scanning == priv->scanning) return; @@ -1718,8 +1799,12 @@ scanning_changed (NMDeviceIwd *self, gboolean new_scanning) _notify (self, PROP_SCANNING); - if (!priv->scanning) + if (!priv->scanning) { update_aps (self); + + if (!priv->scan_requested) + schedule_periodic_scan (self, state); + } } static void @@ -1779,6 +1864,7 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object) value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Scanning"); priv->scanning = g_variant_get_boolean (value); + priv->scan_requested = FALSE; g_signal_connect (priv->dbus_proxy, "g-properties-changed", G_CALLBACK (properties_changed), self); @@ -1861,6 +1947,8 @@ dispose (GObject *object) nm_clear_g_cancellable (&priv->cancellable); + nm_clear_g_source (&priv->periodic_scan_id); + wifi_secrets_cancel (self); cleanup_association_attempt (self, TRUE);