about summary refs log tree commit diff
path: root/src/nm-manager.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2010-11-29 00:47:11 +0100
committerMichael Biebl <biebl@debian.org>2010-11-29 00:47:11 +0100
commit9fae01fa351805b2903e535736e06971bc0b925e (patch)
treec19bccf84c9f894e50fae678ba6ee2b2044e2d30 /src/nm-manager.c
Imported Upstream version 0.8.1 upstream/0.8.1
Diffstat (limited to 'src/nm-manager.c')
-rw-r--r--src/nm-manager.c3463
1 files changed, 3463 insertions, 0 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c
new file mode 100644
index 00000000..7d46285b
--- /dev/null
+++ b/src/nm-manager.c
@@ -0,0 +1,3463 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2007 - 2009 Novell, Inc.
+ * Copyright (C) 2007 - 2010 Red Hat, Inc.
+ */
+
+#include <netinet/ether.h>
+#include <string.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib.h>
+
+#include "nm-glib-compat.h"
+#include "nm-manager.h"
+#include "nm-logging.h"
+#include "nm-dbus-manager.h"
+#include "nm-vpn-manager.h"
+#include "nm-modem-manager.h"
+#include "nm-device-bt.h"
+#include "nm-device-interface.h"
+#include "nm-device-private.h"
+#include "nm-device-ethernet.h"
+#include "nm-device-wifi.h"
+#include "nm-device-olpc-mesh.h"
+#include "nm-device-cdma.h"
+#include "nm-device-gsm.h"
+#include "nm-system.h"
+#include "nm-properties-changed-signal.h"
+#include "nm-setting-bluetooth.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-wireless.h"
+#include "nm-setting-vpn.h"
+#include "nm-marshal.h"
+#include "nm-dbus-glib-types.h"
+#include "nm-udev-manager.h"
+#include "nm-hostname-provider.h"
+#include "nm-bluez-manager.h"
+#include "nm-bluez-common.h"
+#include "nm-sysconfig-settings.h"
+#include "nm-secrets-provider-interface.h"
+#include "nm-settings-interface.h"
+#include "nm-settings-system-interface.h"
+
+#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
+#define NM_AUTOIP_DBUS_IFACE   "org.freedesktop.nm_avahi_autoipd"
+
+static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err);
+static void impl_manager_activate_connection (NMManager *manager,
+								  const char *service_name,
+								  const char *connection_path,
+								  const char *device_path,
+								  const char *specific_object_path,
+								  DBusGMethodInvocation *context);
+
+static gboolean impl_manager_deactivate_connection (NMManager *manager,
+                                                    const char *connection_path,
+                                                    GError **error);
+
+static gboolean impl_manager_sleep (NMManager *manager, gboolean sleep, GError **err);
+
+static gboolean impl_manager_enable (NMManager *manager, gboolean enable, GError **err);
+
+static gboolean impl_manager_set_logging (NMManager *manager,
+                                          const char *level,
+                                          const char *domains,
+                                          GError **error);
+
+/* Legacy 0.6 compatibility interface */
+
+static gboolean impl_manager_legacy_sleep (NMManager *manager, GError **err);
+static gboolean impl_manager_legacy_wake  (NMManager *manager, GError **err);
+static gboolean impl_manager_legacy_state (NMManager *manager, guint32 *state, GError **err);
+
+#include "nm-manager-glue.h"
+
+static void user_destroy_connections (NMManager *manager);
+
+static void connection_added_default_handler (NMManager *manager,
+									 NMConnection *connection,
+									 NMConnectionScope scope);
+
+static void udev_device_added_cb (NMUdevManager *udev_mgr,
+                                  GUdevDevice *device,
+                                  NMDeviceCreatorFn creator_fn,
+                                  gpointer user_data);
+
+static void udev_device_removed_cb (NMUdevManager *udev_mgr,
+                                    GUdevDevice *device,
+                                    gpointer user_data);
+
+static void bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
+					   const char *bdaddr,
+					   const char *name,
+					   const char *object_path,
+					   guint32 uuids,
+					   NMManager *manager);
+
+static void bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
+					     const char *bdaddr,
+					     const char *object_path,
+					     gpointer user_data);
+
+static void bluez_manager_resync_devices (NMManager *self);
+
+static void add_device (NMManager *self, NMDevice *device);
+
+static void hostname_provider_init (NMHostnameProvider *provider_class);
+
+static const char *internal_activate_device (NMManager *manager,
+                                             NMDevice *device,
+                                             NMConnection *connection,
+                                             const char *specific_object,
+                                             gboolean user_requested,
+                                             gboolean assumed,
+                                             GError **error);
+
+static NMDevice *find_device_by_iface (NMManager *self, const gchar *iface);
+
+static GSList * remove_one_device (NMManager *manager,
+                                   GSList *list,
+                                   NMDevice *device,
+                                   gboolean quitting,
+                                   gboolean force_unmanage);
+
+static NMDevice *nm_manager_get_device_by_udi (NMManager *manager, const char *udi);
+
+#define SSD_POKE_INTERVAL 120
+#define ORIGDEV_TAG "originating-device"
+
+typedef struct {
+	DBusGMethodInvocation *context;
+	NMConnectionScope scope;
+	char *connection_path;
+	char *specific_object_path;
+	char *device_path;
+	guint timeout_id;
+} PendingConnectionInfo;
+
+typedef struct {
+	gboolean enabled;
+	gboolean hw_enabled;
+	RfKillType rtype;
+	const char *desc;
+	const char *key;
+	const char *prop;
+	const char *hw_prop;
+	RfKillState (*other_enabled_func) (NMManager *);
+} RadioState;
+
+typedef struct {
+	char *config_file;
+	char *state_file;
+
+	GSList *devices;
+	NMState state;
+
+	NMDBusManager *dbus_mgr;
+	NMUdevManager *udev_mgr;
+	NMBluezManager *bluez_mgr;
+
+	GHashTable *user_connections;
+	DBusGProxy *user_proxy;
+
+	GHashTable *system_connections;
+	NMSysconfigSettings *sys_settings;
+	char *hostname;
+
+	GSList *secrets_calls;
+
+	PendingConnectionInfo *pending_connection_info;
+
+	RadioState radio_states[RFKILL_TYPE_MAX];
+	gboolean sleeping;
+	gboolean net_enabled;
+
+	NMVPNManager *vpn_manager;
+	guint vpn_manager_id;
+
+	NMModemManager *modem_manager;
+	guint modem_added_id;
+	guint modem_removed_id;
+
+	DBusGProxy *aipd_proxy;
+
+	gboolean disposed;
+} NMManagerPrivate;
+
+#define NM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MANAGER, NMManagerPrivate))
+
+G_DEFINE_TYPE_EXTENDED (NMManager, nm_manager, G_TYPE_OBJECT, 0,
+						G_IMPLEMENT_INTERFACE (NM_TYPE_HOSTNAME_PROVIDER,
+											   hostname_provider_init))
+
+enum {
+	DEVICE_ADDED,
+	DEVICE_REMOVED,
+	STATE_CHANGED,
+	STATE_CHANGE,  /* DEPRECATED */
+	PROPERTIES_CHANGED,
+	CONNECTIONS_ADDED,
+	CONNECTION_ADDED,
+	CONNECTION_UPDATED,
+	CONNECTION_REMOVED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+	PROP_0,
+	PROP_STATE,
+	PROP_NETWORKING_ENABLED,
+	PROP_WIRELESS_ENABLED,
+	PROP_WIRELESS_HARDWARE_ENABLED,
+	PROP_WWAN_ENABLED,
+	PROP_WWAN_HARDWARE_ENABLED,
+	PROP_ACTIVE_CONNECTIONS,
+
+	/* Not exported */
+	PROP_HOSTNAME,
+	PROP_SLEEPING,
+
+	LAST_PROP
+};
+
+typedef enum
+{
+	NM_MANAGER_ERROR_UNKNOWN_CONNECTION = 0,
+	NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+	NM_MANAGER_ERROR_UNMANAGED_DEVICE,
+	NM_MANAGER_ERROR_INVALID_SERVICE,
+	NM_MANAGER_ERROR_SYSTEM_CONNECTION,
+	NM_MANAGER_ERROR_PERMISSION_DENIED,
+	NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
+	NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
+	NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
+} NMManagerError;
+
+#define NM_MANAGER_ERROR (nm_manager_error_quark ())
+#define NM_TYPE_MANAGER_ERROR (nm_manager_error_get_type ()) 
+
+static GQuark
+nm_manager_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("nm-manager-error");
+	return quark;
+}
+
+/* This should really be standard. */
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+static GType
+nm_manager_error_get_type (void)
+{
+	static GType etype = 0;
+
+	if (etype == 0) {
+		static const GEnumValue values[] = {
+			/* Connection was not provided by any known settings service. */
+			ENUM_ENTRY (NM_MANAGER_ERROR_UNKNOWN_CONNECTION, "UnknownConnection"),
+			/* Unknown device. */
+			ENUM_ENTRY (NM_MANAGER_ERROR_UNKNOWN_DEVICE, "UnknownDevice"),
+			/* Unmanaged device. */
+			ENUM_ENTRY (NM_MANAGER_ERROR_UNMANAGED_DEVICE, "UnmanagedDevice"),
+			/* Invalid settings service (not a recognized system or user
+			 * settings service name)
+			 */
+			ENUM_ENTRY (NM_MANAGER_ERROR_INVALID_SERVICE, "InvalidService"),
+			/* Connection was superceded by a system connection. */
+			ENUM_ENTRY (NM_MANAGER_ERROR_SYSTEM_CONNECTION, "SystemConnection"),
+			/* User does not have the permission to activate this connection. */
+			ENUM_ENTRY (NM_MANAGER_ERROR_PERMISSION_DENIED, "PermissionDenied"),
+			/* The connection was not active. */
+			ENUM_ENTRY (NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, "ConnectionNotActive"),
+			/* The manager is already in the requested sleep state */
+			ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE, "AlreadyAsleepOrAwake"),
+			/* The manager is already in the requested enabled/disabled state */
+			ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, "AlreadyEnabledOrDisabled"),
+			{ 0, 0, 0 },
+		};
+		etype = g_enum_register_static ("NMManagerError", values);
+	}
+	return etype;
+}
+
+static gboolean
+manager_sleeping (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	if (priv->sleeping || !priv->net_enabled)
+		return TRUE;
+	return FALSE;
+}
+
+static void
+vpn_manager_connection_deactivated_cb (NMVPNManager *manager,
+                                       NMVPNConnection *vpn,
+                                       NMVPNConnectionState 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,
+			 gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMDevice *replace_device, *device = NULL;
+	const char *ip_iface;
+	GSList *iter;
+
+	ip_iface = nm_modem_get_iface (modem);
+
+	replace_device = find_device_by_iface (NM_MANAGER (user_data), ip_iface);
+	if (replace_device) {
+		priv->devices = remove_one_device (NM_MANAGER (user_data),
+		                                   priv->devices,
+		                                   replace_device,
+		                                   FALSE,
+		                                   TRUE);
+	}
+
+	/* Give Bluetooth DUN devices first chance to claim the modem */
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		if (NM_IS_DEVICE_BT (iter->data)) {
+			if (nm_device_bt_modem_added (NM_DEVICE_BT (iter->data), modem, driver))
+				return;
+		}
+	}
+
+	/* If it was a Bluetooth modem and no bluetooth device claimed it, ignore
+	 * it.  The rfcomm port (and thus the modem) gets created automatically
+	 * 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);
+		return;
+	}
+
+	/* Otherwise make a new top-level NMDevice for it */
+	if (NM_IS_MODEM_GSM (modem))
+		device = nm_device_gsm_new (NM_MODEM_GSM (modem), driver);
+	else if (NM_IS_MODEM_CDMA (modem))
+		device = nm_device_cdma_new (NM_MODEM_CDMA (modem), driver);
+	else
+		nm_log_info (LOGD_MB, "unhandled modem '%s'", ip_iface);
+
+	if (device)
+		add_device (self, device);
+}
+
+static void
+nm_manager_update_state (NMManager *manager)
+{
+	NMManagerPrivate *priv;
+	NMState new_state = NM_STATE_DISCONNECTED;
+
+	g_return_if_fail (NM_IS_MANAGER (manager));
+
+	priv = NM_MANAGER_GET_PRIVATE (manager);
+
+	if (manager_sleeping (manager))
+		new_state = NM_STATE_ASLEEP;
+	else {
+		GSList *iter;
+
+		for (iter = priv->devices; iter; iter = iter->next) {
+			NMDevice *dev = NM_DEVICE (iter->data);
+
+			if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
+				new_state = NM_STATE_CONNECTED;
+				break;
+			} else if (nm_device_is_activating (dev)) {
+				new_state = NM_STATE_CONNECTING;
+			}
+		}
+	}
+
+	if (priv->state != new_state) {
+		priv->state = new_state;
+		g_object_notify (G_OBJECT (manager), NM_MANAGER_STATE);
+
+		g_signal_emit (manager, signals[STATE_CHANGED], 0, priv->state);
+
+		/* Emit StateChange too for backwards compatibility */
+		g_signal_emit (manager, signals[STATE_CHANGE], 0, priv->state);
+	}
+}
+
+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);
+}
+
+/* Removes a device from a device list; returns the start of the new device list */
+static GSList *
+remove_one_device (NMManager *manager,
+                   GSList *list,
+                   NMDevice *device,
+                   gboolean quitting,
+                   gboolean force_unmanage)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
+	if (nm_device_get_managed (device)) {
+		gboolean unmanage = !quitting;
+
+		/* Don't unmanage active assume-connection-capable devices at shutdown */
+		if (   nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device))
+		    && nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
+			unmanage = FALSE;
+
+		if (unmanage || force_unmanage)
+			nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
+	}
+
+	g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager);
+
+	nm_sysconfig_settings_device_removed (priv->sys_settings, device);
+	g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device);
+	g_object_unref (device);
+
+	return g_slist_remove (list, device);
+}
+
+static void
+modem_removed (NMModemManager *modem_manager,
+			   NMModem *modem,
+			   gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMDevice *found;
+	GSList *iter;
+
+	/* Give Bluetooth DUN devices first chance to handle the modem removal */
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		if (NM_IS_DEVICE_BT (iter->data)) {
+			if (nm_device_bt_modem_removed (NM_DEVICE_BT (iter->data), modem))
+				return;
+		}
+	}
+
+	/* Otherwise remove the standalone modem */
+	found = nm_manager_get_device_by_udi (self, nm_modem_get_path (modem));
+	if (found)
+		priv->devices = remove_one_device (self, priv->devices, found, FALSE, TRUE);
+}
+
+static void
+aipd_handle_event (DBusGProxy *proxy,
+                   const char *event,
+                   const char *iface,
+                   const char *address,
+                   gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	GSList *iter;
+	gboolean handled = FALSE;
+
+	if (!event || !iface) {
+		nm_log_warn (LOGD_AUTOIP4, "incomplete message received from avahi-autoipd");
+		return;
+	}
+
+	if (   (strcmp (event, "BIND") != 0)
+	    && (strcmp (event, "CONFLICT") != 0)
+	    && (strcmp (event, "UNBIND") != 0)
+	    && (strcmp (event, "STOP") != 0)) {
+		nm_log_warn (LOGD_AUTOIP4, "unknown event '%s' received from avahi-autoipd", event);
+		return;
+	}
+
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *candidate = NM_DEVICE (iter->data);
+
+		if (!strcmp (nm_device_get_iface (candidate), iface)) {
+			nm_device_handle_autoip4_event (candidate, event, address);
+			handled = TRUE;
+			break;
+		}
+	}
+
+	if (!handled)
+		nm_log_warn (LOGD_AUTOIP4, "(%s): unhandled avahi-autoipd event", iface);
+}
+
+static const char *
+hostname_provider_get_hostname (NMHostnameProvider *provider)
+{
+	return NM_MANAGER_GET_PRIVATE (provider)->hostname;
+}
+
+static void
+hostname_provider_init (NMHostnameProvider *provider_class)
+{
+	provider_class->get_hostname = hostname_provider_get_hostname;
+}
+
+NMState
+nm_manager_get_state (NMManager *manager)
+{
+	g_return_val_if_fail (NM_IS_MANAGER (manager), NM_STATE_UNKNOWN);
+
+	return NM_MANAGER_GET_PRIVATE (manager)->state;
+}
+
+static void
+emit_removed (gpointer key, gpointer value, gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	NMConnection *connection = NM_CONNECTION (value);
+
+	g_signal_emit (manager, signals[CONNECTION_REMOVED], 0,
+	               connection,
+	               nm_connection_get_scope (connection));
+}
+
+static void
+pending_connection_info_destroy (PendingConnectionInfo *info)
+{
+	if (!info)
+		return;
+
+	if (info->timeout_id)
+		g_source_remove (info->timeout_id);
+
+	g_free (info->connection_path);
+	g_free (info->specific_object_path);
+	g_free (info->device_path);
+
+	g_slice_free (PendingConnectionInfo, info);
+}
+
+static GPtrArray *
+get_active_connections (NMManager *manager, NMConnection *filter)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	NMVPNManager *vpn_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_act_request_get_active_connection_path (req);
+			g_ptr_array_add (active, g_strdup (path));
+		}
+	}
+
+	/* Add active VPN connections */
+	vpn_manager = nm_vpn_manager_get ();
+	nm_vpn_manager_add_active_connections (vpn_manager, filter, active);
+	g_object_unref (vpn_manager);
+
+	return active;
+}
+
+static void
+remove_connection (NMManager *manager,
+                   NMConnection *connection,
+                   GHashTable *hash)
+{
+	/* Destroys the connection, then associated DBusGProxy due to the
+	 * weak reference notify function placed on the connection when it
+	 * was created.
+	 */
+	g_object_ref (connection);
+	g_hash_table_remove (hash, nm_connection_get_path (connection));
+	g_signal_emit (manager, signals[CONNECTION_REMOVED], 0,
+	               connection,
+	               nm_connection_get_scope (connection));
+	g_object_unref (connection);
+
+	bluez_manager_resync_devices (manager);
+}
+
+/*******************************************************************/
+/* User settings stuff via D-Bus                                   */
+/*******************************************************************/
+
+static void
+user_destroy_connections (NMManager *manager)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
+	if (priv->user_connections) {
+		g_hash_table_foreach (priv->user_connections, emit_removed, manager);
+		g_hash_table_remove_all (priv->user_connections);
+	}
+
+	if (priv->user_proxy) {
+		g_object_unref (priv->user_proxy);
+		priv->user_proxy = NULL;
+	}
+}
+
+typedef struct GetSettingsInfo {
+	NMManager *manager;
+	NMConnection *connection;
+	DBusGProxy *proxy;
+	DBusGProxyCall *call;
+	GSList **calls;
+} GetSettingsInfo;
+
+static void
+free_get_settings_info (gpointer data)
+{
+	GetSettingsInfo *info = (GetSettingsInfo *) data;
+
+	/* If this was the last pending call for a batch of GetSettings calls,
+	 * send out the connections-added signal.
+	 */
+	if (info->calls) {
+		*(info->calls) = g_slist_remove (*(info->calls), info->call);
+		if (g_slist_length (*(info->calls)) == 0) {
+			g_slist_free (*(info->calls));
+			g_slice_free (GSList, (gpointer) info->calls);
+			g_signal_emit (info->manager, signals[CONNECTIONS_ADDED], 0, NM_CONNECTION_SCOPE_USER);
+
+			/* Update the Bluetooth connections for all the new connections */
+			bluez_manager_resync_devices (info->manager);
+		}
+	}
+
+	if (info->manager) {
+		g_object_unref (info->manager);
+		info->manager = NULL;
+	}
+	if (info->connection) {
+		g_object_unref (info->connection);
+		info->connection = NULL;
+	}
+	if (info->proxy) {
+		g_object_unref (info->proxy);
+		info->proxy = NULL;
+	}
+
+	g_slice_free (GetSettingsInfo, data);	
+}
+
+static void
+user_connection_get_settings_cb  (DBusGProxy *proxy,
+                                  DBusGProxyCall *call_id,
+                                  gpointer user_data)
+{
+	GetSettingsInfo *info = (GetSettingsInfo *) user_data;
+	GError *err = NULL;
+	GHashTable *settings = NULL;
+	NMConnection *connection;
+	NMManager *manager;
+
+	g_return_if_fail (info != NULL);
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
+	                            DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings,
+	                            G_TYPE_INVALID)) {
+		nm_log_info (LOGD_USER_SET, "couldn't retrieve connection settings: %s.",
+		             err && err->message ? err->message : "(unknown)");
+		g_error_free (err);
+		goto out;
+	}
+
+	manager = info->manager;
+	connection = info->connection;
+ 	if (connection == NULL) {
+		const char *path = dbus_g_proxy_get_path (proxy);
+		NMManagerPrivate *priv;
+		GError *error = NULL;
+		NMConnection *existing = NULL;
+
+		connection = nm_connection_new_from_hash (settings, &error);
+		if (connection == NULL) {
+			nm_log_warn (LOGD_USER_SET, "invalid connection: '%s' / '%s' invalid: %d",
+			             g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
+			             error->message, error->code);
+			g_error_free (error);
+			goto out;
+		}
+
+		nm_connection_set_path (connection, path);
+		nm_connection_set_scope (connection, NM_CONNECTION_SCOPE_USER);
+
+		/* Add the new connection to the internal hashes only if the same
+		 * connection isn't already there.
+		 */
+		priv = NM_MANAGER_GET_PRIVATE (manager);
+
+		existing = g_hash_table_lookup (priv->user_connections, path);
+		if (!existing || !nm_connection_compare (existing, connection, NM_SETTING_COMPARE_FLAG_EXACT)) {
+			g_hash_table_insert (priv->user_connections,
+			                     g_strdup (path),
+			                     connection);
+			existing = NULL;
+
+			/* Attach the D-Bus proxy representing the remote NMConnection
+			 * to the local NMConnection object to ensure it stays alive to
+			 * continue delivering signals.  It'll be destroyed once the
+			 * NMConnection is destroyed.
+			 */
+			g_object_set_data_full (G_OBJECT (connection),
+			                        "proxy",
+			                        g_object_ref (info->proxy),
+									g_object_unref);
+		} else
+			g_object_unref (connection);
+
+		/* If the connection-added signal is supposed to be batched, don't
+		 * emit the single connection-added here.  Also, don't emit the signal
+		 * if the connection wasn't actually added to the system or user hashes.
+		 */
+		if (!info->calls && !existing) {
+			g_signal_emit (manager, signals[CONNECTION_ADDED], 0, connection, NM_CONNECTION_SCOPE_USER);
+			/* Update the Bluetooth connections for that single new connection */
+			bluez_manager_resync_devices (manager);
+		}
+	} else {
+		// FIXME: merge settings? or just replace?
+		nm_log_dbg (LOGD_USER_SET, "implement merge settings");
+	}
+
+out:
+	if (settings)
+		g_hash_table_destroy (settings);
+
+	return;
+}
+
+static void
+user_connection_removed_cb (DBusGProxy *proxy, gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	NMConnection *connection = NULL;
+	const char *path;
+
+	path = dbus_g_proxy_get_path (proxy);
+	if (path) {
+		connection = g_hash_table_lookup (priv->user_connections, path);
+		if (connection)
+			remove_connection (manager, connection, priv->user_connections);
+	}
+}
+
+static void
+user_connection_updated_cb (DBusGProxy *proxy,
+                            GHashTable *settings,
+                            gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	NMConnection *new_connection;
+	NMConnection *old_connection = NULL;
+	gboolean valid = FALSE;
+	GError *error = NULL;
+	const char *path;
+
+	path = dbus_g_proxy_get_path (proxy);
+	if (path)
+		old_connection = g_hash_table_lookup (priv->user_connections, path);
+
+	g_return_if_fail (old_connection != NULL);
+
+	new_connection = nm_connection_new_from_hash (settings, &error);
+	if (!new_connection) {
+		/* New connection invalid, remove existing connection */
+		nm_log_warn (LOGD_USER_SET, "invalid connection: '%s' / '%s' invalid: %d",
+		             g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
+		             error->message, error->code);
+		g_error_free (error);
+		remove_connection (manager, old_connection, priv->user_connections);
+		return;
+	}
+	g_object_unref (new_connection);
+
+	valid = nm_connection_replace_settings (old_connection, settings, NULL);
+	if (valid) {
+		g_signal_emit (manager, signals[CONNECTION_UPDATED], 0,
+		               old_connection,
+		               nm_connection_get_scope (old_connection));
+
+		bluez_manager_resync_devices (manager);
+	} else {
+		remove_connection (manager, old_connection, priv->user_connections);
+	}
+}
+
+static void
+user_internal_new_connection_cb (DBusGProxy *proxy,
+                                 const char *path,
+                                 NMManager *manager,
+                                 GSList **calls)
+{
+	struct GetSettingsInfo *info;
+	DBusGProxy *con_proxy;
+	DBusGConnection *g_connection;
+	DBusGProxyCall *call;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
+	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	con_proxy = dbus_g_proxy_new_for_name (g_connection,
+	                                       dbus_g_proxy_get_bus_name (proxy),
+	                                       path,
+	                                       NM_DBUS_IFACE_SETTINGS_CONNECTION);
+	if (!con_proxy) {
+		nm_log_err (LOGD_USER_SET, "could not init user connection proxy");
+		return;
+	}
+
+	dbus_g_proxy_add_signal (con_proxy, "Updated",
+	                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (con_proxy, "Updated",
+	                             G_CALLBACK (user_connection_updated_cb),
+	                             manager,
+	                             NULL);
+
+	dbus_g_proxy_add_signal (con_proxy, "Removed", G_TYPE_INVALID, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (con_proxy, "Removed",
+	                             G_CALLBACK (user_connection_removed_cb),
+	                             manager,
+	                             NULL);
+
+	info = g_slice_new0 (GetSettingsInfo);
+	info->manager = g_object_ref (manager);
+	info->calls = calls;
+	call = dbus_g_proxy_begin_call (con_proxy, "GetSettings",
+	                                user_connection_get_settings_cb,
+	                                info,
+	                                free_get_settings_info,
+	                                G_TYPE_INVALID);
+	info->call = call;
+	info->proxy = con_proxy;
+	if (info->calls)
+		*(info->calls) = g_slist_prepend (*(info->calls), call);
+}
+
+static void
+user_list_connections_cb  (DBusGProxy *proxy,
+                           DBusGProxyCall *call_id,
+                           gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	GError *err = NULL;
+	GPtrArray *ops;
+	GSList **calls = NULL;
+	int i;
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
+	                            DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &ops,
+	                            G_TYPE_INVALID)) {
+		nm_log_warn (LOGD_USER_SET, "couldn't retrieve connections: %s",
+		             err && err->message ? err->message : "(unknown)");
+		g_error_free (err);
+		goto out;
+	}
+
+	/* Keep track of all calls made here; don't want to emit connection-added for
+	 * each one, but emit connections-added when they are all done.
+	 */
+	calls = g_slice_new0 (GSList *);
+
+	for (i = 0; i < ops->len; i++) {
+		char *op = g_ptr_array_index (ops, i);
+
+		user_internal_new_connection_cb (proxy, op, manager, calls);
+		g_free (op);
+	}
+
+	g_ptr_array_free (ops, TRUE);
+
+out:
+	return;
+}
+
+static void
+user_new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data)
+{
+	user_internal_new_connection_cb (proxy, path, NM_MANAGER (user_data), NULL);
+}
+
+static void
+user_query_connections (NMManager *manager)
+{
+	NMManagerPrivate *priv;
+	DBusGProxyCall *call;
+	DBusGConnection *g_connection;
+
+	g_return_if_fail (NM_IS_MANAGER (manager));
+
+	priv = NM_MANAGER_GET_PRIVATE (manager);
+	if (!priv->user_proxy) {
+		g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+		priv->user_proxy = dbus_g_proxy_new_for_name (g_connection,
+		                                              NM_DBUS_SERVICE_USER_SETTINGS,
+		                                              NM_DBUS_PATH_SETTINGS,
+		                                              NM_DBUS_IFACE_SETTINGS);
+		if (!priv->user_proxy) {
+			nm_log_err (LOGD_USER_SET, "could not init user settings proxy");
+			return;
+		}
+
+		dbus_g_proxy_add_signal (priv->user_proxy,
+		                         "NewConnection",
+		                         DBUS_TYPE_G_OBJECT_PATH,
+		                         G_TYPE_INVALID);
+
+		dbus_g_proxy_connect_signal (priv->user_proxy, "NewConnection",
+		                             G_CALLBACK (user_new_connection_cb),
+		                             manager,
+		                             NULL);
+	}
+
+	/* grab connections */
+	call = dbus_g_proxy_begin_call (priv->user_proxy, "ListConnections",
+	                                user_list_connections_cb,
+	                                manager,
+	                                NULL,
+	                                G_TYPE_INVALID);
+}
+
+/*******************************************************************/
+/* System settings stuff via NMSysconfigSettings                   */
+/*******************************************************************/
+
+static void
+system_connection_updated_cb (NMSettingsConnectionInterface *connection,
+                              gpointer unused,
+                              NMManager *manager)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	const char *path;
+	NMSettingsConnectionInterface *existing;
+	GError *error = NULL;
+
+	path = nm_connection_get_path (NM_CONNECTION (connection));
+
+	existing = g_hash_table_lookup (priv->system_connections, path);
+	if (!existing)
+		return;
+	if (existing != connection) {
+		nm_log_warn (LOGD_SYS_SET, "existing connection didn't matched updated.");
+		return;
+	}
+
+	if (!nm_connection_verify (NM_CONNECTION (existing), &error)) {
+		/* Updated connection invalid, remove existing connection */
+		nm_log_warn (LOGD_SYS_SET, "invalid connection: '%s' / '%s' invalid: %d",
+		             g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
+		             error->message, error->code);
+		g_error_free (error);
+		remove_connection (manager, NM_CONNECTION (existing), priv->system_connections);
+		return;
+	}
+
+	g_signal_emit (manager, signals[CONNECTION_UPDATED], 0,
+	               existing, NM_CONNECTION_SCOPE_SYSTEM);
+
+	bluez_manager_resync_devices (manager);
+}
+
+static void
+system_connection_removed_cb (NMSettingsConnectionInterface *connection,
+                              NMManager *manager)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	const char *path;
+
+	path = nm_connection_get_path (NM_CONNECTION (connection));
+
+	connection = g_hash_table_lookup (priv->system_connections, path);
+	if (connection)
+		remove_connection (manager, NM_CONNECTION (connection), priv->system_connections);
+}
+
+static void
+system_internal_new_connection (NMManager *manager,
+                                NMSettingsConnectionInterface *connection)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	const char *path;
+
+	g_return_if_fail (connection != NULL);
+
+	g_signal_connect (connection, NM_SETTINGS_CONNECTION_INTERFACE_UPDATED,
+	                  G_CALLBACK (system_connection_updated_cb), manager);
+	g_signal_connect (connection, NM_SETTINGS_CONNECTION_INTERFACE_REMOVED,
+	                  G_CALLBACK (system_connection_removed_cb), manager);
+
+	path = nm_connection_get_path (NM_CONNECTION (connection));
+	g_hash_table_insert (priv->system_connections, g_strdup (path),
+	                     g_object_ref (connection));
+}
+
+static void
+system_new_connection_cb (NMSysconfigSettings *settings,
+                          NMSettingsConnectionInterface *connection,
+                          NMManager *manager)
+{
+	system_internal_new_connection (manager, connection);
+}
+
+static void
+system_query_connections (NMManager *manager)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	GSList *system_connections, *iter;
+
+	system_connections = nm_settings_interface_list_connections (NM_SETTINGS_INTERFACE (priv->sys_settings));
+	for (iter = system_connections; iter; iter = g_slist_next (iter))
+		system_internal_new_connection (manager, NM_SETTINGS_CONNECTION_INTERFACE (iter->data));
+	g_slist_free (system_connections);
+}
+
+static void
+system_unmanaged_devices_changed_cb (NMSysconfigSettings *sys_settings,
+                                     GParamSpec *pspec,
+                                     gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	const GSList *unmanaged_specs, *iter;
+
+	unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (sys_settings);
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *device = NM_DEVICE (iter->data);
+		gboolean managed;
+
+		managed = !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs);
+		nm_device_set_managed (device,
+		                       managed,
+		                       managed ? NM_DEVICE_STATE_REASON_NOW_MANAGED :
+		                                   NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
+	}
+}
+
+static void
+system_hostname_changed_cb (NMSysconfigSettings *sys_settings,
+                            GParamSpec *pspec,
+                            gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	char *hostname;
+
+	hostname = nm_sysconfig_settings_get_hostname (sys_settings);
+
+	if (!hostname && !priv->hostname)
+		return;
+
+	if (hostname && priv->hostname && !strcmp (hostname, priv->hostname))
+		return;
+
+	g_free (priv->hostname);
+	priv->hostname = (hostname && strlen (hostname)) ? g_strdup (hostname) : NULL;
+	g_object_notify (G_OBJECT (manager), NM_MANAGER_HOSTNAME);
+
+	g_free (hostname);
+}
+
+/*******************************************************************/
+/* General NMManager stuff                                         */
+/*******************************************************************/
+
+static NMDevice *
+nm_manager_get_device_by_udi (NMManager *manager, const char *udi)
+{
+	GSList *iter;
+
+	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+		if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi))
+			return NM_DEVICE (iter->data);
+	}
+	return NULL;
+}
+
+static NMDevice *
+nm_manager_get_device_by_path (NMManager *manager, const char *path)
+{
+	GSList *iter;
+
+	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+		if (!strcmp (nm_device_get_path (NM_DEVICE (iter->data)), path))
+			return NM_DEVICE (iter->data);
+	}
+	return NULL;
+}
+
+static void
+nm_manager_name_owner_changed (NMDBusManager *mgr,
+                               const char *name,
+                               const char *old,
+                               const char *new,
+                               gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	gboolean old_owner_good = (old && (strlen (old) > 0));
+	gboolean new_owner_good = (new && (strlen (new) > 0));
+
+	if (strcmp (name, NM_DBUS_SERVICE_USER_SETTINGS) == 0) {
+		if (!old_owner_good && new_owner_good) {
+			/* User Settings service appeared, update stuff */
+			user_query_connections (manager);
+		} else {
+			/* User Settings service disappeared, throw them away (?) */
+			user_destroy_connections (manager);
+			bluez_manager_resync_devices (manager);
+		}
+	}
+}
+
+/* Store value into key-file; supported types: boolean, int, string */
+static gboolean
+write_value_to_state_file (const char *filename,
+                           const char *group,
+                           const char *key,
+                           GType value_type,
+                           gpointer value,
+                           GError **error)
+{
+	GKeyFile *key_file;
+	char *data;
+	gsize len = 0;
+	gboolean ret = FALSE;
+
+	g_return_val_if_fail (filename != NULL, FALSE);
+	g_return_val_if_fail (group != NULL, FALSE);
+	g_return_val_if_fail (key != NULL, FALSE);
+	g_return_val_if_fail (value_type == G_TYPE_BOOLEAN ||
+	                      value_type == G_TYPE_INT ||
+	                      value_type == G_TYPE_STRING,
+	                      FALSE);
+
+	key_file = g_key_file_new ();
+	if (!key_file)
+		return FALSE;
+
+	g_key_file_set_list_separator (key_file, ',');
+	g_key_file_load_from_file (key_file, filename, G_KEY_FILE_KEEP_COMMENTS, NULL);
+	switch (value_type) {
+	case G_TYPE_BOOLEAN:
+		g_key_file_set_boolean (key_file, group, key, *((gboolean *) value));
+		break;
+	case G_TYPE_INT:
+		g_key_file_set_integer (key_file, group, key, *((gint *) value));
+		break;
+	case G_TYPE_STRING:
+		g_key_file_set_string (key_file, group, key, *((const gchar **) value));
+		break;
+	}
+
+	data = g_key_file_to_data (key_file, &len, NULL);
+	if (data) {
+		ret = g_file_set_contents (filename, data, len, error);
+		g_free (data);
+	}
+	g_key_file_free (key_file);
+
+	return ret;
+}
+
+static void
+manager_set_radio_enabled (NMManager *manager,
+                           RadioState *rstate,
+                           gboolean enabled)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	GSList *iter;
+	GError *error = NULL;
+
+	/* Do nothing for radio types not yet implemented */
+	if (!rstate->prop)
+		return;
+
+	if (rstate->enabled == enabled)
+		return;
+
+	/* Can't set wireless enabled if it's disabled in hardware */
+	if (!rstate->hw_enabled && enabled)
+		return;
+
+	rstate->enabled = enabled;
+
+	g_object_notify (G_OBJECT (manager), rstate->prop);
+
+	/* Update enabled key in state file */
+	if (priv->state_file) {
+		if (!write_value_to_state_file (priv->state_file,
+		                                "main", rstate->key,
+		                                G_TYPE_BOOLEAN, (gpointer) &enabled,
+		                                &error)) {
+			nm_log_warn (LOGD_CORE, "writing to state file %s failed: (%d) %s.",
+			             priv->state_file,
+			             error ? error->code : -1,
+			             (error && error->message) ? error->message : "unknown");
+		}
+	}
+
+	/* Don't touch devices if asleep/networking disabled */
+	if (manager_sleeping (manager))
+		return;
+
+	/* enable/disable wireless devices as required */
+	for (iter = priv->devices; iter; iter = iter->next) {
+		RfKillType devtype = RFKILL_TYPE_UNKNOWN;
+
+		g_object_get (G_OBJECT (iter->data), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
+		if (devtype == rstate->rtype) {
+			nm_log_dbg (LOGD_RFKILL, "(%s): setting radio %s",
+			            nm_device_get_iface (NM_DEVICE (iter->data)),
+			            enabled ? "enabled" : "disabled");
+			nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (iter->data), enabled);
+		}
+	}
+}
+
+static void
+manager_hidden_ap_found (NMDeviceInterface *device,
+                         NMAccessPoint *ap,
+                         gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	const struct ether_addr *ap_addr;
+	const GByteArray *ap_ssid;
+	GSList *iter;
+	GSList *connections;
+	gboolean done = FALSE;
+
+	ap_ssid = nm_ap_get_ssid (ap);
+	if (ap_ssid && ap_ssid->len)
+		return;
+
+	ap_addr = nm_ap_get_address (ap);
+	g_assert (ap_addr);
+
+	/* Look for this AP's BSSID in the seen-bssids list of a connection,
+	 * and if a match is found, copy over the SSID */
+	connections = nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_SYSTEM);
+	connections = g_slist_concat (connections,  nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_USER));
+
+	for (iter = connections; iter && !done; iter = g_slist_next (iter)) {
+		NMConnection *connection = NM_CONNECTION (iter->data);
+		NMSettingWireless *s_wireless;
+		const GByteArray *ssid;
+		guint32 num_bssids;
+		guint32 i;
+
+		s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+		if (!s_wireless)
+			goto next;
+
+		num_bssids = nm_setting_wireless_get_num_seen_bssids (s_wireless);
+		if (num_bssids < 1)
+			goto next;
+
+		ssid = nm_setting_wireless_get_ssid (s_wireless);
+		g_assert (ssid);
+
+		for (i = 0; i < num_bssids; i++) {
+			const char *seen_bssid = nm_setting_wireless_get_seen_bssid (s_wireless, i);
+			struct ether_addr seen_addr;
+
+			if (!ether_aton_r (seen_bssid, &seen_addr))
+				continue;
+
+			if (memcmp (ap_addr, &seen_addr, sizeof (struct ether_addr)))
+				continue;
+
+			/* Copy the SSID from the connection to the AP */
+			nm_ap_set_ssid (ap, ssid);
+			done = TRUE;
+		}
+
+next:
+		g_object_unref (connection);
+	}
+	g_slist_free (connections);
+}
+
+static RfKillState
+nm_manager_get_ipw_rfkill_state (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+	RfKillState ipw_state = RFKILL_UNBLOCKED;
+
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *candidate = NM_DEVICE (iter->data);
+		RfKillState candidate_state;
+
+		if (NM_IS_DEVICE_WIFI (candidate)) {
+			candidate_state = nm_device_wifi_get_ipw_rfkill_state (NM_DEVICE_WIFI (candidate));
+
+			if (candidate_state > ipw_state)
+				ipw_state = candidate_state;
+		}
+	}
+
+	return ipw_state;
+}
+
+static RfKillState
+nm_manager_get_modem_enabled_state (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+	RfKillState wwan_state = RFKILL_UNBLOCKED;
+
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *candidate = NM_DEVICE (iter->data);
+		RfKillState candidate_state = RFKILL_UNBLOCKED;
+		RfKillType devtype = RFKILL_TYPE_UNKNOWN;
+
+		g_object_get (G_OBJECT (candidate), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
+		if (devtype == RFKILL_TYPE_WWAN) {
+			if (!nm_device_interface_get_enabled (NM_DEVICE_INTERFACE (candidate)))
+				candidate_state = RFKILL_SOFT_BLOCKED;
+
+			if (candidate_state > wwan_state)
+				wwan_state = candidate_state;
+		}
+	}
+
+	return wwan_state;
+}
+
+static void
+manager_rfkill_update_one_type (NMManager *self,
+                                RadioState *rstate,
+                                RfKillType rtype)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	RfKillState udev_state = RFKILL_UNBLOCKED;
+	RfKillState other_state = RFKILL_UNBLOCKED;
+	RfKillState composite;
+	gboolean new_e = TRUE, new_he = TRUE;
+
+	udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, rtype);
+
+	if (rstate->other_enabled_func)
+		other_state = rstate->other_enabled_func (self);
+
+	/* The composite state is the "worst" of either udev or other states */
+	if (udev_state == RFKILL_HARD_BLOCKED || other_state == RFKILL_HARD_BLOCKED)
+		composite = RFKILL_HARD_BLOCKED;
+	else if (udev_state == RFKILL_SOFT_BLOCKED || other_state == RFKILL_SOFT_BLOCKED)
+		composite = RFKILL_SOFT_BLOCKED;
+	else
+		composite = RFKILL_UNBLOCKED;
+
+	switch (composite) {
+	case RFKILL_UNBLOCKED:
+		new_e = TRUE;
+		new_he = TRUE;
+		break;
+	case RFKILL_SOFT_BLOCKED:
+		new_e = FALSE;
+		new_he = TRUE;
+		break;
+	case RFKILL_HARD_BLOCKED:
+		new_e = FALSE;
+		new_he = FALSE;
+		break;
+	default:
+		break;
+	}
+
+	if (rstate->desc) {
+		nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d enabled %d",
+		            rstate->desc, new_he, new_e);
+	}
+
+	if (new_he != rstate->hw_enabled) {
+		nm_log_info (LOGD_RFKILL, "%s now %s by radio killswitch",
+		             rstate->desc,
+		             (new_e && new_he) ? "enabled" : "disabled");
+
+		rstate->hw_enabled = new_he;
+		if (rstate->hw_prop)
+			g_object_notify (G_OBJECT (self), rstate->hw_prop);
+	}
+	manager_set_radio_enabled (self, rstate, new_e);
+}
+
+static void
+nm_manager_rfkill_update (NMManager *self, RfKillType rtype)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	guint i;
+
+	if (rtype != RFKILL_TYPE_UNKNOWN) {
+		manager_rfkill_update_one_type (self, &priv->radio_states[rtype], rtype);
+		return;
+	}
+
+	/* Otherwise sync all radio types */
+	for (i = 0; i < RFKILL_TYPE_MAX; i++)
+		manager_rfkill_update_one_type (self, &priv->radio_states[i], i);
+}
+
+static void
+manager_ipw_rfkill_state_changed (NMDeviceWifi *device,
+                                  GParamSpec *pspec,
+                                  gpointer user_data)
+{
+	nm_manager_rfkill_update (NM_MANAGER (user_data), RFKILL_TYPE_WLAN);
+}
+
+static void
+manager_modem_enabled_changed (NMModem *device, gpointer user_data)
+{
+	nm_manager_rfkill_update (NM_MANAGER (user_data), RFKILL_TYPE_WWAN);
+}
+
+static void
+add_device (NMManager *self, NMDevice *device)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	const char *iface, *driver, *type_desc;
+	char *path;
+	static guint32 devcount = 0;
+	const GSList *unmanaged_specs;
+	NMConnection *existing = NULL;
+	GHashTableIter iter;
+	gpointer value;
+	gboolean managed = FALSE;
+
+	iface = nm_device_get_ip_iface (device);
+	g_assert (iface);
+
+	if (!NM_IS_DEVICE_MODEM (device) && find_device_by_iface (self, iface)) {
+		g_object_unref (device);
+		return;
+	}
+
+	priv->devices = g_slist_append (priv->devices, device);
+
+	g_signal_connect (device, "state-changed",
+					  G_CALLBACK (manager_device_state_changed),
+					  self);
+
+	if (NM_IS_DEVICE_WIFI (device)) {
+		/* Attach to the access-point-added signal so that the manager can fill
+		 * non-SSID-broadcasting APs with an SSID.
+		 */
+		g_signal_connect (device, "hidden-ap-found",
+						  G_CALLBACK (manager_hidden_ap_found),
+						  self);
+
+		/* Hook up rfkill handling for ipw-based cards until they get converted
+		 * to use the kernel's rfkill subsystem in 2.6.33.
+		 */
+		g_signal_connect (device, "notify::" NM_DEVICE_WIFI_IPW_RFKILL_STATE,
+		                  G_CALLBACK (manager_ipw_rfkill_state_changed),
+		                  self);
+
+		/* Update global rfkill state with this device's rfkill state, and
+		 * then set this device's rfkill state based on the global state.
+		 */
+		nm_manager_rfkill_update (self, RFKILL_TYPE_WLAN);
+		nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device),
+		                                 priv->radio_states[RFKILL_TYPE_WLAN].enabled);
+	} else if (NM_IS_DEVICE_MODEM (device)) {
+		g_signal_connect (device, NM_DEVICE_MODEM_ENABLE_CHANGED,
+		                  G_CALLBACK (manager_modem_enabled_changed),
+		                  self);
+
+		nm_manager_rfkill_update (self, RFKILL_TYPE_WWAN);
+		/* Until we start respecting WWAN rfkill switches the modem itself
+		 * is the source of the enabled/disabled state, so the manager shouldn't
+		 * touch it here.
+		nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device),
+		                                 priv->radio_states[RFKILL_TYPE_WWAN].enabled);
+		*/
+	}
+
+	type_desc = nm_device_get_type_desc (device);
+	g_assert (type_desc);
+	driver = nm_device_get_driver (device);
+	if (!driver)
+		driver = "unknown";
+	nm_log_info (LOGD_HW, "(%s): new %s device (driver: '%s' ifindex: %d)",
+	             iface, type_desc, driver, nm_device_get_ifindex (device));
+
+	path = g_strdup_printf ("/org/freedesktop/NetworkManager/Devices/%d", devcount++);
+	nm_device_set_path (device, path);
+	dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	                                     path,
+	                                     G_OBJECT (device));
+	nm_log_info (LOGD_CORE, "(%s): exported as %s", iface, path);
+	g_free (path);
+
+	/* Check if we should assume the device's active connection by matching its
+	 * config with an existing system connection.
+	 */
+	if (nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device))) {
+		GSList *connections = NULL;
+
+		g_hash_table_iter_init (&iter, priv->system_connections);
+		while (g_hash_table_iter_next (&iter, NULL, &value))
+			connections = g_slist_append (connections, value);
+		existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device),
+		                                                        (const GSList *) connections);
+		g_slist_free (connections);
+
+		if (existing) {
+			NMSettingConnection *s_con;
+
+			s_con = (NMSettingConnection *) nm_connection_get_setting (existing, NM_TYPE_SETTING_CONNECTION);
+			nm_log_dbg (LOGD_DEVICE, "(%s): found existing device connection '%s'",
+			            nm_device_get_iface (device),
+			            nm_setting_connection_get_id (s_con));
+		}
+	}
+
+	/* Start the device if it's supposed to be managed */
+	unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings);
+	if (   !manager_sleeping (self)
+	    && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) {
+		nm_device_set_managed (device,
+		                       TRUE,
+		                       existing ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
+		                                  NM_DEVICE_STATE_REASON_NOW_MANAGED);
+		managed = TRUE;
+	}
+
+	nm_sysconfig_settings_device_added (priv->sys_settings, device);
+	g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
+
+	/* If the device has a connection it can assume, do that now */
+	if (existing && managed && nm_device_is_available (device)) {
+		const char *ac_path;
+		GError *error = NULL;
+
+		nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume existing connection",
+		            nm_device_get_iface (device));
+
+		ac_path = internal_activate_device (self, device, existing, NULL, FALSE, TRUE, &error);
+		if (ac_path)
+			g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+		else {
+			nm_log_warn (LOGD_DEVICE, "assumed connection (%d) %s failed to activate: (%d) %s",
+			             nm_connection_get_scope (existing),
+			             nm_connection_get_path (existing),
+			             error ? error->code : -1,
+			             error && error->message ? error->message : "(unknown)");
+			g_error_free (error);
+		}
+	}
+}
+
+static gboolean
+bdaddr_matches_connection (NMSettingBluetooth *s_bt, const char *bdaddr)
+{
+	const GByteArray *arr;
+	gboolean ret = FALSE;
+
+	arr = nm_setting_bluetooth_get_bdaddr (s_bt);
+
+	if (   arr != NULL 
+	       && arr->len == ETH_ALEN) {
+		char *str;
+
+		str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+				       arr->data[0],
+				       arr->data[1],
+				       arr->data[2],
+				       arr->data[3],
+				       arr->data[4],
+				       arr->data[5]);
+		ret = g_str_equal (str, bdaddr);
+		g_free (str);
+	}
+
+	return ret;
+}
+
+static NMConnection *
+bluez_manager_find_connection (NMManager *manager,
+                               const char *bdaddr,
+                               guint32 capabilities)
+{
+	NMConnection *found = NULL;
+	GSList *connections, *l;
+
+	connections = nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_SYSTEM);
+	connections = g_slist_concat (connections, nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_USER));
+
+	for (l = connections; l != NULL; l = l->next) {
+		NMConnection *candidate = NM_CONNECTION (l->data);
+		NMSettingConnection *s_con;
+		NMSettingBluetooth *s_bt;
+		const char *con_type;
+		const char *bt_type;
+
+		s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION));
+		g_assert (s_con);
+		con_type = nm_setting_connection_get_connection_type (s_con);
+		g_assert (con_type);
+		if (!g_str_equal (con_type, NM_SETTING_BLUETOOTH_SETTING_NAME))
+			continue;
+
+		s_bt = (NMSettingBluetooth *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_BLUETOOTH);
+		if (!s_bt)
+			continue;
+
+		if (!bdaddr_matches_connection (s_bt, bdaddr))
+			continue;
+
+		bt_type = nm_setting_bluetooth_get_connection_type (s_bt);
+		if (   g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)
+		    && !(capabilities & NM_BT_CAPABILITY_DUN))
+		    	continue;
+		if (   g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)
+		    && !(capabilities & NM_BT_CAPABILITY_NAP))
+		    	continue;
+
+		found = candidate;
+		break;
+	}
+
+	g_slist_free (connections);
+	return found;
+}
+
+static void
+bluez_manager_resync_devices (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter, *gone = NULL, *keep = NULL;
+
+	/* Remove devices from the device list that don't have a corresponding connection */
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *candidate = NM_DEVICE (iter->data);
+		guint32 uuids;
+		const char *bdaddr;
+
+		if (NM_IS_DEVICE_BT (candidate)) {
+			uuids = nm_device_bt_get_capabilities (NM_DEVICE_BT (candidate));
+			bdaddr = nm_device_bt_get_hw_address (NM_DEVICE_BT (candidate));
+
+			if (bluez_manager_find_connection (self, bdaddr, uuids))
+				keep = g_slist_prepend (keep, candidate);
+			else
+				gone = g_slist_prepend (gone, candidate);
+		} else
+			keep = g_slist_prepend (keep, candidate);
+	}
+
+	/* Only touch the device list if anything actually changed */
+	if (g_slist_length (gone)) {
+		g_slist_free (priv->devices);
+		priv->devices = keep;
+
+		while (g_slist_length (gone))
+			gone = remove_one_device (self, gone, NM_DEVICE (gone->data), FALSE, TRUE);
+	} else {
+		g_slist_free (keep);
+		g_slist_free (gone);
+	}
+
+	/* Now look for devices without connections */
+	nm_bluez_manager_query_devices (priv->bluez_mgr);
+}
+
+static void
+bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
+                               const char *bdaddr,
+                               const char *name,
+                               const char *object_path,
+                               guint32 capabilities,
+                               NMManager *manager)
+{
+	NMDevice *device;
+	gboolean has_dun = (capabilities & NM_BT_CAPABILITY_DUN);
+	gboolean has_nap = (capabilities & NM_BT_CAPABILITY_NAP);
+
+	g_return_if_fail (bdaddr != NULL);
+	g_return_if_fail (name != NULL);
+	g_return_if_fail (object_path != NULL);
+	g_return_if_fail (capabilities != NM_BT_CAPABILITY_NONE);
+
+	/* Make sure the device is not already in the device list */
+	if (nm_manager_get_device_by_udi (manager, object_path))
+		return;
+
+	if (has_dun == FALSE && has_nap == FALSE)
+		return;
+
+	if (!bluez_manager_find_connection (manager, bdaddr, capabilities))
+		return;
+
+	device = nm_device_bt_new (object_path, bdaddr, name, capabilities, FALSE);
+	if (device) {
+		nm_log_info (LOGD_HW, "BT device %s (%s) added (%s%s%s)",
+		             name,
+		             bdaddr,
+		             has_dun ? "DUN" : "",
+		             has_dun && has_nap ? " " : "",
+		             has_nap ? "NAP" : "");
+
+		add_device (manager, device);
+	}
+}
+
+static void
+bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
+                                 const char *bdaddr,
+                                 const char *object_path,
+                                 gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+
+	g_return_if_fail (bdaddr != NULL);
+	g_return_if_fail (object_path != NULL);
+
+	nm_log_info (LOGD_HW, "BT device %s removed", bdaddr);
+
+	for (iter = priv->devices; iter; iter = iter->next) {
+		NMDevice *device = NM_DEVICE (iter->data);
+
+		if (!strcmp (nm_device_get_udi (device), object_path)) {
+			priv->devices = remove_one_device (self, priv->devices, device, FALSE, TRUE);
+			break;
+		}
+	}
+}
+
+static NMDevice *
+find_device_by_iface (NMManager *self, const gchar *iface)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *device = NM_DEVICE (iter->data);
+		const gchar *d_iface = nm_device_get_ip_iface (device);
+		if (!strcmp (d_iface, iface))
+			return device;
+	}
+
+	return NULL;
+}
+
+static NMDevice *
+find_device_by_ifindex (NMManager *self, guint32 ifindex)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *candidate = NM_DEVICE (iter->data);
+
+		if (ifindex == nm_device_get_ifindex (candidate))
+			return candidate;
+	}
+	return NULL;
+}
+
+static void
+udev_device_added_cb (NMUdevManager *udev_mgr,
+                      GUdevDevice *udev_device,
+                      NMDeviceCreatorFn creator_fn,
+                      gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	GObject *device;
+	guint32 ifindex;
+
+	ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
+	if (find_device_by_ifindex (self, ifindex))
+		return;
+
+	device = creator_fn (udev_mgr, udev_device, manager_sleeping (self));
+	if (device)
+		add_device (self, NM_DEVICE (device));
+}
+
+static void
+udev_device_removed_cb (NMUdevManager *manager,
+                        GUdevDevice *udev_device,
+                        gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMDevice *device;
+	guint32 ifindex;
+
+	ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
+	device = find_device_by_ifindex (self, ifindex);
+	if (device)
+		priv->devices = remove_one_device (self, priv->devices, device, FALSE, TRUE);
+}
+
+static void
+udev_manager_rfkill_changed_cb (NMUdevManager *udev_mgr,
+                                RfKillType rtype,
+                                RfKillState udev_state,
+                                gpointer user_data)
+{
+	nm_manager_rfkill_update (NM_MANAGER (user_data), rtype);
+}
+
+GSList *
+nm_manager_get_devices (NMManager *manager)
+{
+	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
+
+	return NM_MANAGER_GET_PRIVATE (manager)->devices;
+}
+
+static gboolean
+impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	GSList *iter;
+
+	*devices = g_ptr_array_sized_new (g_slist_length (priv->devices));
+
+	for (iter = priv->devices; iter; iter = iter->next)
+		g_ptr_array_add (*devices, g_strdup (nm_device_get_path (NM_DEVICE (iter->data))));
+
+	return TRUE;
+}
+
+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_act_request_get_active_connection_path (req);
+		if (!strcmp (path, ac_path)) {
+			*device = NM_DEVICE (iter->data);
+			return req;
+		}
+	}
+
+	return NULL;
+}
+
+typedef struct GetSecretsInfo {
+	NMManager *manager;
+	NMSecretsProviderInterface *provider;
+
+	char *setting_name;
+	RequestSecretsCaller caller;
+	gboolean request_new;
+
+	/* User connection bits */
+	DBusGProxy *proxy;
+	DBusGProxyCall *call;
+
+	/* System connection bits */
+	guint32 idle_id;
+	char *hint1;
+	char *hint2;
+	char *connection_path;
+} GetSecretsInfo;
+
+static void
+free_get_secrets_info (gpointer data)
+{
+	GetSecretsInfo *info = data;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (info->manager);
+
+	g_object_weak_unref (G_OBJECT (info->provider), (GWeakNotify) free_get_secrets_info, info);
+
+	priv->secrets_calls = g_slist_remove (priv->secrets_calls, info);
+
+	if (info->proxy) {
+		if (info->call)
+			dbus_g_proxy_cancel_call (info->proxy, info->call);
+		g_object_unref (info->proxy);
+	}
+
+	if (info->idle_id)
+		g_source_remove (info->idle_id);
+
+	g_free (info->hint1);
+	g_free (info->hint2);
+	g_free (info->setting_name);
+	g_free (info->connection_path);
+	memset (info, 0, sizeof (GetSecretsInfo));
+	g_free (info);
+}
+
+static void
+provider_cancel_secrets (NMSecretsProviderInterface *provider, gpointer user_data)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (user_data);
+	GSList *iter;
+
+	for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) {
+		GetSecretsInfo *candidate = iter->data;
+
+		if (candidate->provider == provider) {
+			free_get_secrets_info (candidate);
+			break;
+		}
+	}
+}
+
+static void
+user_get_secrets_cb (DBusGProxy *proxy,
+                     DBusGProxyCall *call,
+                     gpointer user_data)
+{
+	GetSecretsInfo *info = (GetSecretsInfo *) user_data;
+	GHashTable *settings = NULL;
+	GError *error = NULL;
+	GObject *provider;
+
+	g_return_if_fail (info != NULL);
+	g_return_if_fail (info->provider);
+	g_return_if_fail (info->setting_name);
+
+	provider = g_object_ref (info->provider);
+
+	if (dbus_g_proxy_end_call (proxy, call, &error,
+	                           DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings,
+	                           G_TYPE_INVALID)) {
+		nm_secrets_provider_interface_get_secrets_result (info->provider,
+		                                                  info->setting_name,
+		                                                  info->caller,
+		                                                  settings,
+		                                                  NULL);
+		g_hash_table_destroy (settings);
+	} else {
+		nm_secrets_provider_interface_get_secrets_result (info->provider,
+		                                                  info->setting_name,
+		                                                  info->caller,
+		                                                  NULL,
+		                                                  error);
+		g_clear_error (&error);
+	}
+
+	info->call = NULL;
+	free_get_secrets_info (info);
+
+	g_object_unref (provider);
+}
+
+static GetSecretsInfo *
+user_get_secrets (NMManager *self,
+                  NMSecretsProviderInterface *provider,
+                  NMConnection *connection,
+                  const char *setting_name,
+                  gboolean request_new,
+                  RequestSecretsCaller caller_id,
+                  const char *hint1,
+                  const char *hint2)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	DBusGConnection *g_connection;
+	GetSecretsInfo *info = NULL;
+	GPtrArray *hints = NULL;
+
+	info = g_malloc0 (sizeof (GetSecretsInfo));
+
+	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	info->proxy = dbus_g_proxy_new_for_name (g_connection,
+	                                         NM_DBUS_SERVICE_USER_SETTINGS,
+	                                         nm_connection_get_path (connection),
+	                                         NM_DBUS_IFACE_SETTINGS_CONNECTION_SECRETS);
+	if (!info->proxy) {
+		nm_log_warn (LOGD_USER_SET, "could not create user connection secrets proxy");
+		g_free (info);
+		return NULL;
+	}
+
+	info->manager = self;
+	info->provider = provider;
+	info->caller = caller_id;
+	info->setting_name = g_strdup (setting_name);
+
+	g_object_weak_ref (G_OBJECT (provider), (GWeakNotify) free_get_secrets_info, info);
+
+	hints = g_ptr_array_sized_new (2);
+	if (hint1)
+		g_ptr_array_add (hints, (char *) hint1);
+	if (hint2)
+		g_ptr_array_add (hints, (char *) hint2);
+
+	info->call = dbus_g_proxy_begin_call_with_timeout (info->proxy, "GetSecrets",
+	                                                   user_get_secrets_cb,
+	                                                   info,
+	                                                   NULL,
+	                                                   G_MAXINT32,
+	                                                   G_TYPE_STRING, setting_name,
+	                                                   DBUS_TYPE_G_ARRAY_OF_STRING, hints,
+	                                                   G_TYPE_BOOLEAN, request_new,
+	                                                   G_TYPE_INVALID);
+	g_ptr_array_free (hints, TRUE);
+	return info;
+}
+
+static void
+system_get_secrets_reply_cb (NMSettingsConnectionInterface *connection,
+                             GHashTable *secrets,
+                             GError *error,
+                             gpointer user_data)
+{
+	GetSecretsInfo *info = user_data;
+	GObject *provider;
+
+	provider = g_object_ref (info->provider);
+
+	nm_secrets_provider_interface_get_secrets_result (info->provider,
+	                                                  info->setting_name,
+	                                                  info->caller,
+	                                                  error ? NULL : secrets,
+	                                                  error);
+	free_get_secrets_info (info);
+	g_object_unref (provider);
+}
+
+static gboolean
+system_get_secrets_idle_cb (gpointer user_data)
+{
+	GetSecretsInfo *info = user_data;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (info->manager);
+	NMSettingsConnectionInterface *connection;
+	GError *error = NULL;
+	const char *hints[3] = { NULL, NULL, NULL };
+
+	info->idle_id = 0;
+
+	connection = nm_settings_interface_get_connection_by_path (NM_SETTINGS_INTERFACE (priv->sys_settings), 
+	                                                           info->connection_path);
+	if (!connection) {
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+		                             "unknown connection (not exported by system settings)");
+		nm_secrets_provider_interface_get_secrets_result (info->provider,
+		                                                  info->setting_name,
+		                                                  info->caller,
+		                                                  NULL,
+		                                                  error);
+		g_error_free (error);
+		free_get_secrets_info (info);
+		return FALSE;
+	}
+
+	hints[0] = info->hint1;
+	hints[1] = info->hint2;
+	nm_settings_connection_interface_get_secrets (connection,
+	                                              info->setting_name,
+	                                              hints,
+	                                              info->request_new,
+	                                              system_get_secrets_reply_cb,
+	                                              info);
+	return FALSE;
+}
+
+static GetSecretsInfo *
+system_get_secrets (NMManager *self,
+                    NMSecretsProviderInterface *provider,
+                    NMConnection *connection,
+                    const char *setting_name,
+                    gboolean request_new,
+                    RequestSecretsCaller caller_id,
+                    const char *hint1,
+                    const char *hint2)
+{
+	GetSecretsInfo *info;
+
+	info = g_malloc0 (sizeof (GetSecretsInfo));
+	info->manager = self;
+	info->provider = provider;
+	info->caller = caller_id;
+	info->setting_name = g_strdup (setting_name);
+	info->hint1 = hint1 ? g_strdup (hint1) : NULL;
+	info->hint2 = hint2 ? g_strdup (hint2) : NULL;
+	info->connection_path = g_strdup (nm_connection_get_path (connection));
+	info->request_new = request_new;
+
+	g_object_weak_ref (G_OBJECT (provider), (GWeakNotify) free_get_secrets_info, info);
+
+	info->idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+	                                 system_get_secrets_idle_cb,
+	                                 info,
+	                                 NULL);
+	return info;
+}
+
+static gboolean
+provider_get_secrets (NMSecretsProviderInterface *provider,
+                      NMConnection *connection,
+                      const char *setting_name,
+                      gboolean request_new,
+                      RequestSecretsCaller caller_id,
+                      const char *hint1,
+                      const char *hint2,
+                      gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GetSecretsInfo *info = NULL;
+	NMConnectionScope scope;
+	GSList *iter;
+
+	g_return_val_if_fail (connection != NULL, FALSE);
+	g_return_val_if_fail (setting_name != NULL, FALSE);
+
+	/* Tear down any pending secrets requests for this secrets provider */
+	for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) {
+		GetSecretsInfo *candidate = iter->data;
+
+		if (provider == candidate->provider) {
+			free_get_secrets_info (candidate);
+			break;
+		}
+	}
+
+	/* Build up the new secrets request */
+	scope = nm_connection_get_scope (connection);
+	if (scope == NM_CONNECTION_SCOPE_SYSTEM) {
+		info = system_get_secrets (self, provider, connection, setting_name,
+		                           request_new, caller_id, hint1, hint2);
+	} else if (scope == NM_CONNECTION_SCOPE_USER) {
+		info = user_get_secrets (self, provider, connection, setting_name,
+		                         request_new, caller_id, hint1, hint2);
+	}
+
+	if (info)
+		priv->secrets_calls = g_slist_append (priv->secrets_calls, info);
+
+	return !!info;
+}
+
+static const char *
+internal_activate_device (NMManager *manager,
+                          NMDevice *device,
+                          NMConnection *connection,
+                          const char *specific_object,
+                          gboolean user_requested,
+                          gboolean assumed,
+                          GError **error)
+{
+	NMActRequest *req;
+	NMDeviceInterface *dev_iface;
+	gboolean success;
+
+	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
+	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
+
+	dev_iface = NM_DEVICE_INTERFACE (device);
+
+	/* Ensure the requested connection is compatible with the device */
+	if (!nm_device_interface_check_connection_compatible (dev_iface, connection, error))
+		return NULL;
+
+	/* 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, assumed, (gpointer) device);
+	g_signal_connect (req, "manager-get-secrets", G_CALLBACK (provider_get_secrets), manager);
+	g_signal_connect (req, "manager-cancel-secrets", G_CALLBACK (provider_cancel_secrets), manager);
+	success = nm_device_interface_activate (dev_iface, req, error);
+	g_object_unref (req);
+
+	return success ? nm_act_request_get_active_connection_path (req) : NULL;
+}
+
+static gboolean
+wait_for_connection_expired (gpointer data)
+{
+	NMManager *manager = NM_MANAGER (data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	PendingConnectionInfo *info = priv->pending_connection_info;
+	GError *error = NULL;
+
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	g_set_error (&error,
+	             NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+	             "%s", "Connection was not provided by any settings service");
+	nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate (timeout): (%d) %s",
+	             info->scope, info->connection_path, error->code, error->message);
+	dbus_g_method_return_error (info->context, error);
+	g_error_free (error);
+
+	info->timeout_id = 0;
+	pending_connection_info_destroy (priv->pending_connection_info);
+	priv->pending_connection_info = NULL;
+
+	return FALSE;
+}
+
+const char *
+nm_manager_activate_connection (NMManager *manager,
+                                NMConnection *connection,
+                                const char *specific_object,
+                                const char *device_path,
+                                gboolean user_requested,
+                                GError **error)
+{
+	NMManagerPrivate *priv;
+	NMDevice *device = NULL;
+	NMSettingConnection *s_con;
+	NMVPNConnection *vpn_connection;
+	const char *path;
+
+	g_return_val_if_fail (manager != NULL, NULL);
+	g_return_val_if_fail (connection != NULL, NULL);
+	g_return_val_if_fail (error != NULL, NULL);
+	g_return_val_if_fail (*error == NULL, NULL);
+
+	priv = NM_MANAGER_GET_PRIVATE (manager);
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	g_assert (s_con);
+
+	if (!strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_VPN_SETTING_NAME)) {
+		NMActRequest *req = NULL;
+		NMVPNManager *vpn_manager;
+
+		/* VPN connection */
+
+		if (specific_object) {
+			/* Find the specifc connection the client requested we use */
+			req = nm_manager_get_act_request_by_path (manager, specific_object, &device);
+			if (!req) {
+				g_set_error (error,
+				             NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
+				             "%s", "Base connection for VPN connection not active.");
+				return NULL;
+			}
+		} else {
+			GSList *iter;
+
+			/* 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;
+
+				candidate_req = nm_device_get_act_request (candidate);
+				if (candidate_req && nm_act_request_get_default (candidate_req)) {
+					device = candidate;
+					req = candidate_req;
+					break;
+				}
+			}
+		}
+
+		if (!device || !req) {
+			g_set_error (error,
+			             NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+			             "%s", "Could not find source connection, or the source connection had no active device.");
+			return NULL;
+		}
+
+		vpn_manager = nm_vpn_manager_get ();
+		vpn_connection = nm_vpn_manager_activate_connection (vpn_manager,
+		                                                     connection,
+		                                                     req,
+		                                                     device,
+		                                                     error);
+		g_signal_connect (vpn_connection, "manager-get-secrets",
+		                  G_CALLBACK (provider_get_secrets), manager);
+		g_signal_connect (vpn_connection, "manager-cancel-secrets",
+		                  G_CALLBACK (provider_cancel_secrets), manager);
+		path = nm_vpn_connection_get_active_connection_path (vpn_connection);
+		g_object_unref (vpn_manager);
+	} else {
+		NMDeviceState state;
+
+		/* Device-based connection */
+		device = nm_manager_get_device_by_path (manager, device_path);
+		if (!device) {
+			g_set_error (error,
+			             NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+			             "%s", "Device not found");
+			return NULL;
+		}
+
+		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
+		if (state < NM_DEVICE_STATE_DISCONNECTED) {
+			g_set_error (error,
+			             NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE,
+			             "%s", "Device not managed by NetworkManager");
+			return NULL;
+		}
+
+		path = internal_activate_device (manager,
+		                                 device,
+		                                 connection,
+		                                 specific_object,
+		                                 user_requested,
+		                                 FALSE,
+		                                 error);
+	}
+
+	return path;
+}
+
+static void
+connection_added_default_handler (NMManager *manager,
+						    NMConnection *connection,
+						    NMConnectionScope scope)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	PendingConnectionInfo *info = priv->pending_connection_info;
+	const char *path;
+	GError *error = NULL;
+
+	if (!info)
+		return;
+
+	if (scope != info->scope)
+		return;
+
+	if (strcmp (info->connection_path, nm_connection_get_path (connection)))
+		return;
+
+	/* Will destroy below; can't be valid during the initial activation start */
+	priv->pending_connection_info = NULL;
+
+	path = nm_manager_activate_connection (manager,
+	                                       connection,
+	                                       info->specific_object_path,
+	                                       info->device_path,
+	                                       TRUE,
+	                                       &error);
+	if (path) {
+		dbus_g_method_return (info->context, path);
+		g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
+	} else {
+		dbus_g_method_return_error (info->context, error);
+		nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate: (%d) %s",
+		             scope, info->connection_path, error->code, error->message);
+		g_error_free (error);
+	}
+
+	pending_connection_info_destroy (info);
+}
+
+static gboolean
+is_user_request_authorized (NMManager *manager,
+                            DBusGMethodInvocation *context,
+                            GError **error)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	DBusConnection *connection;
+	char *sender = NULL;
+	gulong sender_uid = G_MAXULONG;
+	DBusError dbus_error;
+	char *service_owner = NULL;
+	const char *service_name;
+	gulong service_uid = G_MAXULONG;
+	gboolean success = FALSE;
+
+	/* Ensure the request to activate the user connection came from the
+	 * same session as the user settings service.  FIXME: use ConsoleKit
+	 * too.
+	 */
+	if (!priv->user_proxy) {
+		g_set_error (error, NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_INVALID_SERVICE,
+		             "%s", "No user settings service available");
+		goto out;
+	}
+
+	sender = dbus_g_method_get_sender (context);
+	if (!sender) {
+		g_set_error (error, NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		             "%s", "Could not determine D-Bus requestor");
+		goto out;
+	}
+
+	connection = nm_dbus_manager_get_dbus_connection (priv->dbus_mgr);
+	if (!connection) {
+		g_set_error (error, NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		             "%s", "Could not get the D-Bus system bus");
+		goto out;
+	}
+
+	dbus_error_init (&dbus_error);
+	/* FIXME: do this async */
+	sender_uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
+	if (dbus_error_is_set (&dbus_error)) {
+		dbus_error_free (&dbus_error);
+		g_set_error (error, NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		             "%s", "Could not determine the Unix user ID of the requestor");
+		goto out;
+	}
+
+	/* Let root activate anything.
+	 * FIXME: use a PolicyKit permission instead
+	 */
+	if (0 == sender_uid) {
+		success = TRUE;
+		goto out;
+	}
+
+	service_name = dbus_g_proxy_get_bus_name (priv->user_proxy);
+	if (!service_name) {
+		g_set_error (error, NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		             "%s", "Could not determine user settings service name");
+		goto out;
+	}
+
+	service_owner = nm_dbus_manager_get_name_owner (priv->dbus_mgr, service_name, NULL);
+	if (!service_owner) {
+		g_set_error (error, NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		             "%s", "Could not determine D-Bus owner of the user settings service");
+		goto out;
+	}
+
+	dbus_error_init (&dbus_error);
+	/* FIXME: do this async */
+	service_uid = dbus_bus_get_unix_user (connection, service_owner, &dbus_error);
+	if (dbus_error_is_set (&dbus_error)) {
+		dbus_error_free (&dbus_error);
+		g_set_error (error, NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		             "%s", "Could not determine the Unix UID of the sender of the request");
+		goto out;
+	}
+
+	/* And finally, the actual UID check */
+	if (sender_uid != service_uid) {
+		g_set_error (error, NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		             "%s", "Requestor UID does not match the UID of the user settings service");
+		goto out;
+	}
+
+	success = TRUE;
+
+out:
+	g_free (sender);
+	g_free (service_owner);
+	return success;
+}
+
+static void
+impl_manager_activate_connection (NMManager *manager,
+                                  const char *service_name,
+                                  const char *connection_path,
+                                  const char *device_path,
+                                  const char *specific_object_path,
+                                  DBusGMethodInvocation *context)
+{
+	NMConnectionScope scope = NM_CONNECTION_SCOPE_UNKNOWN;
+	NMConnection *connection;
+	GError *error = NULL;
+	char *real_sop = NULL;
+	char *path = NULL;
+
+	if (!strcmp (service_name, NM_DBUS_SERVICE_USER_SETTINGS)) {
+		if (!is_user_request_authorized (manager, context, &error))
+			goto err;
+
+		scope = NM_CONNECTION_SCOPE_USER;
+	} else if (!strcmp (service_name, NM_DBUS_SERVICE_SYSTEM_SETTINGS))
+		scope = NM_CONNECTION_SCOPE_SYSTEM;
+	else {
+		g_set_error (&error,
+		             NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_SERVICE,
+		             "%s", "Invalid settings service name");
+		goto err;
+	}
+
+	/* "/" is special-cased to NULL to get through D-Bus */
+	if (specific_object_path && strcmp (specific_object_path, "/"))
+		real_sop = g_strdup (specific_object_path);
+
+	connection = nm_manager_get_connection_by_object_path (manager, scope, connection_path);
+	if (connection) {
+		path = (char *) nm_manager_activate_connection (manager,
+		                                                connection,
+		                                                real_sop,
+		                                                device_path,
+		                                                TRUE,
+		                                                &error);
+		if (path) {
+			dbus_g_method_return (context, path);
+			g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
+		}
+	} else {
+		PendingConnectionInfo *info;
+		NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
+		if (priv->pending_connection_info) {
+			pending_connection_info_destroy (priv->pending_connection_info);
+			priv->pending_connection_info = NULL;
+		}
+
+		/* Don't have the connection quite yet, probably created by
+		 * the client on-the-fly.  Defer the activation until we have it
+		 */
+
+		info = g_slice_new0 (PendingConnectionInfo);
+		info->context = context;
+		info->device_path = g_strdup (device_path);
+		info->scope = scope;
+		info->connection_path = g_strdup (connection_path);
+		info->specific_object_path = g_strdup (real_sop);
+		info->timeout_id = g_timeout_add_seconds (5, wait_for_connection_expired, manager);
+
+		// FIXME: should probably be per-device, not global to the manager
+		NM_MANAGER_GET_PRIVATE (manager)->pending_connection_info = info;
+	}
+
+ err:
+	if (error) {
+		dbus_g_method_return_error (context, error);
+		nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate: (%d) %s",
+		             scope, connection_path, error->code, error->message);
+		g_error_free (error);
+	}
+
+	g_free (real_sop);
+}
+
+gboolean
+nm_manager_deactivate_connection (NMManager *manager,
+                                  const char *connection_path,
+                                  NMDeviceStateReason reason,
+                                  GError **error)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	NMVPNManager *vpn_manager;
+	GSList *iter;
+	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;
+
+		req = nm_device_get_act_request (device);
+		if (!req)
+			continue;
+
+		if (!strcmp (connection_path, nm_act_request_get_active_connection_path (req))) {
+			nm_device_state_changed (device,
+			                         NM_DEVICE_STATE_DISCONNECTED,
+			                         reason);
+			success = TRUE;
+			goto done;
+		}
+	}
+
+	/* Check for VPN connections next */
+	vpn_manager = nm_vpn_manager_get ();
+	if (reason == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED)
+		vpn_reason = NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED;
+	if (nm_vpn_manager_deactivate_connection (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_object_unref (vpn_manager);
+
+done:
+	g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
+	return success;
+}
+
+static gboolean
+impl_manager_deactivate_connection (NMManager *manager,
+                                    const char *connection_path,
+                                    GError **error)
+{
+	return nm_manager_deactivate_connection (manager,
+	                                         connection_path,
+	                                         NM_DEVICE_STATE_REASON_USER_REQUESTED,
+	                                         error);
+}
+
+static void
+do_sleep_wake (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	const GSList *unmanaged_specs;
+	GSList *iter;
+
+	if (manager_sleeping (self)) {
+		nm_log_info (LOGD_SUSPEND, "sleeping or disabling...");
+
+		/* Just deactivate and down all devices from the device list,
+		 * to keep things fast the device list will get resynced when
+		 * the manager wakes up.
+		 */
+		for (iter = priv->devices; iter; iter = iter->next)
+			nm_device_set_managed (NM_DEVICE (iter->data), FALSE, NM_DEVICE_STATE_REASON_SLEEPING);
+
+	} else {
+		nm_log_info (LOGD_SUSPEND, "waking up and re-enabling...");
+
+		unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings);
+
+		/* Ensure rfkill state is up-to-date since we don't respond to state
+		 * changes during sleep.
+		 */
+		nm_manager_rfkill_update (self, RFKILL_TYPE_UNKNOWN);
+
+		/* Re-manage managed devices */
+		for (iter = priv->devices; iter; iter = iter->next) {
+			NMDevice *device = NM_DEVICE (iter->data);
+			guint i;
+
+			/* enable/disable wireless devices since that we don't respond
+			 * to killswitch changes during sleep.
+			 */
+			for (i = 0; i < RFKILL_TYPE_MAX; i++) {
+				RadioState *rstate = &priv->radio_states[i];
+				gboolean enabled = (rstate->hw_enabled && rstate->enabled);
+				RfKillType devtype = RFKILL_TYPE_UNKNOWN;
+
+				if (rstate->desc) {
+					nm_log_dbg (LOGD_RFKILL, "%s %s devices (hw_enabled %d, enabled %d)",
+					            enabled ? "enabling" : "disabling",
+					            rstate->desc, rstate->hw_enabled, rstate->enabled);
+				}
+
+				g_object_get (G_OBJECT (device), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
+				if (devtype == rstate->rtype)
+					nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), enabled);
+			}
+
+			nm_device_clear_autoconnect_inhibit (device);
+			if (nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs))
+				nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
+			else
+				nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
+		}
+
+		/* Ask for new bluetooth devices */
+		bluez_manager_resync_devices (self);
+	}
+
+	nm_manager_update_state (self);
+}
+
+static gboolean
+impl_manager_sleep (NMManager *self, gboolean do_sleep, GError **error)
+{
+	NMManagerPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
+
+	priv = NM_MANAGER_GET_PRIVATE (self);
+
+	if (priv->sleeping == do_sleep) {
+		g_set_error (error,
+		             NM_MANAGER_ERROR, NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
+		             "Already %s", do_sleep ? "asleep" : "awake");
+		return FALSE;
+	}
+
+	nm_log_info (LOGD_SUSPEND, "%s requested (sleeping: %s  enabled: %s)",
+	             do_sleep ? "sleep" : "wake",
+	             priv->sleeping ? "yes" : "no",
+	             priv->net_enabled ? "yes" : "no");
+
+	priv->sleeping = do_sleep;
+
+	do_sleep_wake (self);
+
+	g_object_notify (G_OBJECT (self), NM_MANAGER_SLEEPING);
+	return TRUE;
+}
+
+static gboolean
+impl_manager_enable (NMManager *self, gboolean enable, GError **error)
+{
+	NMManagerPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
+
+	priv = NM_MANAGER_GET_PRIVATE (self);
+
+	if (priv->net_enabled == enable) {
+		g_set_error (error,
+		             NM_MANAGER_ERROR, NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
+		             "Already %s", enable ? "enabled" : "disabled");
+		return FALSE;
+	}
+
+	/* Update "NetworkingEnabled" key in state file */
+	if (priv->state_file) {
+		GError *err = NULL;
+
+		if (!write_value_to_state_file (priv->state_file,
+		                                "main", "NetworkingEnabled",
+		                                G_TYPE_BOOLEAN, (gpointer) &enable,
+		                                &err)) {
+			/* Not a hard error */
+			nm_log_warn (LOGD_SUSPEND, "writing to state file %s failed: (%d) %s.",
+			             priv->state_file,
+			             err ? err->code : -1,
+			             (err && err->message) ? err->message : "unknown");
+		}
+	}
+
+	nm_log_info (LOGD_SUSPEND, "%s requested (sleeping: %s  enabled: %s)",
+	             enable ? "enable" : "disable",
+	             priv->sleeping ? "yes" : "no",
+	             priv->net_enabled ? "yes" : "no");
+
+	priv->net_enabled = enable;
+
+	do_sleep_wake (self);
+
+	g_object_notify (G_OBJECT (self), NM_MANAGER_NETWORKING_ENABLED);
+	return TRUE;
+}
+
+/* Legacy 0.6 compatibility interface */
+
+static gboolean
+impl_manager_legacy_sleep (NMManager *manager, GError **error)
+{
+	return impl_manager_sleep (manager, TRUE, error);
+}
+
+static gboolean
+impl_manager_legacy_wake  (NMManager *manager, GError **error)
+{
+	return impl_manager_sleep (manager, FALSE, error);
+}
+
+static gboolean
+impl_manager_legacy_state (NMManager *manager, guint32 *state, GError **err)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
+	nm_manager_update_state (manager);
+	*state = priv->state;
+	return TRUE;
+}
+
+static gboolean
+impl_manager_set_logging (NMManager *manager,
+                          const char *level,
+                          const char *domains,
+                          GError **error)
+{
+	if (nm_logging_setup (level, domains, error)) {
+		char *new_domains = nm_logging_domains_to_string ();
+
+		nm_log_info (LOGD_CORE, "logging: level '%s' domains '%s'",
+		             nm_logging_level_to_string (),
+		             new_domains);
+		g_free (new_domains);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/* Connections */
+
+static int
+connection_sort (gconstpointer pa, gconstpointer pb)
+{
+	NMConnection *a = NM_CONNECTION (pa);
+	NMSettingConnection *con_a;
+	NMConnection *b = NM_CONNECTION (pb);
+	NMSettingConnection *con_b;
+
+	con_a = (NMSettingConnection *) nm_connection_get_setting (a, NM_TYPE_SETTING_CONNECTION);
+	g_assert (con_a);
+	con_b = (NMSettingConnection *) nm_connection_get_setting (b, NM_TYPE_SETTING_CONNECTION);
+	g_assert (con_b);
+
+	if (nm_setting_connection_get_autoconnect (con_a) != nm_setting_connection_get_autoconnect (con_b)) {
+		if (nm_setting_connection_get_autoconnect (con_a))
+			return -1;
+		return 1;
+	}
+
+	if (nm_setting_connection_get_timestamp (con_a) > nm_setting_connection_get_timestamp (con_b))
+		return -1;
+	else if (nm_setting_connection_get_timestamp (con_a) == nm_setting_connection_get_timestamp (con_b))
+		return 0;
+	return 1;
+}
+
+static void
+connections_to_slist (gpointer key, gpointer value, gpointer user_data)
+{
+	GSList **list = (GSList **) user_data;
+
+	*list = g_slist_insert_sorted (*list, g_object_ref (value), connection_sort);
+}
+
+/* Returns a GSList of referenced NMConnection objects, caller must
+ * unref the connections in the list and destroy the list.
+ */
+GSList *
+nm_manager_get_connections (NMManager *manager,
+                            NMConnectionScope scope)
+{
+	NMManagerPrivate *priv;
+	GSList *list = NULL;
+
+	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
+
+	priv = NM_MANAGER_GET_PRIVATE (manager);
+	if (scope == NM_CONNECTION_SCOPE_USER)
+		g_hash_table_foreach (priv->user_connections, connections_to_slist, &list);
+	else if (scope == NM_CONNECTION_SCOPE_SYSTEM)
+		g_hash_table_foreach (priv->system_connections, connections_to_slist, &list);
+	else
+		nm_log_err (LOGD_CORE, "unknown NMConnectionScope %d", scope);
+	return list;
+}
+
+NMConnection *
+nm_manager_get_connection_by_object_path (NMManager *manager,
+                                          NMConnectionScope scope,
+                                          const char *path)
+{
+	NMManagerPrivate *priv;
+	NMConnection *connection = NULL;
+
+	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
+	g_return_val_if_fail (path != NULL, NULL);
+
+	priv = NM_MANAGER_GET_PRIVATE (manager);
+	if (scope == NM_CONNECTION_SCOPE_USER)
+		connection = (NMConnection *) g_hash_table_lookup (priv->user_connections, path);
+	else if (scope == NM_CONNECTION_SCOPE_SYSTEM)
+		connection = (NMConnection *) g_hash_table_lookup (priv->system_connections, path);
+	else
+		nm_log_err (LOGD_CORE, "unknown NMConnectionScope %d", scope);
+	return connection;
+}
+
+GPtrArray *
+nm_manager_get_active_connections_by_connection (NMManager *manager,
+                                                 NMConnection *connection)
+{
+	return get_active_connections (manager, connection);
+}
+
+void
+nm_manager_start (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	guint i;
+
+	/* Set initial radio enabled/disabled state */
+	for (i = 0; i < RFKILL_TYPE_MAX; i++) {
+		RadioState *rstate = &priv->radio_states[i];
+		gboolean enabled = TRUE, hw_enabled = TRUE;
+
+		if (!rstate->desc)
+			continue;
+
+		switch (nm_udev_manager_get_rfkill_state (priv->udev_mgr, i)) {
+		case RFKILL_UNBLOCKED:
+			enabled = TRUE;
+			hw_enabled = TRUE;
+			break;
+		case RFKILL_SOFT_BLOCKED:
+			enabled = FALSE;
+			hw_enabled = TRUE;
+			break;
+		case RFKILL_HARD_BLOCKED:
+			enabled = FALSE;
+			hw_enabled = FALSE;
+			break;
+		default:
+			break;
+		}
+
+		rstate->hw_enabled = hw_enabled;
+		nm_log_info (LOGD_RFKILL, "%s %s by radio killswitch; %s by state file",
+		             rstate->desc,
+		             (rstate->hw_enabled && enabled) ? "enabled" : "disabled",
+		             (rstate->enabled) ? "enabled" : "disabled");
+		manager_set_radio_enabled (self, rstate, rstate->enabled && enabled);
+	}
+
+	/* Log overall networking status - enabled/disabled */
+	nm_log_info (LOGD_CORE, "Networking is %s by state file",
+	             priv->net_enabled ? "enabled" : "disabled");
+
+	system_unmanaged_devices_changed_cb (priv->sys_settings, NULL, self);
+	system_hostname_changed_cb (priv->sys_settings, NULL, self);
+	system_query_connections (self);
+
+	/* Get user connections if the user settings service is around, otherwise
+	 * they will be queried when the user settings service shows up on the
+	 * bus in nm_manager_name_owner_changed().
+	 */
+	if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, NM_DBUS_SERVICE_USER_SETTINGS))
+		user_query_connections (self);
+
+	nm_udev_manager_query_devices (priv->udev_mgr);
+	bluez_manager_resync_devices (self);
+}
+
+NMManager *
+nm_manager_get (const char *config_file,
+                const char *plugins,
+                const char *state_file,
+                gboolean initial_net_enabled,
+                gboolean initial_wifi_enabled,
+                gboolean initial_wwan_enabled,
+                GError **error)
+{
+	static NMManager *singleton = NULL;
+	NMManagerPrivate *priv;
+	DBusGConnection *bus;
+
+	if (singleton)
+		return g_object_ref (singleton);
+
+	singleton = (NMManager *) g_object_new (NM_TYPE_MANAGER, NULL);
+	g_assert (singleton);
+
+	priv = NM_MANAGER_GET_PRIVATE (singleton);
+
+	bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	g_assert (bus);
+
+	priv->sys_settings = nm_sysconfig_settings_new (config_file, plugins, bus, error);
+	if (!priv->sys_settings) {
+		g_object_unref (singleton);
+		return NULL;
+	}
+	nm_settings_service_export (NM_SETTINGS_SERVICE (priv->sys_settings));
+
+	priv->config_file = g_strdup (config_file);
+
+	priv->state_file = g_strdup (state_file);
+
+	priv->net_enabled = initial_net_enabled;
+
+	priv->radio_states[RFKILL_TYPE_WLAN].enabled = initial_wifi_enabled;
+	priv->radio_states[RFKILL_TYPE_WWAN].enabled = initial_wwan_enabled;
+
+	g_signal_connect (priv->sys_settings, "notify::" NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS,
+	                  G_CALLBACK (system_unmanaged_devices_changed_cb), singleton);
+	g_signal_connect (priv->sys_settings, "notify::" NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME,
+	                  G_CALLBACK (system_hostname_changed_cb), singleton);
+	g_signal_connect (priv->sys_settings, "new-connection",
+	                  G_CALLBACK (system_new_connection_cb), singleton);
+
+	dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	                                     NM_DBUS_PATH,
+	                                     G_OBJECT (singleton));
+
+	g_signal_connect (priv->dbus_mgr,
+	                  "name-owner-changed",
+	                  G_CALLBACK (nm_manager_name_owner_changed),
+	                  singleton);
+
+	priv->udev_mgr = nm_udev_manager_new ();
+	g_signal_connect (priv->udev_mgr,
+	                  "device-added",
+	                  G_CALLBACK (udev_device_added_cb),
+	                  singleton);
+	g_signal_connect (priv->udev_mgr,
+	                  "device-removed",
+	                  G_CALLBACK (udev_device_removed_cb),
+	                  singleton);
+	g_signal_connect (priv->udev_mgr,
+	                  "rfkill-changed",
+	                  G_CALLBACK (udev_manager_rfkill_changed_cb),
+	                  singleton);
+
+	priv->bluez_mgr = nm_bluez_manager_get ();
+
+	g_signal_connect (priv->bluez_mgr,
+			  "bdaddr-added",
+			  G_CALLBACK (bluez_manager_bdaddr_added_cb),
+			  singleton);
+
+	g_signal_connect (priv->bluez_mgr,
+			  "bdaddr-removed",
+			  G_CALLBACK (bluez_manager_bdaddr_removed_cb),
+			  singleton);
+
+	return singleton;
+}
+
+static void
+dispose (GObject *object)
+{
+	NMManager *manager = NM_MANAGER (object);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
+	if (priv->disposed) {
+		G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
+		return;
+	}
+	priv->disposed = TRUE;
+
+	pending_connection_info_destroy (priv->pending_connection_info);
+	priv->pending_connection_info = NULL;
+
+	while (g_slist_length (priv->secrets_calls))
+		free_get_secrets_info ((GetSecretsInfo *) priv->secrets_calls->data);
+
+	while (g_slist_length (priv->devices)) {
+		priv->devices = remove_one_device (manager,
+		                                   priv->devices,
+		                                   NM_DEVICE (priv->devices->data),
+		                                   TRUE,
+		                                   FALSE);
+	}
+
+	user_destroy_connections (manager);
+	g_hash_table_destroy (priv->user_connections);
+	priv->user_connections = NULL;
+
+	g_hash_table_foreach (priv->system_connections, emit_removed, manager);
+	g_hash_table_remove_all (priv->system_connections);
+	g_hash_table_destroy (priv->system_connections);
+	priv->system_connections = NULL;
+
+	g_free (priv->hostname);
+	g_free (priv->config_file);
+
+	if (priv->sys_settings) {
+		g_object_unref (priv->sys_settings);
+		priv->sys_settings = NULL;
+	}
+
+	if (priv->vpn_manager_id) {
+		g_source_remove (priv->vpn_manager_id);
+		priv->vpn_manager_id = 0;
+	}
+	g_object_unref (priv->vpn_manager);
+
+	if (priv->modem_added_id) {
+		g_source_remove (priv->modem_added_id);
+		priv->modem_added_id = 0;
+	}
+	if (priv->modem_removed_id) {
+		g_source_remove (priv->modem_removed_id);
+		priv->modem_removed_id = 0;
+	}
+	g_object_unref (priv->modem_manager);
+
+	g_object_unref (priv->dbus_mgr);
+	if (priv->bluez_mgr)
+		g_object_unref (priv->bluez_mgr);
+
+	G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	NMManager *self = NM_MANAGER (object);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	switch (prop_id) {
+	case PROP_NETWORKING_ENABLED:
+		/* Construct only for now */
+		priv->net_enabled = g_value_get_boolean (value);
+		break;
+	case PROP_WIRELESS_ENABLED:
+		manager_set_radio_enabled (NM_MANAGER (object),
+		                           &priv->radio_states[RFKILL_TYPE_WLAN],
+		                           g_value_get_boolean (value));
+		break;
+	case PROP_WWAN_ENABLED:
+		manager_set_radio_enabled (NM_MANAGER (object),
+		                           &priv->radio_states[RFKILL_TYPE_WWAN],
+		                           g_value_get_boolean (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec)
+{
+	NMManager *self = NM_MANAGER (object);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	switch (prop_id) {
+	case PROP_STATE:
+		nm_manager_update_state (self);
+		g_value_set_uint (value, priv->state);
+		break;
+	case PROP_NETWORKING_ENABLED:
+		g_value_set_boolean (value, priv->net_enabled);
+		break;
+	case PROP_WIRELESS_ENABLED:
+		g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].enabled);
+		break;
+	case PROP_WIRELESS_HARDWARE_ENABLED:
+		g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].hw_enabled);
+		break;
+	case PROP_WWAN_ENABLED:
+		g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].enabled);
+		break;
+	case PROP_WWAN_HARDWARE_ENABLED:
+		g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].hw_enabled);
+		break;
+	case PROP_ACTIVE_CONNECTIONS:
+		g_value_take_boxed (value, get_active_connections (self, NULL));
+		break;
+	case PROP_HOSTNAME:
+		g_value_set_string (value, priv->hostname);
+		break;
+	case PROP_SLEEPING:
+		g_value_set_boolean (value, priv->sleeping);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_manager_init (NMManager *manager)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	DBusGConnection *g_connection;
+	guint id, i;
+
+	/* Initialize rfkill structures and states */
+	memset (priv->radio_states, 0, sizeof (priv->radio_states));
+
+	priv->radio_states[RFKILL_TYPE_WLAN].enabled = TRUE;
+	priv->radio_states[RFKILL_TYPE_WLAN].key = "WirelessEnabled";
+	priv->radio_states[RFKILL_TYPE_WLAN].prop = NM_MANAGER_WIRELESS_ENABLED;
+	priv->radio_states[RFKILL_TYPE_WLAN].hw_prop = NM_MANAGER_WIRELESS_HARDWARE_ENABLED;
+	priv->radio_states[RFKILL_TYPE_WLAN].desc = "WiFi";
+	priv->radio_states[RFKILL_TYPE_WLAN].other_enabled_func = nm_manager_get_ipw_rfkill_state;
+	priv->radio_states[RFKILL_TYPE_WLAN].rtype = RFKILL_TYPE_WLAN;
+
+	priv->radio_states[RFKILL_TYPE_WWAN].enabled = TRUE;
+	priv->radio_states[RFKILL_TYPE_WWAN].key = "WWANEnabled";
+	priv->radio_states[RFKILL_TYPE_WWAN].prop = NM_MANAGER_WWAN_ENABLED;
+	priv->radio_states[RFKILL_TYPE_WWAN].hw_prop = NM_MANAGER_WWAN_HARDWARE_ENABLED;
+	priv->radio_states[RFKILL_TYPE_WWAN].desc = "WWAN";
+	priv->radio_states[RFKILL_TYPE_WWAN].other_enabled_func = nm_manager_get_modem_enabled_state;
+	priv->radio_states[RFKILL_TYPE_WWAN].rtype = RFKILL_TYPE_WWAN;
+
+	priv->radio_states[RFKILL_TYPE_WIMAX].enabled = TRUE;
+	priv->radio_states[RFKILL_TYPE_WIMAX].key = "WiMAXEnabled";
+	priv->radio_states[RFKILL_TYPE_WIMAX].prop = NULL;
+	priv->radio_states[RFKILL_TYPE_WIMAX].hw_prop = NULL;
+	priv->radio_states[RFKILL_TYPE_WIMAX].desc = "WiMAX";
+	priv->radio_states[RFKILL_TYPE_WIMAX].other_enabled_func = NULL;
+	priv->radio_states[RFKILL_TYPE_WIMAX].rtype = RFKILL_TYPE_WIMAX;
+
+	for (i = 0; i < RFKILL_TYPE_MAX; i++)
+		priv->radio_states[i].hw_enabled = TRUE;
+
+	priv->sleeping = FALSE;
+	priv->state = NM_STATE_DISCONNECTED;
+
+	priv->dbus_mgr = nm_dbus_manager_get ();
+
+	priv->user_connections = g_hash_table_new_full (g_str_hash,
+	                                                g_str_equal,
+	                                                g_free,
+	                                                g_object_unref);
+
+	priv->system_connections = g_hash_table_new_full (g_str_hash,
+	                                                  g_str_equal,
+	                                                  g_free,
+	                                                  g_object_unref);
+
+	priv->modem_manager = nm_modem_manager_get ();
+	priv->modem_added_id = g_signal_connect (priv->modem_manager, "modem-added",
+	                                         G_CALLBACK (modem_added), manager);
+	priv->modem_removed_id = g_signal_connect (priv->modem_manager, "modem-removed",
+	                                           G_CALLBACK (modem_removed), manager);
+
+	priv->vpn_manager = nm_vpn_manager_get ();
+	id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-deactivated",
+	                       G_CALLBACK (vpn_manager_connection_deactivated_cb), manager);
+	priv->vpn_manager_id = id;
+
+	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+
+	/* avahi-autoipd stuff */
+	priv->aipd_proxy = dbus_g_proxy_new_for_name (g_connection,
+	                                              NM_AUTOIP_DBUS_SERVICE,
+	                                              "/",
+	                                              NM_AUTOIP_DBUS_IFACE);
+	if (priv->aipd_proxy) {
+		dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING_STRING,
+		                                   G_TYPE_NONE,
+		                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                                   G_TYPE_INVALID);
+
+		dbus_g_proxy_add_signal (priv->aipd_proxy,
+		                         "Event",
+		                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                         G_TYPE_INVALID);
+
+		dbus_g_proxy_connect_signal (priv->aipd_proxy, "Event",
+		                             G_CALLBACK (aipd_handle_event),
+		                             manager,
+		                             NULL);
+	} else
+		nm_log_warn (LOGD_AUTOIP4, "could not initialize avahi-autoipd D-Bus proxy");
+}
+
+static void
+nm_manager_class_init (NMManagerClass *manager_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
+
+	g_type_class_add_private (manager_class, sizeof (NMManagerPrivate));
+
+	/* virtual methods */
+	manager_class->connection_added = connection_added_default_handler;
+
+	object_class->set_property = set_property;
+	object_class->get_property = get_property;
+	object_class->dispose = dispose;
+
+	/* properties */
+	g_object_class_install_property
+		(object_class, PROP_STATE,
+		 g_param_spec_uint (NM_MANAGER_STATE,
+		                    "State",
+		                    "Current state",
+		                    0, NM_STATE_DISCONNECTED, 0,
+		                    G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_NETWORKING_ENABLED,
+		 g_param_spec_boolean (NM_MANAGER_NETWORKING_ENABLED,
+		                       "NetworkingEnabled",
+		                       "Is networking enabled",
+		                       TRUE,
+		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_WIRELESS_ENABLED,
+		 g_param_spec_boolean (NM_MANAGER_WIRELESS_ENABLED,
+		                       "WirelessEnabled",
+		                       "Is wireless enabled",
+		                       TRUE,
+		                       G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_WIRELESS_HARDWARE_ENABLED,
+		 g_param_spec_boolean (NM_MANAGER_WIRELESS_HARDWARE_ENABLED,
+		                       "WirelessHardwareEnabled",
+		                       "RF kill state",
+		                       TRUE,
+		                       G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_WWAN_ENABLED,
+		 g_param_spec_boolean (NM_MANAGER_WWAN_ENABLED,
+		                       "WwanEnabled",
+		                       "Is mobile broadband enabled",
+		                       TRUE,
+		                       G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_WWAN_HARDWARE_ENABLED,
+		 g_param_spec_boolean (NM_MANAGER_WWAN_HARDWARE_ENABLED,
+		                       "WwanHardwareEnabled",
+		                       "Whether WWAN is disabled by a hardware switch or not",
+		                       TRUE,
+		                       G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_ACTIVE_CONNECTIONS,
+		 g_param_spec_boxed (NM_MANAGER_ACTIVE_CONNECTIONS,
+		                     "Active connections",
+		                     "Active connections",
+		                     DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
+		                     G_PARAM_READABLE));
+
+	/* Hostname is not exported over D-Bus */
+	g_object_class_install_property
+		(object_class, PROP_HOSTNAME,
+		 g_param_spec_string (NM_MANAGER_HOSTNAME,
+		                      "Hostname",
+		                      "Hostname",
+		                      NULL,
+		                      G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT));
+
+	/* Sleeping is not exported over D-Bus */
+	g_object_class_install_property
+		(object_class, PROP_SLEEPING,
+		 g_param_spec_boolean (NM_MANAGER_SLEEPING,
+		                       "Sleeping",
+		                       "Sleeping",
+		                       FALSE,
+		                       G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT));
+
+	/* signals */
+	signals[DEVICE_ADDED] =
+		g_signal_new ("device-added",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, device_added),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__OBJECT,
+		              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+	signals[DEVICE_REMOVED] =
+		g_signal_new ("device-removed",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, device_removed),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__OBJECT,
+		              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+	signals[STATE_CHANGED] =
+		g_signal_new ("state-changed",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, state_changed),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__UINT,
+		              G_TYPE_NONE, 1, G_TYPE_UINT);
+
+	signals[PROPERTIES_CHANGED] =
+		nm_properties_changed_signal_new (object_class,
+		                                  G_STRUCT_OFFSET (NMManagerClass, properties_changed));
+
+	signals[CONNECTIONS_ADDED] =
+		g_signal_new ("connections-added",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, connections_added),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__UINT,
+		              G_TYPE_NONE, 1, G_TYPE_UINT);
+
+	signals[CONNECTION_ADDED] =
+		g_signal_new ("connection-added",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, connection_added),
+		              NULL, NULL,
+		              _nm_marshal_VOID__OBJECT_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
+
+	signals[CONNECTION_UPDATED] =
+		g_signal_new ("connection-updated",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, connection_updated),
+		              NULL, NULL,
+		              _nm_marshal_VOID__OBJECT_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
+
+	signals[CONNECTION_REMOVED] =
+		g_signal_new ("connection-removed",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, connection_removed),
+		              NULL, NULL,
+		              _nm_marshal_VOID__OBJECT_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
+
+	/* StateChange is DEPRECATED */
+	signals[STATE_CHANGE] =
+		g_signal_new ("state-change",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              g_cclosure_marshal_VOID__UINT,
+		              G_TYPE_NONE, 1, G_TYPE_UINT);
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (manager_class),
+	                                 &dbus_glib_nm_manager_object_info);
+
+	dbus_g_error_domain_register (NM_MANAGER_ERROR, NULL, NM_TYPE_MANAGER_ERROR);
+	dbus_g_error_domain_register (NM_LOGGING_ERROR, "org.freedesktop.NetworkManager.Logging", NM_TYPE_LOGGING_ERROR);
+}
+