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.
This commit is contained in:
Andrew Zaborowski 2018-01-22 15:55:08 +01:00 committed by Thomas Haller
parent 5f1c2e16c9
commit 755d4e55c2

View file

@ -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);