summary refs log tree commit diff
path: root/src/nm-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-manager.c')
-rw-r--r--src/nm-manager.c551
1 files changed, 306 insertions, 245 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 22c3bd43..fbc9d23d 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -47,6 +47,7 @@
 #include "nm-device-modem.h"
 #include "nm-device-infiniband.h"
 #include "nm-device-bond.h"
+#include "nm-device-bridge.h"
 #include "nm-device-vlan.h"
 #include "nm-device-adsl.h"
 #include "nm-system.h"
@@ -69,6 +70,7 @@
 #include "nm-device-factory.h"
 #include "wifi-utils.h"
 #include "nm-enum-types.h"
+#include "nm-sleep-monitor.h"
 
 #if WITH_CONCHECK
 #include "nm-connectivity.h"
@@ -78,8 +80,6 @@
 #define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
 #define NM_AUTOIP_DBUS_IFACE   "org.freedesktop.nm_avahi_autoipd"
 
-#define UPOWER_DBUS_SERVICE "org.freedesktop.UPower"
-
 static gboolean impl_manager_get_devices (NMManager *manager,
                                           GPtrArray **devices,
                                           GError **err);
@@ -125,6 +125,10 @@ static gboolean impl_manager_set_logging (NMManager *manager,
                                           const char *domains,
                                           GError **error);
 
+static void impl_manager_get_logging (NMManager *manager,
+                                      char **level,
+                                      char **domains);
+
 #include "nm-manager-glue.h"
 
 static void bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
@@ -149,6 +153,7 @@ static NMActiveConnection *internal_activate_device (NMManager *manager,
                                                      const char *specific_object,
                                                      gboolean user_requested,
                                                      gulong sender_uid,
+                                                     const char *dbus_sender,
                                                      gboolean assumed,
                                                      NMActiveConnection *master,
                                                      GError **error);
@@ -198,6 +203,9 @@ typedef struct {
 typedef struct {
 	char *state_file;
 
+	GSList *active_connections;
+	guint ac_cleanup_id;
+
 	GSList *devices;
 	NMState state;
 #if WITH_CONCHECK
@@ -219,15 +227,13 @@ typedef struct {
 	gboolean net_enabled;
 
 	NMVPNManager *vpn_manager;
-	gulong vpn_manager_activated_id;
-	gulong vpn_manager_deactivated_id;
 
 	NMModemManager *modem_manager;
 	guint modem_added_id;
 	guint modem_removed_id;
 
 	DBusGProxy *aipd_proxy;
-	DBusGProxy *upower_proxy;
+	NMSleepMonitor *sleep_monitor;
 
 	GSList *auth_chains;
 
@@ -254,6 +260,8 @@ enum {
 	PROPERTIES_CHANGED,
 	CHECK_PERMISSIONS,
 	USER_PERMISSIONS_CHANGED,
+	ACTIVE_CONNECTION_ADDED,
+	ACTIVE_CONNECTION_REMOVED,
 
 	LAST_SIGNAL
 };
@@ -296,6 +304,102 @@ nm_manager_error_quark (void)
 
 /************************************************************************/
 
+static void active_connection_state_changed (NMActiveConnection *active,
+                                             GParamSpec *pspec,
+                                             NMManager *self);
+
+static gboolean
+_active_connection_cleanup (gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+	gboolean changed = FALSE;
+
+	priv->ac_cleanup_id = 0;
+
+	iter = priv->active_connections;
+	while (iter) {
+		NMActiveConnection *ac = iter->data;
+
+		iter = iter->next;
+		if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
+			priv->active_connections = g_slist_remove (priv->active_connections, ac);
+			g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, ac);
+			g_signal_handlers_disconnect_by_func (ac, active_connection_state_changed, self);
+			g_object_unref (ac);
+			changed = TRUE;
+		}
+	}
+
+	if (changed)
+		g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+
+	return FALSE;
+}
+
+static void
+active_connection_state_changed (NMActiveConnection *active,
+                                 GParamSpec *pspec,
+                                 NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMActiveConnectionState state;
+
+	state = nm_active_connection_get_state (active);
+	if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
+		/* Destroy active connections from an idle handler to ensure that
+		 * their last property change notifications go out, which wouldn't
+		 * happen if we destroyed them immediately when their state was set
+		 * to DEACTIVATED.
+		 */
+		if (!priv->ac_cleanup_id)
+			priv->ac_cleanup_id = g_idle_add (_active_connection_cleanup, self);
+	}
+}
+
+static void
+active_connection_add (NMManager *self, NMActiveConnection *active)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	g_return_if_fail (g_slist_find (priv->active_connections, active) == FALSE);
+
+	priv->active_connections = g_slist_prepend (priv->active_connections, active);
+	g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE,
+	                  G_CALLBACK (active_connection_state_changed),
+	                  self);
+
+	g_signal_emit (self, signals[ACTIVE_CONNECTION_ADDED], 0, active);
+	g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+}
+
+const GSList *
+nm_manager_get_active_connections (NMManager *manager)
+{
+	return NM_MANAGER_GET_PRIVATE (manager)->active_connections;
+}
+
+static NMActiveConnection *
+active_connection_get_by_path (NMManager *manager, const char *path)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	GSList *iter;
+
+	g_return_val_if_fail (manager != NULL, NULL);
+	g_return_val_if_fail (path != NULL, NULL);
+
+	for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
+		NMActiveConnection *candidate = iter->data;
+
+		if (strcmp (path, nm_active_connection_get_path (candidate)) == 0)
+			return candidate;
+	}
+	return NULL;
+}
+
+/************************************************************************/
+
 static NMDevice *
 nm_manager_get_device_by_udi (NMManager *manager, const char *udi)
 {
@@ -353,29 +457,6 @@ manager_sleeping (NMManager *self)
 }
 
 static void
-vpn_manager_connection_activated_cb (NMVPNManager *manager,
-                                     NMVPNConnection *vpn,
-                                     gpointer user_data)
-{
-	NMConnection *connection = nm_vpn_connection_get_connection (vpn);
-
-	/* Update timestamp for the VPN connection */
-	nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (connection),
-	                                         (guint64) time (NULL), TRUE);
-}
-
-static void
-vpn_manager_connection_deactivated_cb (NMVPNManager *manager,
-                                       NMVPNConnection *vpn,
-                                       NMVPNConnectionState new_state,
-                                       NMVPNConnectionState old_state,
-                                       NMVPNConnectionStateReason reason,
-                                       gpointer user_data)
-{
-	g_object_notify (G_OBJECT (user_data), NM_MANAGER_ACTIVE_CONNECTIONS);
-}
-
-static void
 modem_added (NMModemManager *modem_manager,
 			 NMModem *modem,
 			 const char *driver,
@@ -384,12 +465,16 @@ modem_added (NMModemManager *modem_manager,
 	NMManager *self = NM_MANAGER (user_data);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMDevice *replace_device, *device = NULL;
-	const char *ip_iface;
+	const char *modem_iface;
 	GSList *iter;
 
-	ip_iface = nm_modem_get_iface (modem);
+	/* Don't rely only on the data port; use the control port if available */
+	modem_iface = nm_modem_get_data_port (modem);
+	if (!modem_iface)
+		modem_iface = nm_modem_get_control_port (modem);
+	g_return_if_fail (modem_iface);
 
-	replace_device = find_device_by_ip_iface (NM_MANAGER (user_data), ip_iface);
+	replace_device = find_device_by_ip_iface (NM_MANAGER (user_data), modem_iface);
 	if (replace_device) {
 		priv->devices = remove_one_device (NM_MANAGER (user_data),
 		                                   priv->devices,
@@ -410,7 +495,7 @@ modem_added (NMModemManager *modem_manager,
 	 * by the Bluetooth code during the connection process.
 	 */
 	if (driver && !strcmp (driver, "bluetooth")) {
-		nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", ip_iface);
+		nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", modem_iface);
 		return;
 	}
 
@@ -885,36 +970,6 @@ pending_activation_destroy (PendingActivation *pending,
 	g_slice_free (PendingActivation, pending);
 }
 
-static GPtrArray *
-get_active_connections (NMManager *manager, NMConnection *filter)
-{
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
-	GPtrArray *active;
-	GSList *iter;
-
- 	active = g_ptr_array_sized_new (3);
-
-	/* Add active device connections */
-	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
-		NMActRequest *req;
-		const char *path;
-
-		req = nm_device_get_act_request (NM_DEVICE (iter->data));
-		if (!req)
-			continue;
-
-		if (!filter || (nm_act_request_get_connection (req) == filter)) {
-			path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req));
-			g_ptr_array_add (active, g_strdup (path));
-		}
-	}
-
-	/* Add active VPN connections */
-	nm_vpn_manager_add_active_connections (priv->vpn_manager, filter, active);
-
-	return active;
-}
-
 /*******************************************************************/
 /* Settings stuff via NMSettings                                   */
 /*******************************************************************/
@@ -945,8 +1000,8 @@ find_vlan_parent (NMManager *self,
 	GSList *iter;
 
 	/* The 'parent' property could be either an interface name, a connection
-	 * UUID, or even given by the MAC address of the connection's ethernet,
-	 * InfiniBand, or WiFi setting.
+	 * UUID, or even given by the MAC address of the connection's ethernet
+	 * or WiFi setting.
 	 */
 	s_vlan = nm_connection_get_setting_vlan (connection);
 	g_return_val_if_fail (s_vlan != NULL, NULL);
@@ -1016,6 +1071,9 @@ get_virtual_iface_name (NMManager *self,
 	if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
 		return g_strdup (nm_connection_get_virtual_iface_name (connection));
 
+	if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
+		return g_strdup (nm_connection_get_virtual_iface_name (connection));
+
 	if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
 		NMSettingVlan *s_vlan;
 		const char *ifname;
@@ -1025,11 +1083,20 @@ get_virtual_iface_name (NMManager *self,
 
 		parent = find_vlan_parent (self, connection, TRUE);
 		if (parent) {
+			ifname = nm_connection_get_virtual_iface_name (connection);
+
+			if (!nm_device_supports_vlans (parent)) {
+				nm_log_warn (LOGD_DEVICE, "(%s): No support for VLANs on interface %s of type %s",
+				             ifname ? ifname : nm_connection_get_id (connection),
+				             nm_device_get_ip_iface (parent),
+				             nm_device_get_type_desc (parent));
+				return NULL;
+			}
+
 			/* If the connection doesn't specify the interface name for the VLAN
 			 * device, we create one for it using the VLAN ID and the parent
 			 * interface's name.
 			 */
-			ifname = nm_connection_get_virtual_iface_name (connection);
 			if (ifname)
 				vname = g_strdup (ifname);
 			else {
@@ -1047,9 +1114,9 @@ get_virtual_iface_name (NMManager *self,
 static gboolean
 connection_needs_virtual_device (NMConnection *connection)
 {
-	if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
-		return TRUE;
-	if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME))
+	if (   nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)
+	    || nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)
+	    || nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME))
 		return TRUE;
 
 	return FALSE;
@@ -1111,6 +1178,16 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 		udi = get_virtual_iface_placeholder_udi ();
 		device = nm_device_bond_new (udi, iface);
 		g_free (udi);
+	} else if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) {
+		if (!nm_system_create_bridge (iface)) {
+			nm_log_warn (LOGD_DEVICE, "(%s): failed to add bridging interface for '%s'",
+			             iface, nm_connection_get_id (connection));
+			goto out;
+		}
+
+		udi = get_virtual_iface_placeholder_udi ();
+		device = nm_device_bridge_new (udi, iface);
+		g_free (udi);
 	} else if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
 		g_return_val_if_fail (parent != NULL, FALSE);
 
@@ -1157,17 +1234,24 @@ system_create_virtual_devices (NMManager *self)
 
 static void
 connection_added (NMSettings *settings,
-                  NMSettingsConnection *connection,
+                  NMSettingsConnection *settings_connection,
                   NMManager *manager)
 {
-	if (connection_needs_virtual_device (NM_CONNECTION (connection)))
-		system_create_virtual_device (manager, NM_CONNECTION (connection));
+	NMConnection *connection = NM_CONNECTION (settings_connection);
+
+	if (connection_needs_virtual_device (connection)) {
+		NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
+
+		g_assert (s_con);
+		if (nm_setting_connection_get_autoconnect (s_con))
+			system_create_virtual_device (manager, connection);
+	}
 }
 
 static void
 connection_changed (NMSettings *settings,
-                     NMSettingsConnection *connection,
-                     NMManager *manager)
+                    NMSettingsConnection *connection,
+                    NMManager *manager)
 {
 	/* FIXME: Some virtual devices may need to be updated in the future. */
 }
@@ -1528,7 +1612,7 @@ manager_ipw_rfkill_state_changed (NMDeviceWifi *device,
 }
 
 static void
-manager_modem_enabled_changed (NMModem *device, gpointer user_data)
+manager_modem_enabled_changed (NMDevice *device, gpointer user_data)
 {
 	nm_manager_rfkill_update (NM_MANAGER (user_data), RFKILL_TYPE_WWAN);
 }
@@ -1759,9 +1843,9 @@ add_device (NMManager *self, NMDevice *device)
 		nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume existing connection",
 		            nm_device_get_iface (device));
 
-		ac = internal_activate_device (self, device, existing, NULL, FALSE, 0, TRUE, NULL, &error);
+		ac = internal_activate_device (self, device, existing, NULL, FALSE, 0, NULL, TRUE, NULL, &error);
 		if (ac)
-			g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+			active_connection_add (self, ac);
 		else {
 			nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s",
 			             nm_connection_get_path (existing),
@@ -2007,6 +2091,12 @@ is_bond (int ifindex)
 }
 
 static gboolean
+is_bridge (int ifindex)
+{
+	return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_BRIDGE);
+}
+
+static gboolean
 is_vlan (int ifindex)
 {
 	return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_VLAN);
@@ -2085,6 +2175,8 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
 			device = nm_device_infiniband_new (sysfs_path, iface, driver);
 		else if (is_bond (ifindex))
 			device = nm_device_bond_new (sysfs_path, iface);
+		else if (is_bridge (ifindex))
+			device = nm_device_bridge_new (sysfs_path, iface);
 		else if (is_vlan (ifindex)) {
 			int parent_ifindex = -1;
 			NMDevice *parent;
@@ -2203,37 +2295,6 @@ impl_manager_get_device_by_ip_iface (NMManager *self,
 	return path ? TRUE : FALSE;
 }
 
-static NMActRequest *
-nm_manager_get_act_request_by_path (NMManager *manager,
-                                    const char *path,
-                                    NMDevice **device)
-{
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
-	GSList *iter;
-
-	g_return_val_if_fail (manager != NULL, NULL);
-	g_return_val_if_fail (path != NULL, NULL);
-	g_return_val_if_fail (device != NULL, NULL);
-	g_return_val_if_fail (*device == NULL, NULL);
-
-	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
-		NMActRequest *req;
-		const char *ac_path;
-
-		req = nm_device_get_act_request (NM_DEVICE (iter->data));
-		if (!req)
-			continue;
-
-		ac_path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req));
-		if (!strcmp (path, ac_path)) {
-			*device = NM_DEVICE (iter->data);
-			return req;
-		}
-	}
-
-	return NULL;
-}
-
 static NMActiveConnection *
 internal_activate_device (NMManager *manager,
                           NMDevice *device,
@@ -2241,12 +2302,13 @@ internal_activate_device (NMManager *manager,
                           const char *specific_object,
                           gboolean user_requested,
                           gulong sender_uid,
+                          const char *dbus_sender,
                           gboolean assumed,
                           NMActiveConnection *master,
                           GError **error)
 {
 	NMActRequest *req;
-	gboolean success;
+	NMDevice *master_device = NULL;
 
 	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
@@ -2265,17 +2327,21 @@ internal_activate_device (NMManager *manager,
 		                         NM_DEVICE_STATE_REASON_NONE);
 	}
 
+	if (master)
+		master_device = nm_active_connection_get_device (master);
+
 	req = nm_act_request_new (connection,
 	                          specific_object,
 	                          user_requested,
 	                          sender_uid,
+	                          dbus_sender,
 	                          assumed,
-	                          (gpointer) device,
-	                          master);
-	success = nm_device_activate (device, req, error);
-	g_object_unref (req);
+	                          device,
+	                          master_device);
+	g_assert (req);
+	nm_device_activate (device, req);
 
-	return success ? NM_ACTIVE_CONNECTION (req) : NULL;
+	return NM_ACTIVE_CONNECTION (req);
 }
 
 /**
@@ -2538,48 +2604,50 @@ static NMActiveConnection *
 activate_vpn_connection (NMManager *self,
                          NMConnection *connection,
                          const char *specific_object,
-                         const char *device_path,
                          gulong sender_uid,
                          GError **error)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMActRequest *parent_req = NULL;
+	NMActiveConnection *parent = NULL;
 	NMDevice *device = NULL;
 	GSList *iter;
 
 	if (specific_object) {
 		/* Find the specifc connection the client requested we use */
-		parent_req = nm_manager_get_act_request_by_path (self, specific_object, &device);
-		if (!parent_req) {
+		parent = active_connection_get_by_path (self, specific_object);
+		if (!parent) {
 			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
 			                     "Base connection for VPN connection not active.");
 			return NULL;
 		}
 	} else {
-		/* Just find the current default connection */
-		for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
-			NMDevice *candidate = NM_DEVICE (iter->data);
-			NMActRequest *candidate_req;
+		for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
+			NMActiveConnection *candidate = iter->data;
 
-			candidate_req = nm_device_get_act_request (candidate);
-			if (candidate_req && nm_active_connection_get_default (NM_ACTIVE_CONNECTION (candidate_req))) {
-				device = candidate;
-				parent_req = candidate_req;
+			if (nm_active_connection_get_default (candidate)) {
+				parent = candidate;
 				break;
 			}
 		}
 	}
 
-	if (!device || !parent_req) {
+	if (!parent) {
+		g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+		                     "Could not find source connection.");
+		return NULL;
+	}
+
+	device = nm_active_connection_get_device (parent);
+	if (!device) {
 		g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-		                     "Could not find source connection, or the source connection had no active device.");
+		                     "Source connection had no active device.");
 		return NULL;
 	}
 
 	return nm_vpn_manager_activate_connection (priv->vpn_manager,
 	                                           connection,
 	                                           device,
-	                                           nm_active_connection_get_path (NM_ACTIVE_CONNECTION (parent_req)),
+	                                           nm_active_connection_get_path (parent),
 	                                           TRUE,
 	                                           sender_uid,
 	                                           error);
@@ -2601,7 +2669,7 @@ nm_manager_activate_connection (NMManager *manager,
 	char *iface;
 	NMDevice *master_device = NULL;
 	NMConnection *master_connection = NULL;
-	NMActiveConnection *master_ac = NULL;
+	NMActiveConnection *master_ac = NULL, *ac = NULL;
 
 	g_return_val_if_fail (manager != NULL, NULL);
 	g_return_val_if_fail (connection != NULL, NULL);
@@ -2626,8 +2694,10 @@ nm_manager_activate_connection (NMManager *manager,
 	}
 
 	/* VPN ? */
-	if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME))
-		return activate_vpn_connection (manager, connection, specific_object, device_path, sender_uid, error);
+	if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) {
+		ac = activate_vpn_connection (manager, connection, specific_object, sender_uid, error);
+		goto activated;
+	}
 
 	/* Device-based connection */
 	if (device_path) {
@@ -2751,15 +2821,22 @@ nm_manager_activate_connection (NMManager *manager,
 		            nm_active_connection_get_path (master_ac));
 	}
 
-	return internal_activate_device (manager,
-	                                 device,
-	                                 connection,
-	                                 specific_object,
-	                                 dbus_sender ? TRUE : FALSE,
-	                                 dbus_sender ? sender_uid : 0,
-	                                 FALSE,
-	                                 master_ac,
-	                                 error);
+	ac = internal_activate_device (manager,
+	                               device,
+	                               connection,
+	                               specific_object,
+	                               dbus_sender ? TRUE : FALSE,
+	                               dbus_sender ? sender_uid : 0,
+	                               dbus_sender,
+	                               FALSE,
+	                               master_ac,
+	                               error);
+
+activated:
+	if (ac)
+		active_connection_add (manager, ac);
+
+	return ac;
 }
 
 /* 
@@ -2797,9 +2874,7 @@ pending_activate (NMManager *self, PendingActivation *pending)
 	                                     &error);
 	g_free (sender);
 
-	if (ac)
-		g_object_notify (G_OBJECT (pending->manager), NM_MANAGER_ACTIVE_CONNECTIONS);
-	else {
+	if (!ac) {
 		nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s",
 		             pending->connection_path,
 		             error ? error->code : -1,
@@ -2926,41 +3001,35 @@ nm_manager_deactivate_connection (NMManager *manager,
                                   GError **error)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
-	GSList *iter;
+	NMActiveConnection *active;
 	gboolean success = FALSE;
-	NMVPNConnectionStateReason vpn_reason = NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED;
 
-	/* Check for device connections first */
-	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
-		NMDevice *device = NM_DEVICE (iter->data);
-		NMActRequest *req;
+	active = active_connection_get_by_path (manager, connection_path);
+	if (!active) {
+		g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
+		                     "The connection was not active.");
+		return FALSE;
+	}
 
-		req = nm_device_get_act_request (device);
-		if (!req)
-			continue;
+	if (NM_IS_VPN_CONNECTION (active)) {
+		NMVPNConnectionStateReason vpn_reason = NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED;
 
-		if (!strcmp (connection_path, nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req)))) {
-			nm_device_state_changed (device,
-			                         NM_DEVICE_STATE_DISCONNECTED,
-			                         reason);
+		if (reason == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED)
+			vpn_reason = NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED;
+		if (nm_vpn_manager_deactivate_connection (priv->vpn_manager, NM_VPN_CONNECTION (active), vpn_reason))
 			success = TRUE;
-			goto done;
-		}
-	}
-
-	/* Check for VPN connections next */
-	if (reason == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED)
-		vpn_reason = NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED;
-	if (nm_vpn_manager_deactivate_connection (priv->vpn_manager, connection_path, vpn_reason)) {
-		success = TRUE;
 	} else {
-		g_set_error (error,
-		             NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
-		             "%s", "The connection was not active.");
+		g_assert (NM_IS_ACT_REQUEST (active));
+		/* FIXME: use DEACTIVATING state */
+		nm_device_state_changed (nm_active_connection_get_device (active),
+		                         NM_DEVICE_STATE_DISCONNECTED,
+		                         reason);
+		success = TRUE;
 	}
 
-done:
-	g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
+	if (success)
+		g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
+
 	return success;
 }
 
@@ -3021,25 +3090,16 @@ impl_manager_deactivate_connection (NMManager *self,
 	gulong sender_uid = G_MAXULONG;
 	char *error_desc = NULL;
 
-	/* Check for device connections first */
-	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
-		NMActRequest *req;
-		const char *req_path = NULL;
-
-		req = nm_device_get_act_request (NM_DEVICE (iter->data));
-		if (req)
-			req_path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req));
+	/* Find the connection by its object path */
+	for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
+		NMActiveConnection *ac = iter->data;
 
-		if (req_path && !strcmp (active_path, req_path)) {
-			connection = nm_act_request_get_connection (req);
+		if (g_strcmp0 (nm_active_connection_get_path (ac), active_path) == 0) {
+			connection = nm_active_connection_get_connection (ac);
 			break;
 		}
 	}
 
-	/* Maybe it's a VPN */
-	if (!connection)
-		connection = nm_vpn_manager_get_connection_for_active (priv->vpn_manager, active_path);
-
 	if (!connection) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
@@ -3275,16 +3335,16 @@ impl_manager_sleep (NMManager *self,
 }
 
 static void
-upower_sleeping_cb (DBusGProxy *proxy, gpointer user_data)
+sleeping_cb (DBusGProxy *proxy, gpointer user_data)
 {
-	nm_log_dbg (LOGD_SUSPEND, "Received UPower sleeping signal");
+	nm_log_dbg (LOGD_SUSPEND, "Received sleeping signal");
 	_internal_sleep (NM_MANAGER (user_data), TRUE);
 }
 
 static void
-upower_resuming_cb (DBusGProxy *proxy, gpointer user_data)
+resuming_cb (DBusGProxy *proxy, gpointer user_data)
 {
-	nm_log_dbg (LOGD_SUSPEND, "Received UPower resuming signal");
+	nm_log_dbg (LOGD_SUSPEND, "Received resuming signal");
 	_internal_sleep (NM_MANAGER (user_data), FALSE);
 }
 
@@ -3517,11 +3577,13 @@ impl_manager_set_logging (NMManager *manager,
 	return FALSE;
 }
 
-GPtrArray *
-nm_manager_get_active_connections_by_connection (NMManager *manager,
-                                                 NMConnection *connection)
+static void
+impl_manager_get_logging (NMManager *manager,
+                          char **level,
+                          char **domains)
 {
-	return get_active_connections (manager, connection);
+	*level = g_strdup (nm_logging_level_to_string ());
+	*domains = g_strdup (nm_logging_domains_to_string ());
 }
 
 void
@@ -3971,6 +4033,7 @@ dispose (GObject *object)
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	DBusGConnection *bus;
 	DBusConnection *dbus_connection;
+	GSList *iter;
 
 	if (priv->disposed) {
 		G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
@@ -3990,6 +4053,17 @@ dispose (GObject *object)
 		                                   TRUE);
 	}
 
+	if (priv->ac_cleanup_id) {
+		g_source_remove (priv->ac_cleanup_id);
+		priv->ac_cleanup_id = 0;
+	}
+
+	for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
+		g_signal_handlers_disconnect_by_func (iter->data, active_connection_state_changed, object);
+		g_object_unref (iter->data);
+	}
+	g_slist_free (priv->active_connections);
+
 #if WITH_CONCHECK
 	if (priv->connectivity) {
 		g_object_unref (priv->connectivity);
@@ -4000,15 +4074,6 @@ dispose (GObject *object)
 	g_free (priv->hostname);
 
 	g_object_unref (priv->settings);
-
-	if (priv->vpn_manager_activated_id) {
-		g_source_remove (priv->vpn_manager_activated_id);
-		priv->vpn_manager_activated_id = 0;
-	}
-	if (priv->vpn_manager_deactivated_id) {
-		g_source_remove (priv->vpn_manager_deactivated_id);
-		priv->vpn_manager_deactivated_id = 0;
-	}
 	g_object_unref (priv->vpn_manager);
 
 	if (priv->modem_added_id) {
@@ -4036,8 +4101,8 @@ dispose (GObject *object)
 	if (priv->aipd_proxy)
 		g_object_unref (priv->aipd_proxy);
 
-	if (priv->upower_proxy)
-		g_object_unref (priv->upower_proxy);
+	if (priv->sleep_monitor)
+		g_object_unref (priv->sleep_monitor);
 
 	if (priv->fw_monitor) {
 		if (priv->fw_monitor_id)
@@ -4201,6 +4266,9 @@ get_property (GObject *object, guint prop_id,
 {
 	NMManager *self = NM_MANAGER (object);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+	GPtrArray *active;
+	const char *path;
 
 	switch (prop_id) {
 	case PROP_VERSION:
@@ -4232,7 +4300,12 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WIMAX].hw_enabled);
 		break;
 	case PROP_ACTIVE_CONNECTIONS:
-		g_value_take_boxed (value, get_active_connections (self, NULL));
+		active = g_ptr_array_sized_new (3);
+		for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
+			path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (iter->data));
+			g_ptr_array_add (active, g_strdup (path));
+		}
+		g_value_take_boxed (value, active);
 		break;
 	case PROP_HOSTNAME:
 		g_value_set_string (value, priv->hostname);
@@ -4251,28 +4324,15 @@ periodic_update_active_connection_timestamps (gpointer user_data)
 {
 	NMManager *manager = NM_MANAGER (user_data);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
-	GPtrArray *active;
-	int i;
-
-	active = get_active_connections (manager, NULL);
-
-	for (i = 0; i < active->len; i++) {
-		const char *active_path = g_ptr_array_index (active, i);
-		NMActRequest *req;
-		NMDevice *device = NULL;
+	GSList *iter;
 
-		req = nm_manager_get_act_request_by_path (manager, active_path, &device);
-		if (device && nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
-			nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_act_request_get_connection (req)),
-			                                         (guint64) time (NULL), FALSE);
-		else {
-			/* The connection is probably VPN */
-			NMVPNConnection *vpn_con;
+	for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
+		NMActiveConnection *ac = iter->data;
+		NMSettingsConnection *connection;
 
-			vpn_con = nm_vpn_manager_get_vpn_connection_for_active (priv->vpn_manager, active_path);
-			if (vpn_con && nm_vpn_connection_get_vpn_state (vpn_con) == NM_VPN_CONNECTION_STATE_ACTIVATED)
-				nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_vpn_connection_get_connection (vpn_con)),
-				                                         (guint64) time (NULL), FALSE);
+		if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+			connection = NM_SETTINGS_CONNECTION (nm_active_connection_get_connection (ac));
+			nm_settings_connection_update_timestamp (connection, (guint64) time (NULL), FALSE);
 		}
 	}
 
@@ -4329,10 +4389,6 @@ nm_manager_init (NMManager *manager)
 	                                           G_CALLBACK (modem_removed), manager);
 
 	priv->vpn_manager = nm_vpn_manager_get ();
-	priv->vpn_manager_activated_id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-activated",
-	                                                   G_CALLBACK (vpn_manager_connection_activated_cb), manager);
-	priv->vpn_manager_deactivated_id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-deactivated",
-	                                                   G_CALLBACK (vpn_manager_connection_deactivated_cb), manager);
 
 	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
 
@@ -4359,23 +4415,12 @@ nm_manager_init (NMManager *manager)
 	} else
 		nm_log_warn (LOGD_AUTOIP4, "could not initialize avahi-autoipd D-Bus proxy");
 
-	/* upower sleep/wake handling */
-	priv->upower_proxy = dbus_g_proxy_new_for_name (g_connection,
-	                                                UPOWER_DBUS_SERVICE,
-	                                                "/org/freedesktop/UPower",
-	                                                "org.freedesktop.UPower");
-	if (priv->upower_proxy) {
-		dbus_g_proxy_add_signal (priv->upower_proxy, "Sleeping", G_TYPE_INVALID);
-		dbus_g_proxy_connect_signal (priv->upower_proxy, "Sleeping",
-		                             G_CALLBACK (upower_sleeping_cb),
-		                             manager, NULL);
-
-		dbus_g_proxy_add_signal (priv->upower_proxy, "Resuming", G_TYPE_INVALID);
-		dbus_g_proxy_connect_signal (priv->upower_proxy, "Resuming",
-		                             G_CALLBACK (upower_resuming_cb),
-		                             manager, NULL);
-	} else
-		nm_log_warn (LOGD_SUSPEND, "could not initialize UPower D-Bus proxy");
+	/* sleep/wake handling */
+	priv->sleep_monitor = nm_sleep_monitor_get ();
+	g_signal_connect (priv->sleep_monitor, "sleeping",
+	                  G_CALLBACK (sleeping_cb), manager);
+	g_signal_connect (priv->sleep_monitor, "resuming",
+	                  G_CALLBACK (resuming_cb), manager);
 
 	/* Listen for authorization changes */
 	nm_auth_changed_func_register (authority_changed_cb, manager);
@@ -4563,6 +4608,22 @@ nm_manager_class_init (NMManagerClass *manager_class)
 		              g_cclosure_marshal_VOID__VOID,
 		              G_TYPE_NONE, 0);
 
+	signals[ACTIVE_CONNECTION_ADDED] =
+		g_signal_new (NM_MANAGER_ACTIVE_CONNECTION_ADDED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              g_cclosure_marshal_VOID__OBJECT,
+		              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+	signals[ACTIVE_CONNECTION_REMOVED] =
+		g_signal_new (NM_MANAGER_ACTIVE_CONNECTION_REMOVED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              g_cclosure_marshal_VOID__OBJECT,
+		              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (manager_class),
 	                                 &dbus_glib_nm_manager_object_info);