summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Zaborowski <andrew.zaborowski@intel.com>2018-01-22 15:55:08 +0100
committerThomas Haller <thaller@redhat.com>2018-02-09 21:30:46 +0100
commit755d4e55c2253dc342a232aff725843fcfa727df (patch)
tree7e85c9927b6cb1775158c10b2ed825c0b3e77b48
parent5f1c2e16c9cac48de7fa490df08de06080bd7a0c (diff)
downloadNetworkManager-755d4e55c2253dc342a232aff725843fcfa727df.tar.gz
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.
-rw-r--r--src/devices/wifi/nm-device-iwd.c98
1 files 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,
@@ -864,6 +869,33 @@ check_scanning_prohibited (NMDeviceIwd *self, gboolean periodic)
}
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,
NMAuthSubject *subject,
@@ -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);