summary refs log tree commit diff
path: root/src/nm-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-manager.c')
-rw-r--r--src/nm-manager.c2442
1 files changed, 1098 insertions, 1344 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 1ccfad8e..f3bbebd0 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -30,7 +30,7 @@
 #include <unistd.h>
 
 #include "nm-common-macros.h"
-#include "nm-dbus-manager.h"
+#include "nm-bus-manager.h"
 #include "vpn/nm-vpn-manager.h"
 #include "devices/nm-device.h"
 #include "devices/nm-device-generic.h"
@@ -56,10 +56,12 @@
 #include "nm-dbus-compat.h"
 #include "nm-checkpoint.h"
 #include "nm-checkpoint-manager.h"
-#include "nm-dbus-object.h"
 #include "nm-dispatcher.h"
 #include "NetworkManagerUtils.h"
 
+#include "introspection/org.freedesktop.NetworkManager.h"
+#include "introspection/org.freedesktop.NetworkManager.Device.h"
+
 /*****************************************************************************/
 
 typedef struct {
@@ -78,6 +80,8 @@ enum {
 	INTERNAL_DEVICE_ADDED,
 	DEVICE_REMOVED,
 	INTERNAL_DEVICE_REMOVED,
+	STATE_CHANGED,
+	CHECK_PERMISSIONS,
 	ACTIVE_CONNECTION_ADDED,
 	ACTIVE_CONNECTION_REMOVED,
 	CONFIGURE_QUIT,
@@ -110,7 +114,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMManager,
 	PROP_METERED,
 	PROP_GLOBAL_DNS_CONFIGURATION,
 	PROP_ALL_DEVICES,
-	PROP_CHECKPOINTS,
 
 	/* Not exported */
 	PROP_SLEEPING,
@@ -128,14 +131,16 @@ typedef struct {
 	NMActiveConnection *activating_connection;
 	NMMetered metered;
 
-	CList devices_lst_head;
-
+	GSList *devices;
 	NMState state;
 	NMConfig *config;
-	NMConnectivity *concheck_mgr;
+	NMConnectivityState connectivity_state;
+
 	NMPolicy *policy;
+
 	NMHostnameManager *hostname_manager;
 
+	NMBusManager  *dbus_mgr;
 	struct {
 		GDBusConnection *connection;
 		guint            id;
@@ -168,30 +173,26 @@ typedef struct {
 
 	guint devices_inited_id;
 
-	NMConnectivityState connectivity_state;
-
 	bool startup:1;
 	bool devices_inited:1;
 
 	bool sleeping:1;
 	bool net_enabled:1;
 
-	unsigned connectivity_check_enabled_last:2;
-
 	guint delete_volatile_connection_idle_id;
 	CList delete_volatile_connection_lst_head;
 } NMManagerPrivate;
 
 struct _NMManager {
-	NMDBusObject parent;
+	NMExportedObject parent;
 	NMManagerPrivate _priv;
 };
 
 typedef struct {
-	NMDBusObjectClass parent;
+	NMExportedObjectClass parent;
 } NMManagerClass;
 
-G_DEFINE_TYPE (NMManager, nm_manager, NM_TYPE_DBUS_OBJECT)
+G_DEFINE_TYPE (NMManager, nm_manager, NM_TYPE_EXPORTED_OBJECT)
 
 #define NM_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMManager, NM_IS_MANAGER)
 
@@ -268,20 +269,9 @@ NM_DEFINE_SINGLETON_INSTANCE (NMManager);
 
 /*****************************************************************************/
 
-static const NMDBusInterfaceInfoExtended interface_info_manager;
-static const GDBusSignalInfo signal_info_check_permissions;
-static const GDBusSignalInfo signal_info_state_changed;
-static const GDBusSignalInfo signal_info_device_added;
-static const GDBusSignalInfo signal_info_device_removed;
-
 static gboolean add_device (NMManager *self, NMDevice *device, GError **error);
 
-static void _emit_device_added_removed (NMManager *self,
-                                        NMDevice *device,
-                                        gboolean is_added);
-
 static NMActiveConnection *_new_active_connection (NMManager *self,
-                                                   gboolean is_vpn,
                                                    NMConnection *connection,
                                                    NMConnection *applied,
                                                    const char *specific_object,
@@ -329,8 +319,6 @@ static NMActiveConnection *active_connection_find_first (NMManager *self,
                                                          const char *uuid,
                                                          NMActiveConnectionState max_state);
 
-static NMConnectivity *concheck_get_mgr (NMManager *self);
-
 /*****************************************************************************/
 
 static NM_CACHED_QUARK_FCN ("active-connection-add-and-activate", active_connection_add_and_activate_quark)
@@ -339,73 +327,6 @@ static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark)
 
 /*****************************************************************************/
 
-static gboolean
-_connection_is_vpn (NMConnection *connection)
-{
-	const char *type;
-
-	type = nm_connection_get_connection_type (connection);
-	if (type)
-		return nm_streq (type, NM_SETTING_VPN_SETTING_NAME);
-
-	/* we have an incomplete (invalid) connection at hand. That can only
-	 * happen during AddAndActivate. Determine whether it's VPN type based
-	 * on the existance of a [vpn] section. */
-	return !!nm_connection_get_setting_vpn (connection);
-}
-
-/*****************************************************************************/
-
-static gboolean
-concheck_enabled (NMManager *self, gboolean *out_changed)
-{
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	guint check_enabled;
-
-	check_enabled = nm_connectivity_check_enabled (concheck_get_mgr (self))
-	                ? 1 : 2;
-	if (priv->connectivity_check_enabled_last == check_enabled)
-		NM_SET_OUT (out_changed, FALSE);
-	else {
-		NM_SET_OUT (out_changed, TRUE);
-		priv->connectivity_check_enabled_last = check_enabled;
-	}
-	return check_enabled == 1;
-}
-
-static void
-concheck_config_changed_cb (NMConnectivity *connectivity,
-                            NMManager *self)
-{
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
-	gboolean changed;
-
-	concheck_enabled (self, &changed);
-	if (changed)
-		_notify (self, PROP_CONNECTIVITY_CHECK_ENABLED);
-
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst)
-		nm_device_check_connectivity_update_interval (device);
-}
-
-static NMConnectivity *
-concheck_get_mgr (NMManager *self)
-{
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-
-	if (G_UNLIKELY (!priv->concheck_mgr)) {
-		priv->concheck_mgr = g_object_ref (nm_connectivity_get ());
-		g_signal_connect (priv->concheck_mgr,
-		                  NM_CONNECTIVITY_CONFIG_CHANGED,
-		                  G_CALLBACK (concheck_config_changed_cb),
-		                  self);
-	}
-	return priv->concheck_mgr;
-}
-
-/*****************************************************************************/
-
 typedef struct {
 	int ifindex;
 	guint32 aspired_metric;
@@ -514,10 +435,10 @@ _device_route_metric_get (NMManager *self,
 				 * hence we skip it. */
 				continue;
 			}
-			if (!g_hash_table_add (priv->device_route_metrics,
-			                       _device_route_metric_data_new (device_state->ifindex,
-			                                                      device_state->route_metric_default_aspired,
-			                                                      device_state->route_metric_default_effective)))
+			if (!nm_g_hash_table_add (priv->device_route_metrics,
+			                          _device_route_metric_data_new (device_state->ifindex,
+			                                                         device_state->route_metric_default_aspired,
+			                                                         device_state->route_metric_default_effective)))
 				nm_assert_not_reached ();
 		}
 	}
@@ -610,7 +531,7 @@ again:
 	_LOGT (LOGD_DEVICE, "default-route-metric: ifindex %d reserves metric %u (aspired %u)",
 	       data->ifindex, data->effective_metric, data->aspired_metric);
 
-	if (!g_hash_table_add (priv->device_route_metrics, data))
+	if (!nm_g_hash_table_add (priv->device_route_metrics, data))
 		nm_assert_not_reached ();
 
 out:
@@ -657,7 +578,7 @@ _delete_volatile_connection_do (NMManager *self,
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 
 	if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection),
-	                   NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE))
+	                   NM_SETTINGS_CONNECTION_FLAGS_VOLATILE))
 		return;
 	if (active_connection_find_first (self,
 	                                  connection,
@@ -683,7 +604,7 @@ active_connection_remove (NMManager *self, NMActiveConnection *active)
 	nm_assert (NM_IS_ACTIVE_CONNECTION (active));
 	nm_assert (c_list_contains (&priv->active_connections_lst_head, &active->active_connections_lst));
 
-	notify = nm_dbus_object_is_exported (NM_DBUS_OBJECT (active));
+	notify = nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active));
 
 	c_list_unlink (&active->active_connections_lst);
 	g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active);
@@ -693,7 +614,7 @@ active_connection_remove (NMManager *self, NMActiveConnection *active)
 
 	connection = nm_g_object_ref (nm_active_connection_get_settings_connection (active));
 
-	nm_dbus_object_clear_and_unexport (&active);
+	nm_exported_object_clear_and_unexport (&active);
 
 	if (connection)
 		_delete_volatile_connection_do (self, connection);
@@ -789,8 +710,8 @@ active_connection_add (NMManager *self,
 	                  G_CALLBACK (active_connection_default_changed),
 	                  self);
 
-	if (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (active)))
-		nm_dbus_object_export (NM_DBUS_OBJECT (active));
+	if (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active)))
+		nm_exported_object_export (NM_EXPORTED_OBJECT (active));
 
 	g_signal_emit (self, signals[ACTIVE_CONNECTION_ADDED], 0, active);
 
@@ -854,7 +775,7 @@ _get_activatable_connections_filter (NMSettings *settings,
                                      gpointer user_data)
 {
 	if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection),
-	                  NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE))
+	                  NM_SETTINGS_CONNECTION_FLAGS_VOLATILE))
 		return FALSE;
 	return !active_connection_find_first (user_data, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING);
 }
@@ -872,20 +793,18 @@ nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, gboo
 }
 
 static NMActiveConnection *
-active_connection_get_by_path (NMManager *self, const char *path)
+active_connection_get_by_path (NMManager *manager, const char *path)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	NMActiveConnection *ac;
 
-	ac = (NMActiveConnection *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)),
-	                                                           path);
-	if (   !ac
-	    || !NM_IS_ACTIVE_CONNECTION (ac)
-	    || c_list_is_empty (&ac->active_connections_lst))
-		return NULL;
+	nm_assert (path);
 
-	nm_assert (c_list_contains (&priv->active_connections_lst_head, &ac->active_connections_lst));
-	return ac;
+	c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
+		if (nm_streq0 (path, nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac))))
+			return ac;
+	}
+	return NULL;
 }
 
 /*****************************************************************************/
@@ -893,14 +812,8 @@ active_connection_get_by_path (NMManager *self, const char *path)
 static void
 _config_changed_cb (NMConfig *config, NMConfigData *config_data, NMConfigChangeFlags changes, NMConfigData *old_data, NMManager *self)
 {
-	g_object_freeze_notify (G_OBJECT (self));
-
 	if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG))
 		_notify (self, PROP_GLOBAL_DNS_CONFIGURATION);
-	if ((!nm_config_data_get_connectivity_uri (config_data)) != (!nm_config_data_get_connectivity_uri (old_data)))
-		_notify (self, PROP_CONNECTIVITY_CHECK_AVAILABLE);
-
-	g_object_thaw_notify (G_OBJECT (self));
 }
 
 static void
@@ -971,31 +884,28 @@ _reload_auth_cb (NMAuthChain *chain,
 	g_dbus_method_invocation_return_value (context, NULL);
 
 out:
-	nm_auth_chain_destroy (chain);
+	nm_auth_chain_unref (chain);
 }
 
 static void
-impl_manager_reload (NMDBusObject *obj,
-                     const NMDBusInterfaceInfoExtended *interface_info,
-                     const NMDBusMethodInfoExtended *method_info,
-                     GDBusConnection *connection,
-                     const char *sender,
-                     GDBusMethodInvocation *invocation,
-                     GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+impl_manager_reload (NMManager *self,
+                     GDBusMethodInvocation *context,
+                     guint32 flags)
+{
+	NMManagerPrivate *priv;
 	NMAuthChain *chain;
-	guint32 flags;
+	GError *error = NULL;
 
-	g_variant_get (parameters, "(u)", &flags);
+	g_return_if_fail (NM_IS_MANAGER (self));
 
-	chain = nm_auth_chain_new_context (invocation, _reload_auth_cb, self);
+	priv = NM_MANAGER_GET_PRIVATE (self);
+
+	chain = nm_auth_chain_new_context (context, _reload_auth_cb, self);
 	if (!chain) {
-		g_dbus_method_invocation_return_error_literal (invocation,
-		                                               NM_MANAGER_ERROR,
-		                                               NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                                               "Unable to authenticate request");
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             "Unable to authenticate request");
+		g_dbus_method_invocation_take_error (context, error);
 		return;
 	}
 
@@ -1007,31 +917,27 @@ impl_manager_reload (NMDBusObject *obj,
 /*****************************************************************************/
 
 NMDevice *
-nm_manager_get_device_by_path (NMManager *self, const char *path)
+nm_manager_get_device_by_path (NMManager *manager, const char *path)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
-
-	g_return_val_if_fail (path, NULL);
+	GSList *iter;
 
-	device = (NMDevice *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)),
-	                                                     path);
-	if (   !device
-	    || !NM_IS_DEVICE (device)
-	    || c_list_is_empty (&device->devices_lst))
-		return NULL;
+	g_return_val_if_fail (path != NULL, NULL);
 
-	nm_assert (c_list_contains (&priv->devices_lst_head, &device->devices_lst));
-	return device;
+	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+		if (!strcmp (nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data)), path))
+			return NM_DEVICE (iter->data);
+	}
+	return NULL;
 }
 
 NMDevice *
-nm_manager_get_device_by_ifindex (NMManager *self, int ifindex)
+nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
+	GSList *iter;
+
+	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+		NMDevice *device = NM_DEVICE (iter->data);
 
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
 		if (nm_device_get_ifindex (device) == ifindex)
 			return device;
 	}
@@ -1040,24 +946,19 @@ nm_manager_get_device_by_ifindex (NMManager *self, int ifindex)
 }
 
 static NMDevice *
-find_device_by_permanent_hw_addr (NMManager *self, const char *hwaddr)
+find_device_by_permanent_hw_addr (NMManager *manager, const char *hwaddr)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
+	GSList *iter;
 	const char *device_addr;
-	guint8 hwaddr_bin[NM_UTILS_HWADDR_LEN_MAX];
-	gsize hwaddr_len;
 
 	g_return_val_if_fail (hwaddr != NULL, NULL);
 
-	if (!_nm_utils_hwaddr_aton (hwaddr, hwaddr_bin, sizeof (hwaddr_bin), &hwaddr_len))
-		return NULL;
-
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
-		device_addr = nm_device_get_permanent_hw_address (device);
-		if (   device_addr
-		    && nm_utils_hwaddr_matches (hwaddr_bin, hwaddr_len, device_addr, -1))
-			return device;
+	if (nm_utils_hwaddr_valid (hwaddr, -1)) {
+		for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+			device_addr = nm_device_get_permanent_hw_address (NM_DEVICE (iter->data));
+			if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1))
+				return NM_DEVICE (iter->data);
+		}
 	}
 	return NULL;
 }
@@ -1065,15 +966,16 @@ find_device_by_permanent_hw_addr (NMManager *self, const char *hwaddr)
 static NMDevice *
 find_device_by_ip_iface (NMManager *self, const gchar *iface)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
+	GSList *iter;
+
+	g_return_val_if_fail (iface != NULL, NULL);
 
-	g_return_val_if_fail (iface, NULL);
+	for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *candidate = iter->data;
 
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
-		if (   nm_device_is_real (device)
-		    && nm_streq0 (nm_device_get_ip_iface (device), iface))
-			return device;
+		if (   nm_device_is_real (candidate)
+		    && g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0)
+			return candidate;
 	}
 	return NULL;
 }
@@ -1101,11 +1003,12 @@ find_device_by_iface (NMManager *self,
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMDevice *fallback = NULL;
-	NMDevice *candidate;
+	GSList *iter;
 
 	g_return_val_if_fail (iface != NULL, NULL);
 
-	c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) {
+	for (iter = priv->devices; iter; iter = iter->next) {
+		NMDevice *candidate = iter->data;
 
 		if (strcmp (nm_device_get_iface (candidate), iface))
 			continue;
@@ -1160,6 +1063,22 @@ _nm_state_to_string (NMState state)
 	}
 }
 
+static void
+set_state (NMManager *self, NMState state)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	if (priv->state == state)
+		return;
+
+	priv->state = state;
+
+	_LOGI (LOGD_CORE, "NetworkManager state is now %s", _nm_state_to_string (state));
+
+	_notify (self, PROP_STATE);
+	g_signal_emit (self, signals[STATE_CHANGED], 0, priv->state);
+}
+
 static NMState
 find_best_device_state (NMManager *manager)
 {
@@ -1230,38 +1149,26 @@ nm_manager_update_metered (NMManager *self)
 }
 
 static void
-nm_manager_update_state (NMManager *self)
+nm_manager_update_state (NMManager *manager)
 {
 	NMManagerPrivate *priv;
 	NMState new_state = NM_STATE_DISCONNECTED;
 
-	g_return_if_fail (NM_IS_MANAGER (self));
+	g_return_if_fail (NM_IS_MANAGER (manager));
 
-	priv = NM_MANAGER_GET_PRIVATE (self);
+	priv = NM_MANAGER_GET_PRIVATE (manager);
 
-	if (manager_sleeping (self))
+	if (manager_sleeping (manager))
 		new_state = NM_STATE_ASLEEP;
 	else
-		new_state = find_best_device_state (self);
+		new_state = find_best_device_state (manager);
 
 	if (   new_state >= NM_STATE_CONNECTED_LOCAL
 	    && priv->connectivity_state == NM_CONNECTIVITY_FULL) {
 		new_state = NM_STATE_CONNECTED_GLOBAL;
 	}
 
-	if (priv->state == new_state)
-		return;
-
-	priv->state = new_state;
-
-	_LOGI (LOGD_CORE, "NetworkManager state is now %s", _nm_state_to_string (new_state));
-
-	_notify (self, PROP_STATE);
-	nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self),
-	                            &interface_info_manager,
-	                            &signal_info_state_changed,
-	                            "(u)",
-	                            (guint32) priv->state);
+	set_state (manager, new_state);
 }
 
 static void
@@ -1303,7 +1210,7 @@ static void
 check_if_startup_complete (NMManager *self)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
+	GSList *iter;
 
 	if (!priv->startup)
 		return;
@@ -1316,10 +1223,12 @@ check_if_startup_complete (NMManager *self)
 		return;
 	}
 
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
-		if (nm_device_has_pending_action (device)) {
+	for (iter = priv->devices; iter; iter = iter->next) {
+		NMDevice *dev = iter->data;
+
+		if (nm_device_has_pending_action (dev)) {
 			_LOGD (LOGD_CORE, "check_if_startup_complete returns FALSE because of %s",
-			       nm_device_get_iface (device));
+			       nm_device_get_iface (dev));
 			return;
 		}
 	}
@@ -1331,8 +1240,8 @@ check_if_startup_complete (NMManager *self)
 	/* we no longer care about these signals. Startup-complete only
 	 * happens once. */
 	g_signal_handlers_disconnect_by_func (priv->settings, G_CALLBACK (settings_startup_complete_changed), self);
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
-		g_signal_handlers_disconnect_by_func (device,
+	for (iter = priv->devices; iter; iter = iter->next) {
+		g_signal_handlers_disconnect_by_func (iter->data,
 		                                      G_CALLBACK (device_has_pending_action_changed),
 		                                      self);
 	}
@@ -1364,18 +1273,18 @@ _parent_notify_changed (NMManager *self,
                         NMDevice *device,
                         gboolean device_removed)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *candidate;
+	GSList *iter;
 
 	nm_assert (NM_IS_DEVICE (device));
+	nm_assert (NM_IS_MANAGER (self));
 
-again:
-	c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) {
-		if (nm_device_parent_notify_changed (candidate, device, device_removed)) {
+	for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; ) {
+		if (nm_device_parent_notify_changed (iter->data, device, device_removed)) {
 			/* in the unlikely event that this changes anything, we start iterating
 			 * again, to be sure that the device list is up-to-date. */
-			goto again;
-		}
+			iter = NM_MANAGER_GET_PRIVATE (self)->devices;
+		} else
+			iter = iter->next;
 	}
 }
 
@@ -1415,8 +1324,7 @@ remove_device (NMManager *self,
 	g_signal_handlers_disconnect_matched (device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
 
 	nm_settings_device_removed (priv->settings, device, quitting);
-
-	c_list_unlink (&device->devices_lst);
+	priv->devices = g_slist_remove (priv->devices, device);
 
 	_parent_notify_changed (self, device, TRUE);
 
@@ -1434,7 +1342,8 @@ remove_device (NMManager *self,
 		 * Control that by passing @unconfigure_ip_config.  */
 		nm_device_removed (device, unconfigure_ip_config);
 
-		_emit_device_added_removed (self, device, FALSE);
+		g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
+		_notify (self, PROP_DEVICES);
 	} else {
 		/* unrealize() does not release a slave device from master and
 		 * clear IP configurations, do it here */
@@ -1444,7 +1353,7 @@ remove_device (NMManager *self,
 	g_signal_emit (self, signals[INTERNAL_DEVICE_REMOVED], 0, device);
 	_notify (self, PROP_ALL_DEVICES);
 
-	nm_dbus_object_clear_and_unexport (&device);
+	nm_exported_object_clear_and_unexport (&device);
 
 	check_if_startup_complete (self);
 }
@@ -1473,7 +1382,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM
 	const char *parent_name = NULL;
 	NMSettingsConnection *parent_connection;
 	NMDevice *parent, *first_compatible = NULL;
-	NMDevice *candidate;
+	GSList *iter;
 
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
 
@@ -1506,7 +1415,9 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM
 	/* Check if the parent connection is currently activated or is comaptible
 	 * with some known device.
 	 */
-	c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) {
+	for (iter = priv->devices; iter; iter = iter->next) {
+		NMDevice *candidate = iter->data;
+
 		/* Unmanaged devices are not compatible with any connection */
 		if (!nm_device_get_managed (candidate, FALSE))
 			continue;
@@ -1622,15 +1533,18 @@ NMDevice *
 nm_manager_get_device (NMManager *self, const char *ifname, NMDeviceType device_type)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
+	GSList *iter;
+	NMDevice *d;
 
 	g_return_val_if_fail (ifname, NULL);
 	g_return_val_if_fail (device_type != NM_DEVICE_TYPE_UNKNOWN, NULL);
 
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
-		if (   nm_device_get_device_type (device) == device_type
-		    && nm_streq0 (nm_device_get_iface (device), ifname))
-			return device;
+	for (iter = priv->devices; iter; iter = iter->next) {
+		d = iter->data;
+
+		if (   nm_device_get_device_type (d) == device_type
+		    && nm_streq0 (nm_device_get_iface (d), ifname))
+			return d;
 	}
 
 	return NULL;
@@ -1666,9 +1580,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 	NMDeviceFactory *factory;
 	gs_free NMSettingsConnection **connections = NULL;
 	guint i;
+	GSList *iter;
 	gs_free char *iface = NULL;
 	NMDevice *device = NULL, *parent = NULL;
-	NMDevice *dev_candidate;
 	GError *error = NULL;
 	NMLogLevel log_level;
 
@@ -1684,15 +1598,17 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 	}
 
 	/* See if there's a device that is already compatible with this connection */
-	c_list_for_each_entry (dev_candidate, &priv->devices_lst_head, devices_lst) {
-		if (nm_device_check_connection_compatible (dev_candidate, connection)) {
-			if (nm_device_is_real (dev_candidate)) {
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *candidate = iter->data;
+
+		if (nm_device_check_connection_compatible (candidate, connection)) {
+			if (nm_device_is_real (candidate)) {
 				_LOG3D (LOGD_DEVICE, connection, "already created virtual interface name %s",
 				       iface);
 				return NULL;
 			}
 
-			device = dev_candidate;
+			device = candidate;
 			break;
 		}
 	}
@@ -1888,7 +1804,7 @@ connection_flags_changed (NMSettings *settings,
 	DeleteVolatileConnectionData *data;
 
 	if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection),
-	                   NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE))
+	                   NM_SETTINGS_CONNECTION_FLAGS_VOLATILE))
 		return;
 
 	if (active_connection_find_first (self, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)) {
@@ -1913,10 +1829,10 @@ system_unmanaged_devices_changed_cb (NMSettings *settings,
 {
 	NMManager *self = NM_MANAGER (user_data);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
+	const GSList *iter;
 
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst)
-		nm_device_set_unmanaged_by_user_settings (device);
+	for (iter = priv->devices; iter; iter = g_slist_next (iter))
+		nm_device_set_unmanaged_by_user_settings (NM_DEVICE (iter->data));
 }
 
 static void
@@ -1962,7 +1878,7 @@ manager_update_radio_enabled (NMManager *self,
                               gboolean enabled)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
+	GSList *iter;
 
 	/* Do nothing for radio types not yet implemented */
 	if (!rstate->prop)
@@ -1975,7 +1891,9 @@ manager_update_radio_enabled (NMManager *self,
 		return;
 
 	/* enable/disable wireless devices as required */
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+	for (iter = priv->devices; iter; iter = iter->next) {
+		NMDevice *device = NM_DEVICE (iter->data);
+
 		if (nm_device_get_rfkill_type (device) == rstate->rtype) {
 			_LOG2D (LOGD_RFKILL, device, "rfkill: setting radio %s", enabled ? "enabled" : "disabled");
 			nm_device_set_enabled (device, enabled);
@@ -2118,7 +2036,7 @@ device_auth_done_cb (NMAuthChain *chain,
 	          nm_auth_chain_get_data (chain, "user-data"));
 
 	g_clear_error (&error);
-	nm_auth_chain_destroy (chain);
+	nm_auth_chain_unref (chain);
 }
 
 static void
@@ -2134,6 +2052,7 @@ device_auth_request_cb (NMDevice *device,
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	GError *error = NULL;
 	NMAuthSubject *subject = NULL;
+	char *error_desc = NULL;
 	NMAuthChain *chain;
 
 	/* Validate the caller */
@@ -2146,13 +2065,15 @@ device_auth_request_cb (NMDevice *device,
 	}
 
 	/* Ensure the subject has permissions for this connection */
-	if (   connection
-	    && !nm_auth_is_subject_in_acl_set_error (connection,
-	                                             subject,
-	                                             NM_MANAGER_ERROR,
-	                                             NM_MANAGER_ERROR_PERMISSION_DENIED,
-	                                             &error))
+	if (connection && !nm_auth_is_subject_in_acl (connection,
+	                                              subject,
+	                                              &error_desc)) {
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             error_desc);
+		g_free (error_desc);
 		goto done;
+	}
 
 	/* Validate the request */
 	chain = nm_auth_chain_new_subject (subject, context, device_auth_done_cb, self);
@@ -2349,8 +2270,8 @@ get_existing_connection (NMManager *self,
 	}
 
 	nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added),
-	                                  NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED |
-	                                  NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE,
+	                                  NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED |
+	                                  NM_SETTINGS_CONNECTION_FLAGS_VOLATILE,
 	                                  TRUE);
 	NM_SET_OUT (out_generated, TRUE);
 	return added;
@@ -2414,20 +2335,15 @@ recheck_assume_connection (NMManager *self,
 		GError *error = NULL;
 
 		subject = nm_auth_subject_new_internal ();
-		active = _new_active_connection (self,
-		                                 FALSE,
-		                                 NM_CONNECTION (connection),
-		                                 NULL,
-		                                 NULL,
-		                                 device,
-		                                 subject,
+		active = _new_active_connection (self, NM_CONNECTION (connection), NULL, NULL,
+		                                 device, subject,
 		                                 generated ? NM_ACTIVATION_TYPE_EXTERNAL : NM_ACTIVATION_TYPE_ASSUME,
 		                                 NM_ACTIVATION_REASON_AUTOCONNECT,
 		                                 &error);
 
 		if (!active) {
 			_LOGW (LOGD_DEVICE, "assume: assumed connection %s failed to activate: %s",
-			       nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)),
+			       nm_connection_get_path (NM_CONNECTION (connection)),
 			       error->message);
 			g_error_free (error);
 
@@ -2478,17 +2394,18 @@ device_ip_iface_changed (NMDevice *device,
                          GParamSpec *pspec,
                          NMManager *self)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	const char *ip_iface = nm_device_get_ip_iface (device);
 	NMDeviceType device_type = nm_device_get_device_type (device);
-	NMDevice *candidate;
+	GSList *iter;
 
 	/* Remove NMDevice objects that are actually child devices of others,
 	 * when the other device finally knows its IP interface name.  For example,
 	 * remove the PPP interface that's a child of a WWAN device, since it's
 	 * not really a standalone NMDevice.
 	 */
-	c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) {
+	for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
+		NMDevice *candidate = NM_DEVICE (iter->data);
+
 		if (   candidate != device
 		    && g_strcmp0 (nm_device_get_iface (candidate), ip_iface) == 0
 		    && nm_device_get_device_type (candidate) == device_type
@@ -2510,56 +2427,35 @@ device_iface_changed (NMDevice *device,
 	retry_connections_for_parent_device (self, device);
 }
 
-static void
-_emit_device_added_removed (NMManager *self,
-                            NMDevice *device,
-                            gboolean is_added)
-{
-	nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self),
-	                            &interface_info_manager,
-	                            is_added
-	                              ? &signal_info_device_added
-	                              : &signal_info_device_removed,
-	                            "(o)",
-	                            nm_dbus_object_get_path (NM_DBUS_OBJECT (device)));
-	g_signal_emit (self,
-	               signals[is_added ? DEVICE_ADDED : DEVICE_REMOVED],
-	               0,
-	               device);
-	_notify (self, PROP_DEVICES);
-}
 
 static void
 device_realized (NMDevice *device,
                  GParamSpec *pspec,
                  NMManager *self)
 {
-	_emit_device_added_removed (self, device, nm_device_is_real (device));
+	gboolean real = nm_device_is_real (device);
+
+	/* Emit D-Bus signals */
+	g_signal_emit (self, signals[real ? DEVICE_ADDED : DEVICE_REMOVED], 0, device);
+	_notify (self, PROP_DEVICES);
 }
 
+#if WITH_CONCHECK
 static void
 device_connectivity_changed (NMDevice *device,
+                             GParamSpec *pspec,
                              NMManager *self)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMConnectivityState best_state = NM_CONNECTIVITY_UNKNOWN;
 	NMConnectivityState state;
-	NMDevice *dev;
+	const GSList *devices;
 
-	best_state = nm_device_get_connectivity_state (device);
-	if (best_state < NM_CONNECTIVITY_FULL) {
-		c_list_for_each_entry (dev, &priv->devices_lst_head, devices_lst) {
-			state = nm_device_get_connectivity_state (dev);
-			if (state <= best_state)
-				continue;
+	for (devices = priv->devices; devices; devices = devices->next) {
+		state = nm_device_get_connectivity_state (NM_DEVICE (devices->data));
+		if (state > best_state)
 			best_state = state;
-			if (best_state >= NM_CONNECTIVITY_FULL) {
-				/* it doesn't get better than this. */
-				break;
-			}
-		}
 	}
-	nm_assert (best_state <= NM_CONNECTIVITY_FULL);
 
 	if (best_state != priv->connectivity_state) {
 		priv->connectivity_state = best_state;
@@ -2572,6 +2468,7 @@ device_connectivity_changed (NMDevice *device,
 		nm_dispatcher_call_connectivity (priv->connectivity_state, NULL, NULL, NULL);
 	}
 }
+#endif
 
 static void
 _device_realize_finish (NMManager *self,
@@ -2617,7 +2514,6 @@ add_device (NMManager *self, NMDevice *device, GError **error)
 	GSList *iter, *remove = NULL;
 	int ifindex;
 	const char *dbus_path;
-	NMDevice *candidate;
 
 	/* No duplicates */
 	ifindex = nm_device_get_ifindex (device);
@@ -2634,20 +2530,18 @@ add_device (NMManager *self, NMDevice *device, GError **error)
 	 * FIXME: use parent/child device relationships instead of removing
 	 * the child NMDevice entirely
 	 */
-	c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) {
-		if (   nm_device_is_real (candidate)
-		    && (iface = nm_device_get_ip_iface (candidate))
-		    && nm_device_owns_iface (device, iface))
+	for (iter = priv->devices; iter; iter = iter->next) {
+		NMDevice *candidate = iter->data;
+
+		iface = nm_device_get_ip_iface (candidate);
+		if (nm_device_is_real (candidate) && nm_device_owns_iface (device, iface))
 			remove = g_slist_prepend (remove, candidate);
 	}
 	for (iter = remove; iter; iter = iter->next)
 		remove_device (self, NM_DEVICE (iter->data), FALSE, FALSE);
 	g_slist_free (remove);
 
-	g_object_ref (device);
-
-	nm_assert (c_list_is_empty (&device->devices_lst));
-	c_list_link_tail (&priv->devices_lst_head, &device->devices_lst);
+	priv->devices = g_slist_append (priv->devices, g_object_ref (device));
 
 	g_signal_connect (device, NM_DEVICE_STATE_CHANGED,
 	                  G_CALLBACK (manager_device_state_changed),
@@ -2681,9 +2575,11 @@ add_device (NMManager *self, NMDevice *device, GError **error)
 	                  G_CALLBACK (device_realized),
 	                  self);
 
-	g_signal_connect (device, NM_DEVICE_CONNECTIVITY_CHANGED,
+#if WITH_CONCHECK
+	g_signal_connect (device, "notify::" NM_DEVICE_CONNECTIVITY,
 	                  G_CALLBACK (device_connectivity_changed),
 	                  self);
+#endif
 
 	if (priv->startup) {
 		g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION,
@@ -2712,7 +2608,7 @@ add_device (NMManager *self, NMDevice *device, GError **error)
 	                               NM_UNMANAGED_SLEEPING,
 	                               manager_sleeping (self));
 
-	dbus_path = nm_dbus_object_export (NM_DBUS_OBJECT (device));
+	dbus_path = nm_exported_object_export (NM_EXPORTED_OBJECT (device));
 	_LOG2I (LOGD_DEVICE, device, "new %s device (%s)", type_desc, dbus_path);
 
 	nm_settings_device_added (priv->settings, device);
@@ -2759,11 +2655,12 @@ factory_component_added_cb (NMDeviceFactory *factory,
                             gpointer user_data)
 {
 	NMManager *self = user_data;
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
+	GSList *iter;
 
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
-		if (nm_device_notify_component_added (device, component))
+	g_return_val_if_fail (self, FALSE);
+
+	for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
+		if (nm_device_notify_component_added ((NMDevice *) iter->data, component))
 			return TRUE;
 	}
 	return FALSE;
@@ -2793,10 +2690,9 @@ platform_link_added (NMManager *self,
                      gboolean guess_assume,
                      const NMConfigDeviceStateData *dev_state)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMDeviceFactory *factory;
 	NMDevice *device = NULL;
-	NMDevice *candidate;
+	GSList *iter;
 
 	g_return_if_fail (ifindex > 0);
 
@@ -2804,7 +2700,8 @@ platform_link_added (NMManager *self,
 		return;
 
 	/* Let unrealized devices try to realize themselves with the link */
-	c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) {
+	for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
+		NMDevice *candidate = iter->data;
 		gboolean compatible = TRUE;
 		gs_free_error GError *error = NULL;
 
@@ -3031,12 +2928,12 @@ rfkill_manager_rfkill_changed_cb (NMRfkillManager *rfkill_mgr,
 	nm_manager_rfkill_update (NM_MANAGER (user_data), rtype);
 }
 
-const CList *
+const GSList *
 nm_manager_get_devices (NMManager *manager)
 {
 	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
 
-	return &NM_MANAGER_GET_PRIVATE (manager)->devices_lst_head;
+	return NM_MANAGER_GET_PRIVATE (manager)->devices;
 }
 
 static NMDevice *
@@ -3045,10 +2942,9 @@ nm_manager_get_best_device_for_connection (NMManager *self,
                                            gboolean for_user_request,
                                            GHashTable *unavailable_devices)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	const GSList *devices, *iter;
 	NMActiveConnection *ac;
 	NMDevice *act_device;
-	NMDevice *device;
 	NMDeviceCheckConAvailableFlags flags;
 
 	ac = active_connection_find_first_by_connection (self, connection);
@@ -3061,7 +2957,9 @@ nm_manager_get_best_device_for_connection (NMManager *self,
 	flags = for_user_request ? NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST : NM_DEVICE_CHECK_CON_AVAILABLE_NONE;
 
 	/* Pick the first device that's compatible with the connection. */
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+	devices = nm_manager_get_devices (self);
+	for (iter = devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *device = NM_DEVICE (iter->data);
 
 		if (unavailable_devices && g_hash_table_contains (unavailable_devices, device))
 			continue;
@@ -3074,100 +2972,67 @@ nm_manager_get_best_device_for_connection (NMManager *self,
 	return NULL;
 }
 
-static const char **
-_get_devices_paths (NMManager *self,
-                    gboolean all_devices)
+static void
+_get_devices (NMManager *self,
+              GDBusMethodInvocation *context,
+              gboolean all_devices)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	const char **paths = NULL;
+	gs_free const char **paths = NULL;
 	guint i;
-	NMDevice *device;
+	GSList *iter;
 
-	paths = g_new (const char *, c_list_length (&priv->devices_lst_head) + 1);
+	paths = g_new (const char *, g_slist_length (priv->devices) + 1);
 
-	i = 0;
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+	for (i = 0, iter = priv->devices; iter; iter = iter->next) {
 		const char *path;
 
-		path = nm_dbus_object_get_path (NM_DBUS_OBJECT (device));
-		if (!path)
-			continue;
-
-		if (   !all_devices
-		    && !nm_device_is_real (device))
-			continue;
-
-		paths[i++] = path;
+		path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data));
+		if (   path
+		    && (all_devices || nm_device_is_real (iter->data)))
+			paths[i++] = path;
 	}
 	paths[i++] = NULL;
 
-	return paths;
+	g_dbus_method_invocation_return_value (context,
+	                                       g_variant_new ("(^ao)", (char **) paths));
 }
 
 static void
-impl_manager_get_devices (NMDBusObject *obj,
-                          const NMDBusInterfaceInfoExtended *interface_info,
-                          const NMDBusMethodInfoExtended *method_info,
-                          GDBusConnection *connection,
-                          const char *sender,
-                          GDBusMethodInvocation *invocation,
-                          GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
-	gs_free const char **paths = NULL;
-
-	paths = _get_devices_paths (self, FALSE);
-	g_dbus_method_invocation_return_value (invocation,
-	                                       g_variant_new ("(^ao)", (char **) paths));
+impl_manager_get_devices (NMManager *self,
+                          GDBusMethodInvocation *context)
+{
+	_get_devices (self, context, FALSE);
 }
 
 static void
-impl_manager_get_all_devices (NMDBusObject *obj,
-                              const NMDBusInterfaceInfoExtended *interface_info,
-                              const NMDBusMethodInfoExtended *method_info,
-                              GDBusConnection *connection,
-                              const char *sender,
-                              GDBusMethodInvocation *invocation,
-                              GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
-	gs_free const char **paths = NULL;
-
-	paths = _get_devices_paths (self, TRUE);
-	g_dbus_method_invocation_return_value (invocation,
-	                                       g_variant_new ("(^ao)", (char **) paths));
+impl_manager_get_all_devices (NMManager *self,
+                              GDBusMethodInvocation *context)
+{
+	_get_devices (self, context, TRUE);
 }
 
 static void
-impl_manager_get_device_by_ip_iface (NMDBusObject *obj,
-                                     const NMDBusInterfaceInfoExtended *interface_info,
-                                     const NMDBusMethodInfoExtended *method_info,
-                                     GDBusConnection *connection,
-                                     const char *sender,
-                                     GDBusMethodInvocation *invocation,
-                                     GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
+impl_manager_get_device_by_ip_iface (NMManager *self,
+                                     GDBusMethodInvocation *context,
+                                     const char *iface)
+{
 	NMDevice *device;
 	const char *path = NULL;
-	const char *iface;
-
-	g_variant_get (parameters, "(&s)", &iface);
 
 	device = find_device_by_ip_iface (self, iface);
 	if (device)
-		path = nm_dbus_object_get_path (NM_DBUS_OBJECT (device));
+		path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (device));
 
-	if (!path) {
-		g_dbus_method_invocation_return_error (invocation,
+	if (path == NULL) {
+		g_dbus_method_invocation_return_error (context,
 		                                       NM_MANAGER_ERROR,
 		                                       NM_MANAGER_ERROR_UNKNOWN_DEVICE,
 		                                       "No device found for the requested iface.");
-		return;
+	} else {
+		g_dbus_method_invocation_return_value (context,
+		                                       g_variant_new ("(o)", path));
 	}
-
-	g_dbus_method_invocation_return_value (invocation,
-	                                       g_variant_new ("(o)", path));
 }
 
 static gboolean
@@ -3240,6 +3105,7 @@ find_master (NMManager *self,
 	const char *master;
 	NMDevice *master_device = NULL;
 	NMSettingsConnection *master_connection = NULL;
+	GSList *iter;
 
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
@@ -3268,10 +3134,10 @@ find_master (NMManager *self,
 		/* Try master as a connection UUID */
 		master_connection = nm_settings_get_connection_by_uuid (priv->settings, master);
 		if (master_connection) {
-			NMDevice *candidate;
-
 			/* Check if the master connection is activated on some device already */
-			c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) {
+			for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+				NMDevice *candidate = NM_DEVICE (iter->data);
+
 				if (candidate == device)
 					continue;
 
@@ -3343,6 +3209,7 @@ ensure_master_active_connection (NMManager *self,
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMActiveConnection *master_ac = NULL;
 	NMDeviceState master_state;
+	GSList *iter;
 
 	g_assert (connection);
 	g_assert (master_connection || master_device);
@@ -3419,10 +3286,12 @@ ensure_master_active_connection (NMManager *self,
 		             NM_MANAGER_ERROR_DEPENDENCY_FAILED,
 		             "Device unmanaged or not available for activation");
 	} else if (master_connection) {
-		NMDevice *candidate;
+		gboolean found_device = FALSE;
 
 		/* Find a compatible device and activate it using this connection */
-		c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) {
+		for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+			NMDevice *candidate = NM_DEVICE (iter->data);
+
 			if (candidate == device) {
 				/* A device obviously can't be its own master */
 				continue;
@@ -3431,6 +3300,7 @@ ensure_master_active_connection (NMManager *self,
 			if (!nm_device_check_connection_available (candidate, NM_CONNECTION (master_connection), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL))
 				continue;
 
+			found_device = TRUE;
 			if (!nm_device_is_software (candidate)) {
 				master_state = nm_device_get_state (candidate);
 				if (nm_device_is_real (candidate) && master_state != NM_DEVICE_STATE_DISCONNECTED)
@@ -3496,7 +3366,7 @@ find_slaves (NMManager *manager,
 	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 	g_return_val_if_fail (s_con, NULL);
 
-	devices = g_hash_table_new (nm_direct_hash, NULL);
+	devices = g_hash_table_new (g_direct_hash, g_direct_equal);
 
 	/* Search through all connections, not only inactive ones, because
 	 * even if a slave was already active, it might be deactivated during
@@ -3682,11 +3552,11 @@ _internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **er
 {
 	nm_assert (NM_IS_VPN_CONNECTION (active));
 
-	nm_dbus_object_export (NM_DBUS_OBJECT (active));
+	nm_exported_object_export (NM_EXPORTED_OBJECT (active));
 	if (!nm_vpn_manager_activate_connection (NM_MANAGER_GET_PRIVATE (self)->vpn_manager,
 	                                         NM_VPN_CONNECTION (active),
 	                                         error)) {
-		nm_dbus_object_unexport (NM_DBUS_OBJECT (active));
+		nm_exported_object_unexport (NM_EXPORTED_OBJECT (active));
 		return FALSE;
 	}
 
@@ -3781,6 +3651,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 	NMConnection *existing_connection = NULL;
 	NMActiveConnection *master_ac = NULL;
 	NMAuthSubject *subject;
+	char *error_desc = NULL;
 
 	g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE);
@@ -3788,14 +3659,14 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 
 	g_assert (NM_IS_VPN_CONNECTION (active) == FALSE);
 
-	device = nm_active_connection_get_device (active);
-	g_return_val_if_fail (device != NULL, FALSE);
-
 	connection = nm_active_connection_get_settings_connection (active);
-	nm_assert (connection);
+	g_assert (connection);
 
 	applied = nm_active_connection_get_applied_connection (active);
 
+	device = nm_active_connection_get_device (active);
+	g_return_val_if_fail (device != NULL, FALSE);
+
 	/* If the device is active and its connection is not visible to the
 	 * user that's requesting this new activation, fail, since other users
 	 * should not be allowed to implicitly deactivate private connections
@@ -3803,13 +3674,16 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 	 */
 	existing_connection = nm_device_get_applied_connection (device);
 	subject = nm_active_connection_get_subject (active);
-	if (   existing_connection
-	    && !nm_auth_is_subject_in_acl_set_error (existing_connection,
-	                                             subject,
-	                                             NM_MANAGER_ERROR,
-	                                             NM_MANAGER_ERROR_PERMISSION_DENIED,
-	                                             error)) {
-		g_prefix_error (error, "Private connection already active on the device: ");
+	if (existing_connection &&
+	    !nm_auth_is_subject_in_acl (existing_connection,
+	                                subject,
+	                                &error_desc)) {
+		g_set_error (error,
+		             NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		             "Private connection already active on the device: %s",
+		             error_desc);
+		g_free (error_desc);
 		return FALSE;
 	}
 
@@ -3821,9 +3695,6 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 		return FALSE;
 	}
 
-	if (nm_active_connection_get_activation_type (active) == NM_ACTIVATION_TYPE_MANAGED)
-		nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_MANAGED);
-
 	/* Create any backing resources the device needs */
 	if (!nm_device_is_real (device)) {
 		NMDevice *parent;
@@ -3932,7 +3803,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 		_LOGD (LOGD_CORE, "Activation of '%s' depends on active connection %p %s",
 		       nm_settings_connection_get_id (connection),
 		       master_ac,
-		       nm_dbus_object_get_path (NM_DBUS_OBJECT  (master_ac)) ?: "");
+		       nm_exported_object_get_path (NM_EXPORTED_OBJECT  (master_ac)) ?: "");
 	}
 
 	/* Check slaves for master connection and possibly activate them */
@@ -4004,8 +3875,52 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError
 }
 
 static NMActiveConnection *
+_new_vpn_active_connection (NMManager *self,
+                            NMSettingsConnection *settings_connection,
+                            const char *specific_object,
+                            NMAuthSubject *subject,
+                            NMActivationReason activation_reason,
+                            GError **error)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMActiveConnection *parent = NULL;
+	NMDevice *device = NULL;
+
+	g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
+
+	if (specific_object) {
+		/* Find the specific connection the client requested we use */
+		parent = active_connection_get_by_path (self, specific_object);
+		if (!parent) {
+			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
+			                     "Base connection for VPN connection not active.");
+			return NULL;
+		}
+	} else
+		parent = priv->primary_connection;
+
+	if (!parent) {
+		g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+		                     "Could not find source connection.");
+		return NULL;
+	}
+
+	device = nm_active_connection_get_device (parent);
+	if (!device) {
+		g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+		                     "Source connection had no active device.");
+		return NULL;
+	}
+
+	return (NMActiveConnection *) nm_vpn_connection_new (settings_connection,
+	                                                     device,
+	                                                     nm_exported_object_get_path (NM_EXPORTED_OBJECT (parent)),
+	                                                     activation_reason,
+	                                                     subject);
+}
+
+static NMActiveConnection *
 _new_active_connection (NMManager *self,
-                        gboolean is_vpn,
                         NMConnection *connection,
                         NMConnection *applied,
                         const char *specific_object,
@@ -4015,78 +3930,45 @@ _new_active_connection (NMManager *self,
                         NMActivationReason activation_reason,
                         GError **error)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMSettingsConnection *settings_connection = NULL;
-	NMDevice *parent_device;
+	NMActiveConnection *existing_ac;
+	gboolean is_vpn;
 
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
 	g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
 
-	nm_assert (is_vpn == _connection_is_vpn (connection));
-	nm_assert (is_vpn || NM_IS_DEVICE (device));
-	nm_assert (!nm_streq0 (specific_object, "/"));
+	/* Can't create new AC for already-active connection */
+	existing_ac = active_connection_find_first_by_connection (self, connection);
+	if (NM_IS_VPN_CONNECTION (existing_ac)) {
+		g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE,
+		             "Connection '%s' is already active",
+		             nm_connection_get_id (connection));
+		return NULL;
+	}
+
+	/* Normalize the specific object */
+	if (specific_object && g_strcmp0 (specific_object, "/") == 0)
+		specific_object = NULL;
+
+	is_vpn = nm_connection_is_type (NM_CONNECTION (connection), NM_SETTING_VPN_SETTING_NAME);
 
 	if (NM_IS_SETTINGS_CONNECTION (connection))
 		settings_connection = (NMSettingsConnection *) connection;
 
 	if (is_vpn) {
-		NMActiveConnection *parent;
-
-		/* FIXME: for VPN connections, we don't allow re-activating an
-		 * already active connection. It's a bug, and should be fixed together
-		 * when reworking VPN handling. */
-		if (active_connection_find_first_by_connection (self, connection)) {
-			g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE,
-			             "Connection '%s' is already active",
-			             nm_connection_get_id (connection));
-			return NULL;
-		}
-
-		/* FIXME: apparently, activation here only works if @connection is
-		 * a settings-connection. Which is not the case during AddAndActivatate.
-		 * Probably, AddAndActivate is broken for VPN. */
 		if (activation_type != NM_ACTIVATION_TYPE_MANAGED)
 			g_return_val_if_reached (NULL);
-
-		g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
-
-		if (specific_object) {
-			/* Find the specific connection the client requested we use */
-			parent = active_connection_get_by_path (self, specific_object);
-			if (!parent) {
-				g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
-				                     "Base connection for VPN connection not active.");
-				return NULL;
-			}
-		} else
-			parent = priv->primary_connection;
-
-		if (!parent) {
-			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
-			                     "Could not find source connection.");
-			return NULL;
-		}
-
-		parent_device = nm_active_connection_get_device (parent);
-		if (!parent_device) {
-			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-			                     "Source connection had no active device");
-			return NULL;
-		}
-
-		if (device && device != parent_device) {
-			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-			                     "The device doesn't match the active connection.");
-			return NULL;
-		}
-
-		return (NMActiveConnection *) nm_vpn_connection_new (settings_connection,
-		                                                     parent_device,
-		                                                     nm_dbus_object_get_path (NM_DBUS_OBJECT (parent)),
-		                                                     activation_reason,
-		                                                     subject);
+		return _new_vpn_active_connection (self,
+		                                   settings_connection,
+		                                   specific_object,
+		                                   subject,
+		                                   activation_reason,
+		                                   error);
 	}
 
+	if (device && (activation_type == NM_ACTIVATION_TYPE_MANAGED))
+		nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_MANAGED);
+
 	return (NMActiveConnection *) nm_act_request_new (settings_connection,
 	                                                  applied,
 	                                                  specific_object,
@@ -4111,16 +3993,14 @@ _internal_activation_auth_done (NMActiveConnection *active,
 
 	priv->authorizing_connections = g_slist_remove (priv->authorizing_connections, active);
 
-	if (!success)
-		goto fail;
-
 	/* Don't continue with an internal activation if an equivalent active
 	 * connection already exists. Note that slave autoconnections always force a
 	 * reconnection.  We also check this earlier, but there we may fail to
 	 * detect a duplicate if the existing active connection is undergoing
 	 * authorization in impl_manager_activate_connection().
 	 */
-	if (   nm_auth_subject_is_internal (nm_active_connection_get_subject (active))
+	if (   success
+	    && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))
 	    && nm_active_connection_get_activation_reason (active) != NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES) {
 		c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
 			if (   nm_active_connection_get_device (ac) == nm_active_connection_get_device (active)
@@ -4133,15 +4013,17 @@ _internal_activation_auth_done (NMActiveConnection *active,
 				             NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE,
 				             "Connection '%s' is already active",
 				             nm_active_connection_get_settings_connection_id (active));
-				goto fail;
+				success = FALSE;
+				break;
 			}
 		}
 	}
 
-	if (_internal_activate_generic (self, active, &error))
-		return;
+	if (success) {
+		if (_internal_activate_generic (self, active, &error))
+			return;
+	}
 
-fail:
 	nm_assert (error_desc || error);
 	nm_active_connection_set_state_fail (active,
 	                                     NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN,
@@ -4182,24 +4064,27 @@ nm_manager_activate_connection (NMManager *self,
                                 NMActivationReason activation_reason,
                                 GError **error)
 {
-	NMManagerPrivate *priv;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMActiveConnection *active;
+	char *error_desc = NULL;
 	GSList *iter;
 
-	g_return_val_if_fail (NM_IS_MANAGER (self), NULL);
-	g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), NULL);
-	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
-	g_return_val_if_fail (!error || !*error, NULL);
-	nm_assert (!nm_streq0 (specific_object, "/"));
-
-	priv = NM_MANAGER_GET_PRIVATE (self);
+	g_return_val_if_fail (self != 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);
 
-	if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection),
-	                                          subject,
-	                                          NM_MANAGER_ERROR,
-	                                          NM_MANAGER_ERROR_PERMISSION_DENIED,
-	                                          error))
+	/* Ensure the subject has permissions for this connection */
+	if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection),
+	                                subject,
+	                                &error_desc)) {
+		g_set_error_literal (error,
+		                     NM_MANAGER_ERROR,
+		                     NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                     error_desc);
+		g_free (error_desc);
 		return NULL;
+	}
 
 	/* Look for a active connection that's equivalent and is already pending authorization
 	 * and eventual activation. This is used to de-duplicate concurrent activations which would
@@ -4210,7 +4095,7 @@ nm_manager_activate_connection (NMManager *self,
 		active = iter->data;
 
 		if (   connection == nm_active_connection_get_settings_connection (active)
-		    && nm_streq0 (nm_active_connection_get_specific_object (active), specific_object)
+		    && g_strcmp0 (nm_active_connection_get_specific_object (active), specific_object) == 0
 		    && nm_active_connection_get_device (active) == device
 		    && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))
 		    && nm_auth_subject_is_internal (subject)
@@ -4219,7 +4104,6 @@ nm_manager_activate_connection (NMManager *self,
 	}
 
 	active = _new_active_connection (self,
-	                                 _connection_is_vpn (NM_CONNECTION (connection)),
 	                                 NM_CONNECTION (connection),
 	                                 applied,
 	                                 specific_object,
@@ -4228,11 +4112,10 @@ nm_manager_activate_connection (NMManager *self,
 	                                 activation_type,
 	                                 activation_reason,
 	                                 error);
-	if (!active)
-		return NULL;
-
-	priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active);
-	nm_active_connection_authorize (active, NULL, _internal_activation_auth_done, self, NULL);
+	if (active) {
+		priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active);
+		nm_active_connection_authorize (active, NULL, _internal_activation_auth_done, self, NULL);
+	}
 	return active;
 }
 
@@ -4241,12 +4124,9 @@ nm_manager_activate_connection (NMManager *self,
  * @self: the #NMManager
  * @context: the D-Bus context of the requestor
  * @connection: the partial or complete #NMConnection to be activated
- * @device_path: the object path of the device to be activated, or NULL
+ * @device_path: the object path of the device to be activated, or "/"
  * @out_device: on successful reutrn, the #NMDevice to be activated with @connection
- *   The caller may pass in a device which shortcuts the lookup by path.
- *   In this case, the passed in device must have the matching @device_path
- *   already.
- * @out_is_vpn: on successful return, %TRUE if @connection is a VPN connection
+ * @out_vpn: on successful return, %TRUE if @connection is a VPN connection
  * @error: location to store an error on failure
  *
  * Performs basic validation on an activation request, including ensuring that
@@ -4262,16 +4142,17 @@ validate_activation_request (NMManager *self,
                              NMConnection *connection,
                              const char *device_path,
                              NMDevice **out_device,
-                             gboolean *out_is_vpn,
+                             gboolean *out_vpn,
                              GError **error)
 {
 	NMDevice *device = NULL;
-	gboolean is_vpn = FALSE;
-	gs_unref_object NMAuthSubject *subject = NULL;
+	gboolean vpn = FALSE;
+	NMAuthSubject *subject = NULL;
+	char *error_desc = NULL;
 
-	nm_assert (NM_IS_CONNECTION (connection));
-	nm_assert (out_device);
-	nm_assert (out_is_vpn);
+	g_assert (connection);
+	g_assert (out_device);
+	g_assert (out_vpn);
 
 	/* Validate the caller */
 	subject = nm_auth_subject_new_unix_process_from_context (context);
@@ -4283,80 +4164,76 @@ validate_activation_request (NMManager *self,
 		return NULL;
 	}
 
-	if (!nm_auth_is_subject_in_acl_set_error (connection,
-	                                          subject,
-	                                          NM_MANAGER_ERROR,
-	                                          NM_MANAGER_ERROR_PERMISSION_DENIED,
-	                                          error))
-		return NULL;
+	/* Ensure the subject has permissions for this connection */
+	if (!nm_auth_is_subject_in_acl (connection,
+	                                subject,
+	                                &error_desc)) {
+		g_set_error_literal (error,
+		                     NM_MANAGER_ERROR,
+		                     NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                     error_desc);
+		g_free (error_desc);
+		goto error;
+	}
+
+	/* Check whether it's a VPN or not */
+	if (   nm_connection_get_setting_vpn (connection)
+	    || nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME))
+		vpn = TRUE;
 
-	is_vpn = _connection_is_vpn (connection);
+	/* Normalize device path */
+	if (device_path && g_strcmp0 (device_path, "/") == 0)
+		device_path = NULL;
 
-	if (*out_device) {
-		device = *out_device;
-		nm_assert (NM_IS_DEVICE (device));
-		nm_assert (device_path);
-		nm_assert (nm_streq0 (device_path, nm_dbus_object_get_path (NM_DBUS_OBJECT (device))));
-		nm_assert (device == nm_manager_get_device_by_path (self, device_path));
-	} else if (device_path) {
+	/* And validate it */
+	if (device_path) {
 		device = nm_manager_get_device_by_path (self, device_path);
 		if (!device) {
 			g_set_error_literal (error,
 			                     NM_MANAGER_ERROR,
 			                     NM_MANAGER_ERROR_UNKNOWN_DEVICE,
 			                     "Device not found");
-			return NULL;
+			goto error;
 		}
-	} else if (!is_vpn) {
+	} else
 		device = nm_manager_get_best_device_for_connection (self, connection, TRUE, NULL);
-		if (!device) {
-			gs_free char *iface = NULL;
-
-			/* VPN and software-device connections don't need a device yet,
-			 * but non-virtual connections do ... */
-			if (!nm_connection_is_virtual (connection)) {
-				g_set_error_literal (error,
-				                     NM_MANAGER_ERROR,
-				                     NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-				                     "No suitable device found for this connection.");
-				return NULL;
-			}
 
-			/* Look for an existing device with the connection's interface name */
-			iface = nm_manager_get_connection_iface (self, connection, NULL, error);
-			if (!iface)
-				return NULL;
+	if (!device && !vpn) {
+		gs_free char *iface = NULL;
 
-			device = find_device_by_iface (self, iface, connection, NULL);
-			if (!device) {
-				g_set_error_literal (error,
-				                     NM_MANAGER_ERROR,
-				                     NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-				                     "Failed to find a compatible device for this connection");
-				return NULL;
-			}
+		/* VPN and software-device connections don't need a device yet,
+		 * but non-virtual connections do ... */
+		if (!nm_connection_is_virtual (connection)) {
+			g_set_error_literal (error,
+			                     NM_MANAGER_ERROR,
+			                     NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+			                     "No suitable device found for this connection.");
+			goto error;
 		}
+
+		/* Look for an existing device with the connection's interface name */
+		iface = nm_manager_get_connection_iface (self, connection, NULL, error);
+		if (!iface)
+			goto error;
+
+		device = find_device_by_iface (self, iface, connection, NULL);
 	}
 
-	if (is_vpn && device) {
-		/* VPN's are treated specially. Maybe the should accept a device as well,
-		 * however, later on during activation, we don't handle the device.
-		 *
-		 * Maybe we should, and maybe it makes sense to specify a device
-		 * when activating a VPN. But for now, just error out.  */
+	if ((!vpn || device_path) && !device) {
 		g_set_error_literal (error,
 		                     NM_MANAGER_ERROR,
 		                     NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-		                     "Cannot specify device when activating VPN");
-		return NULL;
+		                     "Failed to find a compatible device for this connection");
+		goto error;
 	}
 
-	nm_assert (   ( is_vpn && !device)
-	           || (!is_vpn && NM_IS_DEVICE (device)));
-
 	*out_device = device;
-	*out_is_vpn = is_vpn;
-	return g_steal_pointer (&subject);
+	*out_vpn = vpn;
+	return subject;
+
+error:
+	g_object_unref (subject);
+	return NULL;
 }
 
 /*****************************************************************************/
@@ -4378,27 +4255,24 @@ _activation_auth_done (NMActiveConnection *active,
 	subject = nm_active_connection_get_subject (active);
 	connection = nm_active_connection_get_settings_connection (active);
 
-	if (!success) {
+	if (success) {
+		if (_internal_activate_generic (self, active, &error)) {
+			nm_settings_connection_autoconnect_blocked_reason_set (connection,
+			                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST,
+			                                                       FALSE);
+			g_dbus_method_invocation_return_value (context,
+			                                       g_variant_new ("(o)",
+			                                       nm_exported_object_get_path (NM_EXPORTED_OBJECT (active))));
+			nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, TRUE, NULL,
+			                            subject, NULL);
+			return;
+		}
+	} else {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
 		                             error_desc);
-		goto fail;
 	}
 
-	if (!_internal_activate_generic (self, active, &error))
-		goto fail;
-
-	nm_settings_connection_autoconnect_blocked_reason_set (connection,
-	                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST,
-	                                                       FALSE);
-	g_dbus_method_invocation_return_value (context,
-	                                       g_variant_new ("(o)",
-	                                       nm_dbus_object_get_path (NM_DBUS_OBJECT (active))));
-	nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, TRUE, NULL,
-	                            subject, NULL);
-	return;
-
-fail:
 	nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE, NULL,
 	                            subject, error->message);
 	nm_active_connection_set_state_fail (active,
@@ -4409,15 +4283,12 @@ fail:
 }
 
 static void
-impl_manager_activate_connection (NMDBusObject *obj,
-                                  const NMDBusInterfaceInfoExtended *interface_info,
-                                  const NMDBusMethodInfoExtended *method_info,
-                                  GDBusConnection *dbus_connection,
-                                  const char *sender,
-                                  GDBusMethodInvocation *invocation,
-                                  GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
+impl_manager_activate_connection (NMManager *self,
+                                  GDBusMethodInvocation *context,
+                                  const char *connection_path,
+                                  const char *device_path,
+                                  const char *specific_object_path)
+{
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	gs_unref_object NMActiveConnection *active = NULL;
 	gs_unref_object NMAuthSubject *subject = NULL;
@@ -4425,15 +4296,14 @@ impl_manager_activate_connection (NMDBusObject *obj,
 	NMDevice *device = NULL;
 	gboolean is_vpn = FALSE;
 	GError *error = NULL;
-	const char *connection_path;
-	const char *device_path;
-	const char *specific_object_path;
 
-	g_variant_get (parameters, "(&o&o&o)", &connection_path, &device_path, &specific_object_path);
-
-	connection_path = nm_utils_dbus_normalize_object_path (connection_path);
-	specific_object_path = nm_utils_dbus_normalize_object_path (specific_object_path);
-	device_path = nm_utils_dbus_normalize_object_path (device_path);
+	/* Normalize object paths */
+	if (g_strcmp0 (connection_path, "/") == 0)
+		connection_path = NULL;
+	if (g_strcmp0 (specific_object_path, "/") == 0)
+		specific_object_path = NULL;
+	if (g_strcmp0 (device_path, "/") == 0)
+		device_path = NULL;
 
 	/* If the connection path is given and valid, that connection is activated.
 	 * Otherwise the "best" connection for the device is chosen and activated,
@@ -4468,7 +4338,7 @@ impl_manager_activate_connection (NMDBusObject *obj,
 	}
 
 	subject = validate_activation_request (self,
-	                                       invocation,
+	                                       context,
 	                                       NM_CONNECTION (connection),
 	                                       device_path,
 	                                       &device,
@@ -4478,7 +4348,6 @@ impl_manager_activate_connection (NMDBusObject *obj,
 		goto error;
 
 	active = _new_active_connection (self,
-	                                 is_vpn,
 	                                 NM_CONNECTION (connection),
 	                                 NULL,
 	                                 specific_object_path,
@@ -4497,7 +4366,7 @@ impl_manager_activate_connection (NMDBusObject *obj,
 	                                NULL,
 	                                _activation_auth_done,
 	                                self,
-	                                invocation);
+	                                context);
 	return;
 
 error:
@@ -4505,7 +4374,7 @@ error:
 		nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE, NULL,
 		                            subject, error->message);
 	}
-	g_dbus_method_invocation_take_error (invocation, error);
+	g_dbus_method_invocation_take_error (context, error);
 }
 
 /*****************************************************************************/
@@ -4526,7 +4395,7 @@ activation_add_done (NMSettings *settings,
 	AddAndActivateInfo *info = user_data;
 	NMManager *self;
 	gs_unref_object NMActiveConnection *active = NULL;
-	gs_free_error GError *local = NULL;
+	GError *local = NULL;
 
 	self = info->manager;
 	active = info->active;
@@ -4545,8 +4414,8 @@ activation_add_done (NMSettings *settings,
 			g_dbus_method_invocation_return_value (
 			    context,
 			    g_variant_new ("(oo)",
-			                   nm_dbus_object_get_path (NM_DBUS_OBJECT (new_connection)),
-			                   nm_dbus_object_get_path (NM_DBUS_OBJECT (active))));
+			                   nm_connection_get_path (NM_CONNECTION (new_connection)),
+			                   nm_exported_object_get_path (NM_EXPORTED_OBJECT (active))));
 			nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE,
 			                            nm_active_connection_get_settings_connection (active),
 			                            TRUE,
@@ -4559,7 +4428,6 @@ activation_add_done (NMSettings *settings,
 	}
 
 	nm_assert (error);
-
 	nm_active_connection_set_state_fail (active,
 	                                     NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN,
 	                                     error->message);
@@ -4572,6 +4440,7 @@ activation_add_done (NMSettings *settings,
 	                            NULL,
 	                            nm_active_connection_get_subject (active),
 	                            error->message);
+	g_clear_error (&local);
 }
 
 static void
@@ -4586,12 +4455,27 @@ _add_and_activate_auth_done (NMActiveConnection *active,
 	GDBusMethodInvocation *context = user_data2;
 	AddAndActivateInfo *info;
 	GError *error = NULL;
-	gs_unref_object NMConnection *connection = NULL;
 
-	connection = g_object_steal_qdata (G_OBJECT (active),
-	                                   active_connection_add_and_activate_quark ());
+	if (success) {
+		NMConnection *connection;
+
+		connection = g_object_steal_qdata (G_OBJECT (active),
+		                                   active_connection_add_and_activate_quark ());
+
+		info = g_slice_new (AddAndActivateInfo);
+		info->manager = self;
+		info->active = g_object_ref (active);
 
-	if (!success) {
+		/* Basic sender auth checks performed; try to add the connection */
+		nm_settings_add_connection_dbus (priv->settings,
+		                                 connection,
+		                                 FALSE,
+		                                 context,
+		                                 activation_add_done,
+		                                 info);
+		g_object_unref (connection);
+	} else {
+		g_assert (error_desc);
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
 		                             error_desc);
@@ -4602,50 +4486,32 @@ _add_and_activate_auth_done (NMActiveConnection *active,
 		                            nm_active_connection_get_subject (active),
 		                            error->message);
 		g_dbus_method_invocation_take_error (context, error);
-		g_object_unref (active);
-		return;
 	}
 
-	info = g_slice_new (AddAndActivateInfo);
-	info->manager = self;
-
-	/* we pass on the reference to @active. */
-	info->active = active;
-
-	/* Basic sender auth checks performed; try to add the connection */
-	nm_settings_add_connection_dbus (priv->settings,
-	                                 connection,
-	                                 FALSE,
-	                                 context,
-	                                 activation_add_done,
-	                                 info);
+	g_object_unref (active);
 }
 
 static void
-impl_manager_add_and_activate_connection (NMDBusObject *obj,
-                                          const NMDBusInterfaceInfoExtended *interface_info,
-                                          const NMDBusMethodInfoExtended *method_info,
-                                          GDBusConnection *dbus_connection,
-                                          const char *sender,
-                                          GDBusMethodInvocation *invocation,
-                                          GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
+impl_manager_add_and_activate_connection (NMManager *self,
+                                          GDBusMethodInvocation *context,
+                                          GVariant *settings,
+                                          const char *device_path,
+                                          const char *specific_object_path)
+{
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	gs_unref_object NMConnection *connection = NULL;
+	NMConnection *connection = NULL;
+	GSList *all_connections = NULL;
 	NMActiveConnection *active = NULL;
-	gs_unref_object NMAuthSubject *subject = NULL;
+	NMAuthSubject *subject = NULL;
 	GError *error = NULL;
 	NMDevice *device = NULL;
-	gboolean is_vpn = FALSE;
-	gs_unref_variant GVariant *settings = NULL;
-	const char *device_path;
-	const char *specific_object_path;
+	gboolean vpn = FALSE;
 
-	g_variant_get (parameters, "(@a{sa{sv}}&o&o)", &settings, &device_path, &specific_object_path);
-
-	specific_object_path = nm_utils_dbus_normalize_object_path (specific_object_path);
-	device_path = nm_utils_dbus_normalize_object_path (device_path);
+	/* Normalize object paths */
+	if (g_strcmp0 (specific_object_path, "/") == 0)
+		specific_object_path = NULL;
+	if (g_strcmp0 (device_path, "/") == 0)
+		device_path = NULL;
 
 	/* Try to create a new connection with the given settings.
 	 * We allow empty settings for AddAndActivateConnection(). In that case,
@@ -4659,16 +4525,29 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
 		_nm_connection_replace_settings (connection, settings, NM_SETTING_PARSE_FLAGS_STRICT, NULL);
 
 	subject = validate_activation_request (self,
-	                                       invocation,
+	                                       context,
 	                                       connection,
 	                                       device_path,
 	                                       &device,
-	                                       &is_vpn,
+	                                       &vpn,
 	                                       &error);
 	if (!subject)
 		goto error;
 
-	if (is_vpn) {
+	{
+		gs_free NMSettingsConnection **connections = NULL;
+		guint i, len;
+
+		connections = nm_settings_get_connections_clone (priv->settings, &len,
+		                                                 NULL, NULL,
+		                                                 nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL);
+		all_connections = NULL;
+		for (i = len; i > 0; ) {
+			i--;
+			all_connections = g_slist_prepend (all_connections, connections[i]);
+		}
+	}
+	if (vpn) {
 		/* Try to fill the VPN's connection setting and name at least */
 		if (!nm_connection_get_setting_vpn (connection)) {
 			error = g_error_new_literal (NM_CONNECTION_ERROR,
@@ -4681,7 +4560,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
 		nm_utils_complete_generic (priv->platform,
 		                           connection,
 		                           NM_SETTING_VPN_SETTING_NAME,
-		                           (NMConnection *const*) nm_settings_get_connections (priv->settings, NULL),
+		                           all_connections,
 		                           NULL,
 		                           _("VPN connection"),
 		                           NULL,
@@ -4691,13 +4570,14 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
 		if (!nm_device_complete_connection (device,
 		                                    connection,
 		                                    specific_object_path,
-		                                    (NMConnection *const*) nm_settings_get_connections (priv->settings, NULL),
+		                                    all_connections,
 		                                    &error))
 			goto error;
 	}
+	g_slist_free (all_connections);
+	all_connections = NULL;
 
 	active = _new_active_connection (self,
-	                                 is_vpn,
 	                                 connection,
 	                                 NULL,
 	                                 specific_object_path,
@@ -4709,26 +4589,24 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
 	if (!active)
 		goto error;
 
-	/* FIXME: nm_active_connection_authorize() already has two user-data pointers
-	 *        to piggyback additional data. Instead of attaching the third argument to
-	 *        @active's user-data, add a third paramter.
-	 *        Or alternatively, allocate a data structure to pass on additional data.
-	 *        Then we don't need two user-data pointers. */
 	g_object_set_qdata_full (G_OBJECT (active),
 	                         active_connection_add_and_activate_quark (),
 	                         connection,
 	                         g_object_unref);
 
-	nm_active_connection_authorize (active, connection, _add_and_activate_auth_done, self, invocation);
-
-	/* we passed the pointers on to the callback of authorize. */
-	g_steal_pointer (&connection);
-	g_steal_pointer (&active);
+	nm_active_connection_authorize (active, connection, _add_and_activate_auth_done, self, context);
+	g_object_unref (subject);
 	return;
 
 error:
 	nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, NULL, FALSE, NULL, subject, error->message);
-	g_dbus_method_invocation_take_error (invocation, error);
+	g_clear_object (&connection);
+	g_slist_free (all_connections);
+	g_clear_object (&subject);
+	g_clear_object (&active);
+
+	g_assert (error);
+	g_dbus_method_invocation_take_error (context, error);
 }
 
 /*****************************************************************************/
@@ -4824,28 +4702,21 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
 	else
 		g_dbus_method_invocation_return_value (context, NULL);
 
-	nm_auth_chain_destroy (chain);
+	nm_auth_chain_unref (chain);
 }
 
 static void
-impl_manager_deactivate_connection (NMDBusObject *obj,
-                                    const NMDBusInterfaceInfoExtended *interface_info,
-                                    const NMDBusMethodInfoExtended *method_info,
-                                    GDBusConnection *dbus_connection,
-                                    const char *sender,
-                                    GDBusMethodInvocation *invocation,
-                                    GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
+impl_manager_deactivate_connection (NMManager *self,
+                                    GDBusMethodInvocation *context,
+                                    const char *active_path)
+{
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMActiveConnection *ac;
 	NMSettingsConnection *connection = NULL;
 	GError *error = NULL;
 	NMAuthSubject *subject = NULL;
 	NMAuthChain *chain;
-	const char *active_path;
-
-	g_variant_get (parameters, "(&o)", &active_path);
+	char *error_desc = NULL;
 
 	/* Find the connection by its object path */
 	ac = active_connection_get_by_path (self, active_path);
@@ -4860,7 +4731,7 @@ impl_manager_deactivate_connection (NMDBusObject *obj,
 	}
 
 	/* Validate the caller */
-	subject = nm_auth_subject_new_unix_process_from_context (invocation);
+	subject = nm_auth_subject_new_unix_process_from_context (context);
 	if (!subject) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
@@ -4868,15 +4739,19 @@ impl_manager_deactivate_connection (NMDBusObject *obj,
 		goto done;
 	}
 
-	if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection),
-	                                          subject,
-	                                          NM_MANAGER_ERROR,
-	                                          NM_MANAGER_ERROR_PERMISSION_DENIED,
-	                                          &error))
+	/* Ensure the subject has permissions for this connection */
+	if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection),
+	                                subject,
+	                                &error_desc)) {
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             error_desc);
+		g_free (error_desc);
 		goto done;
+	}
 
 	/* Validate the user request */
-	chain = nm_auth_chain_new_subject (subject, invocation, deactivate_net_auth_done_cb, self);
+	chain = nm_auth_chain_new_subject (subject, context, deactivate_net_auth_done_cb, self);
 	if (!chain) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
@@ -4894,7 +4769,7 @@ done:
 			nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE, connection, FALSE, NULL,
 			                            subject, error->message);
 		}
-		g_dbus_method_invocation_take_error (invocation, error);
+		g_dbus_method_invocation_take_error (context, error);
 	}
 	g_clear_object (&subject);
 }
@@ -5002,7 +4877,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	gboolean suspending, waking_from_suspend;
-	NMDevice *device;
+	GSList *iter;
 
 	suspending = sleeping_changed && priv->sleeping;
 	waking_from_suspend = sleeping_changed && !priv->sleeping;
@@ -5013,7 +4888,9 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 		/* FIXME: are there still hardware devices that need to be disabled around
 		 * suspend/resume?
 		 */
-		c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+		for (iter = priv->devices; iter; iter = iter->next) {
+			NMDevice *device = iter->data;
+
 			/* FIXME: shouldn't we be unmanaging software devices if !suspending? */
 			if (nm_device_is_software (device))
 				continue;
@@ -5041,7 +4918,9 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 
 		if (waking_from_suspend) {
 			sleep_devices_clear (self);
-			c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+			for (iter = priv->devices; iter; iter = iter->next) {
+				NMDevice *device = iter->data;
+
 				if (nm_device_is_software (device))
 					continue;
 
@@ -5068,7 +4947,8 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 		nm_manager_rfkill_update (self, RFKILL_TYPE_UNKNOWN);
 
 		/* Re-manage managed devices */
-		c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+		for (iter = priv->devices; iter; iter = iter->next) {
+			NMDevice *device = NM_DEVICE (iter->data);
 			guint i;
 
 			if (nm_device_is_software (device)) {
@@ -5161,28 +5041,27 @@ sleep_auth_done_cb (NMAuthChain *chain,
 		g_dbus_method_invocation_return_value (context, NULL);
 	}
 
-	nm_auth_chain_destroy (chain);
+	nm_auth_chain_unref (chain);
 }
 #endif
 
 static void
-impl_manager_sleep (NMDBusObject *obj,
-                    const NMDBusInterfaceInfoExtended *interface_info,
-                    const NMDBusMethodInfoExtended *method_info,
-                    GDBusConnection *connection,
-                    const char *sender,
-                    GDBusMethodInvocation *invocation,
-                    GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+impl_manager_sleep (NMManager *self,
+                    GDBusMethodInvocation *context,
+                    gboolean do_sleep)
+{
+	NMManagerPrivate *priv;
 	GError *error = NULL;
 	gs_unref_object NMAuthSubject *subject = NULL;
-	gboolean do_sleep;
+#if 0
+	NMAuthChain *chain;
+	const char *error_desc = NULL;
+#endif
 
-	g_variant_get (parameters, "(b)", &do_sleep);
+	g_return_if_fail (NM_IS_MANAGER (self));
 
-	subject = nm_auth_subject_new_unix_process_from_context (invocation);
+	priv = NM_MANAGER_GET_PRIVATE (self);
+	subject = nm_auth_subject_new_unix_process_from_context (context);
 
 	if (priv->sleeping == do_sleep) {
 		error = g_error_new (NM_MANAGER_ERROR,
@@ -5190,7 +5069,7 @@ impl_manager_sleep (NMDBusObject *obj,
 		                     "Already %s", do_sleep ? "asleep" : "awake");
 		nm_audit_log_control_op (NM_AUDIT_OP_SLEEP_CONTROL, do_sleep ? "on" : "off", FALSE, subject,
 		                         error->message);
-		g_dbus_method_invocation_take_error (invocation, error);
+		g_dbus_method_invocation_take_error (context, error);
 		return;
 	}
 
@@ -5204,8 +5083,22 @@ impl_manager_sleep (NMDBusObject *obj,
 	 */
 	_internal_sleep (self, do_sleep);
 	nm_audit_log_control_op (NM_AUDIT_OP_SLEEP_CONTROL, do_sleep ? "on" : "off", TRUE, subject, NULL);
-	g_dbus_method_invocation_return_value (invocation, NULL);
+	g_dbus_method_invocation_return_value (context, NULL);
 	return;
+
+#if 0
+	chain = nm_auth_chain_new (context, sleep_auth_done_cb, self, &error_desc);
+	if (chain) {
+		priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+		nm_auth_chain_set_data (chain, "sleep", GUINT_TO_POINTER (do_sleep), NULL);
+		nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, TRUE);
+	} else {
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             error_desc);
+		g_dbus_method_invocation_take_error (context, error);
+	}
+#endif
 }
 
 static void
@@ -5281,25 +5174,21 @@ enable_net_done_cb (NMAuthChain *chain,
 		g_dbus_method_invocation_take_error (context, ret_error);
 	}
 
-	nm_auth_chain_destroy (chain);
+	nm_auth_chain_unref (chain);
 }
 
 static void
-impl_manager_enable (NMDBusObject *obj,
-                     const NMDBusInterfaceInfoExtended *interface_info,
-                     const NMDBusMethodInfoExtended *method_info,
-                     GDBusConnection *connection,
-                     const char *sender,
-                     GDBusMethodInvocation *invocation,
-                     GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+impl_manager_enable (NMManager *self,
+                     GDBusMethodInvocation *context,
+                     gboolean enable)
+{
+	NMManagerPrivate *priv;
 	NMAuthChain *chain;
 	GError *error = NULL;
-	gboolean enable;
 
-	g_variant_get (parameters, "(b)", &enable);
+	g_return_if_fail (NM_IS_MANAGER (self));
+
+	priv = NM_MANAGER_GET_PRIVATE (self);
 
 	if (priv->net_enabled == enable) {
 		error = g_error_new (NM_MANAGER_ERROR,
@@ -5308,7 +5197,7 @@ impl_manager_enable (NMDBusObject *obj,
 		goto done;
 	}
 
-	chain = nm_auth_chain_new_context (invocation, enable_net_done_cb, self);
+	chain = nm_auth_chain_new_context (context, enable_net_done_cb, self);
 	if (!chain) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
@@ -5322,7 +5211,7 @@ impl_manager_enable (NMDBusObject *obj,
 
 done:
 	if (error)
-		g_dbus_method_invocation_take_error (invocation, error);
+		g_dbus_method_invocation_take_error (context, error);
 }
 
 /* Permissions */
@@ -5389,28 +5278,23 @@ get_permissions_done_cb (NMAuthChain *chain,
 		                                       g_variant_new ("(a{ss})", &results));
 	}
 
-	nm_auth_chain_destroy (chain);
+	nm_auth_chain_unref (chain);
 }
 
 static void
-impl_manager_get_permissions (NMDBusObject *obj,
-                              const NMDBusInterfaceInfoExtended *interface_info,
-                              const NMDBusMethodInfoExtended *method_info,
-                              GDBusConnection *connection,
-                              const char *sender,
-                              GDBusMethodInvocation *invocation,
-                              GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
+impl_manager_get_permissions (NMManager *self,
+                              GDBusMethodInvocation *context)
+{
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMAuthChain *chain;
+	GError *error = NULL;
 
-	chain = nm_auth_chain_new_context (invocation, get_permissions_done_cb, self);
+	chain = nm_auth_chain_new_context (context, get_permissions_done_cb, self);
 	if (!chain) {
-		g_dbus_method_invocation_return_error_literal (invocation,
-		                                               NM_MANAGER_ERROR,
-		                                               NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                                               "Unable to authenticate request.");
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             "Unable to authenticate request.");
+		g_dbus_method_invocation_take_error (context, error);
 		return;
 	}
 
@@ -5434,123 +5318,83 @@ impl_manager_get_permissions (NMDBusObject *obj,
 }
 
 static void
-impl_manager_state (NMDBusObject *obj,
-                    const NMDBusInterfaceInfoExtended *interface_info,
-                    const NMDBusMethodInfoExtended *method_info,
-                    GDBusConnection *connection,
-                    const char *sender,
-                    GDBusMethodInvocation *invocation,
-                    GVariant *parameters)
+impl_manager_get_state (NMManager *self,
+                        GDBusMethodInvocation *context)
 {
-	NMManager *self = NM_MANAGER (obj);
-
 	nm_manager_update_state (self);
-	g_dbus_method_invocation_return_value (invocation,
+	g_dbus_method_invocation_return_value (context,
 	                                       g_variant_new ("(u)", NM_MANAGER_GET_PRIVATE (self)->state));
 }
 
 static void
-impl_manager_set_logging (NMDBusObject *obj,
-                          const NMDBusInterfaceInfoExtended *interface_info,
-                          const NMDBusMethodInfoExtended *method_info,
-                          GDBusConnection *connection,
-                          const char *sender,
-                          GDBusMethodInvocation *invocation,
-                          GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
+impl_manager_set_logging (NMManager *self,
+                          GDBusMethodInvocation *context,
+                          const char *level,
+                          const char *domains)
+{
 	GError *error = NULL;
-	const char *level;
-	const char *domains;
 
 	/* The permission is already enforced by the D-Bus daemon, but we ensure
 	 * that the caller is still alive so that clients are forced to wait and
 	 * we'll be able to switch to polkit without breaking behavior.
 	 */
-	if (!nm_dbus_manager_ensure_uid (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)),
-	                                 invocation,
-	                                 G_MAXULONG,
-	                                 NM_MANAGER_ERROR,
-	                                 NM_MANAGER_ERROR_PERMISSION_DENIED))
+	if (!nm_bus_manager_ensure_uid (nm_bus_manager_get (),
+	                                context,
+	                                G_MAXULONG,
+	                                NM_MANAGER_ERROR,
+	                                NM_MANAGER_ERROR_PERMISSION_DENIED))
 		return;
 
-	g_variant_get (parameters, "(&s&s)", &level, &domains);
-
 	if (nm_logging_setup (level, domains, NULL, &error)) {
 		_LOGI (LOGD_CORE, "logging: level '%s' domains '%s'",
 		       nm_logging_level_to_string (), nm_logging_domains_to_string ());
 	}
 
 	if (error)
-		g_dbus_method_invocation_take_error (invocation, error);
+		g_dbus_method_invocation_take_error (context, error);
 	else
-		g_dbus_method_invocation_return_value (invocation, NULL);
+		g_dbus_method_invocation_return_value (context, NULL);
 }
 
 static void
-impl_manager_get_logging (NMDBusObject *obj,
-                          const NMDBusInterfaceInfoExtended *interface_info,
-                          const NMDBusMethodInfoExtended *method_info,
-                          GDBusConnection *connection,
-                          const char *sender,
-                          GDBusMethodInvocation *invocation,
-                          GVariant *parameters)
-{
-	g_dbus_method_invocation_return_value (invocation,
+impl_manager_get_logging (NMManager *manager,
+                          GDBusMethodInvocation *context)
+{
+	g_dbus_method_invocation_return_value (context,
 	                                       g_variant_new ("(ss)",
 	                                                      nm_logging_level_to_string (),
 	                                                      nm_logging_domains_to_string ()));
 }
 
 typedef struct {
-	NMManager *self;
-	GDBusMethodInvocation *context;
 	guint remaining;
+	GDBusMethodInvocation *context;
+	NMConnectivityState state;
 } ConnectivityCheckData;
 
 static void
-device_connectivity_done (NMDevice *device,
-                          NMDeviceConnectivityHandle *handle,
-                          NMConnectivityState state,
-                          GError *error,
-                          gpointer user_data)
+device_connectivity_done (NMDevice *device, NMConnectivityState state, gpointer user_data)
 {
 	ConnectivityCheckData *data = user_data;
-	NMManager *self;
-	NMManagerPrivate *priv;
-
-	nm_assert (data);
-	nm_assert (data->remaining > 0);
-	nm_assert (NM_IS_MANAGER (data->self));
 
 	data->remaining--;
 
-	self = data->self;
-	priv = NM_MANAGER_GET_PRIVATE (self);
+	/* We check if the state is already FULL so that we can provide the
+	 * response without waiting for slower devices that are not going to
+	 * affect the overall state anyway. */
 
-	if (   data->context
-	    && (   data->remaining == 0
-	        || (   state == NM_CONNECTIVITY_FULL
-	            && priv->connectivity_state == NM_CONNECTIVITY_FULL))) {
-		/* despite having a @handle and @state returned by the requests, we always
-		 * return the current connectivity_state. That is, because the connectivity_state
-		 * and the answer to the connectivity check shall agree.
-		 *
-		 * However, if one of the requests (early) returns full connectivity and agrees with
-		 * the accumulated connectivity state, we no longer have to wait. The result is set.
-		 *
-		 * This also works well, because NMDevice first emits change signals to its own
-		 * connectivity state, which is then taken into account for the accumulated global
-		 * state. All this happens, before the callback is invoked. */
-		g_dbus_method_invocation_return_value (g_steal_pointer (&data->context),
-		                                       g_variant_new ("(u)",
-		                                                      (guint) priv->connectivity_state));
+	if (data->state != NM_CONNECTIVITY_FULL) {
+		if (state > data->state)
+			data->state = state;
+
+		if (data->state == NM_CONNECTIVITY_FULL || !data->remaining) {
+			g_dbus_method_invocation_return_value (data->context,
+			                                       g_variant_new ("(u)", data->state));
+		}
 	}
 
-	if (data->remaining == 0) {
-		g_object_unref (self);
+	if (!data->remaining)
 		g_slice_free (ConnectivityCheckData, data);
-	}
 }
 
 static void
@@ -5564,7 +5408,7 @@ check_connectivity_auth_done_cb (NMAuthChain *chain,
 	GError *error = NULL;
 	NMAuthCallResult result;
 	ConnectivityCheckData *data;
-	NMDevice *device;
+	const GSList *devices;
 
 	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
 
@@ -5580,59 +5424,39 @@ check_connectivity_auth_done_cb (NMAuthChain *chain,
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
 		                             "Not authorized to recheck connectivity");
-	}
-
-	if (error) {
-		g_dbus_method_invocation_take_error (context, error);
-		goto out;
-	}
-
-	data = g_slice_new (ConnectivityCheckData);
-	data->self = g_object_ref (self);
-	data->context = context;
-	data->remaining = 0;
+	} else {
+		/* it's allowed */
+		data = g_slice_new0 (ConnectivityCheckData);
+		data->context = context;
 
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
-		if (nm_device_check_connectivity (device,
-		                                  device_connectivity_done,
-		                                  data))
+		for (devices = priv->devices; devices; devices = devices->next) {
 			data->remaining++;
+			nm_device_check_connectivity (NM_DEVICE (devices->data),
+			                              device_connectivity_done,
+			                              data);
+		}
 	}
 
-	if (data->remaining == 0) {
-		/* call the handler at least once. */
-		data->remaining = 1;
-		device_connectivity_done (NULL,
-		                          NULL,
-		                          NM_CONNECTIVITY_UNKNOWN,
-		                          NULL,
-		                          data);
-		/* @data got destroyed. */
-	}
-
-out:
-	nm_auth_chain_destroy (chain);
+	if (error)
+		g_dbus_method_invocation_take_error (context, error);
+	nm_auth_chain_unref (chain);
 }
 
 static void
-impl_manager_check_connectivity (NMDBusObject *obj,
-                                 const NMDBusInterfaceInfoExtended *interface_info,
-                                 const NMDBusMethodInfoExtended *method_info,
-                                 GDBusConnection *connection,
-                                 const char *sender,
-                                 GDBusMethodInvocation *invocation,
-                                 GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
+impl_manager_check_connectivity (NMManager *self,
+                                 GDBusMethodInvocation *context)
+{
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMAuthChain *chain;
+	GError *error = NULL;
 
-	chain = nm_auth_chain_new_context (invocation, check_connectivity_auth_done_cb, self);
+	/* Validate the request */
+	chain = nm_auth_chain_new_context (context, check_connectivity_auth_done_cb, self);
 	if (!chain) {
-		g_dbus_method_invocation_return_error_literal(invocation,
-		                                              NM_MANAGER_ERROR,
-		                                              NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                                              "Unable to authenticate request.");
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             "Unable to authenticate request.");
+		g_dbus_method_invocation_take_error (context, error);
 		return;
 	}
 
@@ -5649,14 +5473,15 @@ start_factory (NMDeviceFactory *factory, gpointer user_data)
 void
 nm_manager_write_device_state (NMManager *self)
 {
+	const GSList *devices;
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
 	gs_unref_hashtable GHashTable *seen_ifindexes = NULL;
 	gint nm_owned;
 
-	seen_ifindexes = g_hash_table_new (nm_direct_hash, NULL);
+	seen_ifindexes = g_hash_table_new (NULL, NULL);
 
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+	for (devices = priv->devices; devices; devices = devices->next) {
+		NMDevice *device = NM_DEVICE (devices->data);
 		int ifindex;
 		gboolean managed;
 		NMConfigDeviceStateManagedType managed_type;
@@ -5797,10 +5622,10 @@ void
 nm_manager_stop (NMManager *self)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
 
-	while ((device = c_list_first_entry (&priv->devices_lst_head, NMDevice, devices_lst)))
-		remove_device (self, device, TRUE, TRUE);
+	/* Remove all devices */
+	while (priv->devices)
+		remove_device (self, NM_DEVICE (priv->devices->data), TRUE, TRUE);
 
 	_active_connection_cleanup (self);
 
@@ -5812,20 +5637,21 @@ handle_firmware_changed (gpointer user_data)
 {
 	NMManager *self = NM_MANAGER (user_data);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMDevice *device;
+	GSList *iter;
 
 	priv->fw_changed_id = 0;
 
 	/* Try to re-enable devices with missing firmware */
-	c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
-		NMDeviceState state = nm_device_get_state (device);
+	for (iter = priv->devices; iter; iter = iter->next) {
+		NMDevice *candidate = NM_DEVICE (iter->data);
+		NMDeviceState state = nm_device_get_state (candidate);
 
-		if (   nm_device_get_firmware_missing (device)
+		if (   nm_device_get_firmware_missing (candidate)
 		    && (state == NM_DEVICE_STATE_UNAVAILABLE)) {
-			_LOG2I (LOGD_CORE, device, "firmware may now be available");
+			_LOG2I (LOGD_CORE, candidate, "firmware may now be available");
 
 			/* Re-set unavailable state to try bringing the device up again */
-			nm_device_state_changed (device,
+			nm_device_state_changed (candidate,
 			                         NM_DEVICE_STATE_UNAVAILABLE,
 			                         NM_DEVICE_STATE_REASON_NONE);
 		}
@@ -5944,133 +5770,318 @@ policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer u
 	}
 }
 
-/*****************************************************************************/
+#define NM_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied"
 
 typedef struct {
 	NMManager *self;
-	NMDBusObject *obj;
-	const NMDBusInterfaceInfoExtended *interface_info;
-	const NMDBusPropertyInfoExtended *property_info;
-	GVariant *value;
-	guint64 export_version_id;
-} DBusSetPropertyHandle;
+	GDBusConnection *connection;
+	GDBusMessage *message;
+	NMAuthSubject *subject;
+	const char *permission;
+	const char *audit_op;
+	char *audit_prop_value;
+	GType interface_type;
+	const char *glib_propname;
+} PropertyFilterData;
 
-#define NM_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied"
+static void
+free_property_filter_data (PropertyFilterData *pfd)
+{
+	g_object_unref (pfd->self);
+	g_object_unref (pfd->connection);
+	g_object_unref (pfd->message);
+	g_clear_object (&pfd->subject);
+	g_free (pfd->audit_prop_value);
+	g_slice_free (PropertyFilterData, pfd);
+}
 
 static void
-_dbus_set_property_auth_cb (NMAuthChain *chain,
-                            GError *error,
-                            GDBusMethodInvocation *invocation,
-                            gpointer user_data)
+prop_set_auth_done_cb (NMAuthChain *chain,
+                       GError *error,
+                       GDBusMethodInvocation *context, /* NULL */
+                       gpointer user_data)
 {
-	DBusSetPropertyHandle *handle_data = user_data;
-	gs_unref_object NMDBusObject *obj = handle_data->obj;
-	const NMDBusInterfaceInfoExtended *interface_info = handle_data->interface_info;
-	const NMDBusPropertyInfoExtended *property_info = handle_data->property_info;
-	gs_unref_variant GVariant *value = handle_data->value;
-	guint64 export_version_id = handle_data->export_version_id;
-	gs_unref_object NMManager *self = handle_data->self;
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	PropertyFilterData *pfd = user_data;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pfd->self);
 	NMAuthCallResult result;
-	const char *error_name = NULL;
-	const char *error_message = NULL;
-	GValue gvalue;
-
-	g_slice_free (DBusSetPropertyHandle, handle_data);
+	GDBusMessage *reply = NULL;
+	const char *error_message;
+	gs_unref_object NMExportedObject *object = NULL;
+	const NMGlobalDnsConfig *global_dns;
+	gs_unref_variant GVariant *value = NULL;
+	GVariant *args;
 
 	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
-	result = nm_auth_chain_get_result (chain, property_info->writable.permission);
+	result = nm_auth_chain_get_result (chain, pfd->permission);
+	if (error || (result != NM_AUTH_CALL_RESULT_YES)) {
+		reply = g_dbus_message_new_method_error_literal (pfd->message,
+		                                                 NM_PERM_DENIED_ERROR,
+		                                                 (error_message = "Not authorized to perform this operation"));
+		if (error)
+			error_message = error->message;
+		goto done;
+	}
 
-	if (   error
-	    || result != NM_AUTH_CALL_RESULT_YES) {
-		error_name = NM_PERM_DENIED_ERROR;
-		error_message = error ? error->message : "Not authorized to perform this operation";
-		goto out;
+	object = NM_EXPORTED_OBJECT (nm_bus_manager_get_registered_object (priv->dbus_mgr,
+	                                                                   g_dbus_message_get_path (pfd->message)));
+	if (!object) {
+		reply = g_dbus_message_new_method_error_literal (pfd->message,
+		                                                 "org.freedesktop.DBus.Error.UnknownObject",
+		                                                 (error_message = "Object doesn't exist."));
+		goto done;
 	}
 
-	if (export_version_id != nm_dbus_object_get_export_version_id (obj)) {
-		error_name = "org.freedesktop.DBus.Error.UnknownObject";
-		error_message = "Object was deleted while authenticating";
-		goto out;
+	/* do some extra type checking... */
+	if (!nm_exported_object_get_interface_by_type (object, pfd->interface_type)) {
+		reply = g_dbus_message_new_method_error_literal (pfd->message,
+		                                                 "org.freedesktop.DBus.Error.InvalidArgs",
+		                                                 (error_message = "Object is of unexpected type."));
+		goto done;
 	}
 
-	/* Handle some properties specially *sigh* */
-	if (   interface_info == &interface_info_manager
-	    && nm_streq (property_info->property_name, NM_MANAGER_GLOBAL_DNS_CONFIGURATION)) {
-		const NMGlobalDnsConfig *global_dns;
+	args = g_dbus_message_get_body (pfd->message);
+	g_variant_get (args, "(&s&sv)", NULL, NULL, &value);
+	g_assert (pfd->glib_propname);
 
+	if (!strcmp (pfd->glib_propname, NM_MANAGER_GLOBAL_DNS_CONFIGURATION)) {
+		g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("a{sv}")));
 		global_dns = nm_config_data_get_global_dns_config (nm_config_get_data (priv->config));
-		if (   global_dns
-		    && !nm_global_dns_config_is_internal (global_dns)) {
-			error_name = NM_PERM_DENIED_ERROR;
-			error_message = "Global DNS configuration already set via configuration file";
-			goto out;
+
+		if (global_dns && !nm_global_dns_config_is_internal (global_dns)) {
+			reply = g_dbus_message_new_method_error_literal (pfd->message,
+			                                                 NM_PERM_DENIED_ERROR,
+			                                                 (error_message = "Global DNS configuration already set via configuration file"));
+			goto done;
 		}
+		/* ... but set the property on the @object itself. It would be correct to set the property
+		 * on the skeleton interface, but as it is now, the result is the same. */
+		g_object_set (object, pfd->glib_propname, value, NULL);
+	} else if (!strcmp (pfd->glib_propname, NM_DEVICE_STATISTICS_REFRESH_RATE_MS)) {
+		g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32));
+		/* the same here */
+		g_object_set (object, pfd->glib_propname, (guint) g_variant_get_uint32 (value), NULL);
+	} else {
+		g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN));
+		/* the same here */
+		g_object_set (object, pfd->glib_propname, g_variant_get_boolean (value), NULL);
 	}
 
-	g_dbus_gvariant_to_gvalue (value, &gvalue);
-	g_object_set_property (G_OBJECT (obj), property_info->property_name, &gvalue);
-	g_value_unset (&gvalue);
+	reply = g_dbus_message_new_method_reply (pfd->message);
+	g_dbus_message_set_body (reply, g_variant_new_tuple (NULL, 0));
+	error_message = NULL;
+done:
+	nm_audit_log_control_op (pfd->audit_op, pfd->audit_prop_value, !error_message, pfd->subject, error_message);
 
-out:
-	nm_audit_log_control_op (property_info->writable.audit_op,
-	                         property_info->property_name,
-	                         !error_message,
-	                         nm_auth_chain_get_subject (chain),
-	                         error_message);
-	if (error_message)
-		g_dbus_method_invocation_return_dbus_error (invocation, error_name, error_message);
-	else
-		g_dbus_method_invocation_return_value (invocation, NULL);
-	nm_auth_chain_destroy (chain);
+	g_dbus_connection_send_message (pfd->connection, reply,
+	                                G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+	                                NULL, NULL);
+	g_object_unref (reply);
+	nm_auth_chain_unref (chain);
+
+	free_property_filter_data (pfd);
 }
 
-void
-nm_manager_dbus_set_property_handle (NMDBusObject *obj,
-                                     const NMDBusInterfaceInfoExtended *interface_info,
-                                     const NMDBusPropertyInfoExtended *property_info,
-                                     GDBusConnection *connection,
-                                     const char *sender,
-                                     GDBusMethodInvocation *invocation,
-                                     GVariant *value,
-                                     gpointer user_data)
+static gboolean
+do_set_property_check (gpointer user_data)
 {
-	NMManager *self = user_data;
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	PropertyFilterData *pfd = user_data;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pfd->self);
+	GDBusMessage *reply = NULL;
 	NMAuthChain *chain;
 	const char *error_message = NULL;
-	gs_unref_object NMAuthSubject *subject = NULL;
-	DBusSetPropertyHandle *handle_data;
 
-	subject = nm_auth_subject_new_unix_process_from_context (invocation);
-	if (!subject) {
-		error_message = "Could not determine request UID";
-		goto err;
+	pfd->subject = nm_auth_subject_new_unix_process_from_message (pfd->connection, pfd->message);
+	if (!pfd->subject) {
+		reply = g_dbus_message_new_method_error_literal (pfd->message,
+		                                                 NM_PERM_DENIED_ERROR,
+		                                                 (error_message = "Could not determine request UID."));
+		goto out;
 	}
 
-	handle_data = g_slice_new0 (DBusSetPropertyHandle);
-	handle_data->self = g_object_ref (self);
-	handle_data->obj = g_object_ref (obj);
-	handle_data->interface_info = interface_info;
-	handle_data->property_info = property_info;
-	handle_data->value = g_variant_ref (value);
-	handle_data->export_version_id = nm_dbus_object_get_export_version_id (obj);
+	/* Validate the user request */
+	chain = nm_auth_chain_new_subject (pfd->subject, NULL, prop_set_auth_done_cb, pfd);
+	if (!chain) {
+		reply = g_dbus_message_new_method_error_literal (pfd->message,
+		                                                 NM_PERM_DENIED_ERROR,
+		                                                 (error_message = "Could not authenticate request."));
+		goto out;
+	}
 
-	chain = nm_auth_chain_new_subject (subject, invocation, _dbus_set_property_auth_cb, handle_data);
 	priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-	nm_auth_chain_add_call (chain, property_info->writable.permission, TRUE);
-	return;
+	nm_auth_chain_add_call (chain, pfd->permission, TRUE);
+
+out:
+	if (reply) {
+		nm_audit_log_control_op (pfd->audit_op, pfd->audit_prop_value, FALSE, pfd->subject, error_message);
+		g_dbus_connection_send_message (pfd->connection, reply,
+		                                G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+		                                NULL, NULL);
+		g_object_unref (reply);
+		free_property_filter_data (pfd);
+	}
+
+	return FALSE;
+}
+
+static GDBusMessage *
+prop_filter (GDBusConnection *connection,
+             GDBusMessage *message,
+             gboolean incoming,
+             gpointer user_data)
+{
+	gs_unref_object NMManager *self = NULL;
+	GVariant *args;
+	const char *propiface = NULL;
+	const char *propname = NULL;
+	const char *glib_propname = NULL, *permission = NULL;
+	const char *audit_op = NULL;
+	GType interface_type = G_TYPE_INVALID;
+	PropertyFilterData *pfd;
+	const GVariantType *expected_type = G_VARIANT_TYPE_BOOLEAN;
+	gs_unref_variant GVariant *value = NULL;
+
+	self = g_weak_ref_get (user_data);
+	if (!self)
+		return message;
+
+	/* The sole purpose of this function is to validate property accesses on the
+	 * NMManager object since gdbus doesn't give us this functionality.
+	 */
+
+	/* Only filter org.freedesktop.DBus.Properties.Set calls */
+	if (   !incoming
+	    || g_dbus_message_get_message_type (message) != G_DBUS_MESSAGE_TYPE_METHOD_CALL
+	    || g_strcmp0 (g_dbus_message_get_interface (message), DBUS_INTERFACE_PROPERTIES) != 0
+	    || g_strcmp0 (g_dbus_message_get_member (message), "Set") != 0)
+		return message;
+
+	args = g_dbus_message_get_body (message);
+	if (!g_variant_is_of_type (args, G_VARIANT_TYPE ("(ssv)")))
+		return message;
+	g_variant_get (args, "(&s&sv)", &propiface, &propname, &value);
+
+	/* Only filter calls to filtered properties, on existing objects */
+	if (!strcmp (propiface, NM_DBUS_INTERFACE)) {
+		if (!strcmp (propname, "WirelessEnabled")) {
+			glib_propname = NM_MANAGER_WIRELESS_ENABLED;
+			permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI;
+			audit_op = NM_AUDIT_OP_RADIO_CONTROL;
+		} else if (!strcmp (propname, "WwanEnabled")) {
+			glib_propname = NM_MANAGER_WWAN_ENABLED;
+			permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN;
+			audit_op = NM_AUDIT_OP_RADIO_CONTROL;
+		} else if (!strcmp (propname, "WimaxEnabled")) {
+			glib_propname = NM_MANAGER_WIMAX_ENABLED;
+			permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX;
+			audit_op = NM_AUDIT_OP_RADIO_CONTROL;
+		} else if (!strcmp (propname, "GlobalDnsConfiguration")) {
+			glib_propname = NM_MANAGER_GLOBAL_DNS_CONFIGURATION;
+			permission = NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS;
+			audit_op = NM_AUDIT_OP_NET_CONTROL;
+			expected_type = G_VARIANT_TYPE ("a{sv}");
+		} else if (!strcmp (propname, "ConnectivityCheckEnabled")) {
+			glib_propname = NM_MANAGER_CONNECTIVITY_CHECK_ENABLED;
+			permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK;
+			audit_op = NM_AUDIT_OP_NET_CONTROL;
+		} else
+			return message;
+		interface_type = NMDBUS_TYPE_MANAGER_SKELETON;
+	} else if (!strcmp (propiface, NM_DBUS_INTERFACE_DEVICE)) {
+		if (!strcmp (propname, "Autoconnect")) {
+			glib_propname = NM_DEVICE_AUTOCONNECT;
+			permission = NM_AUTH_PERMISSION_NETWORK_CONTROL;
+			audit_op = NM_AUDIT_OP_DEVICE_AUTOCONNECT;
+		} else if (!strcmp (propname, "Managed")) {
+			glib_propname = NM_DEVICE_MANAGED;
+			permission = NM_AUTH_PERMISSION_NETWORK_CONTROL;
+			audit_op = NM_AUDIT_OP_DEVICE_MANAGED;
+		} else
+			return message;
+		interface_type = NMDBUS_TYPE_DEVICE_SKELETON;
+	} else if (!strcmp (propiface, NM_DBUS_INTERFACE_DEVICE_STATISTICS)) {
+		if (!strcmp (propname, "RefreshRateMs")) {
+			glib_propname = NM_DEVICE_STATISTICS_REFRESH_RATE_MS;
+			permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS;
+			audit_op = NM_AUDIT_OP_STATISTICS;
+			expected_type = G_VARIANT_TYPE ("u");
+		} else
+			return message;
+		interface_type = NMDBUS_TYPE_DEVICE_SKELETON;
+	} else
+		return message;
+
+	if (!g_variant_is_of_type (value, expected_type))
+		return message;
+
+	/* This filter function is called from a gdbus worker thread which we can't
+	 * make other D-Bus calls from. In particular, we cannot call
+	 * org.freedesktop.DBus.GetConnectionUnixUser to find the remote UID.
+	 */
+	pfd = g_slice_new0 (PropertyFilterData);
+	pfd->self = self;
+	self = NULL;
+	pfd->connection = g_object_ref (connection);
+	pfd->message = message;
+	pfd->permission = permission;
+	pfd->interface_type = interface_type;
+	pfd->glib_propname = glib_propname;
+	pfd->audit_op = audit_op;
+	if (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) {
+		pfd->audit_prop_value = g_strdup_printf ("%s:%d", pfd->glib_propname,
+		                                         g_variant_get_boolean (value));
+	} else
+		pfd->audit_prop_value = g_strdup (pfd->glib_propname);
+
+	g_idle_add (do_set_property_check, pfd);
+
+	return NULL;
+}
+
+/*****************************************************************************/
+
+static int
+_set_prop_filter_free2 (gpointer user_data)
+{
+	g_slice_free (GWeakRef, user_data);
+	return G_SOURCE_REMOVE;
+}
+
+static void
+_set_prop_filter_free (gpointer user_data)
+{
+	g_weak_ref_clear (user_data);
+
+	/* Delay the final deletion of the user_data. There is a race when
+	 * calling g_dbus_connection_remove_filter() that the callback and user_data
+	 * might have been copied and being executed after the destroy function
+	 * runs (bgo #704568).
+	 * This doesn't really fix the race, but it should work well enough. */
+	g_timeout_add_seconds (2, _set_prop_filter_free2, user_data);
+}
+
+static void
+_set_prop_filter (NMManager *self, GDBusConnection *connection)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	nm_assert ((!priv->prop_filter.connection) == (!priv->prop_filter.id));
+
+	if (priv->prop_filter.connection == connection)
+		return;
+
+	if (priv->prop_filter.connection) {
+		g_dbus_connection_remove_filter (priv->prop_filter.connection, priv->prop_filter.id);
+		priv->prop_filter.id = 0;
+		g_clear_object (&priv->prop_filter.connection);
+	}
+	if (connection) {
+		GWeakRef *wptr;
 
-err:
-	nm_audit_log_control_op (property_info->writable.audit_op,
-	                         property_info->property_name,
-	                         FALSE,
-	                         invocation,
-	                         error_message);
-	g_dbus_method_invocation_return_error_literal (invocation,
-	                                               G_DBUS_ERROR,
-	                                               G_DBUS_ERROR_AUTH_FAILED,
-	                                               error_message);
+		wptr = g_slice_new (GWeakRef);
+		g_weak_ref_init  (wptr, self);
+		priv->prop_filter.id = g_dbus_connection_add_filter (connection, prop_filter, wptr, _set_prop_filter_free);
+		priv->prop_filter.connection = g_object_ref (connection);
+	}
 }
 
 /*****************************************************************************/
@@ -6081,7 +6092,7 @@ _checkpoint_mgr_get (NMManager *self, gboolean create_as_needed)
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 
 	if (G_UNLIKELY (!priv->checkpoint_mgr) && create_as_needed)
-		priv->checkpoint_mgr = nm_checkpoint_manager_new (self, obj_properties[PROP_CHECKPOINTS]);
+		priv->checkpoint_mgr = nm_checkpoint_manager_new (self);
 	return priv->checkpoint_mgr;
 }
 
@@ -6100,15 +6111,13 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
 	GVariant *variant = NULL;
 	GError *error = NULL;
 	const char *arg = NULL;
-	guint32 add_timeout;
 
 	op = nm_auth_chain_get_data (chain, "audit-op");
 	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
 	result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK);
 
-	if (NM_IN_STRSET (op, NM_AUDIT_OP_CHECKPOINT_DESTROY,
-	                      NM_AUDIT_OP_CHECKPOINT_ROLLBACK,
-	                      NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT))
+	if (   nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_DESTROY)
+	    || nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ROLLBACK))
 		arg = checkpoint_path = nm_auth_chain_get_data (chain, "checkpoint_path");
 
 	if (auth_error) {
@@ -6132,7 +6141,7 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
 			                                           (NMCheckpointCreateFlags) flags,
 			                                           &error);
 			if (checkpoint) {
-				arg = nm_dbus_object_get_path (NM_DBUS_OBJECT (checkpoint));
+				arg = nm_exported_object_get_path (NM_EXPORTED_OBJECT (checkpoint));
 				variant = g_variant_new ("(o)", arg);
 			}
 		} else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_DESTROY)) {
@@ -6141,10 +6150,6 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
 		} else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ROLLBACK)) {
 			nm_checkpoint_manager_rollback (_checkpoint_mgr_get (self, TRUE),
 			                                checkpoint_path, &variant, &error);
-		} else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT)) {
-			add_timeout = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "add_timeout"));
-			nm_checkpoint_manager_adjust_rollback_timeout (_checkpoint_mgr_get (self, TRUE),
-			                                               checkpoint_path, add_timeout, &error);
 		} else
 			g_return_if_reached ();
 	}
@@ -6157,71 +6162,63 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
 	else
 		g_dbus_method_invocation_return_value (context, variant);
 
-	nm_auth_chain_destroy (chain);
+
+	nm_auth_chain_unref (chain);
 }
 
 static void
-impl_manager_checkpoint_create (NMDBusObject *obj,
-                                const NMDBusInterfaceInfoExtended *interface_info,
-                                const NMDBusMethodInfoExtended *method_info,
-                                GDBusConnection *connection,
-                                const char *sender,
-                                GDBusMethodInvocation *invocation,
-                                GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+impl_manager_checkpoint_create (NMManager *self,
+                                GDBusMethodInvocation *context,
+                                const char *const *devices,
+                                guint32 rollback_timeout,
+                                guint32 flags)
+{
+	NMManagerPrivate *priv;
 	NMAuthChain *chain;
-	char **devices;
-	guint32 rollback_timeout;
-	guint32 flags;
+	GError *error = NULL;
 
 	G_STATIC_ASSERT_EXPR (sizeof (flags) <= sizeof (NMCheckpointCreateFlags));
+	g_return_if_fail (NM_IS_MANAGER (self));
+	priv = NM_MANAGER_GET_PRIVATE (self);
 
-	chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self);
+	chain = nm_auth_chain_new_context (context, checkpoint_auth_done_cb, self);
 	if (!chain) {
-		g_dbus_method_invocation_return_error_literal (invocation,
-		                                               NM_MANAGER_ERROR,
-		                                               NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                                               "Unable to authenticate request.");
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             "Unable to authenticate request.");
+		g_dbus_method_invocation_take_error (context, error);
 		return;
 	}
 
-	g_variant_get (parameters, "(^aouu)", &devices, &rollback_timeout, &flags);
-
 	priv->auth_chains = g_slist_append (priv->auth_chains, chain);
 	nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_CREATE, NULL);
-	nm_auth_chain_set_data (chain, "devices", devices, (GDestroyNotify) g_strfreev);
+	nm_auth_chain_set_data (chain, "devices", g_strdupv ((char **) devices), (GDestroyNotify) g_strfreev);
 	nm_auth_chain_set_data (chain, "flags",  GUINT_TO_POINTER (flags), NULL);
 	nm_auth_chain_set_data (chain, "timeout", GUINT_TO_POINTER (rollback_timeout), NULL);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE);
 }
 
 static void
-impl_manager_checkpoint_destroy (NMDBusObject *obj,
-                                 const NMDBusInterfaceInfoExtended *interface_info,
-                                 const NMDBusMethodInfoExtended *method_info,
-                                 GDBusConnection *connection,
-                                 const char *sender,
-                                 GDBusMethodInvocation *invocation,
-                                 GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+impl_manager_checkpoint_destroy (NMManager *self,
+                                 GDBusMethodInvocation *context,
+                                 const char *checkpoint_path)
+{
+	NMManagerPrivate *priv;
+	GError *error = NULL;
 	NMAuthChain *chain;
-	const char *checkpoint_path;
 
-	chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self);
+	g_return_if_fail (NM_IS_MANAGER (self));
+	priv = NM_MANAGER_GET_PRIVATE (self);
+
+	chain = nm_auth_chain_new_context (context, checkpoint_auth_done_cb, self);
 	if (!chain) {
-		g_dbus_method_invocation_return_error_literal (invocation,
-		                                               NM_MANAGER_ERROR,
-		                                               NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                                               "Unable to authenticate request.");
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             "Unable to authenticate request.");
+		g_dbus_method_invocation_take_error (context, error);
 		return;
 	}
 
-	g_variant_get (parameters, "(&o)", &checkpoint_path);
-
 	priv->auth_chains = g_slist_append (priv->auth_chains, chain);
 	nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_DESTROY, NULL);
 	nm_auth_chain_set_data (chain, "checkpoint_path", g_strdup (checkpoint_path), g_free);
@@ -6229,66 +6226,29 @@ impl_manager_checkpoint_destroy (NMDBusObject *obj,
 }
 
 static void
-impl_manager_checkpoint_rollback (NMDBusObject *obj,
-                                  const NMDBusInterfaceInfoExtended *interface_info,
-                                  const NMDBusMethodInfoExtended *method_info,
-                                  GDBusConnection *connection,
-                                  const char *sender,
-                                  GDBusMethodInvocation *invocation,
-                                  GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+impl_manager_checkpoint_rollback (NMManager *self,
+                                  GDBusMethodInvocation *context,
+                                  const char *checkpoint_path)
+{
+	NMManagerPrivate *priv;
+	GError *error = NULL;
 	NMAuthChain *chain;
-	const char *checkpoint_path;
-
-	chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self);
-	if (!chain) {
-		g_dbus_method_invocation_return_error_literal (invocation,
-		                                               NM_MANAGER_ERROR,
-		                                               NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                                               "Unable to authenticate request.");
-		return;
-	}
-
-	g_variant_get (parameters, "(&o)", &checkpoint_path);
-
-	priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-	nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_ROLLBACK, NULL);
-	nm_auth_chain_set_data (chain, "checkpoint_path", g_strdup (checkpoint_path), g_free);
-	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE);
-}
 
-static void
-impl_manager_checkpoint_adjust_rollback_timeout (NMDBusObject *obj,
-                                                 const NMDBusInterfaceInfoExtended *interface_info,
-                                                 const NMDBusMethodInfoExtended *method_info,
-                                                 GDBusConnection *connection,
-                                                 const char *sender,
-                                                 GDBusMethodInvocation *invocation,
-                                                 GVariant *parameters)
-{
-	NMManager *self = NM_MANAGER (obj);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMAuthChain *chain;
-	const char *checkpoint_path;
-	guint32 add_timeout;
+	g_return_if_fail (NM_IS_MANAGER (self));
+	priv = NM_MANAGER_GET_PRIVATE (self);
 
-	chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self);
+	chain = nm_auth_chain_new_context (context, checkpoint_auth_done_cb, self);
 	if (!chain) {
-		g_dbus_method_invocation_return_error_literal (invocation,
-		                                               NM_MANAGER_ERROR,
-		                                               NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                                               "Unable to authenticate request.");
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             "Unable to authenticate request.");
+		g_dbus_method_invocation_take_error (context, error);
 		return;
 	}
 
-	g_variant_get (parameters, "(&ou)", &checkpoint_path, &add_timeout);
-
 	priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-	nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT, NULL);
+	nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_ROLLBACK, NULL);
 	nm_auth_chain_set_data (chain, "checkpoint_path", g_strdup (checkpoint_path), g_free);
-	nm_auth_chain_set_data (chain, "add_timeout", GUINT_TO_POINTER (add_timeout), NULL);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE);
 }
 
@@ -6298,10 +6258,7 @@ static void
 auth_mgr_changed (NMAuthManager *auth_manager, gpointer user_data)
 {
 	/* Let clients know they should re-check their authorization */
-	nm_dbus_object_emit_signal (user_data,
-	                            &interface_info_manager,
-	                            &signal_info_check_permissions,
-	                            "()");
+	g_signal_emit (NM_MANAGER (user_data), signals[CHECK_PERMISSIONS], 0);
 }
 
 #define KERN_RFKILL_OP_CHANGE_ALL 3
@@ -6426,6 +6383,14 @@ periodic_update_active_connection_timestamps (gpointer user_data)
 	return G_SOURCE_CONTINUE;
 }
 
+static void
+dbus_connection_changed_cb (NMBusManager *dbus_mgr,
+                            GDBusConnection *connection,
+                            gpointer user_data)
+{
+	_set_prop_filter (NM_MANAGER (user_data), connection);
+}
+
 /*****************************************************************************/
 
 void
@@ -6492,7 +6457,8 @@ nm_manager_setup (void)
 	nm_singleton_instance_register ();
 	_LOGD (LOGD_CORE, "setup %s singleton (%p)", "NMManager", singleton_instance);
 
-	nm_dbus_object_export (NM_DBUS_OBJECT (self));
+	nm_exported_object_export ((NMExportedObject *) self);
+
 	return self;
 }
 
@@ -6505,9 +6471,11 @@ constructed (GObject *object)
 
 	G_OBJECT_CLASS (nm_manager_parent_class)->constructed (object);
 
+	_set_prop_filter (self, nm_bus_manager_get_connection (priv->dbus_mgr));
+
 	priv->settings = nm_settings_new ();
 
-	nm_dbus_object_export (NM_DBUS_OBJECT (priv->settings));
+	nm_exported_object_export (NM_EXPORTED_OBJECT (priv->settings));
 
 	g_signal_connect (priv->settings, "notify::" NM_SETTINGS_STARTUP_COMPLETE,
 	                  G_CALLBACK (settings_startup_complete_changed), self);
@@ -6575,7 +6543,6 @@ nm_manager_init (NMManager *self)
 	GFile *file;
 
 	c_list_init (&priv->link_cb_lst);
-	c_list_init (&priv->devices_lst_head);
 	c_list_init (&priv->active_connections_lst_head);
 	c_list_init (&priv->delete_volatile_connection_lst_head);
 
@@ -6607,6 +6574,12 @@ nm_manager_init (NMManager *self)
 	priv->state = NM_STATE_DISCONNECTED;
 	priv->startup = TRUE;
 
+	priv->dbus_mgr = g_object_ref (nm_bus_manager_get ());
+	g_signal_connect (priv->dbus_mgr,
+	                  NM_BUS_MANAGER_DBUS_CONNECTION_CHANGED,
+	                  G_CALLBACK (dbus_connection_changed_cb),
+	                  self);
+
 	/* sleep/wake handling */
 	priv->sleep_monitor = nm_sleep_monitor_new ();
 	g_signal_connect (priv->sleep_monitor, NM_SLEEP_MONITOR_SLEEPING,
@@ -6641,7 +6614,13 @@ nm_manager_init (NMManager *self)
 	priv->timestamp_update_id = g_timeout_add_seconds (300, (GSourceFunc) periodic_update_active_connection_timestamps, self);
 
 	priv->metered = NM_METERED_UNKNOWN;
-	priv->sleep_devices = g_hash_table_new (nm_direct_hash, NULL);
+	priv->sleep_devices = g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+static gboolean
+device_is_real (GObject *device, gpointer user_data)
+{
+	return nm_device_is_real (NM_DEVICE (device));
 }
 
 static void
@@ -6656,6 +6635,7 @@ get_property (GObject *object, guint prop_id,
 	const char *path;
 	NMActiveConnection *ac;
 	GPtrArray *ptrarr;
+	gboolean vbool;
 
 	switch (prop_id) {
 	case PROP_VERSION:
@@ -6697,7 +6677,7 @@ get_property (GObject *object, guint prop_id,
 	case PROP_ACTIVE_CONNECTIONS:
 		ptrarr = g_ptr_array_new ();
 		c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
-			path = nm_dbus_object_get_path (NM_DBUS_OBJECT (ac));
+			path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac));
 			if (path)
 				g_ptr_array_add (ptrarr, g_strdup (path));
 		}
@@ -6712,10 +6692,15 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_boolean (value, nm_config_data_get_connectivity_uri (config_data) != NULL);
 		break;
 	case PROP_CONNECTIVITY_CHECK_ENABLED:
-		g_value_set_boolean (value, concheck_enabled (self, NULL));
+#if WITH_CONCHECK
+		vbool = nm_connectivity_check_enabled (nm_connectivity_get ());
+#else
+		vbool = FALSE;
+#endif
+		g_value_set_boolean (value, vbool);
 		break;
 	case PROP_PRIMARY_CONNECTION:
-		nm_dbus_utils_g_value_set_object_path (value, priv->primary_connection);
+		nm_utils_g_value_set_object_path (value, priv->primary_connection);
 		break;
 	case PROP_PRIMARY_CONNECTION_TYPE:
 		type = NULL;
@@ -6729,15 +6714,13 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_string (value, type ? type : "");
 		break;
 	case PROP_ACTIVATING_CONNECTION:
-		nm_dbus_utils_g_value_set_object_path (value, priv->activating_connection);
+		nm_utils_g_value_set_object_path (value, priv->activating_connection);
 		break;
 	case PROP_SLEEPING:
 		g_value_set_boolean (value, priv->sleeping);
 		break;
 	case PROP_DEVICES:
-		g_value_take_boxed (value,
-		                    nm_utils_strv_make_deep_copied (_get_devices_paths (self,
-		                                                                        FALSE)));
+		nm_utils_g_value_set_object_path_array (value, priv->devices, device_is_real, NULL);
 		break;
 	case PROP_METERED:
 		g_value_set_uint (value, priv->metered);
@@ -6748,16 +6731,7 @@ get_property (GObject *object, guint prop_id,
 		nm_global_dns_config_to_dbus (dns_config, value);
 		break;
 	case PROP_ALL_DEVICES:
-		g_value_take_boxed (value,
-		                    nm_utils_strv_make_deep_copied (_get_devices_paths (self,
-		                                                                        TRUE)));
-		break;
-	case PROP_CHECKPOINTS:
-		g_value_take_boxed (value,
-		                    priv->checkpoint_mgr
-		                    ? nm_utils_strv_make_deep_copied (nm_checkpoint_manager_get_checkpoint_paths (priv->checkpoint_mgr,
-		                                                                                                  NULL))
-		                    : NULL);
+		nm_utils_g_value_set_object_path_array (value, priv->devices, NULL, NULL);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -6824,6 +6798,11 @@ dispose (GObject *object)
 	CList *iter, *iter_safe;
 	NMActiveConnection *ac, *ac_safe;
 
+	nm_clear_g_source (&priv->delete_volatile_connection_idle_id);
+	_delete_volatile_connection_all (self, FALSE);
+	nm_assert (!priv->delete_volatile_connection_idle_id);
+	nm_assert (c_list_is_empty (&priv->delete_volatile_connection_lst_head));
+
 	g_signal_handlers_disconnect_by_func (priv->platform,
 	                                      G_CALLBACK (platform_link_cb),
 	                                      self);
@@ -6835,18 +6814,14 @@ dispose (GObject *object)
 		g_slice_free (PlatformLinkCbData, data);
 	}
 
-	g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_destroy);
+	g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref);
 	priv->auth_chains = NULL;
 
 	nm_clear_g_source (&priv->devices_inited_id);
 
-	g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_free);
-
-	if (priv->concheck_mgr) {
-		g_signal_handlers_disconnect_by_func (priv->concheck_mgr,
-		                                      G_CALLBACK (concheck_config_changed_cb),
-		                                      self);
-		g_clear_object (&priv->concheck_mgr);
+	if (priv->checkpoint_mgr) {
+		nm_checkpoint_manager_destroy_all (priv->checkpoint_mgr, NULL);
+		g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_unref);
 	}
 
 	if (priv->auth_mgr) {
@@ -6856,7 +6831,7 @@ dispose (GObject *object)
 		g_clear_object (&priv->auth_mgr);
 	}
 
-	nm_assert (c_list_is_empty (&priv->devices_lst_head));
+	g_assert (priv->devices == NULL);
 
 	nm_clear_g_source (&priv->ac_cleanup_id);
 
@@ -6893,6 +6868,13 @@ dispose (GObject *object)
 
 	g_clear_object (&priv->vpn_manager);
 
+	/* Unregister property filter */
+	if (priv->dbus_mgr) {
+		g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self);
+		g_clear_object (&priv->dbus_mgr);
+	}
+	_set_prop_filter (self, NULL);
+
 	sleep_devices_clear (self);
 	g_clear_pointer (&priv->sleep_devices, g_hash_table_unref);
 
@@ -6915,11 +6897,6 @@ dispose (GObject *object)
 		g_clear_object (&priv->rfkill_mgr);
 	}
 
-	nm_clear_g_source (&priv->delete_volatile_connection_idle_id);
-	_delete_volatile_connection_all (self, FALSE);
-	nm_assert (!priv->delete_volatile_connection_idle_id);
-	nm_assert (c_list_is_empty (&priv->delete_volatile_connection_lst_head));
-
 	nm_device_factory_manager_for_each_factory (_deinit_device_factory, self);
 
 	nm_clear_g_source (&priv->timestamp_update_id);
@@ -6941,274 +6918,22 @@ finalize (GObject *object)
 	g_object_unref (priv->platform);
 }
 
-static const GDBusSignalInfo signal_info_check_permissions = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
-	"CheckPermissions",
-);
-
-static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
-	"StateChanged",
-	.args = NM_DEFINE_GDBUS_ARG_INFOS (
-		NM_DEFINE_GDBUS_ARG_INFO ("state", "u"),
-	),
-);
-
-static const GDBusSignalInfo signal_info_device_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
-	"DeviceAdded",
-	.args = NM_DEFINE_GDBUS_ARG_INFOS (
-		NM_DEFINE_GDBUS_ARG_INFO ("device_path", "o"),
-	),
-);
-
-static const GDBusSignalInfo signal_info_device_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
-	"DeviceRemoved",
-	.args = NM_DEFINE_GDBUS_ARG_INFOS (
-		NM_DEFINE_GDBUS_ARG_INFO ("device_path", "o"),
-	),
-);
-
-static const NMDBusInterfaceInfoExtended interface_info_manager = {
-	.parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (
-		NM_DBUS_INTERFACE,
-		.methods = NM_DEFINE_GDBUS_METHOD_INFOS (
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"Reload",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("flags", "u"),
-					),
-				),
-				.handle = impl_manager_reload,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"GetDevices",
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("devices", "ao"),
-					),
-				),
-				.handle = impl_manager_get_devices,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"GetAllDevices",
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("devices", "ao"),
-					),
-				),
-				.handle = impl_manager_get_all_devices,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"GetDeviceByIpIface",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("iface", "s"),
-					),
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("device", "o"),
-					),
-				),
-				.handle = impl_manager_get_device_by_ip_iface,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"ActivateConnection",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("connection",      "o"),
-						NM_DEFINE_GDBUS_ARG_INFO ("device",          "o"),
-						NM_DEFINE_GDBUS_ARG_INFO ("specific_object", "o"),
-					),
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("active_connection", "o"),
-					),
-				),
-				.handle = impl_manager_activate_connection,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"AddAndActivateConnection",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("connection",      "a{sa{sv}}"),
-						NM_DEFINE_GDBUS_ARG_INFO ("device",          "o"),
-						NM_DEFINE_GDBUS_ARG_INFO ("specific_object", "o"),
-					),
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("path",              "o"),
-						NM_DEFINE_GDBUS_ARG_INFO ("active_connection", "o"),
-					),
-				),
-				.handle = impl_manager_add_and_activate_connection,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"DeactivateConnection",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("active_connection", "o"),
-					),
-				),
-				.handle = impl_manager_deactivate_connection,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"Sleep",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("sleep", "b"),
-					),
-				),
-				.handle = impl_manager_sleep,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"Enable",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("enable", "b"),
-					),
-				),
-				.handle = impl_manager_enable,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"GetPermissions",
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("permissions", "a{ss}"),
-					),
-				),
-				.handle = impl_manager_get_permissions,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"SetLogging",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("level",   "s"),
-						NM_DEFINE_GDBUS_ARG_INFO ("domains", "s"),
-					),
-				),
-				.handle = impl_manager_set_logging,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"GetLogging",
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("level",   "s"),
-						NM_DEFINE_GDBUS_ARG_INFO ("domains", "s"),
-					),
-				),
-				.handle = impl_manager_get_logging,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"CheckConnectivity",
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("connectivity", "u"),
-					),
-				),
-				.handle = impl_manager_check_connectivity,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"state",
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("state", "u"),
-					),
-				),
-				.handle = impl_manager_state,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"CheckpointCreate",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("devices",          "ao"),
-						NM_DEFINE_GDBUS_ARG_INFO ("rollback_timeout", "u"),
-						NM_DEFINE_GDBUS_ARG_INFO ("flags",            "u"),
-					),
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"),
-					),
-				),
-				.handle = impl_manager_checkpoint_create,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"CheckpointDestroy",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"),
-					),
-				),
-				.handle = impl_manager_checkpoint_destroy,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"CheckpointRollback",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"),
-					),
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("result", "a{su}"),
-					),
-				),
-				.handle = impl_manager_checkpoint_rollback,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"CheckpointAdjustRollbackTimeout",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"),
-						NM_DEFINE_GDBUS_ARG_INFO ("add_timeout", "u"),
-					),
-				),
-				.handle = impl_manager_checkpoint_adjust_rollback_timeout,
-			),
-		),
-		.signals = NM_DEFINE_GDBUS_SIGNAL_INFOS (
-			&nm_signal_info_property_changed_legacy,
-			&signal_info_check_permissions,
-			&signal_info_state_changed,
-			&signal_info_device_added,
-			&signal_info_device_removed,
-		),
-		.properties = NM_DEFINE_GDBUS_PROPERTY_INFOS (
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("Devices",                    "ao",    NM_MANAGER_DEVICES),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("AllDevices",                 "ao",    NM_MANAGER_ALL_DEVICES),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("Checkpoints",                "ao",    NM_MANAGER_CHECKPOINTS),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("NetworkingEnabled",          "b",     NM_MANAGER_NETWORKING_ENABLED),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("WirelessEnabled",            "b",     NM_MANAGER_WIRELESS_ENABLED,              NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI,               NM_AUDIT_OP_RADIO_CONTROL),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("WirelessHardwareEnabled",    "b",     NM_MANAGER_WIRELESS_HARDWARE_ENABLED),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("WwanEnabled",                "b",     NM_MANAGER_WWAN_ENABLED,                  NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN,               NM_AUDIT_OP_RADIO_CONTROL),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("WwanHardwareEnabled",        "b",     NM_MANAGER_WWAN_HARDWARE_ENABLED),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("WimaxEnabled",               "b",     NM_MANAGER_WIMAX_ENABLED,                 NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX,              NM_AUDIT_OP_RADIO_CONTROL),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("WimaxHardwareEnabled",       "b",     NM_MANAGER_WIMAX_HARDWARE_ENABLED),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("ActiveConnections",          "ao",    NM_MANAGER_ACTIVE_CONNECTIONS),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("PrimaryConnection",          "o",     NM_MANAGER_PRIMARY_CONNECTION),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("PrimartConnectionType",      "s",     NM_MANAGER_PRIMARY_CONNECTION_TYPE),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("Metered",                    "u",     NM_MANAGER_METERED),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("ActivatingConnection",       "o",     NM_MANAGER_ACTIVATING_CONNECTION),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("Startup",                    "b",     NM_MANAGER_STARTUP),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("Version",                    "s",     NM_MANAGER_VERSION),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("Capabilities",               "u",     NM_MANAGER_CAPABILITIES),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("State",                      "u",     NM_MANAGER_STATE),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("Connectivity",               "u",     NM_MANAGER_CONNECTIVITY),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L     ("ConnectivityCheckAvailable", "b",     NM_MANAGER_CONNECTIVITY_CHECK_AVAILABLE),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("ConnectivityCheckEnabled",   "b",     NM_MANAGER_CONNECTIVITY_CHECK_ENABLED,    NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK, NM_AUDIT_OP_NET_CONTROL),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("GlobalDnsConfiguration",     "a{sv}", NM_MANAGER_GLOBAL_DNS_CONFIGURATION,      NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS,        NM_AUDIT_OP_NET_CONTROL),
-		),
-	),
-	.legacy_property_changed = TRUE,
-};
-
 static void
 nm_manager_class_init (NMManagerClass *manager_class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
-	NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (manager_class);
+	NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (manager_class);
 
-	dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_STATIC (NM_DBUS_PATH);
-	dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_manager);
+	exported_object_class->export_path = NM_DBUS_PATH;
 
+	/* virtual methods */
 	object_class->constructed = constructed;
 	object_class->set_property = set_property;
 	object_class->get_property = get_property;
 	object_class->dispose = dispose;
 	object_class->finalize = finalize;
 
+	/* properties */
 	obj_properties[PROP_VERSION] =
 	    g_param_spec_string (NM_MANAGER_VERSION, "", "",
 	                         NULL,
@@ -7216,11 +6941,11 @@ nm_manager_class_init (NMManagerClass *manager_class)
 	                         G_PARAM_STATIC_STRINGS);
 
 	obj_properties[PROP_CAPABILITIES] =
-	    g_param_spec_variant (NM_MANAGER_CAPABILITIES, "", "",
-	                          G_VARIANT_TYPE ("au"),
-	                          NULL,
-	                          G_PARAM_READABLE |
-	                          G_PARAM_STATIC_STRINGS);
+		g_param_spec_variant (NM_MANAGER_CAPABILITIES, "", "",
+		                      G_VARIANT_TYPE ("au"),
+		                      NULL,
+		                      G_PARAM_READABLE |
+		                      G_PARAM_STATIC_STRINGS);
 
 	obj_properties[PROP_STATE] =
 	    g_param_spec_uint (NM_MANAGER_STATE, "", "",
@@ -7371,17 +7096,11 @@ nm_manager_class_init (NMManagerClass *manager_class)
 	                        G_PARAM_READABLE |
 	                        G_PARAM_STATIC_STRINGS);
 
-	obj_properties[PROP_CHECKPOINTS] =
-	    g_param_spec_boxed (NM_MANAGER_CHECKPOINTS, "", "",
-	                        G_TYPE_STRV,
-	                        G_PARAM_READABLE |
-	                        G_PARAM_STATIC_STRINGS);
-
 	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	/* signals */
 
-	/* emitted only for realized devices */
+	/* D-Bus exported; emitted only for realized devices */
 	signals[DEVICE_ADDED] =
 	    g_signal_new (NM_MANAGER_DEVICE_ADDED,
 	                  G_OBJECT_CLASS_TYPE (object_class),
@@ -7397,7 +7116,7 @@ nm_manager_class_init (NMManagerClass *manager_class)
 	                  NULL, NULL, NULL,
 	                  G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
-	/* emitted only for realized devices when a device
+	/* D-Bus exported; emitted only for realized devices when a device
 	 * becomes unrealized or removed */
 	signals[DEVICE_REMOVED] =
 	    g_signal_new (NM_MANAGER_DEVICE_REMOVED,
@@ -7414,6 +7133,20 @@ nm_manager_class_init (NMManagerClass *manager_class)
 	                  NULL, NULL, NULL,
 	                  G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
+	signals[STATE_CHANGED] =
+	    g_signal_new (NM_MANAGER_STATE_CHANGED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL, NULL,
+	                  G_TYPE_NONE, 1, G_TYPE_UINT);
+
+	signals[CHECK_PERMISSIONS] =
+	    g_signal_new (NM_MANAGER_CHECK_PERMISSIONS,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL, NULL,
+	                  G_TYPE_NONE, 0);
+
 	signals[ACTIVE_CONNECTION_ADDED] =
 	    g_signal_new (NM_MANAGER_ACTIVE_CONNECTION_ADDED,
 	                  G_OBJECT_CLASS_TYPE (object_class),
@@ -7434,4 +7167,25 @@ nm_manager_class_init (NMManagerClass *manager_class)
 	                  G_SIGNAL_RUN_FIRST,
 	                  0, NULL, NULL, NULL,
 	                  G_TYPE_NONE, 0);
+
+	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (manager_class),
+	                                        NMDBUS_TYPE_MANAGER_SKELETON,
+	                                        "Reload", impl_manager_reload,
+	                                        "GetDevices", impl_manager_get_devices,
+	                                        "GetAllDevices", impl_manager_get_all_devices,
+	                                        "GetDeviceByIpIface", impl_manager_get_device_by_ip_iface,
+	                                        "ActivateConnection", impl_manager_activate_connection,
+	                                        "AddAndActivateConnection", impl_manager_add_and_activate_connection,
+	                                        "DeactivateConnection", impl_manager_deactivate_connection,
+	                                        "Sleep", impl_manager_sleep,
+	                                        "Enable", impl_manager_enable,
+	                                        "GetPermissions", impl_manager_get_permissions,
+	                                        "SetLogging", impl_manager_set_logging,
+	                                        "GetLogging", impl_manager_get_logging,
+	                                        "CheckConnectivity", impl_manager_check_connectivity,
+	                                        "state", impl_manager_get_state,
+	                                        "CheckpointCreate", impl_manager_checkpoint_create,
+	                                        "CheckpointDestroy", impl_manager_checkpoint_destroy,
+	                                        "CheckpointRollback", impl_manager_checkpoint_rollback,
+	                                        NULL);
 }