diff --git a/include/NetworkManager.h b/include/NetworkManager.h
index 91076c203..c8d5074a1 100644
--- a/include/NetworkManager.h
+++ b/include/NetworkManager.h
@@ -362,6 +362,9 @@ typedef enum {
/* The device's existing connection was assumed */
NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED,
+ /* The supplicant is now available */
+ NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
+
/* Unused */
NM_DEVICE_STATE_REASON_LAST = 0xFFFF
} NMDeviceStateReason;
diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml
index 3dbb6e229..a8362acba 100644
--- a/introspection/nm-device.xml
+++ b/introspection/nm-device.xml
@@ -380,6 +380,11 @@
The device's existing connection was assumed.
+
+
+
+ The 802.1x supplicant is now available.
+
diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c
index bb94c35b8..508ff6a44 100644
--- a/src/modem-manager/nm-modem.c
+++ b/src/modem-manager/nm-modem.c
@@ -38,8 +38,6 @@ typedef struct {
guint32 ip_method;
char *device;
- guint state_to_disconnected_id;
-
/* PPP stats */
guint32 in_bytes;
guint32 out_bytes;
@@ -415,15 +413,6 @@ real_get_generic_capabilities (NMDevice *dev)
return NM_DEVICE_CAP_NM_SUPPORTED;
}
-static gboolean
-unavailable_to_disconnected (gpointer user_data)
-{
- nm_device_state_changed (NM_DEVICE (user_data),
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NONE);
- return FALSE;
-}
-
static void
device_state_changed (NMDeviceInterface *device,
NMDeviceState new_state,
@@ -434,19 +423,6 @@ device_state_changed (NMDeviceInterface *device,
NMModem *self = NM_MODEM (user_data);
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
- /* Remove any previous delayed transition to disconnected */
- if (priv->state_to_disconnected_id) {
- g_source_remove (priv->state_to_disconnected_id);
- priv->state_to_disconnected_id = 0;
- }
-
- /* If transitioning to UNAVAILBLE and we have a carrier, transition to
- * DISCONNECTED because the device is ready to use. Otherwise the carrier-on
- * handler will handle the transition to DISCONNECTED when the carrier is detected.
- */
- if (new_state == NM_DEVICE_STATE_UNAVAILABLE)
- priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, user_data);
-
/* Make sure we don't leave the serial device open */
switch (new_state) {
case NM_DEVICE_STATE_NEED_AUTH:
@@ -601,11 +577,6 @@ finalize (GObject *object)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
- if (priv->state_to_disconnected_id) {
- g_source_remove (priv->state_to_disconnected_id);
- priv->state_to_disconnected_id = 0;
- }
-
if (priv->proxy)
g_object_unref (priv->proxy);
diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c
index d50f4c3a7..0ced44fd2 100644
--- a/src/nm-device-bt.c
+++ b/src/nm-device-bt.c
@@ -51,7 +51,6 @@ typedef struct {
char *name;
guint32 capabilities;
- guint state_to_disconnected_id;
DBusGProxy *type_proxy;
NMPPPManager *ppp_manager;
@@ -715,55 +714,6 @@ nm_device_bt_init (NMDeviceBt *self)
{
}
-static gboolean
-unavailable_to_disconnected (gpointer user_data)
-{
- nm_device_state_changed (NM_DEVICE (user_data),
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NONE);
- return FALSE;
-}
-
-static void
-device_state_changed (NMDeviceInterface *device,
- NMDeviceState new_state,
- NMDeviceState old_state,
- NMDeviceStateReason reason,
- gpointer user_data)
-{
- NMDeviceBt *self = NM_DEVICE_BT (user_data);
- NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
-
- /* Remove any previous delayed transition to disconnected */
- if (priv->state_to_disconnected_id) {
- g_source_remove (priv->state_to_disconnected_id);
- priv->state_to_disconnected_id = 0;
- }
-
- /* Transition to DISCONNECTED from an idle handler */
- if (new_state == NM_DEVICE_STATE_UNAVAILABLE)
- priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, self);
-}
-
-static GObject*
-constructor (GType type,
- guint n_construct_params,
- GObjectConstructParam *construct_params)
-{
- GObject *object;
-
- object = G_OBJECT_CLASS (nm_device_bt_parent_class)->constructor (type,
- n_construct_params,
- construct_params);
- if (!object)
- return NULL;
-
- g_signal_connect (NM_DEVICE (object), "state-changed",
- G_CALLBACK (device_state_changed), NM_DEVICE_BT (object));
-
- return object;
-}
-
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
@@ -822,11 +772,6 @@ finalize (GObject *object)
g_free (priv->bdaddr);
g_free (priv->name);
- if (priv->state_to_disconnected_id) {
- g_source_remove (priv->state_to_disconnected_id);
- priv->state_to_disconnected_id = 0;
- }
-
G_OBJECT_CLASS (nm_device_bt_parent_class)->finalize (object);
}
@@ -838,7 +783,6 @@ nm_device_bt_class_init (NMDeviceBtClass *klass)
g_type_class_add_private (object_class, sizeof (NMDeviceBtPrivate));
- object_class->constructor = constructor;
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->finalize = finalize;
diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c
index b1b01204f..2d2e8fbbc 100644
--- a/src/nm-device-ethernet.c
+++ b/src/nm-device-ethernet.c
@@ -106,7 +106,6 @@ typedef struct {
struct ether_addr hw_addr;
gboolean carrier;
guint32 ifindex;
- guint state_to_disconnected_id;
NMNetlinkMonitor * monitor;
gulong link_connected_id;
@@ -242,39 +241,6 @@ carrier_off (NMNetlinkMonitor *monitor,
}
}
-static gboolean
-unavailable_to_disconnected (gpointer user_data)
-{
- nm_device_state_changed (NM_DEVICE (user_data), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
- return FALSE;
-}
-
-static void
-device_state_changed (NMDeviceInterface *device,
- NMDeviceState new_state,
- NMDeviceState old_state,
- NMDeviceStateReason reason,
- gpointer user_data)
-{
- NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
- NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-
- /* Remove any previous delayed transition to disconnected */
- if (priv->state_to_disconnected_id) {
- g_source_remove (priv->state_to_disconnected_id);
- priv->state_to_disconnected_id = 0;
- }
-
- /* If transitioning to UNAVAILBLE and we have a carrier, transition to
- * DISCONNECTED because the device is ready to use. Otherwise the carrier-on
- * handler will handle the transition to DISCONNECTED when the carrier is detected.
- */
- if ((new_state == NM_DEVICE_STATE_UNAVAILABLE) && priv->carrier) {
- priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, self);
- return;
- }
-}
-
static GObject*
constructor (GType type,
guint n_construct_params,
@@ -319,8 +285,6 @@ constructor (GType type,
priv->carrier = TRUE;
}
- g_signal_connect (self, "state-changed", G_CALLBACK (device_state_changed), self);
-
return object;
}
@@ -1698,11 +1662,6 @@ dispose (GObject *object)
priv->monitor = NULL;
}
- if (priv->state_to_disconnected_id) {
- g_source_remove (priv->state_to_disconnected_id);
- priv->state_to_disconnected_id = 0;
- }
-
G_OBJECT_CLASS (nm_device_ethernet_parent_class)->dispose (object);
}
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index eefb1366a..b4cdc4448 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -156,7 +156,6 @@ struct _NMDeviceWifiPrivate {
NMAccessPoint * current_ap;
guint32 rate;
gboolean enabled; /* rfkilled or not */
- guint state_to_disconnected_id;
glong scheduled_scan_time;
guint8 scan_interval; /* seconds */
@@ -2249,6 +2248,15 @@ supplicant_iface_state_cb_handler (gpointer user_data)
/* Request a scan to get latest results */
cancel_pending_scan (self);
request_wireless_scan (self);
+
+ /* If the interface can now be activated because the supplicant is now
+ * available, transition to DISCONNECTED.
+ */
+ if ( (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_UNAVAILABLE)
+ && nm_device_can_activate (NM_DEVICE (self))) {
+ nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE);
+ }
} else if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
cleanup_association_attempt (self, FALSE);
supplicant_interface_release (self);
@@ -3224,15 +3232,6 @@ spec_match_list (NMDevice *device, const GSList *specs)
return matched;
}
-static gboolean
-unavailable_to_disconnected (gpointer user_data)
-{
- nm_device_state_changed (NM_DEVICE (user_data),
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NONE);
- return FALSE;
-}
-
static void
device_state_changed (NMDevice *device,
NMDeviceState new_state,
@@ -3244,12 +3243,6 @@ device_state_changed (NMDevice *device,
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
gboolean clear_aps = FALSE;
- /* Remove any previous delayed transition to disconnected */
- if (priv->state_to_disconnected_id) {
- g_source_remove (priv->state_to_disconnected_id);
- priv->state_to_disconnected_id = 0;
- }
-
if (new_state <= NM_DEVICE_STATE_UNAVAILABLE) {
/* Clean up the supplicant interface because in these states the
* device cannot be used.
@@ -3276,9 +3269,6 @@ device_state_changed (NMDevice *device,
if (!priv->supplicant.iface)
supplicant_interface_acquire (self);
-
- if (priv->supplicant.iface)
- priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, self);
}
clear_aps = TRUE;
break;
@@ -3459,11 +3449,6 @@ dispose (GObject *object)
set_current_ap (self, NULL);
remove_all_aps (self);
- if (priv->state_to_disconnected_id) {
- g_source_remove (priv->state_to_disconnected_id);
- priv->state_to_disconnected_id = 0;
- }
-
G_OBJECT_CLASS (nm_device_wifi_parent_class)->dispose (object);
}
diff --git a/src/nm-device.c b/src/nm-device.c
index f2367163c..d5a1b55c1 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -77,6 +77,7 @@ typedef struct {
NMDeviceState state;
guint failed_to_disconnected_id;
+ guint unavailable_to_disconnected_id;
char * udi;
char * path;
@@ -1960,6 +1961,21 @@ clear_act_request (NMDevice *self)
priv->act_request = NULL;
}
+static void
+delayed_transitions_clear (NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ if (priv->failed_to_disconnected_id) {
+ g_source_remove (priv->failed_to_disconnected_id);
+ priv->failed_to_disconnected_id = 0;
+ }
+ if (priv->unavailable_to_disconnected_id) {
+ g_source_remove (priv->unavailable_to_disconnected_id);
+ priv->unavailable_to_disconnected_id = 0;
+ }
+}
+
/*
* nm_device_deactivate_quickly
*
@@ -1981,10 +1997,8 @@ nm_device_deactivate_quickly (NMDevice *self)
activation_source_clear (self, TRUE, AF_INET);
activation_source_clear (self, TRUE, AF_INET6);
- if (priv->failed_to_disconnected_id) {
- g_source_remove (priv->failed_to_disconnected_id);
- priv->failed_to_disconnected_id = 0;
- }
+ /* Clear any delayed transitions */
+ delayed_transitions_clear (self);
/* Stop any ongoing DHCP transaction on this device */
if (nm_device_get_act_request (self)) {
@@ -2723,10 +2737,8 @@ dispose (GObject *object)
}
}
- if (priv->failed_to_disconnected_id) {
- g_source_remove (priv->failed_to_disconnected_id);
- priv->failed_to_disconnected_id = 0;
- }
+ /* Clear any delayed transitions */
+ delayed_transitions_clear (self);
if (priv->managed && take_down) {
NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;
@@ -2985,6 +2997,17 @@ failed_to_disconnected (gpointer user_data)
return FALSE;
}
+static gboolean
+unavailable_to_disconnected (gpointer user_data)
+{
+ NMDevice *self = NM_DEVICE (user_data);
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ priv->unavailable_to_disconnected_id = 0;
+ nm_device_state_changed (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
+ return FALSE;
+}
+
void
nm_device_state_changed (NMDevice *device,
NMDeviceState state,
@@ -3006,10 +3029,8 @@ nm_device_state_changed (NMDevice *device,
nm_info ("(%s): device state change: %d -> %d (reason %d)",
nm_device_get_iface (device), old_state, state, reason);
- if (priv->failed_to_disconnected_id) {
- g_source_remove (priv->failed_to_disconnected_id);
- priv->failed_to_disconnected_id = 0;
- }
+ /* Clear any delayed transitions */
+ delayed_transitions_clear (device);
/* Cache the activation request for the dispatcher */
req = priv->act_request ? g_object_ref (priv->act_request) : NULL;
@@ -3049,12 +3070,26 @@ nm_device_state_changed (NMDevice *device,
/* Post-process the event after internal notification */
switch (state) {
+ case NM_DEVICE_STATE_UNAVAILABLE:
+ /* If the device can activate now (ie, it's got a carrier, the supplicant
+ * is active, or whatever) schedule a delayed transition to DISCONNECTED
+ * to get things rolling. The device can't transition immediately becuase
+ * we can't change states again from the state handler for a variety of
+ * reasons.
+ */
+ if (nm_device_can_activate (device))
+ priv->unavailable_to_disconnected_id = g_idle_add (unavailable_to_disconnected, device);
+ break;
case NM_DEVICE_STATE_ACTIVATED:
nm_info ("Activation (%s) successful, device activated.", nm_device_get_iface (device));
nm_utils_call_dispatcher ("up", nm_act_request_get_connection (req), device, NULL);
break;
case NM_DEVICE_STATE_FAILED:
nm_info ("Activation (%s) failed.", nm_device_get_iface (device));
+ /* Schedule the transition to DISCONNECTED. The device can't transition
+ * immediately becuase we can't change states again from the state
+ * handler for a variety of reasons.
+ */
priv->failed_to_disconnected_id = g_idle_add (failed_to_disconnected, device);
break;
default: