NetworkManager r3819 - in trunk: . include introspection libnm-glib marshallers src src/vpn-manager



Author: tambeti
Date: Fri Jul 11 10:28:53 2008
New Revision: 3819
URL: http://svn.gnome.org/viewvc/NetworkManager?rev=3819&view=rev

Log:
2008-07-11  Dan Williams  <dcbw redhat com>

	Modify the NMDevice::state-changed signal to include the previous state
	and reason. Enables the applet to provide more information why device
	activation failed.


Modified:
   trunk/ChangeLog
   trunk/include/NetworkManager.h
   trunk/introspection/nm-device.xml
   trunk/libnm-glib/nm-device.c
   trunk/libnm-glib/nm-device.h
   trunk/marshallers/nm-marshal.list
   trunk/src/NetworkManagerPolicy.c
   trunk/src/nm-activation-request.c
   trunk/src/nm-cdma-device.c
   trunk/src/nm-device-ethernet.c
   trunk/src/nm-device-interface.c
   trunk/src/nm-device-interface.h
   trunk/src/nm-device-private.h
   trunk/src/nm-device-wifi.c
   trunk/src/nm-device.c
   trunk/src/nm-device.h
   trunk/src/nm-gsm-device.c
   trunk/src/nm-manager.c
   trunk/src/nm-serial-device.c
   trunk/src/vpn-manager/nm-vpn-connection.c

Modified: trunk/include/NetworkManager.h
==============================================================================
--- trunk/include/NetworkManager.h	(original)
+++ trunk/include/NetworkManager.h	Fri Jul 11 10:28:53 2008
@@ -212,6 +212,108 @@
 } NMDeviceState;
 
 
+/*
+ * Device state change reason codes
+ */
+typedef enum {
+	/* No reason given */
+	NM_DEVICE_STATE_REASON_NONE = 0,
+
+	/* Unknown error */
+	NM_DEVICE_STATE_REASON_UNKNOWN,
+
+	/* Device is now managed */
+	NM_DEVICE_STATE_REASON_NOW_MANAGED,
+
+	/* Device is now managed unmanaged */
+	NM_DEVICE_STATE_REASON_NOW_UNMANAGED,
+
+	/* The device could not be readied for configuration */
+	NM_DEVICE_STATE_REASON_CONFIG_FAILED,
+
+	/* IP configuration could not be reserved (no available address, timeout, etc) */
+	NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE,
+
+	/* The IP config is no longer valid */
+	NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED,
+
+	/* Secrets were required, but not provided */
+	NM_DEVICE_STATE_REASON_NO_SECRETS,
+
+	/* 802.1x supplicant disconnected */
+	NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT,
+
+	/* 802.1x supplicant configuration failed */
+	NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED,
+
+	/* 802.1x supplicant failed */
+	NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED,
+
+	/* 802.1x supplicant took too long to authenticate */
+	NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT,
+
+	/* PPP service failed to start */
+	NM_DEVICE_STATE_REASON_PPP_START_FAILED,
+
+	/* PPP service disconnected */
+	NM_DEVICE_STATE_REASON_PPP_DISCONNECT,
+
+	/* PPP failed */
+	NM_DEVICE_STATE_REASON_PPP_FAILED,
+
+	/* DHCP client failed to start */
+	NM_DEVICE_STATE_REASON_DHCP_START_FAILED,
+
+	/* DHCP client error */
+	NM_DEVICE_STATE_REASON_DHCP_ERROR,
+
+	/* DHCP client failed */
+	NM_DEVICE_STATE_REASON_DHCP_FAILED,
+
+	/* Shared connection service failed to start */
+	NM_DEVICE_STATE_REASON_SHARED_START_FAILED,
+
+	/* AutoIP service failed to start */
+	NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED,
+
+	/* AutoIP service error */
+	NM_DEVICE_STATE_REASON_AUTOIP_ERROR,
+
+	/* AutoIP service failed */
+	NM_DEVICE_STATE_REASON_AUTOIP_FAILED,
+
+	/* The line is busy */
+	NM_DEVICE_STATE_REASON_MODEM_BUSY,
+
+	/* No dial tone */
+	NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE,
+
+	/* No carrier could be established */
+	NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER,
+
+	/* The dialing request timed out */
+	NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT,
+
+	/* The dialing attempt failed */
+	NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED,
+
+	/* Modem initialization failed */
+	NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED,
+
+	/* Failed to select the specified APN */
+	NM_DEVICE_STATE_REASON_GSM_APN_FAILED,
+
+	/* Failed to register with the requested network */
+	NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED,
+
+	/* PIN check failed */
+	NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED,
+
+	/* Unused */
+	NM_DEVICE_STATE_REASON_LAST = 0xFFFF
+} NMDeviceStateReason;
+
+
 typedef enum {
 	NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0,
 
@@ -222,6 +324,5 @@
 	NM_ACTIVE_CONNECTION_STATE_ACTIVATED
 } NMActiveConnectionState;
 
-
 #endif /* NETWORK_MANAGER_H */
 

Modified: trunk/introspection/nm-device.xml
==============================================================================
--- trunk/introspection/nm-device.xml	(original)
+++ trunk/introspection/nm-device.xml	Fri Jul 11 10:28:53 2008
@@ -52,11 +52,21 @@
 
 
     <signal name="StateChanged">
-      <arg name="state" type="u" tp:type="NM_DEVICE_STATE">
+      <arg name="new-state" type="u" tp:type="NM_DEVICE_STATE">
         <tp:docstring>
           The new state of the device.
         </tp:docstring>
       </arg>
+      <arg name="old-state" type="u" tp:type="NM_DEVICE_STATE">
+        <tp:docstring>
+          The previous state of the device.
+        </tp:docstring>
+      </arg>
+      <arg name="reason" type="u" tp:type="NM_DEVICE_STATE_REASON">
+        <tp:docstring>
+          A reason for the state transition.
+        </tp:docstring>
+      </arg>
     </signal>
 
     <tp:enum name="NM_DEVICE_STATE" type="u">

Modified: trunk/libnm-glib/nm-device.c
==============================================================================
--- trunk/libnm-glib/nm-device.c	(original)
+++ trunk/libnm-glib/nm-device.c	Fri Jul 11 10:28:53 2008
@@ -9,6 +9,7 @@
 #include "nm-device-private.h"
 #include "nm-object-private.h"
 #include "nm-object-cache.h"
+#include "nm-marshal.h"
 
 #include "nm-device-bindings.h"
 
@@ -47,6 +48,14 @@
 	LAST_PROP
 };
 
+enum {
+	STATE_CHANGED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 
 static void
 nm_device_init (NMDevice *device)
@@ -108,7 +117,6 @@
 		{ NM_DEVICE_CAPABILITIES, nm_object_demarshal_generic, &priv->capabilities },
 		{ NM_DEVICE_MANAGED,      nm_object_demarshal_generic, &priv->managed },
 		{ NM_DEVICE_IP4_CONFIG,   demarshal_ip4_config,        &priv->ip4_config },
-		{ NM_DEVICE_STATE,        nm_object_demarshal_generic, &priv->state },
 		{ NULL },
 	};
 
@@ -117,6 +125,23 @@
 	                                     property_changed_info);
 }
 
+static void
+device_state_changed (DBusGProxy *proxy,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
+{
+	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+	if (priv->state != new_state) {
+		priv->state = new_state;
+		g_signal_emit (self, signals[STATE_CHANGED], 0, new_state, old_state, reason);
+		nm_object_queue_notify (NM_OBJECT (self), "state");
+	}
+}
+
 static GObject*
 constructor (GType type,
 			 guint n_construct_params,
@@ -140,6 +165,21 @@
 
 	register_for_property_changed (NM_DEVICE (object));
 
+	dbus_g_object_register_marshaller (nm_marshal_VOID__UINT_UINT_UINT,
+									   G_TYPE_NONE,
+									   G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
+									   G_TYPE_INVALID);
+
+	dbus_g_proxy_add_signal (priv->proxy,
+	                         "StateChanged",
+	                         G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
+	                         G_TYPE_INVALID);
+
+	dbus_g_proxy_connect_signal (priv->proxy, "StateChanged",
+								 G_CALLBACK (device_state_changed),
+								 NM_DEVICE (object),
+								 NULL);
+
 	return G_OBJECT (object);
 }
 
@@ -303,6 +343,17 @@
 						  "Product string",
 						  NULL,
 						  G_PARAM_READABLE));
+
+	/* signals */
+	signals[STATE_CHANGED] =
+		g_signal_new ("state-changed",
+				    G_OBJECT_CLASS_TYPE (object_class),
+				    G_SIGNAL_RUN_FIRST,
+				    G_STRUCT_OFFSET (NMDeviceClass, state_changed),
+				    NULL, NULL,
+				    nm_marshal_VOID__UINT_UINT_UINT,
+				    G_TYPE_NONE, 3,
+				    G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
 }
 
 GObject *

Modified: trunk/libnm-glib/nm-device.h
==============================================================================
--- trunk/libnm-glib/nm-device.h	(original)
+++ trunk/libnm-glib/nm-device.h	Fri Jul 11 10:28:53 2008
@@ -34,6 +34,12 @@
 
 typedef struct {
 	NMObjectClass parent;
+
+	/* Signals */
+	void (*state_changed) (NMDevice *device,
+	                       NMDeviceState new_state,
+	                       NMDeviceState old_state,
+	                       NMDeviceStateReason reason);
 } NMDeviceClass;
 
 GType nm_device_get_type (void);

Modified: trunk/marshallers/nm-marshal.list
==============================================================================
--- trunk/marshallers/nm-marshal.list	(original)
+++ trunk/marshallers/nm-marshal.list	Fri Jul 11 10:28:53 2008
@@ -7,6 +7,7 @@
 VOID:POINTER
 VOID:STRING,STRING,STRING
 VOID:UINT,UINT
+VOID:UINT,UINT,UINT
 VOID:STRING,STRING
 VOID:STRING,UCHAR
 VOID:STRING,OBJECT

Modified: trunk/src/NetworkManagerPolicy.c
==============================================================================
--- trunk/src/NetworkManagerPolicy.c	(original)
+++ trunk/src/NetworkManagerPolicy.c	Fri Jul 11 10:28:53 2008
@@ -515,12 +515,16 @@
 }
 
 static void
-device_state_changed (NMDevice *device, NMDeviceState state, gpointer user_data)
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
 {
 	NMPolicy *policy = (NMPolicy *) user_data;
 	NMConnection *connection = get_device_connection (device);
 
-	switch (state) {
+	switch (new_state) {
 	case NM_DEVICE_STATE_FAILED:
 		/* Mark the connection invalid so it doesn't get automatically chosen */
 		if (connection) {

Modified: trunk/src/nm-activation-request.c
==============================================================================
--- trunk/src/nm-activation-request.c	(original)
+++ trunk/src/nm-activation-request.c	Fri Jul 11 10:28:53 2008
@@ -78,8 +78,46 @@
 	LAST_PROP
 };
 
-static void device_state_changed (NMDevice *device, NMDeviceState state, gpointer user_data);
 
+static void
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
+{
+	NMActRequest *self = NM_ACT_REQUEST (user_data);
+	NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
+	NMActiveConnectionState new_ac_state;
+	gboolean new_default = FALSE;
+
+	/* Set NMActiveConnection state based on the device's state */
+	switch (new_state) {
+	case NM_DEVICE_STATE_PREPARE:
+	case NM_DEVICE_STATE_CONFIG:
+	case NM_DEVICE_STATE_NEED_AUTH:
+	case NM_DEVICE_STATE_IP_CONFIG:
+		new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATING;
+		break;
+	case NM_DEVICE_STATE_ACTIVATED:
+		new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATED;
+		new_default = priv->is_default;
+		break;
+	default:
+		new_ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
+		break;
+	}
+
+	if (new_ac_state != priv->state) {
+		priv->state = new_ac_state;
+		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
+	}
+
+	if (new_default != priv->is_default) {
+		priv->is_default = new_default;
+		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT);
+	}
+}
 
 NMActRequest *
 nm_act_request_new (NMConnection *connection,
@@ -303,42 +341,6 @@
 	nm_active_connection_install_type_info (object_class);
 }
 
-static void
-device_state_changed (NMDevice *device, NMDeviceState state, gpointer user_data)
-{
-	NMActRequest *self = NM_ACT_REQUEST (user_data);
-	NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
-	NMActiveConnectionState new_state;
-	gboolean new_default = FALSE;
-
-	/* Set NMActiveConnection state based on the device's state */
-	switch (state) {
-	case NM_DEVICE_STATE_PREPARE:
-	case NM_DEVICE_STATE_CONFIG:
-	case NM_DEVICE_STATE_NEED_AUTH:
-	case NM_DEVICE_STATE_IP_CONFIG:
-		new_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATING;
-		break;
-	case NM_DEVICE_STATE_ACTIVATED:
-		new_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATED;
-		new_default = priv->is_default;
-		break;
-	default:
-		new_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
-		break;
-	}
-
-	if (new_state != priv->state) {
-		priv->state = new_state;
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
-	}
-
-	if (new_default != priv->is_default) {
-		priv->is_default = new_default;
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT);
-	}
-}
-
 typedef struct GetSecretsInfo {
 	NMActRequest *req;
 	char *setting_name;

Modified: trunk/src/nm-cdma-device.c
==============================================================================
--- trunk/src/nm-cdma-device.c	(original)
+++ trunk/src/nm-cdma-device.c	Fri Jul 11 10:28:53 2008
@@ -81,6 +81,7 @@
            int reply_index,
            gpointer user_data)
 {
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_UNKNOWN;
 	gboolean success = FALSE;
 
 	switch (reply_index) {
@@ -90,15 +91,19 @@
 		break;
 	case 1:
 		nm_info ("Busy");
+		reason = NM_DEVICE_STATE_REASON_MODEM_BUSY;
 		break;
 	case 2:
 		nm_warning ("No dial tone");
+		reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE;
 		break;
 	case 3:
 		nm_warning ("No carrier");
+		reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER;
 		break;
 	case -1:
 		nm_warning ("Dialing timed out");
+		reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT;
 		break;
 	default:
 		nm_warning ("Dialing failed");
@@ -108,7 +113,7 @@
 	if (success)
 		nm_device_activate_schedule_stage2_device_config (NM_DEVICE (device));
 	else
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED, reason);
 }
 
 static void
@@ -127,7 +132,9 @@
 	g_free (command);
 
 	if (id == 0)
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_UNKNOWN);
 }
 
 static void
@@ -141,11 +148,15 @@
 		break;
 	case -1:
 		nm_warning ("Modem initialization timed out");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
 		break;
 	default:
 		nm_warning ("Modem initialization failed");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
 		return;
 	}
 }
@@ -160,11 +171,11 @@
 		id = nm_serial_device_wait_for_reply (device, 10, responses, responses, init_done, NULL);
 
 	if (id == 0)
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN);
 }
 
 static NMActStageReturn
-real_act_stage1_prepare (NMDevice *device)
+real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 {
 	NMSerialDevice *serial_device = NM_SERIAL_DEVICE (device);
 	NMSettingSerial *setting;
@@ -172,10 +183,14 @@
 
 	setting = NM_SETTING_SERIAL (cdma_device_get_setting (NM_CDMA_DEVICE (device), NM_TYPE_SETTING_SERIAL));
 
-	if (!nm_serial_device_open (serial_device, setting))
+	if (!nm_serial_device_open (serial_device, setting)) {
+		*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
 		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
 
 	id = nm_serial_device_flash (serial_device, 100, init_modem, NULL);
+	if (!id)
+		*reason = NM_DEVICE_STATE_REASON_UNKNOWN;
 
 	return id ? NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE;
 }
@@ -352,12 +367,18 @@
 static gboolean
 unavailable_to_disconnected (gpointer user_data)
 {
-	nm_device_state_changed (NM_DEVICE (user_data), NM_DEVICE_STATE_DISCONNECTED);
+	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 state, gpointer user_data)
+device_state_changed (NMDeviceInterface *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
 {
 	NMCdmaDevice *self = NM_CDMA_DEVICE (user_data);
 	NMCdmaDevicePrivate *priv = NM_CDMA_DEVICE_GET_PRIVATE (self);
@@ -372,11 +393,11 @@
 	 * 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 (state == NM_DEVICE_STATE_UNAVAILABLE)
+	if (new_state == NM_DEVICE_STATE_UNAVAILABLE)
 		priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, self);
 
 	/* Make sure we don't leave the serial device open */
-	switch (state) {
+	switch (new_state) {
 	case NM_DEVICE_STATE_NEED_AUTH:
 	case NM_DEVICE_STATE_UNMANAGED:
 	case NM_DEVICE_STATE_UNAVAILABLE:

Modified: trunk/src/nm-device-ethernet.c
==============================================================================
--- trunk/src/nm-device-ethernet.c	(original)
+++ trunk/src/nm-device-ethernet.c	Fri Jul 11 10:28:53 2008
@@ -176,10 +176,10 @@
 nm_info ("(%s): carrier now %s (device state %d)", nm_device_get_iface (NM_DEVICE (self)), carrier ? "ON" : "OFF", state);
 	if (state == NM_DEVICE_STATE_UNAVAILABLE) {
 		if (carrier)
-			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED);
+			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
 	} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
 		if (!carrier)
-			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE);
+			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NONE);
 	}
 }
 
@@ -224,12 +224,16 @@
 static gboolean
 unavailable_to_disconnected (gpointer user_data)
 {
-	nm_device_state_changed (NM_DEVICE (user_data), NM_DEVICE_STATE_DISCONNECTED);
+	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 state, gpointer user_data)
+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);
@@ -244,7 +248,7 @@
 	 * 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 ((state == NM_DEVICE_STATE_UNAVAILABLE) && priv->carrier) {
+	if ((new_state == NM_DEVICE_STATE_UNAVAILABLE) && priv->carrier) {
 		priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, self);
 		return;
 	}
@@ -714,7 +718,8 @@
 	req = nm_device_get_act_request (dev);
 
 	if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
-		nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED);
+		nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED,
+		                         NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
 		return FALSE;
 	}
 
@@ -731,11 +736,11 @@
 	if (!setting_name)
 		goto time_out;
 
-	nm_info ("Activation (%s/wired): disconnected during association,"
+	nm_info ("Activation (%s/wired): disconnected during authentication,"
 	         " asking for new key.", nm_device_get_iface (dev));
 	supplicant_interface_clean (self);
 
-	nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH);
+	nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
 	nm_act_request_request_connection_secrets (req, setting_name, TRUE,
 	                                           SECRETS_CALLER_ETHERNET, NULL, NULL);
 
@@ -743,7 +748,7 @@
 
 time_out:
 	nm_info ("%s: link timed out.", nm_device_get_iface (dev));
-	nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED);
+	nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
 
 	return FALSE;
 }
@@ -779,15 +784,16 @@
 supplicant_mgr_state_cb_handler (gpointer user_data)
 {
 	struct state_cb_data *info = (struct state_cb_data *) user_data;
+	NMDevice *device = NM_DEVICE (info->self);
 
 	/* If the supplicant went away, release the supplicant interface */
 	if (info->new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
-		NMDevice *dev = NM_DEVICE (info->self);
-
 		supplicant_interface_clean (info->self);
 
-		if (nm_device_is_activating (dev))
-			nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED);
+		if (nm_device_get_state (device) > NM_DEVICE_STATE_UNAVAILABLE) {
+			nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE,
+			                         NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+		}
 	}
 
 	g_slice_free (struct state_cb_data, info);
@@ -816,7 +822,7 @@
 {
 	DBusGProxy *proxy;
 	const char *con_path;
-	NMSupplicantConfig *config;
+	NMSupplicantConfig *config = NULL;
 	NMSetting8021x *security;
 	NMConnection *connection;
 
@@ -829,31 +835,30 @@
 		return NULL;
 
 	security = NM_SETTING_802_1X (nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X));
-	if (nm_supplicant_config_add_setting_8021x (config, security, con_path, TRUE))
-		return config;
-
-	nm_warning ("Couldn't add 802.1X security setting to supplicant config.");
-	g_object_unref (config);
+	if (!nm_supplicant_config_add_setting_8021x (config, security, con_path, TRUE)) {
+		nm_warning ("Couldn't add 802.1X security setting to supplicant config.");
+		g_object_unref (config);
+		config = NULL;
+	}
 
-	return NULL;
+	return config;
 }
 
 static gboolean
 supplicant_iface_state_cb_handler (gpointer user_data)
 {
 	struct state_cb_data *info = (struct state_cb_data *) user_data;
-	NMDevice *dev = NM_DEVICE (info->self);
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (info->self);
+	NMDevice *device = NM_DEVICE (info->self);
 
 	if (info->new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
 		NMSupplicantConfig *config;
 		const char *iface;
 		gboolean success = FALSE;
 
-		iface = nm_device_get_iface (NM_DEVICE (info->self));
+		iface = nm_device_get_iface (device);
 		config = build_supplicant_config (info->self);
 		if (config) {
-			NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (info->self);
-
 			success = nm_supplicant_interface_set_config (priv->supplicant.iface, config);
 			g_object_unref (config);
 
@@ -864,14 +869,14 @@
 			nm_warning ("Activation (%s/wired): couldn't build security configuration.", iface);
 
 		if (!success)
-			nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED);
-	}
+			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
+	} else if (info->new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
+		NMDeviceState state = nm_device_get_state (device);
 
-	else if (info->new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
 		supplicant_interface_clean (info->self);
 
-		if (nm_device_is_activating (dev))
-			nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED);
+		if (nm_device_is_activating (device) || state == NM_DEVICE_STATE_ACTIVATED)
+			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
 	}
 
 	g_slice_free (struct state_cb_data, info);
@@ -951,7 +956,7 @@
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
 
 	supplicant_interface_clean (self);
-	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED);
+	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
 
 	return FALSE;
 }
@@ -986,7 +991,7 @@
 	if (tries > 3)
 		return NM_ACT_STAGE_RETURN_FAILURE;
 
-	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH);
+	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
 
 	nm_connection_clear_secrets (connection);
 	setting_name = nm_connection_need_secrets (connection, NULL);
@@ -1027,7 +1032,7 @@
 	if (handle_auth_or_fail (self, req, TRUE) == NM_ACT_STAGE_RETURN_POSTPONE)
 		nm_info ("Activation (%s/wired): asking for new secrets", iface);
 	else
-		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS);
 
 	return FALSE;
 }
@@ -1079,7 +1084,7 @@
 }
 
 static NMActStageReturn
-nm_8021x_stage2_config (NMDeviceEthernet *self)
+nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason)
 {
 	NMConnection *connection;
 	NMSetting8021x *security;
@@ -1092,6 +1097,7 @@
 	security = NM_SETTING_802_1X (nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X));
 	if (!security) {
 		nm_warning ("Invalid or missing 802.1X security");
+		*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
 		return ret;
 	}
 
@@ -1101,16 +1107,22 @@
 	/* If we need secrets, get them */
 	setting_name = nm_connection_need_secrets (connection, NULL);
 	if (setting_name) {
+		NMActRequest *req = nm_device_get_act_request (NM_DEVICE (self));
+
 		nm_info ("Activation (%s/wired): connection '%s' has security, but secrets are required.",
 			    iface, s_connection->id);
 
-		ret = handle_auth_or_fail (self, nm_device_get_act_request (NM_DEVICE (self)), FALSE);
+		ret = handle_auth_or_fail (self, req, FALSE);
+		if (ret != NM_ACT_STAGE_RETURN_POSTPONE)
+			*reason = NM_DEVICE_STATE_REASON_NO_SECRETS;
 	} else {
 		nm_info ("Activation (%s/wired): connection '%s' requires no security. No secrets needed.",
 			    iface, s_connection->id);
 
 		if (supplicant_interface_init (self))
 			ret = NM_ACT_STAGE_RETURN_POSTPONE;
+		else
+			*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
 	}
 
 	return ret;
@@ -1126,19 +1138,16 @@
 
 	switch (status) {
 	case NM_PPP_STATUS_NETWORK:
-		nm_device_state_changed (device, NM_DEVICE_STATE_IP_CONFIG);
+		nm_device_state_changed (device, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE);
 		break;
 	case NM_PPP_STATUS_DISCONNECT:
-		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_DISCONNECT);
 		break;
 	case NM_PPP_STATUS_DEAD:
-		if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
-			nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED);
-		else
-			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED);
 		break;
 	case NM_PPP_STATUS_AUTHENTICATE:
-		nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH);
+		nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
 		break;
 	default:
 		break;
@@ -1159,12 +1168,12 @@
 }
 
 static NMActStageReturn
-pppoe_stage2_config (NMDeviceEthernet *self)
+pppoe_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 	NMActRequest *req;
 	GError *err = NULL;
-	NMActStageReturn ret;
+	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
 
 	req = nm_device_get_act_request (NM_DEVICE (self));
 	g_assert (req);
@@ -1182,24 +1191,27 @@
 					   self);
 		ret = NM_ACT_STAGE_RETURN_POSTPONE;
 	} else {
-		nm_warning ("%s", err->message);
+		nm_warning ("(%s): PPPoE failed to start: %s",
+		            nm_device_get_iface (NM_DEVICE (self)), err->message);
 		g_error_free (err);
 
 		g_object_unref (priv->ppp_manager);
 		priv->ppp_manager = NULL;
 
-		ret = NM_ACT_STAGE_RETURN_FAILURE;
+		*reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED;
 	}
 
 	return ret;
 }
 
 static NMActStageReturn
-real_act_stage2_config (NMDevice *device)
+real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 {
 	NMSettingConnection *s_connection;
 	NMActStageReturn ret;
 
+	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+
 	s_connection = NM_SETTING_CONNECTION (device_get_setting (device, NM_TYPE_SETTING_CONNECTION));
 	g_assert (s_connection);
 
@@ -1208,13 +1220,14 @@
 
 		security = (NMSetting8021x *) device_get_setting (device, NM_TYPE_SETTING_802_1X);
 		if (security)
-			ret = nm_8021x_stage2_config (NM_DEVICE_ETHERNET (device));
+			ret = nm_8021x_stage2_config (NM_DEVICE_ETHERNET (device), reason);
 		else
 			ret = NM_ACT_STAGE_RETURN_SUCCESS;
 	} else if (!strcmp (s_connection->type, NM_SETTING_PPPOE_SETTING_NAME))
-		ret = pppoe_stage2_config (NM_DEVICE_ETHERNET (device));
+		ret = pppoe_stage2_config (NM_DEVICE_ETHERNET (device), reason);
 	else {
 		nm_warning ("Invalid connection type '%s' for ethernet device", s_connection->type);
+		*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
 		ret = NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
@@ -1222,7 +1235,9 @@
 }
 
 static NMActStageReturn
-real_act_stage4_get_ip4_config (NMDevice *device, NMIP4Config **config)
+real_act_stage4_get_ip4_config (NMDevice *device,
+                                NMIP4Config **config,
+                                NMDeviceStateReason *reason)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
@@ -1235,9 +1250,9 @@
 		/* Regular ethernet connection. */
 
 		/* Chain up to parent */
-		ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage4_get_ip4_config (device, config);
+		ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage4_get_ip4_config (device, config, reason);
 
-		if ((ret == NM_ACT_STAGE_RETURN_SUCCESS)) {
+		if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
 			NMConnection *connection;
 			NMSettingWired *s_wired;
 

Modified: trunk/src/nm-device-interface.c
==============================================================================
--- trunk/src/nm-device-interface.c	(original)
+++ trunk/src/nm-device-interface.c	Fri Jul 11 10:28:53 2008
@@ -1,5 +1,6 @@
 /* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
 
+#include "nm-marshal.h"
 #include "nm-setting-connection.h"
 #include "nm-device-interface.h"
 #include "nm-ip4-config.h"
@@ -125,9 +126,9 @@
 				  G_SIGNAL_RUN_FIRST,
 				  G_STRUCT_OFFSET (NMDeviceInterface, state_changed),
 				  NULL, NULL,
-				  g_cclosure_marshal_VOID__UINT,
-				  G_TYPE_NONE, 1,
-				  G_TYPE_UINT);
+				  nm_marshal_VOID__UINT_UINT_UINT,
+				  G_TYPE_NONE, 3,
+				  G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
 
 	dbus_g_object_type_install_info (iface_type,
 									 &dbus_glib_nm_device_interface_object_info);

Modified: trunk/src/nm-device-interface.h
==============================================================================
--- trunk/src/nm-device-interface.h	(original)
+++ trunk/src/nm-device-interface.h	Fri Jul 11 10:28:53 2008
@@ -63,7 +63,10 @@
 	void (*deactivate) (NMDeviceInterface *device);
 
 	/* Signals */
-	void (*state_changed) (NMDeviceInterface *device, NMDeviceState state);
+	void (*state_changed) (NMDeviceInterface *device,
+	                       NMDeviceState new_state,
+	                       NMDeviceState old_state,
+	                       NMDeviceStateReason reason);
 };
 
 GQuark nm_device_interface_error_quark (void);

Modified: trunk/src/nm-device-private.h
==============================================================================
--- trunk/src/nm-device-private.h	(original)
+++ trunk/src/nm-device-private.h	Fri Jul 11 10:28:53 2008
@@ -30,7 +30,9 @@
 
 void nm_device_activate_schedule_stage3_ip_config_start (NMDevice *device);
 
-void nm_device_state_changed (NMDevice *device, NMDeviceState state);
+void nm_device_state_changed (NMDevice *device,
+                              NMDeviceState state,
+                              NMDeviceStateReason reason);
 
 gboolean nm_device_hw_bring_up (NMDevice *self, gboolean wait);
 

Modified: trunk/src/nm-device-wifi.c
==============================================================================
--- trunk/src/nm-device-wifi.c	(original)
+++ trunk/src/nm-device-wifi.c	Fri Jul 11 10:28:53 2008
@@ -2011,10 +2011,11 @@
 	req = nm_device_get_act_request (dev);
 	ap = nm_device_wifi_get_activation_ap (self);
 	if (req == NULL || ap == NULL) {
+		/* shouldn't ever happen */
 		nm_warning ("couldn't get activation request or activation AP.");
 		if (nm_device_is_activating (dev)) {
 			cleanup_association_attempt (self, TRUE);
-			nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED);
+			nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE);
 		}
 		return FALSE;
 	}
@@ -2024,7 +2025,7 @@
 	 * fail.
 	 */
 	if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
-		nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED);
+		nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
 		return FALSE;
 	}
 
@@ -2061,7 +2062,7 @@
 		nm_info ("Activation (%s/wireless): disconnected during association,"
 		         " asking for new key.", nm_device_get_iface (dev));
 		cleanup_association_attempt (self, TRUE);
-		nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH);
+		nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
 		nm_act_request_request_connection_secrets (req, setting_name, TRUE,
 		                                           SECRETS_CALLER_WIFI, NULL, NULL);
 
@@ -2139,7 +2140,8 @@
 	} else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
 		cleanup_association_attempt (self, FALSE);
 		supplicant_interface_release (self);
-		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE);
+		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE,
+		                         NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
 	}
 	
 	g_slice_free (struct state_cb_data, cb_data);
@@ -2263,8 +2265,10 @@
 			supplicant_interface_release (self);
 		}
 
-		if (nm_device_get_state (dev) > NM_DEVICE_STATE_UNAVAILABLE)
-			nm_device_state_changed (dev, NM_DEVICE_STATE_UNAVAILABLE);
+		if (nm_device_get_state (dev) > NM_DEVICE_STATE_UNAVAILABLE) {
+			nm_device_state_changed (dev, NM_DEVICE_STATE_UNAVAILABLE,
+			                         NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+		}
 	} else if (new_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) {
 		dev_state = nm_device_get_state (dev);
 		if (    priv->enabled
@@ -2276,8 +2280,10 @@
 			/* if wireless is enabled and we have a supplicant interface,
 			 * we can transition to the DISCONNECTED state.
 			 */
-			if (priv->supplicant.iface)
-				nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED);
+			if (priv->supplicant.iface) {
+				nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED,
+				                         NM_DEVICE_STATE_REASON_NONE);
+			}
 		}
 	}
 
@@ -2326,7 +2332,7 @@
 	         cb_data->message);
 
 	cleanup_association_attempt (self, TRUE);
-	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED);
+	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
 
 out:
 	g_free (cb_data->name);
@@ -2401,7 +2407,7 @@
 		return NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
-	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH);
+	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
 
 	nm_connection_clear_secrets (connection);
 	setting_name = nm_connection_need_secrets (connection, NULL);
@@ -2463,7 +2469,8 @@
 		nm_info ("Activation (%s/wireless): association took too long, "
 		         "failing activation.",
 		         nm_device_get_iface (dev));
-		nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
 	} else {
 		/* Authentication failed, encryption key is probably bad */
 		nm_info ("Activation (%s/wireless): association took too long.",
@@ -2473,7 +2480,8 @@
 			nm_info ("Activation (%s/wireless): asking for new secrets",
 			         nm_device_get_iface (dev));
 		} else {
-			nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED);
+			nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED,
+			                         NM_DEVICE_STATE_REASON_NO_SECRETS);
 		}
 	}
 
@@ -2650,11 +2658,14 @@
 
 
 static NMActStageReturn
-real_act_stage1_prepare (NMDevice *dev)
+real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
 	NMDeviceWifi *self = NM_DEVICE_WIFI (dev);
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	NMAccessPoint *ap = NULL;
+	NMActRequest *req;
+	NMConnection *connection;
+	GSList *iter;
 
 	/* If the user is trying to connect to an AP that NM doesn't yet know about
 	 * (hidden network or something), create an fake AP from the security
@@ -2662,54 +2673,51 @@
 	 * scan list, which should show up when the connection is successful.
 	 */
 	ap = nm_device_wifi_get_activation_ap (self);
-	if (!ap) {
-		NMActRequest *req;
-		NMConnection *connection;
-		GSList *iter;
-
-		req = nm_device_get_act_request (NM_DEVICE (self));
-		g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+	if (ap)
+		goto done;
 
-		connection = nm_act_request_get_connection (req);
-		g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+	req = nm_device_get_act_request (NM_DEVICE (self));
+	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-		/* Find a compatible AP in the scan list */
-		for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) {
-			NMAccessPoint *candidate = NM_AP (iter->data);
+	connection = nm_act_request_get_connection (req);
+	g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-			if (nm_ap_check_compatible (candidate, connection)) {
-				ap = candidate;
-				break;
-			}
+	/* Find a compatible AP in the scan list */
+	for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) {
+		NMAccessPoint *candidate = NM_AP (iter->data);
+
+		if (nm_ap_check_compatible (candidate, connection)) {
+			ap = candidate;
+			break;
 		}
+	}
 
-		/* If no compatible AP was found, create a fake AP (network is likely
-		 * hidden) and try to use that.
-		 */
-		if (!ap) {
-			ap = nm_ap_new_fake_from_connection (connection);
-			g_return_val_if_fail (ap != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-			switch (nm_ap_get_mode (ap)) {
-				case NM_802_11_MODE_ADHOC:
-					nm_ap_set_user_created (ap, TRUE);
-					break;
-				case NM_802_11_MODE_INFRA:
-				default:
-					nm_ap_set_broadcast (ap, FALSE);
-					break;
-			}
+	/* If no compatible AP was found, create a fake AP (network is likely
+	 * hidden) and try to use that.
+	 */
+	if (!ap) {
+		ap = nm_ap_new_fake_from_connection (connection);
+		g_return_val_if_fail (ap != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-			priv->ap_list = g_slist_append (priv->ap_list, ap);
-			nm_ap_export_to_dbus (ap);
-			g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, ap);
+		switch (nm_ap_get_mode (ap)) {
+			case NM_802_11_MODE_ADHOC:
+				nm_ap_set_user_created (ap, TRUE);
+				break;
+			case NM_802_11_MODE_INFRA:
+			default:
+				nm_ap_set_broadcast (ap, FALSE);
+				break;
 		}
 
-		nm_act_request_set_specific_object (req, nm_ap_get_dbus_path (ap));
+		priv->ap_list = g_slist_append (priv->ap_list, ap);
+		nm_ap_export_to_dbus (ap);
+		g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, ap);
 	}
 
-	set_current_ap (self, ap);
+	nm_act_request_set_specific_object (req, nm_ap_get_dbus_path (ap));
 
+done:
+	set_current_ap (self, ap);
 	return NM_ACT_STAGE_RETURN_SUCCESS;
 }
 
@@ -2749,7 +2757,7 @@
 }
 
 static NMActStageReturn
-real_act_stage2_config (NMDevice *dev)
+real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason)
 {
 	NMDeviceWifi * self = NM_DEVICE_WIFI (dev);
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
@@ -2763,6 +2771,8 @@
 	NMSettingConnection *	s_connection;
 	const char *			setting_name;
 
+	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+
 	remove_supplicant_timeouts (self);
 
 	req = nm_device_get_act_request (dev);
@@ -2780,11 +2790,17 @@
 	/* If we need secrets, get them */
 	setting_name = nm_connection_need_secrets (connection, NULL);
 	if (setting_name) {
+		NMActStageReturn auth_ret;
+
 		nm_info ("Activation (%s/wireless): access point '%s' has security,"
 		         " but secrets are required.",
 		         iface, s_connection->id);
 
-		return handle_auth_or_fail (self, req, FALSE);
+		auth_ret = handle_auth_or_fail (self, req, FALSE);
+		if (auth_ret == NM_ACT_STAGE_RETURN_FAILURE) {
+			*reason = NM_DEVICE_STATE_REASON_NO_SECRETS;
+			goto out;
+		}
 	} else {
 		NMSettingWireless *s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, 
 																		 NM_TYPE_SETTING_WIRELESS);
@@ -2804,6 +2820,7 @@
 	if (config == NULL) {
 		nm_warning ("Activation (%s/wireless): couldn't build wireless "
 			"configuration.", iface);
+		*reason = NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED;
 		goto out;
 	}
 
@@ -2817,19 +2834,21 @@
 	if (!nm_supplicant_interface_set_config (priv->supplicant.iface, config)) {
 		nm_warning ("Activation (%s/wireless): couldn't send wireless "
 			"configuration to the supplicant.", iface);
+		*reason = NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED;
 		goto out;
 	}
 
-	if (!start_supplicant_connection_timeout (self))
+	if (!start_supplicant_connection_timeout (self)) {
+		*reason = NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED;
 		goto out;
+	}
 
 	/* We'll get stage3 started when the supplicant connects */
 	ret = NM_ACT_STAGE_RETURN_POSTPONE;
 
 out:
-	if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
+	if (ret == NM_ACT_STAGE_RETURN_FAILURE)
 		cleanup_association_attempt (self, TRUE);
-	}
 
 	if (config) {
 		/* Supplicant interface object refs the config; we no longer care about
@@ -2842,7 +2861,8 @@
 
 static NMActStageReturn
 real_act_stage4_get_ip4_config (NMDevice *dev,
-                                NMIP4Config **config)
+                                NMIP4Config **config,
+                                NMDeviceStateReason *reason)
 {
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
 	NMDeviceClass *parent_class;
@@ -2852,7 +2872,7 @@
 
 	/* Chain up to parent */
 	parent_class = NM_DEVICE_CLASS (nm_device_wifi_parent_class);
-	ret = parent_class->act_stage4_get_ip4_config (dev, config);
+	ret = parent_class->act_stage4_get_ip4_config (dev, config, reason);
 
 	if ((ret == NM_ACT_STAGE_RETURN_SUCCESS) && *config) {
 		NMConnection *connection;
@@ -2874,7 +2894,8 @@
 
 static NMActStageReturn
 real_act_stage4_ip_config_timeout (NMDevice *dev,
-                                   NMIP4Config **config)
+                                   NMIP4Config **config,
+                                   NMDeviceStateReason *reason)
 {
 	NMDeviceWifi *	self = NM_DEVICE_WIFI (dev);
 	NMAccessPoint *		ap = nm_device_wifi_get_activation_ap (self);
@@ -2910,6 +2931,8 @@
 		if (ret == NM_ACT_STAGE_RETURN_POSTPONE) {
 			nm_info ("Activation (%s/wireless): asking for new secrets",
 			         nm_device_get_iface (dev));
+		} else {
+			*reason = NM_DEVICE_STATE_REASON_NO_SECRETS;
 		}
 	} else if (nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) {
 		NMDeviceWifiClass *	klass;
@@ -2918,12 +2941,13 @@
 		/* For Ad-Hoc networks, chain up to parent to get a Zeroconf IP */
 		klass = NM_DEVICE_WIFI_GET_CLASS (self);
 		parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass));
-		ret = parent_class->act_stage4_ip_config_timeout (dev, &real_config);
+		ret = parent_class->act_stage4_ip_config_timeout (dev, &real_config, reason);
 	} else {
 		/* Non-encrypted network or authentication is enforced by some
 		 * entity (AP, RADIUS server, etc), but IP configure failed.  Alert
 		 * the user.
 		 */
+		*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
 		ret = NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
@@ -3250,12 +3274,18 @@
 static gboolean
 unavailable_to_disconnected (gpointer user_data)
 {
-	nm_device_state_changed (NM_DEVICE (user_data), NM_DEVICE_STATE_DISCONNECTED);
+	nm_device_state_changed (NM_DEVICE (user_data),
+	                         NM_DEVICE_STATE_DISCONNECTED,
+	                         NM_DEVICE_STATE_REASON_NONE);
 	return FALSE;
 }
 
 static void
-state_changed_cb (NMDevice *device, NMDeviceState state, gpointer user_data)
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
 {
 	NMDeviceWifi *self = NM_DEVICE_WIFI (device);
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
@@ -3267,7 +3297,7 @@
 		priv->state_to_disconnected_id = 0;
 	}
 
-	if (state <= NM_DEVICE_STATE_UNAVAILABLE) {
+	if (new_state <= NM_DEVICE_STATE_UNAVAILABLE) {
 		/* Clean up the supplicant interface because in these states the
 		 * device cannot be used.
 		 */
@@ -3275,7 +3305,7 @@
 			supplicant_interface_release (self);
 	}
 
-	switch (state) {
+	switch (new_state) {
 	case NM_DEVICE_STATE_UNMANAGED:
 		clear_aps = TRUE;
 		break;
@@ -3333,7 +3363,7 @@
 		return NULL;
 
 	g_signal_connect (obj, "state-changed",
-				   G_CALLBACK (state_changed_cb),
+				   G_CALLBACK (device_state_changed),
 				   NULL);
 
 	return NM_DEVICE_WIFI (obj);
@@ -3398,10 +3428,15 @@
 		if (!priv->supplicant.iface)
 			supplicant_interface_acquire (self);
 
-		if (priv->supplicant.iface)
-			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED);
+		if (priv->supplicant.iface) {
+			nm_device_state_changed (NM_DEVICE (self),
+			                         NM_DEVICE_STATE_DISCONNECTED,
+			                         NM_DEVICE_STATE_REASON_NONE);
+		}
 	} else {
-		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE);
+		nm_device_state_changed (NM_DEVICE (self),
+		                         NM_DEVICE_STATE_UNAVAILABLE,
+		                         NM_DEVICE_STATE_REASON_NONE);
 		nm_device_hw_take_down (NM_DEVICE (self), TRUE);
 	}
 }

Modified: trunk/src/nm-device.c
==============================================================================
--- trunk/src/nm-device.c	(original)
+++ trunk/src/nm-device.c	Fri Jul 11 10:28:53 2008
@@ -154,7 +154,7 @@
 	NMDevice *self = NM_DEVICE (user_data);
 
 	self->priv->start_timer = 0;
-	nm_device_state_changed (self, NM_DEVICE_STATE_UNAVAILABLE);
+	nm_device_state_changed (self, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
 	return FALSE;
 }
 
@@ -381,7 +381,7 @@
 
 	switch (status) {
 	case NM_DNSMASQ_STATUS_DEAD:
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
 		break;
 	default:
 		break;
@@ -400,6 +400,7 @@
 	NMDevice *self = NM_DEVICE (user_data);
 	const char *     iface;
 	NMActStageReturn ret;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
 	/* Clear the activation source ID now that this stage has run */
 	if (self->priv->act_source_id > 0)
@@ -407,13 +408,13 @@
 
 	iface = nm_device_get_iface (self);
 	nm_info ("Activation (%s) Stage 1 of 5 (Device Prepare) started...", iface);
-	nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE);
+	nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
 
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self);
+	ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self, &reason);
 	if (ret == NM_ACT_STAGE_RETURN_POSTPONE) {
 		goto out;
 	} else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		goto out;
 	}
 	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
@@ -449,14 +450,14 @@
 }
 
 static NMActStageReturn
-real_act_stage1_prepare (NMDevice *dev)
+real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
 	/* Nothing to do */
 	return NM_ACT_STAGE_RETURN_SUCCESS;
 }
 
 static NMActStageReturn
-real_act_stage2_config (NMDevice *dev)
+real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason)
 {
 	/* Nothing to do */
 	return NM_ACT_STAGE_RETURN_SUCCESS;
@@ -475,6 +476,7 @@
 	NMDevice *self = NM_DEVICE (user_data);
 	const char *     iface;
 	NMActStageReturn ret;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
 	/* Clear the activation source ID now that this stage has run */
 	if (self->priv->act_source_id > 0)
@@ -482,19 +484,19 @@
 
 	iface = nm_device_get_iface (self);
 	nm_info ("Activation (%s) Stage 2 of 5 (Device Configure) starting...", iface);
-	nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG);
+	nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE);
 
 	if (!nm_device_bring_up (self, FALSE)) {
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
 		goto out;
 	}
 
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self);
+	ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self, &reason);
 	if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
 		goto out;
 	else if (ret == NM_ACT_STAGE_RETURN_FAILURE)
 	{
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		goto out;
 	}
 	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);	
@@ -563,7 +565,7 @@
 }
 
 static NMIP4Config *
-aipd_get_ip4_config (NMDevice *self)
+aipd_get_ip4_config (NMDevice *self, NMDeviceStateReason *reason)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMIP4Config *config = NULL;
@@ -572,6 +574,11 @@
 	g_return_val_if_fail (priv->aipd_addr > 0, NULL);
 
 	config = nm_ip4_config_new ();
+	if (!config) {
+		*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
+		return NULL;
+	}
+
 	addr = g_malloc0 (sizeof (NMSettingIP4Address));
 	addr->address = (guint32) priv->aipd_addr;
 	addr->prefix = 16;
@@ -581,13 +588,15 @@
 }
 
 static gboolean
-handle_autoip_change (NMDevice *self)
+handle_autoip_change (NMDevice *self, NMDeviceStateReason *reason)
 {
 	NMActRequest *req;
 	NMConnection *connection;
 	NMIP4Config *config;
 
-	config = aipd_get_ip4_config (self);
+	g_return_val_if_fail (reason != NULL, FALSE);
+
+	config = aipd_get_ip4_config (self, reason);
 	if (!config) {
 		nm_warning ("failed to get autoip config for rebind");
 		return FALSE;
@@ -600,7 +609,7 @@
 
 	g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config);
 
-	if (!nm_device_set_ip4_config (self, config)) {
+	if (!nm_device_set_ip4_config (self, config, reason)) {
 		nm_warning ("(%s): failed to update IP4 config in response to autoip event.",
 		            nm_device_get_iface (self));
 		return FALSE;
@@ -644,18 +653,19 @@
 
 	if (strcmp (event, "BIND") == 0) {
 		struct in_addr ip;
+		NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
 		if (inet_pton (AF_INET, address, &ip) <= 0) {
 			nm_warning ("(%s): invalid address %s received from avahi-autoipd.",
 			            iface, address);
-			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_AUTOIP_ERROR);
 			return;
 		}
 
 		if ((ip.s_addr & IPV4LL_NETMASK) != IPV4LL_NETWORK) {
 			nm_warning ("(%s): invalid address %s received from avahi-autoipd.",
 			            iface, address);
-			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_AUTOIP_ERROR);
 			return;
 		}
 
@@ -672,8 +682,8 @@
 			break;
 		case NM_DEVICE_STATE_ACTIVATED:
 			priv->aipd_addr = ip.s_addr;
-			if (!handle_autoip_change (self))
-				nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+			if (!handle_autoip_change (self, &reason))
+				nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 			break;
 		default:
 			nm_warning ("(%s): unexpected avahi-autoip event %s for %s.",
@@ -685,7 +695,7 @@
 		            iface, address, event);
 
 		/* The address is gone; terminate the connection or fail activation */
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
 	}
 }
 
@@ -716,7 +726,7 @@
 
 	state = nm_device_get_state (self);
 	if (nm_device_is_activating (self) || (state == NM_DEVICE_STATE_ACTIVATED))
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_AUTOIP_FAILED);
 }
 
 static gboolean
@@ -798,13 +808,15 @@
 }
 
 static NMActStageReturn
-real_act_stage3_ip_config_start (NMDevice *self)
+real_act_stage3_ip_config_start (NMDevice *self, NMDeviceStateReason *reason)
 {
 	NMSettingIP4Config *s_ip4;
 	NMActRequest *req;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
 	const char *iface;
 
+	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+
 	iface = nm_device_get_iface (self);
 
 	req = nm_device_get_act_request (self);
@@ -830,8 +842,10 @@
 			 * stuff happens.	
 			 */
 			ret = NM_ACT_STAGE_RETURN_POSTPONE;
-		} else
+		} else {
+			*reason = NM_DEVICE_STATE_REASON_DHCP_START_FAILED;
 			ret = NM_ACT_STAGE_RETURN_FAILURE;
+		}
 	} else if (s_ip4 && !strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_AUTOIP)) {
 		GError *error = NULL;
 
@@ -845,6 +859,7 @@
 			         " to start avahi-autoipd: %s", iface, error->message);
 			g_error_free (error);
 			aipd_cleanup (self);
+			*reason = NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED;
 			ret = NM_ACT_STAGE_RETURN_FAILURE;
 		}
 	}
@@ -863,8 +878,9 @@
 nm_device_activate_stage3_ip_config_start (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
-	const char *     iface;
+	const char *iface;
 	NMActStageReturn ret;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
 	/* Clear the activation source ID now that this stage has run */
 	if (self->priv->act_source_id > 0)
@@ -872,14 +888,14 @@
 
 	iface = nm_device_get_iface (self);
 	nm_info ("Activation (%s) Stage 3 of 5 (IP Configure Start) started...", iface);
-	nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG);
+	nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE);
 
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip_config_start (self);
+	ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip_config_start (self, &reason);
 	if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
 		goto out;
 	else if (ret == NM_ACT_STAGE_RETURN_FAILURE)
 	{
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		goto out;
 	}
 	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);	
@@ -940,7 +956,7 @@
 }
 
 static NMIP4Config *
-nm_device_new_ip4_shared_config (NMDevice *self)
+nm_device_new_ip4_shared_config (NMDevice *self, NMDeviceStateReason *reason)
 {
 	NMIP4Config *config = NULL;
 	NMSettingIP4Address *addr;
@@ -952,8 +968,10 @@
 		shared_ips = g_hash_table_new (g_direct_hash, g_direct_equal);
 
 	tmp_addr = reserve_shared_ip ();
-	if (!tmp_addr)
+	if (!tmp_addr) {
+		*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
 		return NULL;
+	}
 
 	config = nm_ip4_config_new ();
 	addr = g_malloc0 (sizeof (NMSettingIP4Address));
@@ -970,7 +988,8 @@
 
 static NMActStageReturn
 real_act_stage4_get_ip4_config (NMDevice *self,
-                                NMIP4Config **config)
+                                NMIP4Config **config,
+                                NMDeviceStateReason *reason)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
@@ -979,6 +998,7 @@
 
 	g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 	g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
+	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
 	connection = nm_act_request_get_connection (nm_device_get_act_request (self));
 	g_assert (connection);
@@ -990,17 +1010,22 @@
 											 nm_device_get_iface (self));
 		if (*config)
 			nm_utils_merge_ip4_config (*config, s_ip4);
+		else
+			*reason = NM_DEVICE_STATE_REASON_DHCP_ERROR;
 	} else {
 		g_assert (s_ip4);
+		g_assert (s_ip4->method);
 
 		if (!strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_AUTOIP)) {
-			*config = aipd_get_ip4_config (self);
+			*config = aipd_get_ip4_config (self, reason);
 		} else if (!strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
 			*config = nm_ip4_config_new ();
 			if (*config)
 				nm_utils_merge_ip4_config (*config, s_ip4);
+			else
+				*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
 		} else if (!strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
-			*config = nm_device_new_ip4_shared_config (self);
+			*config = nm_device_new_ip4_shared_config (self, reason);
 			if (*config)
 				priv->dnsmasq_manager = nm_dnsmasq_manager_new (nm_device_get_ip_iface (self));
 		}
@@ -1026,9 +1051,10 @@
 nm_device_activate_stage4_ip_config_get (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
-	NMIP4Config *    ip4_config = NULL;
+	NMIP4Config *ip4_config = NULL;
 	NMActStageReturn ret;
-	const char *     iface = NULL;
+	const char *iface = NULL;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
 	/* Clear the activation source ID now that this stage has run */
 	if (self->priv->act_source_id > 0)
@@ -1037,12 +1063,12 @@
 	iface = nm_device_get_iface (self);
 	nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Get) started...", iface);
 
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_get_ip4_config (self, &ip4_config);
+	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_get_ip4_config (self, &ip4_config, &reason);
 	if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
 		goto out;
 	else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE))
 	{
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		goto out;
 	}
 	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);	
@@ -1083,12 +1109,14 @@
 
 static NMActStageReturn
 real_act_stage4_ip_config_timeout (NMDevice *self,
-                                   NMIP4Config **config)
+                                   NMIP4Config **config,
+                                   NMDeviceStateReason *reason)
 {
 	g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 	g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
 	/* DHCP failed; connection must fail */
+	*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
 	return NM_ACT_STAGE_RETURN_FAILURE;
 }
 
@@ -1103,9 +1131,10 @@
 nm_device_activate_stage4_ip_config_timeout (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
-	NMIP4Config *    ip4_config = NULL;
-	const char *     iface;
+	NMIP4Config *ip4_config = NULL;
+	const char *iface;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
 	/* Clear the activation source ID now that this stage has run */
 	if (self->priv->act_source_id > 0)
@@ -1114,11 +1143,11 @@
 	iface = nm_device_get_iface (self);
 	nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Timeout) started...", iface);
 
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip_config_timeout (self, &ip4_config);
+	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip_config_timeout (self, &ip4_config, &reason);
 	if (ret == NM_ACT_STAGE_RETURN_POSTPONE) {
 		goto out;
 	} else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE)) {
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		goto out;
 	}
 	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);	
@@ -1173,6 +1202,7 @@
 	const char *iface;
 	NMConnection *connection;
 	NMSettingIP4Config *s_ip4;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
 	ip4_config = g_object_get_data (G_OBJECT (nm_device_get_act_request (self)),
 									NM_ACT_REQUEST_IP4_CONFIG);
@@ -1186,8 +1216,8 @@
 	nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) started...",
 	         iface);
 
-	if (!nm_device_set_ip4_config (self, ip4_config)) {
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+	if (!nm_device_set_ip4_config (self, ip4_config, &reason)) {
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		goto out;
 	}
 
@@ -1199,7 +1229,7 @@
 		if (!nm_dnsmasq_manager_start (priv->dnsmasq_manager, ip4_config, &error)) {
 			nm_warning ("(%s): failed to start dnsmasq: %s", iface, error->message);
 			g_error_free (error);
-			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
 			goto out;
 		}
 
@@ -1208,7 +1238,7 @@
 		                                           self);
 	}
 
-	nm_device_state_changed (self, NM_DEVICE_STATE_ACTIVATED);
+	nm_device_state_changed (self, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
 
 out:
 	nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) complete.",
@@ -1338,6 +1368,7 @@
 nm_device_deactivate (NMDeviceInterface *device)
 {
 	NMDevice *self = NM_DEVICE (device);
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
 	g_return_if_fail (self != NULL);
 
@@ -1346,7 +1377,7 @@
 	nm_device_deactivate_quickly (self);
 
 	/* Clean up nameservers and addresses */
-	nm_device_set_ip4_config (self, NULL);
+	nm_device_set_ip4_config (self, NULL, &reason);
 
 	/* Take out any entries in the routing table and any IP address the device had. */
 	nm_system_device_flush_ip4_routes (self);
@@ -1393,7 +1424,7 @@
 {
 	NMDevice *self = NM_DEVICE (user_data);
 
-	nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
+	nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS);
 }
 
 static gboolean
@@ -1452,7 +1483,7 @@
 	 * that the activation request isn't deferred because the deferred bit
 	 * gets cleared a bit too early, when the connection becomes valid.
 	 */
-	nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE);
+	nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
 	nm_device_activate_schedule_stage1_device_prepare (self);
 
 	return TRUE;
@@ -1515,6 +1546,7 @@
 	NMSettingIP4Config *s_ip4;
 	NMConnection *connection;
 	NMActRequest *req;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
 	if (!nm_device_get_use_dhcp (device)) {
 		nm_warning ("got DHCP rebind for device that wasn't using DHCP.");
@@ -1525,7 +1557,7 @@
 											 nm_device_get_iface (device));
 	if (!config) {
 		nm_warning ("failed to get DHCP config for rebind");
-		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
 		return;
 	}
 
@@ -1539,9 +1571,9 @@
 
 	g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config);
 
-	if (!nm_device_set_ip4_config (device, config)) {
+	if (!nm_device_set_ip4_config (device, config, &reason)) {
 		nm_warning ("Failed to update IP4 config in response to DHCP event.");
-		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
 	}
 }
 
@@ -1580,11 +1612,11 @@
 	case DHC_ABEND: /* dhclient exited abnormally */
 	case DHC_END: /* dhclient exited normally */
 		if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
-			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED);
+			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DHCP_FAILED);
 		} else if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) {
 			if (nm_device_get_use_dhcp (device)) {
 				/* dhclient quit and therefore can't renew our lease, kill the conneciton */
-				nm_device_state_changed (device, NM_DEVICE_STATE_FAILED);
+				nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
 			}
 		}
 		break;
@@ -1658,13 +1690,14 @@
 
 
 gboolean
-nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config)
+nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, NMDeviceStateReason *reason)
 {
 	NMDevicePrivate *priv;
 	const char *ip_iface;
 	gboolean success;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
+	g_return_val_if_fail (reason != NULL, FALSE);
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
@@ -1881,8 +1914,10 @@
 	 */
 
 	if (self->priv->managed) {
+		NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
+
 		nm_device_take_down (self, FALSE);
-		nm_device_set_ip4_config (self, NULL);
+		nm_device_set_ip4_config (self, NULL, &reason);
 	}
 
 	clear_act_request (self);
@@ -2070,12 +2105,14 @@
 	NMDevice *device = NM_DEVICE (user_data);
 
 	device->priv->failed_to_disconnected_id = 0;
-	nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED);
+	nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
 	return FALSE;
 }
 
 void
-nm_device_state_changed (NMDevice *device, NMDeviceState state)
+nm_device_state_changed (NMDevice *device,
+                         NMDeviceState state,
+                         NMDeviceStateReason reason)
 {
 	NMDevicePrivate *priv;
 	NMDeviceState old_state;
@@ -2121,7 +2158,7 @@
 	}
 
 	g_object_notify (G_OBJECT (device), NM_DEVICE_INTERFACE_STATE);
-	g_signal_emit_by_name (device, "state-changed", state);
+	g_signal_emit_by_name (device, "state-changed", state, old_state, 0);
 
 	/* Post-process the event after internal notification */
 
@@ -2184,6 +2221,9 @@
 	g_object_notify (G_OBJECT (device), NM_DEVICE_INTERFACE_MANAGED);
 
 	/* If now managed, jump to unavailable */
-	nm_device_state_changed (device, managed ? NM_DEVICE_STATE_UNAVAILABLE : NM_DEVICE_STATE_UNMANAGED);
+	if (managed)
+		nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
+	else
+		nm_device_state_changed (device, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
 }
 

Modified: trunk/src/nm-device.h
==============================================================================
--- trunk/src/nm-device.h	(original)
+++ trunk/src/nm-device.h	Fri Jul 11 10:28:53 2008
@@ -98,13 +98,18 @@
 	                                             NMConnection *connection,
 	                                             GError **error);
 
-	NMActStageReturn	(* act_stage1_prepare)	(NMDevice *self);
-	NMActStageReturn	(* act_stage2_config)	(NMDevice *self);
-	NMActStageReturn	(* act_stage3_ip_config_start) (NMDevice *self);
+	NMActStageReturn	(* act_stage1_prepare)	(NMDevice *self,
+	                                             NMDeviceStateReason *reason);
+	NMActStageReturn	(* act_stage2_config)	(NMDevice *self,
+	                                             NMDeviceStateReason *reason);
+	NMActStageReturn	(* act_stage3_ip_config_start) (NMDevice *self,
+	                                                    NMDeviceStateReason *reason);
 	NMActStageReturn	(* act_stage4_get_ip4_config)	(NMDevice *self,
-														 NMIP4Config **config);
+														 NMIP4Config **config,
+	                                                     NMDeviceStateReason *reason);
 	NMActStageReturn	(* act_stage4_ip_config_timeout)	(NMDevice *self,
-												 NMIP4Config **config);
+	                                                         NMIP4Config **config,
+	                                                         NMDeviceStateReason *reason);
 	void			(* deactivate)			(NMDevice *self);
 	void			(* deactivate_quickly)	(NMDevice *self);
 
@@ -133,7 +138,8 @@
 
 NMIP4Config *	nm_device_get_ip4_config	(NMDevice *dev);
 gboolean		nm_device_set_ip4_config	(NMDevice *dev,
-								 NMIP4Config *config);
+                                             NMIP4Config *config,
+                                             NMDeviceStateReason *reason);
 
 void		nm_device_take_down (NMDevice *dev, gboolean wait);
 

Modified: trunk/src/nm-gsm-device.c
==============================================================================
--- trunk/src/nm-gsm-device.c	(original)
+++ trunk/src/nm-gsm-device.c	Fri Jul 11 10:28:53 2008
@@ -83,7 +83,7 @@
 		id = nm_serial_device_wait_for_reply (serial, timeout, responses, terminators, callback, NULL);
 
 	if (id == 0)
-		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN);
 }
 
 static void
@@ -100,7 +100,7 @@
 		id = nm_serial_device_get_reply (serial, timeout, terminators, callback, NULL);
 
 	if (id == 0)
-		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN);
 }
 
 static NMSetting *
@@ -127,6 +127,7 @@
 		 gpointer user_data)
 {
 	gboolean success = FALSE;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_UNKNOWN;
 
 	switch (reply_index) {
 	case 0:
@@ -135,25 +136,30 @@
 		break;
 	case 1:
 		nm_info ("Busy");
+		reason = NM_DEVICE_STATE_REASON_MODEM_BUSY;
 		break;
 	case 2:
 		nm_warning ("No dial tone");
+		reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE;
 		break;
 	case 3:
 		nm_warning ("No carrier");
+		reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER;
 		break;
 	case -1:
 		nm_warning ("Dialing timed out");
+		reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT;
 		break;
 	default:
 		nm_warning ("Dialing failed");
+		reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED;
 		break;
 	}
 
 	if (success)
 		nm_device_activate_schedule_stage2_device_config (NM_DEVICE (device));
 	else
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED, reason);
 }
 
 static void
@@ -194,7 +200,9 @@
 		break;
 	default:
 		nm_warning ("Setting APN failed");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_GSM_APN_FAILED);
 		break;
 	}
 }
@@ -231,11 +239,15 @@
 		break;
 	case -1:
 		nm_warning ("Manual registration timed out");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED);
 		break;
 	default:
 		nm_warning ("Manual registration failed");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED);
 		break;
 	}
 }
@@ -301,15 +313,21 @@
 		break;
 	case 3:
 		nm_warning ("Automatic registration failed: not registered and not searching.");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED);
 		break;
 	case -1:
 		nm_warning ("Automatic registration timed out");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED);
 		break;
 	default:
 		nm_warning ("Automatic registration failed");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED);
 		break;
 	}
 }
@@ -347,11 +365,15 @@
 		break;
 	case -1:
 		nm_warning ("Modem second stage initialization timed out");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
 		break;
 	default:
 		nm_warning ("Modem second stage initialization failed");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
 		return;
 	}
 }
@@ -377,7 +399,9 @@
 		break;
 	case -1:
 		nm_warning ("Did not receive response for secret");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_NO_SECRETS);
 		break;
 	default:
 		nm_warning ("Invalid secret");
@@ -443,7 +467,9 @@
 		g_free (command);
 	} else {
 		nm_info ("(%s): GSM %s secret required", nm_device_get_iface (NM_DEVICE (device)), secret_name);
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_NEED_AUTH);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_NEED_AUTH,
+		                         NM_DEVICE_STATE_REASON_NONE);
 		nm_act_request_request_connection_secrets (req,
 		                                           NM_SETTING_GSM_SETTING_NAME,
 		                                           retry,
@@ -472,11 +498,15 @@
 		break;
 	case -1:
 		nm_warning ("PIN checking timed out");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED);
 		break;
 	default:
 		nm_warning ("PIN checking failed");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED);
 		return;
 	}
 }
@@ -501,11 +531,15 @@
 		break;
 	case -1:
 		nm_warning ("Modem initialization timed out");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
 		break;
 	default:
 		nm_warning ("Modem initialization failed");
-		nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (NM_DEVICE (device),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
 		return;
 	}
 }
@@ -519,7 +553,7 @@
 }
 
 static NMActStageReturn
-real_act_stage1_prepare (NMDevice *device)
+real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 {
 	NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (device);
 	NMSerialDevice *serial_device = NM_SERIAL_DEVICE (device);
@@ -530,10 +564,14 @@
 
 	setting = NM_SETTING_SERIAL (gsm_device_get_setting (NM_GSM_DEVICE (device), NM_TYPE_SETTING_SERIAL));
 
-	if (!nm_serial_device_open (serial_device, setting))
+	if (!nm_serial_device_open (serial_device, setting)) {
+		*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
 		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
 
 	id = nm_serial_device_flash (serial_device, 100, init_modem, NULL);
+	if (!id)
+		*reason = NM_DEVICE_STATE_REASON_UNKNOWN;
 
 	return id ? NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE;
 }
@@ -723,12 +761,18 @@
 static gboolean
 unavailable_to_disconnected (gpointer user_data)
 {
-	nm_device_state_changed (NM_DEVICE (user_data), NM_DEVICE_STATE_DISCONNECTED);
+	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 state, gpointer user_data)
+device_state_changed (NMDeviceInterface *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
 {
 	NMGsmDevice *self = NM_GSM_DEVICE (user_data);
 	NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (self);
@@ -743,11 +787,11 @@
 	 * 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 (state == NM_DEVICE_STATE_UNAVAILABLE)
+	if (new_state == NM_DEVICE_STATE_UNAVAILABLE)
 		priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, self);
 
 	/* Make sure we don't leave the serial device open */
-	switch (state) {
+	switch (new_state) {
 	case NM_DEVICE_STATE_NEED_AUTH:
 	case NM_DEVICE_STATE_UNMANAGED:
 	case NM_DEVICE_STATE_UNAVAILABLE:

Modified: trunk/src/nm-manager.c
==============================================================================
--- trunk/src/nm-manager.c	(original)
+++ trunk/src/nm-manager.c	Fri Jul 11 10:28:53 2008
@@ -53,10 +53,6 @@
 									 NMConnection *connection,
 									 NMConnectionScope scope);
 
-static void manager_device_state_changed (NMDevice *device,
-                                          NMDeviceState state,
-                                          gpointer user_data);
-
 static void hal_manager_udi_added_cb (NMHalManager *hal_mgr,
                                       const char *udi,
                                       const char *type_name,
@@ -370,6 +366,30 @@
 }
 
 static void
+manager_device_state_changed (NMDevice *device,
+                              NMDeviceState new_state,
+                              NMDeviceState old_state,
+                              NMDeviceStateReason reason,
+                              gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+
+	switch (new_state) {
+	case NM_DEVICE_STATE_UNMANAGED:
+	case NM_DEVICE_STATE_UNAVAILABLE:
+	case NM_DEVICE_STATE_DISCONNECTED:
+	case NM_DEVICE_STATE_PREPARE:
+	case NM_DEVICE_STATE_FAILED:
+		g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
+		break;
+	default:
+		break;
+	}
+
+	nm_manager_update_state (manager);
+}
+
+static void
 remove_one_device (NMManager *manager, NMDevice *device)
 {
 	if (nm_device_get_managed (device))
@@ -1449,26 +1469,6 @@
 }
 
 static void
-manager_device_state_changed (NMDevice *device, NMDeviceState state, gpointer user_data)
-{
-	NMManager *manager = NM_MANAGER (user_data);
-
-	switch (state) {
-	case NM_DEVICE_STATE_UNMANAGED:
-	case NM_DEVICE_STATE_UNAVAILABLE:
-	case NM_DEVICE_STATE_DISCONNECTED:
-	case NM_DEVICE_STATE_PREPARE:
-	case NM_DEVICE_STATE_FAILED:
-		g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
-		break;
-	default:
-		break;
-	}
-
-	nm_manager_update_state (manager);
-}
-
-static void
 manager_hidden_ap_found (NMDeviceInterface *device,
                          NMAccessPoint *ap,
                          gpointer user_data)
@@ -1696,8 +1696,12 @@
 	if (!nm_device_interface_check_connection_compatible (dev_iface, connection, error))
 		return NULL;
 
-	if (nm_device_get_act_request (device))
-		nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED);
+	/* Tear down any existing connection */
+	if (nm_device_get_act_request (device)) {
+		nm_device_state_changed (device,
+		                         NM_DEVICE_STATE_DISCONNECTED,
+		                         NM_DEVICE_STATE_REASON_NONE);
+	}
 
 	req = nm_act_request_new (connection, specific_object, user_requested, (gpointer) device);
 	success = nm_device_interface_activate (dev_iface, req, error);
@@ -1947,7 +1951,9 @@
 			continue;
 
 		if (!strcmp (connection_path, nm_act_request_get_active_connection_path (req))) {
-			nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED);
+			nm_device_state_changed (device,
+			                         NM_DEVICE_STATE_DISCONNECTED,
+			                         NM_DEVICE_STATE_REASON_NONE);
 			success = TRUE;
 			goto done;
 		}

Modified: trunk/src/nm-serial-device.c
==============================================================================
--- trunk/src/nm-serial-device.c	(original)
+++ trunk/src/nm-serial-device.c	Fri Jul 11 10:28:53 2008
@@ -312,7 +312,8 @@
 
 	nm_serial_device_add_timeout (device, timeout);
 
-	return priv->pending_id;}
+	return priv->pending_id;
+}
 
 static void
 nm_serial_device_pending_done (NMSerialDevice *self)
@@ -975,10 +976,10 @@
 
 	switch (status) {
 	case NM_PPP_STATUS_NETWORK:
-		nm_device_state_changed (device, NM_DEVICE_STATE_IP_CONFIG);
+		nm_device_state_changed (device, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE);
 		break;
 	case NM_PPP_STATUS_DISCONNECT:
-		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED);
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_DISCONNECT);
 		break;
 	default:
 		break;
@@ -1016,7 +1017,7 @@
 }
 
 static NMActStageReturn
-real_act_stage2_config (NMDevice *device)
+real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 {
 	NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
 	NMActRequest *req;
@@ -1050,6 +1051,7 @@
 		g_object_unref (priv->ppp_manager);
 		priv->ppp_manager = NULL;
 
+		*reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED;
 		ret = NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
@@ -1057,7 +1059,9 @@
 }
 
 static NMActStageReturn
-real_act_stage4_get_ip4_config (NMDevice *device, NMIP4Config **config)
+real_act_stage4_get_ip4_config (NMDevice *device,
+                                NMIP4Config **config,
+                                NMDeviceStateReason *reason)
 {
 	NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
 

Modified: trunk/src/vpn-manager/nm-vpn-connection.c
==============================================================================
--- trunk/src/vpn-manager/nm-vpn-connection.c	(original)
+++ trunk/src/vpn-manager/nm-vpn-connection.c	Fri Jul 11 10:28:53 2008
@@ -175,15 +175,19 @@
 }
 
 static void
-device_state_changed (NMDevice *device, NMDeviceState state, gpointer user_data)
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
 {
 	NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
 
-	if (state <= NM_DEVICE_STATE_DISCONNECTED) {
+	if (new_state <= NM_DEVICE_STATE_DISCONNECTED) {
 		nm_vpn_connection_set_vpn_state (connection,
 		                                 NM_VPN_CONNECTION_STATE_DISCONNECTED,
 		                                 NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
-	} else if (state == NM_DEVICE_STATE_FAILED) {
+	} else if (new_state == NM_DEVICE_STATE_FAILED) {
 		nm_vpn_connection_set_vpn_state (connection,
 		                                 NM_VPN_CONNECTION_STATE_FAILED,
 		                                 NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
@@ -907,8 +911,17 @@
 
 			/* Reset routes, nameservers, and domains of the currently active device */
 			dev_ip4_config = nm_device_get_ip4_config (priv->parent_dev);
-			if (dev_ip4_config)
-				nm_device_set_ip4_config (priv->parent_dev, g_object_ref (dev_ip4_config));
+			if (dev_ip4_config) {
+				NMDeviceStateReason dev_reason = NM_DEVICE_STATE_REASON_NONE;
+
+				/* Since the config we're setting is also the device's current
+				 * config, have to ref the config to ensure it doesn't get
+				 * destroyed when the device unrefs it in nm_device_set_ip4_config().
+				 */
+				nm_device_set_ip4_config (priv->parent_dev,
+				                          g_object_ref (dev_ip4_config),
+				                          &dev_reason);
+			}
 		}
 
 		if (priv->banner) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]