about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2015-12-24 00:24:58 +0100
committerMichael Biebl <biebl@debian.org>2015-12-24 00:24:58 +0100
commit54f6333410ffd570e62717d9e77c5c987175e397 (patch)
treed0698cc29d0f53c0b6d2c68d35ee2e9d72153948 /src
parenta6ece1a2aa19a6268335c87d4fdef20123dd04a5 (diff)
Imported Upstream version 1.0.10 upstream/1.0.10
Diffstat (limited to 'src')
-rw-r--r--src/devices/adsl/nm-atm-manager.c38
-rw-r--r--src/devices/adsl/nm-device-adsl.c383
-rw-r--r--src/devices/adsl/nm-device-adsl.h6
-rw-r--r--src/devices/nm-device-ethernet.c2
-rw-r--r--src/devices/nm-device-vlan.c12
-rw-r--r--src/devices/nm-device.c4
-rw-r--r--src/devices/wifi/nm-device-wifi.c40
-rw-r--r--src/dhcp-manager/nm-dhcp-helper.c4
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.c11
-rw-r--r--src/dhcp-manager/nm-dhcp-utils.c6
-rw-r--r--src/dns-manager/nm-dns-manager.c13
-rw-r--r--src/main-utils.c7
-rw-r--r--src/main.c28
-rw-r--r--src/nm-firewall-manager.c13
-rw-r--r--src/nm-iface-helper.c7
-rw-r--r--src/nm-ip4-config.c34
-rw-r--r--src/nm-ip6-config.c26
-rw-r--r--src/nm-manager.c14
-rw-r--r--src/nm-policy.c4
-rw-r--r--src/nm-sleep-monitor-systemd.c12
-rw-r--r--src/nm-sleep-monitor-upower.c12
-rw-r--r--src/platform/nm-linux-platform.c140
-rw-r--r--src/platform/tests/Makefile.am8
-rw-r--r--src/platform/tests/Makefile.in62
-rw-r--r--src/platform/tests/dump.c139
-rw-r--r--src/platform/tests/monitor.c22
-rw-r--r--src/platform/tests/platform.c902
-rw-r--r--src/platform/tests/test-link.c6
-rw-r--r--src/ppp-manager/nm-ppp-manager.c3
-rw-r--r--src/settings/nm-agent-manager.c84
-rw-r--r--src/settings/nm-inotify-helper.c43
-rw-r--r--src/settings/nm-settings-connection.c2
-rw-r--r--src/settings/nm-settings.c2
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.c14
-rw-r--r--src/tests/test-ip4-config.c22
-rw-r--r--src/tests/test-ip6-config.c22
-rw-r--r--src/vpn-manager/nm-vpn-connection.c5
-rw-r--r--src/vpn-manager/nm-vpn-manager.c14
38 files changed, 574 insertions, 1592 deletions
diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c
index 0830f85d..aeb5af6c 100644
--- a/src/devices/adsl/nm-atm-manager.c
+++ b/src/devices/adsl/nm-atm-manager.c
@@ -30,6 +30,8 @@
 #include "nm-device-factory.h"
 #include "nm-logging.h"
 #include "nm-glib-compat.h"
+#include "nm-platform.h"
+#include "gsystem-local-alloc.h"
 
 typedef struct {
 	GUdevClient *client;
@@ -103,6 +105,8 @@ adsl_add (NMAtmManager *self, GUdevDevice *udev_device)
 	NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self);
 	const char *ifname, *sysfs_path = NULL;
 	char *driver = NULL;
+	gs_free char *atm_index_path = NULL;
+	int atm_index;
 	NMDevice *device;
 
 	g_return_if_fail (udev_device != NULL);
@@ -115,20 +119,34 @@ adsl_add (NMAtmManager *self, GUdevDevice *udev_device)
 
 	nm_log_dbg (LOGD_HW, "(%s): found ATM device", ifname);
 
-	if (dev_get_attrs (udev_device, &sysfs_path, &driver)) {
-		g_assert (sysfs_path);
+	atm_index_path = g_strdup_printf ("/sys/class/atm/%s/atmindex",
+	                                  ASSERT_VALID_PATH_COMPONENT (ifname));
+	atm_index = (int) nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET,
+	                                                      atm_index_path,
+	                                                      10, 0, G_MAXINT,
+	                                                      -1);
+	if (atm_index < 0) {
+		nm_log_warn (LOGD_HW, "(%s): failed to get ATM index", ifname);
+		return;
+	}
 
-		device = nm_device_adsl_new (sysfs_path, ifname, driver);
-		g_assert (device);
+	if (!dev_get_attrs (udev_device, &sysfs_path, &driver)) {
+		nm_log_warn (LOGD_HW, "(%s): failed to get ATM attributes", ifname);
+		return;
+	}
 
-		priv->devices = g_slist_prepend (priv->devices, device);
-		g_object_weak_ref (G_OBJECT (device), device_destroyed, self);
+	g_assert (sysfs_path);
 
-		g_signal_emit_by_name (self, NM_DEVICE_FACTORY_DEVICE_ADDED, device);
-		g_object_unref (device);
+	device = nm_device_adsl_new (sysfs_path, ifname, driver, atm_index);
+	g_assert (device);
 
-		g_free (driver);
-	}
+	priv->devices = g_slist_prepend (priv->devices, device);
+	g_object_weak_ref (G_OBJECT (device), device_destroyed, self);
+
+	g_signal_emit_by_name (self, NM_DEVICE_FACTORY_DEVICE_ADDED, device);
+	g_object_unref (device);
+
+	g_free (driver);
 }
 
 static void
diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c
index 4d2cac5b..bcef39a2 100644
--- a/src/devices/adsl/nm-device-adsl.c
+++ b/src/devices/adsl/nm-device-adsl.c
@@ -55,10 +55,16 @@ G_DEFINE_TYPE (NMDeviceAdsl, nm_device_adsl, NM_TYPE_DEVICE)
 
 #define NM_DEVICE_ADSL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_ADSL, NMDeviceAdslPrivate))
 
+enum {
+	PROP_0,
+	PROP_ATM_INDEX,
+
+	LAST_PROP
+};
+
 /**********************************************/
 
 typedef struct {
-	gboolean      disposed;
 	guint         carrier_poll_id;
 	int           atm_index;
 
@@ -69,6 +75,8 @@ typedef struct {
 	int           brfd;
 	int           nas_ifindex;
 	char *        nas_ifname;
+	guint         nas_update_id;
+	guint         nas_update_count;
 } NMDeviceAdslPrivate;
 
 /**************************************************************/
@@ -136,76 +144,6 @@ complete_connection (NMDevice *device,
 
 /**************************************************************/
 
-static void
-set_nas_iface (NMDeviceAdsl *self, int idx, const char *name)
-{
-	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
-
-	g_return_if_fail (name != NULL);
-
-	g_warn_if_fail (priv->nas_ifindex <= 0);
-	priv->nas_ifindex = idx > 0 ? idx : nm_platform_link_get_ifindex (NM_PLATFORM_GET, name);
-	g_warn_if_fail (priv->nas_ifindex > 0);
-
-	g_warn_if_fail (priv->nas_ifname == NULL);
-	priv->nas_ifname = g_strdup (name);
-}
-
-static gboolean
-br2684_create_iface (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
-{
-	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
-	struct atm_newif_br2684 ni;
-	int err, fd, errsv;
-	gboolean success = FALSE;
-	guint num = 0;
-
-	g_return_val_if_fail (s_adsl != NULL, FALSE);
-
-	fd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
-	if (fd < 0) {
-		errsv = errno;
-		_LOGE (LOGD_ADSL, "failed to open ATM control socket (%d)", errsv);
-		return FALSE;
-	}
-
-	memset (&ni, 0, sizeof (ni));
-	ni.backend_num = ATM_BACKEND_BR2684;
-	ni.media = BR2684_MEDIA_ETHERNET;
-	ni.mtu = 1500;
-
-	/* Loop attempting to create an interface that doesn't exist yet.  The
-	 * kernel can create one for us automatically, but due to API issues it
-	 * cannot return that name to us.  Since we want to know the name right
-	 * away, just brute-force it.
-	 */
-	while (num < 10000) {
-		memset (&ni.ifname, 0, sizeof (ni.ifname));
-		g_snprintf (ni.ifname, sizeof (ni.ifname), "nas%d", num);
-
-		err = ioctl (fd, ATM_NEWBACKENDIF, &ni);
-		if (err == 0) {
-			set_nas_iface (self, -1, ni.ifname);
-			_LOGI (LOGD_ADSL, "using NAS interface %s (%d)",
-			       priv->nas_ifname, priv->nas_ifindex);
-			success = TRUE;
-			break;
-		} else {
-			errsv = errno;
-			if (errsv == -EEXIST) {
-				/* Try again */
-				num++;
-			} else {
-				_LOGW (LOGD_ADSL, "failed to create br2684 interface (%d)", errsv);
-				break;
-			}
-		}
-	}
-
-	close (fd);
-	return success;
-}
-
 static gboolean
 br2684_assign_vcc (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
 {
@@ -295,7 +233,13 @@ error:
 }
 
 static void
-link_changed_cb (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *info, NMPlatformSignalChangeType change_type, NMPlatformReason reason, NMDeviceAdsl *self)
+link_changed_cb (NMPlatform *platform,
+                 NMPObjectType obj_type,
+                 int ifindex,
+                 NMPlatformLink *info,
+                 NMPlatformSignalChangeType change_type,
+                 NMPlatformReason reason,
+                 NMDeviceAdsl *self)
 {
 	if (change_type == NM_PLATFORM_SIGNAL_REMOVED) {
 		NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
@@ -303,9 +247,9 @@ link_changed_cb (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPl
 
 		/* This only gets called for PPPoE connections and "nas" interfaces */
 
-		if (priv->nas_ifindex >= 0 && ifindex == priv->nas_ifindex) {
+		if (priv->nas_ifindex > 0 && ifindex == priv->nas_ifindex) {
 				/* NAS device went away for some reason; kill the connection */
-				_LOGD (LOGD_ADSL, "NAS interface disappeared");
+				_LOGD (LOGD_ADSL, "br2684 interface disappeared");
 				nm_device_state_changed (device,
 				                         NM_DEVICE_STATE_FAILED,
 				                         NM_DEVICE_STATE_REASON_BR2684_FAILED);
@@ -313,11 +257,140 @@ link_changed_cb (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPl
 	}
 }
 
+static gboolean
+pppoe_vcc_config (NMDeviceAdsl *self)
+{
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	NMDevice *device = NM_DEVICE (self);
+	NMSettingAdsl *s_adsl;
+
+	s_adsl = nm_connection_get_setting_adsl (nm_device_get_connection (device));
+	g_assert (s_adsl);
+
+	/* Set up the VCC */
+	if (!br2684_assign_vcc (self, s_adsl))
+		return FALSE;
+
+	/* Watch for the 'nas' interface going away */
+	g_signal_connect (nm_platform_get (), NM_PLATFORM_SIGNAL_LINK_CHANGED,
+	                  G_CALLBACK (link_changed_cb),
+	                  self);
+
+	_LOGD (LOGD_ADSL, "ATM setup successful");
+
+	/* otherwise we're good for stage3 */
+	nm_platform_link_set_up (NM_PLATFORM_GET, priv->nas_ifindex, NULL);
+
+	return TRUE;
+}
+
+static gboolean
+nas_update_cb (gpointer user_data)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (user_data);
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	NMDevice *device = NM_DEVICE (self);
+
+	g_assert (priv->nas_ifname);
+
+	priv->nas_update_count++;
+
+	if (priv->nas_update_count > 10) {
+		priv->nas_update_id = 0;
+		_LOGW (LOGD_ADSL, "failed to find br2684 interface %s ifindex after timeout", priv->nas_ifname);
+		nm_device_state_changed (device,
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_BR2684_FAILED);
+		return G_SOURCE_REMOVE;
+	}
+
+	g_warn_if_fail (priv->nas_ifindex < 0);
+	priv->nas_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->nas_ifname);
+	if (priv->nas_ifindex < 0) {
+		/* Keep waiting for it to appear */
+		return G_SOURCE_CONTINUE;
+	}
+
+	priv->nas_update_id = 0;
+	_LOGD (LOGD_ADSL, "using br2684 iface '%s' index %d", priv->nas_ifname, priv->nas_ifindex);
+
+	if (pppoe_vcc_config (self)) {
+		nm_device_activate_schedule_stage3_ip_config_start (device);
+	} else {
+		nm_device_state_changed (device,
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_BR2684_FAILED);
+	}
+
+	return G_SOURCE_REMOVE;
+}
+
+static NMActStageReturn
+br2684_create_iface (NMDeviceAdsl *self,
+                     NMSettingAdsl *s_adsl,
+                     NMDeviceStateReason *out_reason)
+{
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	struct atm_newif_br2684 ni;
+	int err, fd, errsv;
+	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
+	guint num = 0;
+
+	g_return_val_if_fail (s_adsl != NULL, FALSE);
+
+	if (priv->nas_update_id) {
+		g_warn_if_fail (priv->nas_update_id == 0);
+		nm_clear_g_source (&priv->nas_update_id);
+	}
+
+	fd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
+	if (fd < 0) {
+		errsv = errno;
+		_LOGE (LOGD_ADSL, "failed to open ATM control socket (%d)", errsv);
+		*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
+		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
+
+	memset (&ni, 0, sizeof (ni));
+	ni.backend_num = ATM_BACKEND_BR2684;
+	ni.media = BR2684_MEDIA_ETHERNET;
+	ni.mtu = 1500;
+
+	/* Loop attempting to create an interface that doesn't exist yet.  The
+	 * kernel can create one for us automatically, but due to API issues it
+	 * cannot return that name to us.  Since we want to know the name right
+	 * away, just brute-force it.
+	 */
+	while (num < 10000) {
+		memset (&ni.ifname, 0, sizeof (ni.ifname));
+		g_snprintf (ni.ifname, sizeof (ni.ifname), "nas%d", num++);
+
+		err = ioctl (fd, ATM_NEWBACKENDIF, &ni);
+		if (err == 0) {
+			g_free (priv->nas_ifname);
+			priv->nas_ifname = g_strdup (ni.ifname);
+			_LOGD (LOGD_ADSL, "waiting for br2684 iface '%s' to appear", priv->nas_ifname);
+
+			priv->nas_update_count = 0;
+			priv->nas_update_id = g_timeout_add (100, nas_update_cb, self);
+			ret = NM_ACT_STAGE_RETURN_POSTPONE;
+			break;
+		} else if (errno != EEXIST) {
+			errsv = errno;
+			_LOGW (LOGD_ADSL, "failed to create br2684 interface (%d)", errsv);
+			*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
+			break;
+		}
+	}
+
+	close (fd);
+	return ret;
+}
+
 static NMActStageReturn
 act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason)
 {
 	NMDeviceAdsl *self = NM_DEVICE_ADSL (device);
-	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
 	NMSettingAdsl *s_adsl;
 	const char *protocol;
@@ -331,37 +404,14 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason)
 	_LOGD (LOGD_ADSL, "using ADSL protocol '%s'", protocol);
 
 	if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) {
-
 		/* PPPoE needs RFC2684 bridging before we can do PPP over it */
-		if (!br2684_create_iface (self, s_adsl)) {
-			*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
-			goto done;
-		}
-
-		/* Set up the VCC */
-		if (!br2684_assign_vcc (self, s_adsl)) {
-			*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
-			goto done;
-		}
-
-		/* Watch for the 'nas' interface going away */
-		g_signal_connect (nm_platform_get (), NM_PLATFORM_SIGNAL_LINK_CHANGED,
-		                  G_CALLBACK (link_changed_cb),
-		                  self);
-
-		_LOGD (LOGD_ADSL, "ATM setup successful");
-
-		/* otherwise we're good for stage3 */
-		nm_platform_link_set_up (NM_PLATFORM_GET, priv->nas_ifindex, NULL);
-		ret = NM_ACT_STAGE_RETURN_SUCCESS;
-
+		ret = br2684_create_iface (self, s_adsl, out_reason);
 	} else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) {
 		/* PPPoA doesn't need anything special */
 		ret = NM_ACT_STAGE_RETURN_SUCCESS;
 	} else
 		_LOGW (LOGD_ADSL, "unhandled ADSL protocol '%s'", protocol);
 
-done:
 	return ret;
 }
 
@@ -425,7 +475,7 @@ act_stage3_ip4_config_start (NMDevice *device,
 		g_assert (priv->nas_ifname);
 		ppp_iface = priv->nas_ifname;
 
-		_LOGD (LOGD_ADSL, "starting PPPoE on NAS interface %s", priv->nas_ifname);
+		_LOGD (LOGD_ADSL, "starting PPPoE on br2684 interface %s", priv->nas_ifname);
 	} else {
 		ppp_iface = nm_device_get_iface (device);
 		_LOGD (LOGD_ADSL, "starting PPPoA");
@@ -454,31 +504,37 @@ act_stage3_ip4_config_start (NMDevice *device,
 }
 
 static void
-deactivate (NMDevice *device)
+adsl_cleanup (NMDeviceAdsl *self)
 {
-	NMDeviceAdsl *self = NM_DEVICE_ADSL (device);
 	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
 
 	if (priv->ppp_manager) {
-		g_object_unref (priv->ppp_manager);
-		priv->ppp_manager = NULL;
+		g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_state_changed), self);
+		g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_ip4_config), self);
+		g_clear_object (&priv->ppp_manager);
 	}
 
-	g_signal_handlers_disconnect_by_func (nm_platform_get (), G_CALLBACK (link_changed_cb), device);
+	g_signal_handlers_disconnect_by_func (nm_platform_get (), G_CALLBACK (link_changed_cb), self);
 
 	if (priv->brfd >= 0) {
 		close (priv->brfd);
 		priv->brfd = -1;
 	}
 
+	nm_clear_g_source (&priv->nas_update_id);
+
 	/* FIXME: kernel has no way of explicitly deleting the 'nasX' interface yet,
 	 * so it gets leaked.  It does get destroyed when it's no longer in use,
 	 * but we have no control over that.
 	 */
-	if (priv->nas_ifindex >= 0)
-		priv->nas_ifindex = -1;
-	g_free (priv->nas_ifname);
-	priv->nas_ifname = NULL;
+	priv->nas_ifindex = -1;
+	g_clear_pointer (&priv->nas_ifname, g_free);
+}
+
+static void
+deactivate (NMDevice *device)
+{
+	adsl_cleanup (NM_DEVICE_ADSL (device));
 }
 
 /**************************************************************/
@@ -505,89 +561,74 @@ carrier_update_cb (gpointer user_data)
 NMDevice *
 nm_device_adsl_new (const char *udi,
                     const char *iface,
-                    const char *driver)
+                    const char *driver,
+                    int atm_index)
 {
 	g_return_val_if_fail (udi != NULL, NULL);
+	g_return_val_if_fail (atm_index >= 0, NULL);
 
 	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ADSL,
 	                                  NM_DEVICE_UDI, udi,
 	                                  NM_DEVICE_IFACE, iface,
 	                                  NM_DEVICE_DRIVER, driver,
+	                                  NM_DEVICE_ADSL_ATM_INDEX, atm_index,
 	                                  NM_DEVICE_TYPE_DESC, "ADSL",
 	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ADSL,
 	                                  NULL);
 }
 
-static int
-get_atm_index (const char *iface)
+static void
+constructed (GObject *object)
 {
-	char *path;
-	int idx;
-
-	path = g_strdup_printf ("/sys/class/atm/%s/atmindex",
-	                        ASSERT_VALID_PATH_COMPONENT (iface));
-	idx = (int) nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET, path, 10, 0, G_MAXINT, -1);
-	g_free (path);
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (object);
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
 
-	return idx;
-}
+	G_OBJECT_CLASS (nm_device_adsl_parent_class)->constructed (object);
 
-static GObject*
-constructor (GType type,
-			 guint n_construct_params,
-			 GObjectConstructParam *construct_params)
-{
-	GObject *object;
-	NMDeviceAdsl *self;
-	NMDeviceAdslPrivate *priv;
-
-	object = G_OBJECT_CLASS (nm_device_adsl_parent_class)->constructor (type,
-	                                                                    n_construct_params,
-	                                                                    construct_params);
-	if (!object)
-		return NULL;
-
-	self = NM_DEVICE_ADSL (object);
-	priv = NM_DEVICE_ADSL_GET_PRIVATE (object);
-
-	priv->atm_index = get_atm_index (nm_device_get_iface (NM_DEVICE (object)));
-	if (priv->atm_index < 0) {
-		_LOGE (LOGD_ADSL, "error reading ATM device index");
-		g_object_unref (object);
-		return NULL;
-	} else
-		_LOGD (LOGD_ADSL, "ATM device index %d", priv->atm_index);
+	priv->carrier_poll_id = g_timeout_add_seconds (5, carrier_update_cb, self);
 
-	/* Poll the carrier */
-	priv->carrier_poll_id = g_timeout_add_seconds (5, carrier_update_cb, object);
+	_LOGD (LOGD_ADSL, "ATM device index %d", priv->atm_index);
 
-	return object;
+	g_return_if_fail (priv->atm_index >= 0);
 }
 
 static void
 dispose (GObject *object)
 {
-	NMDeviceAdsl *self = NM_DEVICE_ADSL (object);
-	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	adsl_cleanup (NM_DEVICE_ADSL (object));
 
-	if (priv->disposed) {
-		G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object);
-		return;
-	}
+	nm_clear_g_source (&NM_DEVICE_ADSL_GET_PRIVATE (object)->carrier_poll_id);
 
-	priv->disposed = TRUE;
+	G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object);
+}
 
-	if (priv->carrier_poll_id) {
-		g_source_remove (priv->carrier_poll_id);
-		priv->carrier_poll_id = 0;
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	case PROP_ATM_INDEX:
+		g_value_set_int (value, NM_DEVICE_ADSL_GET_PRIVATE (object)->atm_index);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
 	}
+}
 
-	g_signal_handlers_disconnect_by_func (nm_platform_get (), G_CALLBACK (link_changed_cb), self);
-
-	g_free (priv->nas_ifname);
-	priv->nas_ifname = NULL;
-
-	G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object);
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	case PROP_ATM_INDEX:
+		/* construct only */
+		NM_DEVICE_ADSL_GET_PRIVATE (object)->atm_index = g_value_get_int (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -603,8 +644,10 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass)
 
 	g_type_class_add_private (object_class, sizeof (NMDeviceAdslPrivate));
 
-	object_class->constructor  = constructor;
+	object_class->constructed  = constructed;
 	object_class->dispose      = dispose;
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 
 	parent_class->get_generic_capabilities = get_generic_capabilities;
 
@@ -615,6 +658,14 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass)
 	parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start;
 	parent_class->deactivate = deactivate;
 
+	/* properties */
+	g_object_class_install_property
+		(object_class, PROP_ATM_INDEX,
+		 g_param_spec_int (NM_DEVICE_ADSL_ATM_INDEX, "", "",
+		                   -1, G_MAXINT, -1,
+		                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+		                   G_PARAM_STATIC_STRINGS));
+
 	nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
 	                                        G_TYPE_FROM_CLASS (klass),
 	                                        &dbus_glib_nm_device_adsl_object_info);
diff --git a/src/devices/adsl/nm-device-adsl.h b/src/devices/adsl/nm-device-adsl.h
index f21381c2..bf41ed79 100644
--- a/src/devices/adsl/nm-device-adsl.h
+++ b/src/devices/adsl/nm-device-adsl.h
@@ -36,20 +36,22 @@ G_BEGIN_DECLS
 #define NM_IS_DEVICE_ADSL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_ADSL))
 #define NM_DEVICE_ADSL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass))
 
+#define NM_DEVICE_ADSL_ATM_INDEX "atm-index"
+
 typedef struct {
 	NMDevice parent;
 } NMDeviceAdsl;
 
 typedef struct {
 	NMDeviceClass parent;
-
 } NMDeviceAdslClass;
 
 GType nm_device_adsl_get_type (void);
 
 NMDevice *nm_device_adsl_new (const char *udi,
                               const char *iface,
-                              const char *driver);
+                              const char *driver,
+                              int atm_index);
 
 G_END_DECLS
 
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 8a023843..2dda84b3 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -883,7 +883,7 @@ nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason)
 	}
 
 	if (!priv->supplicant.mgr)
-		priv->supplicant.mgr = nm_supplicant_manager_get ();
+		priv->supplicant.mgr = g_object_ref (nm_supplicant_manager_get ());
 
 	/* If we need secrets, get them */
 	setting_name = nm_connection_need_secrets (connection, NULL);
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index b330397f..7cce6593 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -96,7 +96,7 @@ parent_hwaddr_changed (NMDevice *parent,
 	NMDeviceVlan *self = NM_DEVICE_VLAN (user_data);
 	NMConnection *connection;
 	NMSettingWired *s_wired;
-	const char *cloned_mac = NULL;
+	const char *cloned_mac = NULL, *new_mac;
 
 	/* Never touch assumed devices */
 	if (nm_device_uses_assumed_connection (self))
@@ -112,9 +112,13 @@ parent_hwaddr_changed (NMDevice *parent,
 		cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
 
 	if (!cloned_mac) {
-		_LOGD (LOGD_VLAN, "parent hardware address changed");
-		nm_device_set_hw_addr (self, nm_device_get_hw_address (parent),
-		                       "set", LOGD_VLAN);
+		new_mac = nm_device_get_hw_address (parent);
+		_LOGD (LOGD_VLAN, "parent hardware address changed to %s%s%s",
+		       NM_PRINT_FMT_QUOTE_STRING (new_mac));
+		if (new_mac) {
+			nm_device_set_hw_addr (self, nm_device_get_hw_address (parent),
+			                       "set", LOGD_VLAN);
+		}
 	}
 }
 
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 9b69d5ab..bb39ca55 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -7007,7 +7007,7 @@ nm_device_start_ip_check (NMDevice *self)
 		if (priv->ip4_config && priv->ip4_state == IP_DONE) {
 			guint gw = 0;
 
-			ping_binary = "/usr/bin/ping";
+			ping_binary = nm_utils_find_helper ("ping", "/usr/bin/ping", NULL);
 			log_domain = LOGD_IP4;
 
 			gw = nm_ip4_config_get_gateway (priv->ip4_config);
@@ -7016,7 +7016,7 @@ nm_device_start_ip_check (NMDevice *self)
 		} else if (priv->ip6_config && priv->ip6_state == IP_DONE) {
 			const struct in6_addr *gw = NULL;
 
-			ping_binary = "/usr/bin/ping6";
+			ping_binary = nm_utils_find_helper ("ping6", "/usr/bin/ping6", NULL);
 			log_domain = LOGD_IP6;
 
 			gw = nm_ip6_config_get_gateway (priv->ip6_config);
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 15d41206..1bf64bcc 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -136,6 +136,8 @@ struct _NMDeviceWifiPrivate {
 	guint32           failed_link_count;
 	guint             periodic_source_id;
 	guint             link_timeout_id;
+	guint32           failed_iface_count;
+	guint             reacquire_iface_id;
 
 	NMDeviceWifiCapabilities capabilities;
 };
@@ -217,8 +219,7 @@ constructor (GType type,
 		_LOGI (LOGD_HW | LOGD_WIFI, "driver supports Access Point (AP) mode");
 
 	/* Connect to the supplicant manager */
-	priv->sup_mgr = nm_supplicant_manager_get ();
-	g_assert (priv->sup_mgr);
+	priv->sup_mgr = g_object_ref (nm_supplicant_manager_get ());
 
 	return object;
 }
@@ -1959,6 +1960,15 @@ cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect)
 }
 
 static void
+cleanup_supplicant_failures (NMDeviceWifi *self)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	nm_clear_g_source (&priv->reacquire_iface_id);
+	priv->failed_iface_count = 0;
+}
+
+static void
 wifi_secrets_cb (NMActRequest *req,
                  guint32 call_id,
                  NMConnection *connection,
@@ -2158,6 +2168,24 @@ handle_8021x_or_psk_auth_fail (NMDeviceWifi *self,
 	return handled;
 }
 
+static gboolean
+reacquire_interface_cb (gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+	NMDeviceWifi *self = NM_DEVICE_WIFI (device);
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	priv->reacquire_iface_id = 0;
+	priv->failed_iface_count++;
+
+	_LOGW (LOGD_WIFI, "re-acquiring supplicant interface (#%d).", priv->failed_iface_count);
+
+	if (!priv->sup_iface)
+		supplicant_interface_acquire (self);
+
+	return G_SOURCE_REMOVE;
+}
+
 static void
 supplicant_iface_state_cb (NMSupplicantInterface *iface,
                            guint32 new_state,
@@ -2264,7 +2292,10 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
 		 * ready if the supplicant comes back.
 		 */
 		supplicant_interface_release (self);
-		supplicant_interface_acquire (self);
+		if (priv->failed_iface_count < 5)
+			priv->reacquire_iface_id = g_timeout_add_seconds (10, reacquire_interface_cb, self);
+		else
+			_LOGI (LOGD_DEVICE | LOGD_WIFI, "supplicant interface keeps failing, giving up");
 		break;
 	default:
 		break;
@@ -3061,6 +3092,7 @@ device_state_changed (NMDevice *device,
 		}
 
 		cleanup_association_attempt (self, TRUE);
+		cleanup_supplicant_failures (self);
 		remove_all_aps (self);
 	}
 
@@ -3147,6 +3179,7 @@ set_enabled (NMDevice *device, gboolean enabled)
 		}
 
 		/* Re-initialize the supplicant interface and wait for it to be ready */
+		cleanup_supplicant_failures (self);
 		if (priv->sup_iface)
 			supplicant_interface_release (self);
 		supplicant_interface_acquire (self);
@@ -3201,6 +3234,7 @@ dispose (GObject *object)
 
 	cleanup_association_attempt (self, TRUE);
 	supplicant_interface_release (self);
+	cleanup_supplicant_failures (self);
 
 	g_clear_object (&priv->sup_mgr);
 
diff --git a/src/dhcp-manager/nm-dhcp-helper.c b/src/dhcp-manager/nm-dhcp-helper.c
index 7855f68c..5bcb0e27 100644
--- a/src/dhcp-manager/nm-dhcp-helper.c
+++ b/src/dhcp-manager/nm-dhcp-helper.c
@@ -160,6 +160,10 @@ main (int argc, char *argv[])
 	GDBusConnection *connection;
 	GError *error = NULL;
 
+#if !GLIB_CHECK_VERSION (2, 36, 0)
+	g_type_init ();
+#endif
+
 	connection = g_dbus_connection_new_for_address_sync ("unix:path=" NMRUNDIR "/private-dhcp",
 	                                                     G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 	                                                     NULL, NULL, &error);
diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c
index 20ddefc3..af6ec087 100644
--- a/src/dhcp-manager/nm-dhcp-manager.c
+++ b/src/dhcp-manager/nm-dhcp-manager.c
@@ -373,16 +373,7 @@ nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self,
 
 /***************************************************/
 
-NMDhcpManager *
-nm_dhcp_manager_get (void)
-{
-	static NMDhcpManager *singleton = NULL;
-
-	if (G_UNLIKELY (singleton == NULL))
-		singleton = g_object_new (NM_TYPE_DHCP_MANAGER, NULL);
-	g_assert (singleton);
-	return singleton;
-}
+NM_DEFINE_SINGLETON_GETTER (NMDhcpManager, nm_dhcp_manager_get, NM_TYPE_DHCP_MANAGER);
 
 static void
 nm_dhcp_manager_init (NMDhcpManager *self)
diff --git a/src/dhcp-manager/nm-dhcp-utils.c b/src/dhcp-manager/nm-dhcp-utils.c
index ab7f26d5..75809422 100644
--- a/src/dhcp-manager/nm-dhcp-utils.c
+++ b/src/dhcp-manager/nm-dhcp-utils.c
@@ -479,7 +479,7 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface,
 	str = g_hash_table_lookup (options, "dhcp_lease_time");
 	if (str) {
 		address.lifetime = address.preferred = strtoul (str, NULL, 10);
-		nm_log_info (LOGD_DHCP4, "  lease time %d", address.lifetime);
+		nm_log_info (LOGD_DHCP4, "  lease time %u", address.lifetime);
 	}
 
 	address.source = NM_IP_CONFIG_SOURCE_DHCP;
@@ -623,13 +623,13 @@ nm_dhcp_utils_ip6_config_from_options (const char *iface,
 	str = g_hash_table_lookup (options, "max_life");
 	if (str) {
 		address.lifetime = strtoul (str, NULL, 10);
-		nm_log_info (LOGD_DHCP6, "  valid_lft %d", address.lifetime);
+		nm_log_info (LOGD_DHCP6, "  valid_lft %u", address.lifetime);
 	}
 
 	str = g_hash_table_lookup (options, "preferred_life");
 	if (str) {
 		address.preferred = strtoul (str, NULL, 10);
-		nm_log_info (LOGD_DHCP6, "  preferred_lft %d", address.preferred);
+		nm_log_info (LOGD_DHCP6, "  preferred_lft %u", address.preferred);
 	}
 
 	str = g_hash_table_lookup (options, "ip6_address");
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index f041c29e..c4be7df2 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -1074,18 +1074,7 @@ nm_dns_manager_end_updates (NMDnsManager *mgr, const char *func)
 
 /******************************************************************/
 
-NMDnsManager *
-nm_dns_manager_get (void)
-{
-	static NMDnsManager * singleton = NULL;
-
-	if (!singleton) {
-		singleton = NM_DNS_MANAGER (g_object_new (NM_TYPE_DNS_MANAGER, NULL));
-		g_assert (singleton);
-	}
-
-	return singleton;
-}
+NM_DEFINE_SINGLETON_GETTER (NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER);
 
 static void
 init_resolv_conf_mode (NMDnsManager *self)
diff --git a/src/main-utils.c b/src/main-utils.c
index b0d8df3e..da327c40 100644
--- a/src/main-utils.c
+++ b/src/main-utils.c
@@ -84,8 +84,11 @@ nm_main_utils_setup_signals (GMainLoop *main_loop)
 	signal (SIGPIPE, SIG_IGN);
 
 	g_unix_signal_add (SIGHUP, sighup_handler, GINT_TO_POINTER (SIGHUP));
-	g_unix_signal_add (SIGUSR1, sighup_handler, GINT_TO_POINTER (SIGUSR1));
-	g_unix_signal_add (SIGUSR2, sighup_handler, GINT_TO_POINTER (SIGUSR2));
+	if (nm_glib_check_version (2, 36, 0)) {
+		g_unix_signal_add (SIGUSR1, sighup_handler, GINT_TO_POINTER (SIGUSR1));
+		g_unix_signal_add (SIGUSR2, sighup_handler, GINT_TO_POINTER (SIGUSR2));
+	} else
+		nm_log_warn (LOGD_CORE, "glib-version: cannot handle SIGUSR1 and SIGUSR2 signals. Consider upgrading glib to 2.36.0 or newer");
 	g_unix_signal_add (SIGINT, sigint_handler, main_loop);
 	g_unix_signal_add (SIGTERM, sigterm_handler, main_loop);
 }
diff --git a/src/main.c b/src/main.c
index 53d2cf64..2de36dc1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -46,12 +46,9 @@
 #include "main-utils.h"
 #include "nm-manager.h"
 #include "nm-linux-platform.h"
-#include "nm-dns-manager.h"
 #include "nm-dbus-manager.h"
-#include "nm-supplicant-manager.h"
+#include "nm-device.h"
 #include "nm-dhcp-manager.h"
-#include "nm-firewall-manager.h"
-#include "nm-vpn-manager.h"
 #include "nm-logging.h"
 #include "nm-config.h"
 #include "nm-session-monitor.h"
@@ -293,11 +290,6 @@ main (int argc, char *argv[])
 	gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE;
 	gboolean success = FALSE;
 	NMManager *manager = NULL;
-	gs_unref_object NMVpnManager *vpn_manager = NULL;
-	gs_unref_object NMDnsManager *dns_mgr = NULL;
-	gs_unref_object NMSupplicantManager *sup_mgr = NULL;
-	gs_unref_object NMDhcpManager *dhcp_mgr = NULL;
-	gs_unref_object NMFirewallManager *fw_mgr = NULL;
 	gs_unref_object NMSettings *settings = NULL;
 	gs_unref_object NMConfig *config = NULL;
 	gs_unref_object NMSessionMonitor *session_monitor = NULL;
@@ -483,16 +475,6 @@ main (int argc, char *argv[])
 
 	nm_auth_manager_setup (nm_config_get_auth_polkit (config));
 
-	vpn_manager = nm_vpn_manager_get ();
-	g_assert (vpn_manager != NULL);
-
-	dns_mgr = nm_dns_manager_get ();
-	g_assert (dns_mgr != NULL);
-
-	/* Initialize DHCP manager */
-	dhcp_mgr = nm_dhcp_manager_get ();
-	g_assert (dhcp_mgr != NULL);
-
 	nm_dispatcher_init ();
 
 	settings = nm_settings_new (&error);
@@ -509,14 +491,6 @@ main (int argc, char *argv[])
 	                          wwan_enabled,
 	                          wimax_enabled);
 
-	/* Initialize the supplicant manager */
-	sup_mgr = nm_supplicant_manager_get ();
-	g_assert (sup_mgr != NULL);
-
-	/* Initialize Firewall manager */
-	fw_mgr = nm_firewall_manager_get ();
-	g_assert (fw_mgr != NULL);
-
 	/* Initialize session monitor */
 	session_monitor = nm_session_monitor_get ();
 	g_assert (session_monitor != NULL);
diff --git a/src/nm-firewall-manager.c b/src/nm-firewall-manager.c
index 59520b3b..4d302e9d 100644
--- a/src/nm-firewall-manager.c
+++ b/src/nm-firewall-manager.c
@@ -337,18 +337,7 @@ name_owner_changed (NMDBusManager *dbus_mgr,
 
 /*******************************************************************/
 
-NMFirewallManager *
-nm_firewall_manager_get (void)
-{
-	static NMFirewallManager *singleton = NULL;
-
-	if (G_UNLIKELY (!singleton)) {
-		singleton = NM_FIREWALL_MANAGER (g_object_new (NM_TYPE_FIREWALL_MANAGER, NULL));
-		g_assert (singleton);
-	}
-
-	return singleton;
-}
+NM_DEFINE_SINGLETON_GETTER (NMFirewallManager, nm_firewall_manager_get, NM_TYPE_FIREWALL_MANAGER);
 
 static void
 nm_firewall_manager_init (NMFirewallManager * self)
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 18966c57..25bde8ed 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -327,7 +327,6 @@ int
 main (int argc, char *argv[])
 {
 	char *bad_domains = NULL;
-	gs_unref_object NMDhcpManager *dhcp_mgr = NULL;
 	GError *error = NULL;
 	gboolean wrote_pidfile = FALSE;
 	gs_free char *pidfile = NULL;
@@ -437,11 +436,7 @@ main (int argc, char *argv[])
 	if (global_opt.dhcp4_address) {
 		nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip4_property_path (global_opt.ifname, "promote_secondaries"), "1");
 
-		/* Initialize DHCP manager */
-		dhcp_mgr = nm_dhcp_manager_get ();
-		g_assert (dhcp_mgr != NULL);
-
-		dhcp4_client = nm_dhcp_manager_start_ip4 (dhcp_mgr,
+		dhcp4_client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
 		                                          global_opt.ifname,
 		                                          ifindex,
 		                                          hwaddr,
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 5918f3dc..f625d350 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -876,8 +876,8 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
 
 /**
  * nm_ip4_config_replace:
- * @dst: config from which to remove everything in @src
- * @src: config to remove from @dst
+ * @dst: config to replace with @src content
+ * @src: source config to copy
  * @relevant_changes: return whether there are changes to the
  * destination object that are relevant. This is equal to
  * nm_ip4_config_equal() showing any difference.
@@ -922,7 +922,10 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
 	/* default gateway */
 	if (   src_priv->gateway != dst_priv->gateway
 	    || src_priv->has_gateway != dst_priv->has_gateway) {
-		nm_ip4_config_set_gateway (dst, src_priv->gateway);
+		if (src_priv->has_gateway)
+			nm_ip4_config_set_gateway (dst, src_priv->gateway);
+		else
+			nm_ip4_config_unset_gateway (dst);
 		has_relevant_changes = TRUE;
 	}
 
@@ -1629,16 +1632,31 @@ void
 nm_ip4_config_add_search (NMIP4Config *config, const char *new)
 {
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
-	int i;
+	char *search;
+	size_t len;
 
 	g_return_if_fail (new != NULL);
 	g_return_if_fail (new[0] != '\0');
 
-	for (i = 0; i < priv->searches->len; i++)
-		if (!g_strcmp0 (g_ptr_array_index (priv->searches, i), new))
-			return;
+	search = g_strdup (new);
+
+	/* Remove trailing dot as it has no effect */
+	len = strlen (search);
+	if (search[len - 1] == '.')
+		search[len - 1] = 0;
+
+	if (!search[0]) {
+		g_free (search);
+		return;
+	}
+
+	if (_nm_utils_strv_find_first ((char **) priv->searches->pdata,
+	                               priv->searches->len, search) >= 0) {
+		g_free (search);
+		return;
+	}
 
-	g_ptr_array_add (priv->searches, g_strdup (new));
+	g_ptr_array_add (priv->searches, search);
 	_NOTIFY (config, PROP_SEARCHES);
 }
 
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index ef256231..f68c4339 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -35,6 +35,7 @@
 #include "nm-route-manager.h"
 #include "NetworkManagerUtils.h"
 #include "nm-macros-internal.h"
+#include "nm-core-internal.h"
 
 G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, G_TYPE_OBJECT)
 
@@ -1553,16 +1554,31 @@ void
 nm_ip6_config_add_search (NMIP6Config *config, const char *new)
 {
 	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
-	int i;
+	char *search;
+	size_t len;
 
 	g_return_if_fail (new != NULL);
 	g_return_if_fail (new[0] != '\0');
 
-	for (i = 0; i < priv->searches->len; i++)
-		if (!g_strcmp0 (g_ptr_array_index (priv->searches, i), new))
-			return;
+	search = g_strdup (new);
+
+	/* Remove trailing dot as it has no effect */
+	len = strlen (search);
+	if (search[len - 1] == '.')
+		search[len - 1] = 0;
+
+	if (!search[0]) {
+		g_free (search);
+		return;
+	}
+
+	if (_nm_utils_strv_find_first ((char **) priv->searches->pdata,
+	                               priv->searches->len, search) >= 0) {
+		g_free (search);
+		return;
+	}
 
-	g_ptr_array_add (priv->searches, g_strdup (new));
+	g_ptr_array_add (priv->searches, search);
 	_NOTIFY (config, PROP_SEARCHES);
 }
 
diff --git a/src/nm-manager.c b/src/nm-manager.c
index cc52ea78..a1e4fb4f 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -4880,7 +4880,7 @@ nm_manager_init (NMManager *manager)
 	                  G_CALLBACK (dbus_connection_changed_cb),
 	                  manager);
 
-	priv->vpn_manager = nm_vpn_manager_get ();
+	priv->vpn_manager = g_object_ref (nm_vpn_manager_get ());
 
 	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
 
@@ -4908,10 +4908,10 @@ nm_manager_init (NMManager *manager)
 		nm_log_warn (LOGD_AUTOIP4, "could not initialize avahi-autoipd D-Bus proxy");
 
 	/* sleep/wake handling */
-	priv->sleep_monitor = nm_sleep_monitor_get ();
-	g_signal_connect (priv->sleep_monitor, "sleeping",
+	priv->sleep_monitor = g_object_ref (nm_sleep_monitor_get ());
+	g_signal_connect (priv->sleep_monitor, NM_SLEEP_MONITOR_SLEEPING,
 	                  G_CALLBACK (sleeping_cb), manager);
-	g_signal_connect (priv->sleep_monitor, "resuming",
+	g_signal_connect (priv->sleep_monitor, NM_SLEEP_MONITOR_RESUMING,
 	                  G_CALLBACK (resuming_cb), manager);
 
 	/* Listen for authorization changes */
@@ -5142,7 +5142,11 @@ dispose (GObject *object)
 	}
 
 	g_clear_object (&priv->aipd_proxy);
-	g_clear_object (&priv->sleep_monitor);
+	if (priv->sleep_monitor) {
+		g_signal_handlers_disconnect_by_func (priv->sleep_monitor, sleeping_cb, manager);
+		g_signal_handlers_disconnect_by_func (priv->sleep_monitor, resuming_cb, manager);
+		g_clear_object (&priv->sleep_monitor);
+	}
 
 	if (priv->fw_monitor) {
 		g_signal_handlers_disconnect_by_func (priv->fw_monitor, firmware_dir_changed, manager);
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 1be5c4a3..fc2a9bf7 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -1792,7 +1792,7 @@ nm_policy_new (NMManager *manager, NMSettings *settings)
 	priv->fw_started_id = g_signal_connect (nm_firewall_manager_get (), "started",
 	                                        G_CALLBACK (firewall_started), policy);
 
-	priv->dns_manager = nm_dns_manager_get ();
+	priv->dns_manager = g_object_ref (nm_dns_manager_get ());
 	nm_dns_manager_set_initial_hostname (priv->dns_manager, priv->orig_hostname);
 	priv->config_changed_id = g_signal_connect (priv->dns_manager, "config-changed",
 	                                            G_CALLBACK (dns_config_changed), policy);
@@ -1903,7 +1903,7 @@ dispose (GObject *object)
 
 	if (priv->dns_manager) {
 		g_signal_handler_disconnect (priv->dns_manager, priv->config_changed_id);
-		priv->dns_manager = NULL;
+		g_clear_object (&priv->dns_manager);
 	}
 
 	for (iter = priv->manager_ids; iter; iter = g_slist_next (iter))
diff --git a/src/nm-sleep-monitor-systemd.c b/src/nm-sleep-monitor-systemd.c
index c0bc65e4..44523a4a 100644
--- a/src/nm-sleep-monitor-systemd.c
+++ b/src/nm-sleep-monitor-systemd.c
@@ -243,16 +243,6 @@ nm_sleep_monitor_class_init (NMSleepMonitorClass *klass)
 	                                  G_TYPE_NONE, 0);
 }
 
-NMSleepMonitor *
-nm_sleep_monitor_get (void)
-{
-	static NMSleepMonitor *singleton = NULL;
-
-	if (singleton)
-		return g_object_ref (singleton);
-
-	singleton = NM_SLEEP_MONITOR (g_object_new (NM_TYPE_SLEEP_MONITOR, NULL));
-	return singleton;
-}
+NM_DEFINE_SINGLETON_GETTER (NMSleepMonitor, nm_sleep_monitor_get, NM_TYPE_SLEEP_MONITOR);
 
 /* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/nm-sleep-monitor-upower.c b/src/nm-sleep-monitor-upower.c
index 39cce595..0c46ae10 100644
--- a/src/nm-sleep-monitor-upower.c
+++ b/src/nm-sleep-monitor-upower.c
@@ -133,16 +133,6 @@ nm_sleep_monitor_class_init (NMSleepMonitorClass *klass)
                                           G_TYPE_NONE, 0);
 }
 
-NMSleepMonitor *
-nm_sleep_monitor_get (void)
-{
-        static NMSleepMonitor *singleton = NULL;
-
-        if (singleton)
-                return g_object_ref (singleton);
-
-        singleton = NM_SLEEP_MONITOR (g_object_new (NM_TYPE_SLEEP_MONITOR, NULL));
-        return singleton;
-}
+NM_DEFINE_SINGLETON_GETTER (NMSleepMonitor, nm_sleep_monitor_get, NM_TYPE_SLEEP_MONITOR);
 
 /* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 2dd0b512..ee6ba421 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -384,6 +384,7 @@ _nl_link_parse_info_data (struct nl_sock *sk, int ifindex,
 	NMNLInfoDataClosure data = { .parser = parser, .parser_data = parser_data };
 	struct nl_msg *msg = NULL;
 	struct nl_cb *cb;
+	struct nl_cb *cb0;
 	int err;
 
 	err = rtnl_link_build_get_request (ifindex, NULL, &msg);
@@ -395,7 +396,9 @@ _nl_link_parse_info_data (struct nl_sock *sk, int ifindex,
 	if (err < 0)
 		return err;
 
-	cb = nl_cb_clone (nl_socket_get_cb (sk));
+	cb0 = nl_socket_get_cb (sk);
+	cb = nl_cb_clone (cb0);
+	nl_cb_put (cb0);
 	if (cb == NULL)
 		return -NLE_NOMEM;
 	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, _nl_link_parse_info_data_cb, &data);
@@ -416,8 +419,11 @@ _nl_sock_flush_data (struct nl_sock *sk)
 {
 	int nle;
 	struct nl_cb *cb;
+	struct nl_cb *cb0;
 
-	cb = nl_cb_clone (nl_socket_get_cb (sk));
+	cb0 = nl_socket_get_cb (sk);
+	cb = nl_cb_clone (cb0);
+	nl_cb_put (cb0);
 	if (cb == NULL)
 		return -NLE_NOMEM;
 
@@ -747,7 +753,6 @@ struct _NMLinuxPlatformPrivate {
 	} delayed_action;
 
 	GHashTable *prune_candidates;
-	GHashTable *delayed_deletion;
 
 	GHashTable *wifi_data;
 };
@@ -1658,33 +1663,6 @@ delayed_action_handle_idle (gpointer user_data)
 }
 
 static void
-delayed_action_clear_REFRESH_LINK (NMPlatform *platform, int ifindex)
-{
-	NMLinuxPlatformPrivate *priv;
-	gssize idx;
-	gpointer user_data;
-
-	if (ifindex <= 0)
-		return;
-
-	priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
-	if (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK))
-		return;
-
-	user_data = GINT_TO_POINTER (ifindex);
-
-	idx = _nm_utils_ptrarray_find_first (priv->delayed_action.list_refresh_link->pdata, priv->delayed_action.list_refresh_link->len, user_data);
-	if (idx < 0)
-		return;
-
-	_LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, user_data, "clear");
-
-	g_ptr_array_remove_index_fast (priv->delayed_action.list_refresh_link, idx);
-	if (priv->delayed_action.list_refresh_link->len == 0)
-		priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK;
-}
-
-static void
 delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
@@ -1793,39 +1771,6 @@ cache_prune_candidates_prune (NMPlatform *platform)
 }
 
 static void
-cache_delayed_deletion_prune (NMPlatform *platform)
-{
-	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
-	GPtrArray *prune_list = NULL;
-	GHashTableIter iter;
-	guint i;
-	NMPObject *obj;
-
-	if (g_hash_table_size (priv->delayed_deletion) == 0)
-		return;
-
-	g_hash_table_iter_init (&iter, priv->delayed_deletion);
-	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &obj)) {
-		if (obj) {
-			if (!prune_list)
-				prune_list = g_ptr_array_new_full (g_hash_table_size (priv->delayed_deletion), (GDestroyNotify) nmp_object_unref);
-			g_ptr_array_add (prune_list, nmp_object_ref (obj));
-		}
-	}
-
-	g_hash_table_remove_all (priv->delayed_deletion);
-
-	if (prune_list) {
-		for (i = 0; i < prune_list->len; i++) {
-			obj = prune_list->pdata[i];
-			_LOGt ("delayed-deletion: delete %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
-			cache_remove_netlink (platform, obj, NULL, NULL, NM_PLATFORM_REASON_EXTERNAL);
-		}
-		g_ptr_array_unref (prune_list);
-	}
-}
-
-static void
 cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data)
 {
 	NMPlatform *platform = NM_PLATFORM (user_data);
@@ -1945,6 +1890,20 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
 				                         NULL);
 			}
 		}
+		if (   NM_IN_SET (ops_type, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED)
+		    && (new && new->_link.netlink.is_in_netlink)
+		    && (!old || !old->_link.netlink.is_in_netlink))
+		{
+			if (   new->link.type == NM_LINK_TYPE_VETH
+			    && new->link.parent == 0) {
+				/* the initial notification when adding a veth pair can lack the parent/IFLA_LINK
+				 * (https://bugzilla.redhat.com/show_bug.cgi?id=1285827).
+				 * Request it again. */
+				delayed_action_schedule (platform,
+				                         DELAYED_ACTION_TYPE_REFRESH_LINK,
+				                         GINT_TO_POINTER (new->link.ifindex));
+			}
+		}
 		{
 			/* on enslave/release, we also refresh the master. */
 			int ifindex1 = 0, ifindex2 = 0;
@@ -1964,7 +1923,22 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
 				if (ifindex2 > 0 && ifindex1 != ifindex2)
 					delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (ifindex2));
 			}
-
+		}
+		{
+			if (   (       (ops_type == NMP_CACHE_OPS_REMOVED)
+			        || (   (ops_type == NMP_CACHE_OPS_UPDATED)
+			            && new
+			            && !new->_link.netlink.is_in_netlink))
+			    && old
+			    && old->_link.netlink.is_in_netlink
+			    && old->link.master) {
+				/* sometimes we receive a wrong RTM_DELLINK message when unslaving
+				 * a device. Refetch the link again to check whether the device
+				 * is really gone.
+				 *
+				 * https://bugzilla.redhat.com/show_bug.cgi?id=1285719#c2 */
+				delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (old->link.ifindex));
+			}
 		}
 		break;
 	case NMP_OBJECT_TYPE_IP4_ADDRESS:
@@ -2051,13 +2025,8 @@ do_request_link (NMPlatform *platform, int ifindex, const char *name, gboolean h
 	_LOGt ("do_request_link (%d,%s)", ifindex, name ? name : "");
 
 	if (ifindex > 0) {
-		NMPObject *obj;
-
 		cache_prune_candidates_record_one (platform,
 		                                   (NMPObject *) nmp_cache_lookup_link (priv->cache, ifindex));
-		obj = nmp_object_new_link (ifindex);
-		_LOGt ("delayed-deletion: protect object %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
-		g_hash_table_insert (priv->delayed_deletion, obj, NULL);
 	}
 
 	event_handler_read_netlink_all (platform, FALSE);
@@ -2067,7 +2036,6 @@ do_request_link (NMPlatform *platform, int ifindex, const char *name, gboolean h
 
 	event_handler_read_netlink_all (platform, TRUE);
 
-	cache_delayed_deletion_prune (platform);
 	cache_prune_candidates_prune (platform);
 
 	if (handle_delayed_action)
@@ -2373,7 +2341,6 @@ static int
 event_notification (struct nl_msg *msg, gpointer user_data)
 {
 	NMPlatform *platform = NM_PLATFORM (user_data);
-	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (user_data);
 	auto_nl_object struct nl_object *nlo = NULL;
 	auto_nmp_obj NMPObject *obj = NULL;
 	struct nlmsghdr *msghdr;
@@ -2416,31 +2383,12 @@ event_notification (struct nl_msg *msg, gpointer user_data)
 		switch (msghdr->nlmsg_type) {
 
 		case RTM_NEWLINK:
-			if (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK) {
-				if (g_hash_table_lookup (priv->delayed_deletion, obj) != NULL) {
-					/* the object is scheduled for delayed deletion. Replace that object
-					 * by clearing the value from priv->delayed_deletion. */
-					_LOGt ("delayed-deletion: clear delayed deletion of protected object %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
-					g_hash_table_insert (priv->delayed_deletion, nmp_object_ref (obj), NULL);
-				}
-				delayed_action_clear_REFRESH_LINK (platform, obj->link.ifindex);
-			}
-			/* fall-through */
 		case RTM_NEWADDR:
 		case RTM_NEWROUTE:
 			cache_update_netlink (platform, obj, &obj_cache, NULL, NM_PLATFORM_REASON_EXTERNAL);
 			break;
 
 		case RTM_DELLINK:
-			if (   NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK
-			    && g_hash_table_contains (priv->delayed_deletion, obj)) {
-				/* We sometimes receive spurious RTM_DELLINK events. In this case, we want to delay
-				 * the deletion of the object until later. */
-				_LOGt ("delayed-deletion: delay deletion of protected object %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
-				g_hash_table_insert (priv->delayed_deletion, nmp_object_ref (obj), nmp_object_ref (obj));
-				break;
-			}
-			/* fall-through */
 		case RTM_DELADDR:
 		case RTM_DELROUTE:
 			cache_remove_netlink (platform, obj, &obj_cache, NULL, NM_PLATFORM_REASON_EXTERNAL);
@@ -4636,11 +4584,16 @@ event_handler_read_netlink_one (NMPlatform *platform)
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
 	int nle;
 
+	errno = 0;
 	nle = nl_recvmsgs_default (priv->nlh_event);
 
 	/* Work around a libnl bug fixed in 3.2.22 (375a6294) */
-	if (nle == 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
+	if (nle == 0 && errno == EAGAIN) {
+		/* EAGAIN is equal to EWOULDBLOCK. If it would not be, we'd have to
+		 * workaround libnl3 mapping EWOULDBLOCK to -NLE_FAILURE. */
+		G_STATIC_ASSERT (EAGAIN == EWOULDBLOCK);
 		nle = -NLE_AGAIN;
+	}
 
 	if (nle < 0)
 		switch (nle) {
@@ -4883,10 +4836,6 @@ nm_linux_platform_init (NMLinuxPlatform *self)
 
 	self->priv = priv;
 
-	priv->delayed_deletion = g_hash_table_new_full ((GHashFunc) nmp_object_id_hash,
-	                                                (GEqualFunc) nmp_object_id_equal,
-	                                                (GDestroyNotify) nmp_object_unref,
-	                                                (GDestroyNotify) nmp_object_unref);
 	priv->cache = nmp_cache_new ();
 	priv->delayed_action.list_master_connected = g_ptr_array_new ();
 	priv->delayed_action.list_refresh_link = g_ptr_array_new ();
@@ -4989,7 +4938,6 @@ dispose (GObject *object)
 	nm_clear_g_source (&priv->delayed_action.idle_id);
 
 	g_clear_pointer (&priv->prune_candidates, g_hash_table_unref);
-	g_clear_pointer (&priv->delayed_deletion, g_hash_table_unref);
 
 	G_OBJECT_CLASS (nm_linux_platform_parent_class)->dispose (object);
 }
diff --git a/src/platform/tests/Makefile.am b/src/platform/tests/Makefile.am
index 35aa098a..085f56ca 100644
--- a/src/platform/tests/Makefile.am
+++ b/src/platform/tests/Makefile.am
@@ -31,9 +31,7 @@ PLATFORM_LDADD = \
 @GNOME_CODE_COVERAGE_RULES@
 
 noinst_PROGRAMS = \
-	dump \
 	monitor \
-	platform \
 	test-link-fake \
 	test-link-linux \
 	test-address-fake \
@@ -50,12 +48,6 @@ EXTRA_DIST = test-common.h
 monitor_SOURCES = monitor.c $(PLATFORM_SOURCES)
 monitor_LDADD = $(PLATFORM_LDADD)
 
-dump_SOURCES = dump.c $(PLATFORM_SOURCES)
-dump_LDADD = $(PLATFORM_LDADD)
-
-platform_SOURCES = platform.c $(PLATFORM_SOURCES)
-platform_LDADD = $(PLATFORM_LDADD)
-
 test_link_fake_SOURCES = test-link.c $(TEST_SOURCES)
 test_link_fake_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
diff --git a/src/platform/tests/Makefile.in b/src/platform/tests/Makefile.in
index f45f3a9c..e21a3bb6 100644
--- a/src/platform/tests/Makefile.in
+++ b/src/platform/tests/Makefile.in
@@ -89,12 +89,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 @REQUIRE_ROOT_TESTS_TRUE@am__append_1 = -DREQUIRE_ROOT_TESTS=1
-noinst_PROGRAMS = dump$(EXEEXT) monitor$(EXEEXT) platform$(EXEEXT) \
-	test-link-fake$(EXEEXT) test-link-linux$(EXEEXT) \
-	test-address-fake$(EXEEXT) test-address-linux$(EXEEXT) \
-	test-general$(EXEEXT) test-nmp-object$(EXEEXT) \
-	test-route-fake$(EXEEXT) test-route-linux$(EXEEXT) \
-	test-cleanup-fake$(EXEEXT) test-cleanup-linux$(EXEEXT)
+noinst_PROGRAMS = monitor$(EXEEXT) test-link-fake$(EXEEXT) \
+	test-link-linux$(EXEEXT) test-address-fake$(EXEEXT) \
+	test-address-linux$(EXEEXT) test-general$(EXEEXT) \
+	test-nmp-object$(EXEEXT) test-route-fake$(EXEEXT) \
+	test-route-linux$(EXEEXT) test-cleanup-fake$(EXEEXT) \
+	test-cleanup-linux$(EXEEXT)
 TESTS = test-address-fake$(EXEEXT) test-address-linux$(EXEEXT) \
 	test-cleanup-fake$(EXEEXT) test-cleanup-linux$(EXEEXT) \
 	test-general$(EXEEXT) test-link-fake$(EXEEXT) \
@@ -125,19 +125,13 @@ CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
 am__objects_1 = nm-platform.$(OBJEXT) nm-fake-platform.$(OBJEXT) \
 	nm-linux-platform.$(OBJEXT)
-am_dump_OBJECTS = dump.$(OBJEXT) $(am__objects_1)
-dump_OBJECTS = $(am_dump_OBJECTS)
-dump_DEPENDENCIES = $(PLATFORM_LDADD)
+am_monitor_OBJECTS = monitor.$(OBJEXT) $(am__objects_1)
+monitor_OBJECTS = $(am_monitor_OBJECTS)
+monitor_DEPENDENCIES = $(PLATFORM_LDADD)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-am_monitor_OBJECTS = monitor.$(OBJEXT) $(am__objects_1)
-monitor_OBJECTS = $(am_monitor_OBJECTS)
-monitor_DEPENDENCIES = $(PLATFORM_LDADD)
-am_platform_OBJECTS = platform.$(OBJEXT) $(am__objects_1)
-platform_OBJECTS = $(am_platform_OBJECTS)
-platform_DEPENDENCIES = $(PLATFORM_LDADD)
 am__objects_2 = test_address_fake-nm-platform.$(OBJEXT) \
 	test_address_fake-nm-fake-platform.$(OBJEXT) \
 	test_address_fake-nm-linux-platform.$(OBJEXT)
@@ -251,18 +245,18 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(dump_SOURCES) $(monitor_SOURCES) $(platform_SOURCES) \
-	$(test_address_fake_SOURCES) $(test_address_linux_SOURCES) \
-	$(test_cleanup_fake_SOURCES) $(test_cleanup_linux_SOURCES) \
-	$(test_general_SOURCES) $(test_link_fake_SOURCES) \
-	$(test_link_linux_SOURCES) $(test_nmp_object_SOURCES) \
-	$(test_route_fake_SOURCES) $(test_route_linux_SOURCES)
-DIST_SOURCES = $(dump_SOURCES) $(monitor_SOURCES) $(platform_SOURCES) \
-	$(test_address_fake_SOURCES) $(test_address_linux_SOURCES) \
-	$(test_cleanup_fake_SOURCES) $(test_cleanup_linux_SOURCES) \
-	$(test_general_SOURCES) $(test_link_fake_SOURCES) \
-	$(test_link_linux_SOURCES) $(test_nmp_object_SOURCES) \
-	$(test_route_fake_SOURCES) $(test_route_linux_SOURCES)
+SOURCES = $(monitor_SOURCES) $(test_address_fake_SOURCES) \
+	$(test_address_linux_SOURCES) $(test_cleanup_fake_SOURCES) \
+	$(test_cleanup_linux_SOURCES) $(test_general_SOURCES) \
+	$(test_link_fake_SOURCES) $(test_link_linux_SOURCES) \
+	$(test_nmp_object_SOURCES) $(test_route_fake_SOURCES) \
+	$(test_route_linux_SOURCES)
+DIST_SOURCES = $(monitor_SOURCES) $(test_address_fake_SOURCES) \
+	$(test_address_linux_SOURCES) $(test_cleanup_fake_SOURCES) \
+	$(test_cleanup_linux_SOURCES) $(test_general_SOURCES) \
+	$(test_link_fake_SOURCES) $(test_link_linux_SOURCES) \
+	$(test_nmp_object_SOURCES) $(test_route_fake_SOURCES) \
+	$(test_route_linux_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -779,10 +773,6 @@ PLATFORM_LDADD = \
 EXTRA_DIST = test-common.h
 monitor_SOURCES = monitor.c $(PLATFORM_SOURCES)
 monitor_LDADD = $(PLATFORM_LDADD)
-dump_SOURCES = dump.c $(PLATFORM_SOURCES)
-dump_LDADD = $(PLATFORM_LDADD)
-platform_SOURCES = platform.c $(PLATFORM_SOURCES)
-platform_LDADD = $(PLATFORM_LDADD)
 test_link_fake_SOURCES = test-link.c $(TEST_SOURCES)
 test_link_fake_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
@@ -894,18 +884,10 @@ clean-noinstPROGRAMS:
 	echo " rm -f" $$list; \
 	rm -f $$list
 
-dump$(EXEEXT): $(dump_OBJECTS) $(dump_DEPENDENCIES) $(EXTRA_dump_DEPENDENCIES) 
-	@rm -f dump$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(dump_OBJECTS) $(dump_LDADD) $(LIBS)
-
 monitor$(EXEEXT): $(monitor_OBJECTS) $(monitor_DEPENDENCIES) $(EXTRA_monitor_DEPENDENCIES) 
 	@rm -f monitor$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(monitor_OBJECTS) $(monitor_LDADD) $(LIBS)
 
-platform$(EXEEXT): $(platform_OBJECTS) $(platform_DEPENDENCIES) $(EXTRA_platform_DEPENDENCIES) 
-	@rm -f platform$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(platform_OBJECTS) $(platform_LDADD) $(LIBS)
-
 test-address-fake$(EXEEXT): $(test_address_fake_OBJECTS) $(test_address_fake_DEPENDENCIES) $(EXTRA_test_address_fake_DEPENDENCIES) 
 	@rm -f test-address-fake$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(test_address_fake_OBJECTS) $(test_address_fake_LDADD) $(LIBS)
@@ -952,12 +934,10 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/monitor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-fake-platform.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-linux-platform.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-platform.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/platform.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-general.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nmp-object.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_fake-nm-fake-platform.Po@am__quote@
diff --git a/src/platform/tests/dump.c b/src/platform/tests/dump.c
deleted file mode 100644
index 54de1da7..00000000
--- a/src/platform/tests/dump.c
+++ /dev/null
@@ -1,139 +0,0 @@
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-
-#include "nm-platform.h"
-#include "nm-linux-platform.h"
-#include "nm-fake-platform.h"
-#include "nm-macros-internal.h"
-
-static void
-dump_interface (NMPlatformLink *link)
-{
-	GArray *ip6_addresses;
-	GArray *ip4_addresses;
-	const NMPlatformIP6Address *ip6_address;
-	const NMPlatformIP4Address *ip4_address;
-	GArray *ip6_routes;
-	GArray *ip4_routes;
-	const NMPlatformIP6Route *ip6_route;
-	const NMPlatformIP4Route *ip4_route;
-	char networkstr[INET6_ADDRSTRLEN];
-	char gatewaystr[INET6_ADDRSTRLEN];
-	int vlan_id, vlan_parent;
-	const char *address;
-	size_t addrlen;
-	int i;
-
-	g_assert (NM_FLAGS_HAS (link->flags, IFF_UP) || !link->connected);
-
-	printf ("%d: %s: %s", link->ifindex, link->name, nm_link_type_to_string (link->type));
-	if (NM_FLAGS_HAS (link->flags, IFF_UP))
-		printf (" %s", link->connected ? "CONNECTED" : "DISCONNECTED");
-	else
-		printf (" DOWN");
-	if (NM_FLAGS_HAS (link->flags, IFF_NOARP))
-		printf (" noarp");
-	if (link->master)
-		printf (" master %d", link->master);
-	if (link->parent)
-		printf (" parent %d", link->parent);
-	printf (" mtu %d", link->mtu);
-	printf ("\n");
-	if (link->driver)
-		printf ("    driver: %s\n", link->driver);
-	printf ("    UDI: %s\n", nm_platform_link_get_udi (NM_PLATFORM_GET, link->ifindex));
-	if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, link->ifindex, &vlan_parent, &vlan_id))
-		g_assert_not_reached ();
-	if (vlan_parent)
-		printf ("    vlan parent %d id %d\n", vlan_parent, vlan_id);
-
-	if (nm_platform_link_is_software (NM_PLATFORM_GET, link->ifindex))
-		printf ("    class software\n");
-	if (nm_platform_link_supports_slaves (NM_PLATFORM_GET, link->ifindex))
-		printf ("    class supports-slaves\n");
-	if (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, link->ifindex))
-		printf ("    feature carrier-detect\n");
-	if (nm_platform_link_supports_vlans (NM_PLATFORM_GET, link->ifindex))
-		printf ("    feature vlans\n");
-
-	address = nm_platform_link_get_address (NM_PLATFORM_GET, link->ifindex, &addrlen);
-	if (address) {
-		printf ("    link-address ");
-		for (i = 0; i < addrlen; i++)
-			printf ("%s%02hhx", i ? ":" : "", address[i]);
-		printf ("\n");
-	}
-
-	ip4_addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, link->ifindex);
-	ip6_addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, link->ifindex);
-
-	g_assert (ip4_addresses);
-	g_assert (ip6_addresses);
-
-	for (i = 0; i < ip4_addresses->len; i++) {
-		ip4_address = &g_array_index (ip4_addresses, NMPlatformIP4Address, i);
-		printf ("    ip4-address %s\n", nm_platform_ip4_address_to_string (ip4_address));
-	}
-
-	for (i = 0; i < ip6_addresses->len; i++) {
-		ip6_address = &g_array_index (ip6_addresses, NMPlatformIP6Address, i);
-		printf ("    ip6-address %s\n", nm_platform_ip6_address_to_string (ip6_address));
-	}
-
-	g_array_unref (ip4_addresses);
-	g_array_unref (ip6_addresses);
-
-	ip4_routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
-	ip6_routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
-
-	g_assert (ip4_routes);
-	g_assert (ip6_routes);
-
-	for (i = 0; i < ip4_routes->len; i++) {
-		ip4_route = &g_array_index (ip4_routes, NMPlatformIP4Route, i);
-		inet_ntop (AF_INET, &ip4_route->network, networkstr, sizeof (networkstr));
-		inet_ntop (AF_INET, &ip4_route->gateway, gatewaystr, sizeof (gatewaystr));
-		printf ("    ip4-route %s/%d via %s\n", networkstr, ip4_route->plen, gatewaystr);
-	}
-
-	for (i = 0; i < ip6_routes->len; i++) {
-		ip6_route = &g_array_index (ip6_routes, NMPlatformIP6Route, i);
-		inet_ntop (AF_INET6, &ip6_route->network, networkstr, sizeof (networkstr));
-		inet_ntop (AF_INET6, &ip6_route->gateway, gatewaystr, sizeof (gatewaystr));
-		printf ("    ip6-route %s/%d via %s\n", networkstr, ip6_route->plen, gatewaystr);
-	}
-
-	g_array_unref (ip4_routes);
-	g_array_unref (ip6_routes);
-}
-
-static void
-dump_all (void)
-{
-	GArray *links = nm_platform_link_get_all (NM_PLATFORM_GET);
-	int i;
-
-	for (i = 0; i < links->len; i++)
-		dump_interface (&g_array_index (links, NMPlatformLink, i));
-}
-
-int
-main (int argc, char **argv)
-{
-#if !GLIB_CHECK_VERSION (2, 35, 0)
-	g_type_init ();
-#endif
-
-	g_assert (argc <= 2);
-	if (argc > 1 && !g_strcmp0 (argv[1], "--fake"))
-		nm_fake_platform_setup ();
-	else
-		nm_linux_platform_setup ();
-
-	dump_all ();
-
-	return EXIT_SUCCESS;
-}
diff --git a/src/platform/tests/monitor.c b/src/platform/tests/monitor.c
index 9aff1047..f1058db8 100644
--- a/src/platform/tests/monitor.c
+++ b/src/platform/tests/monitor.c
@@ -3,10 +3,13 @@
 #include <stdlib.h>
 #include <syslog.h>
 
-#include "nm-fake-platform.h"
 #include "nm-linux-platform.h"
 #include "nm-logging.h"
 
+#include "nm-test-utils.h"
+
+NMTST_DEFINE ();
+
 int
 main (int argc, char **argv)
 {
@@ -16,15 +19,16 @@ main (int argc, char **argv)
 	g_type_init ();
 #endif
 
+	if (!g_getenv ("G_MESSAGES_DEBUG"))
+		g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+
+	nmtst_init_with_logging (&argc, &argv, "DEBUG", "ALL");
+
+	nm_log_info (LOGD_PLATFORM, "platform monitor start");
+
 	loop = g_main_loop_new (NULL, FALSE);
-	nm_logging_setup ("debug", NULL, NULL, NULL);
-	openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR, LOG_DAEMON);
-
-	g_assert (argc <= 2);
-	if (argc > 1 && !g_strcmp0 (argv[1], "--fake"))
-		nm_fake_platform_setup ();
-	else
-		nm_linux_platform_setup ();
+
+	nm_linux_platform_setup ();
 
 	g_main_loop_run (loop);
 
diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c
deleted file mode 100644
index 24e828c1..00000000
--- a/src/platform/tests/platform.c
+++ /dev/null
@@ -1,902 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* nm-platform.c - Handle runtime kernel networking configuration
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2013 Red Hat, Inc.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <netlink/route/addr.h>
-
-#include "gsystem-local-alloc.h"
-#include "nm-platform.h"
-#include "nm-linux-platform.h"
-#include "nm-fake-platform.h"
-
-#define error(...) fprintf (stderr, __VA_ARGS__)
-
-typedef gboolean boolean_t;
-typedef int decimal_t;
-typedef const char *string_t;
-
-#define print_boolean(value) printf ("%s\n", value ? "yes" : "no")
-#define print_decimal(value) printf ("%d\n", value)
-#define print_string(value) printf ("%s\n", value)
-
-static gboolean
-do_sysctl_set (char **argv)
-{
-	return nm_platform_sysctl_set (NM_PLATFORM_GET, argv[0], argv[1]);
-}
-
-static gboolean
-do_sysctl_get (char **argv)
-{
-	gs_free char *value = nm_platform_sysctl_get (NM_PLATFORM_GET, argv[0]);
-
-	printf ("%s\n", value);
-
-	return !!value;
-}
-
-static int
-parse_ifindex (const char *str)
-{
-	char *endptr;
-	int ifindex = 0;
-
-	ifindex = strtol (str, &endptr, 10);
-
-	if (*endptr) {
-		ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, str);
-	}
-
-	return ifindex;
-}
-
-static gboolean
-do_link_get_all (char **argv)
-{
-	GArray *links;
-	NMPlatformLink *device;
-	int i;
-
-	links = nm_platform_link_get_all (NM_PLATFORM_GET);
-	for (i = 0; i < links->len; i++) {
-		device = &g_array_index (links, NMPlatformLink, i);
-
-		printf ("%d: %s type %d\n", device->ifindex, device->name, device->type);
-	}
-	g_array_unref (links);
-
-	return TRUE;
-}
-
-static gboolean
-do_dummy_add (char **argv)
-{
-	return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
-}
-
-static gboolean
-do_bridge_add (char **argv)
-{
-	return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
-}
-
-static gboolean
-do_bond_add (char **argv)
-{
-	return nm_platform_bond_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
-}
-
-static gboolean
-do_team_add (char **argv)
-{
-	return nm_platform_team_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
-}
-
-static gboolean
-do_vlan_add (char **argv)
-{
-	const char *name = *argv++;
-	int parent = parse_ifindex (*argv++);
-	int vlanid = strtol (*argv++, NULL, 10);
-	guint32 vlan_flags = strtol (*argv++, NULL, 10);
-
-	return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags, NULL) == NM_PLATFORM_ERROR_SUCCESS;
-}
-
-static gboolean
-do_link_exists (char **argv)
-{
-	gboolean value = !!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, argv[0]);
-
-	print_boolean (value);
-
-	return TRUE;
-}
-
-#define LINK_CMD(cmdname) \
-	static gboolean \
-	do_link_##cmdname (char **argv) \
-	{ \
-		int ifindex = parse_ifindex (argv[0]); \
-		return ifindex ? nm_platform_link_##cmdname (NM_PLATFORM_GET, ifindex) : FALSE; \
-	}
-
-#define LINK_CMD_GET_FULL(cmdname, type, cond) \
-	static gboolean \
-	do_link_##cmdname (char **argv) \
-	{ \
-		int ifindex = parse_ifindex (argv[0]); \
-		if (ifindex) { \
-			type##_t value = nm_platform_link_##cmdname (NM_PLATFORM_GET, ifindex); \
-			if (cond) { \
-				print_##type (value); \
-				return TRUE; \
-			} \
-		} \
-		return FALSE; \
-	}
-#define LINK_CMD_GET(cmdname, type) LINK_CMD_GET_FULL (cmdname, type, TRUE);
-
-LINK_CMD (delete)
-
-/* do_link_delete_by_ifname:
- *
- * We don't need this as we allow ifname instead of ifindex anyway.
- */
-
-static gboolean
-do_link_get_ifindex (char **argv)
-{
-	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, argv[0]);
-
-	if (ifindex)
-		printf ("%d\n", ifindex);
-
-	return !!ifindex;
-}
-
-LINK_CMD_GET_FULL (get_name, string, value)
-LINK_CMD_GET_FULL (get_type, decimal, value > 0)
-LINK_CMD_GET (is_software, boolean)
-LINK_CMD_GET (supports_slaves, boolean)
-
-static gboolean
-do_link_set_up (char **argv)
-{
-	int ifindex = parse_ifindex (argv[0]);
-
-	return ifindex ? nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL) : FALSE;
-}
-
-LINK_CMD (set_down)
-LINK_CMD (set_arp)
-LINK_CMD (set_noarp)
-LINK_CMD_GET (is_up, boolean)
-LINK_CMD_GET (is_connected, boolean)
-LINK_CMD_GET (uses_arp, boolean)
-
-static gboolean
-do_link_set_address (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	char *hex = *argv++;
-	int hexlen = strlen (hex);
-	char address[hexlen/2];
-	char *endptr;
-	int i;
-
-	g_assert (!(hexlen % 2));
-
-	for (i = 0; i < sizeof (address); i++) {
-		char digit[3];
-
-		digit[0] = hex[2*i];
-		digit[1] = hex[2*i+1];
-		digit[2] = '\0';
-
-		address[i] = strtoul (digit, &endptr, 16);
-		g_assert (!*endptr);
-	}
-
-	return nm_platform_link_set_address (NM_PLATFORM_GET, ifindex, address, sizeof (address));
-}
-
-static gboolean
-do_link_get_address (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	const char *address;
-	size_t length;
-	int i;
-
-	address = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &length);
-
-	if (!address || length <= 0)
-		return FALSE;
-
-	for (i = 0; i < length; i++)
-		printf ("%02x", address[i]);
-	printf ("\n");
-
-	return TRUE;
-}
-
-static gboolean
-do_link_set_mtu (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	int mtu = strtoul (*argv++, NULL, 10);
-
-	return nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, mtu);
-}
-
-LINK_CMD_GET (get_mtu, decimal);
-LINK_CMD_GET (supports_carrier_detect, boolean)
-LINK_CMD_GET (supports_vlans, boolean)
-
-static gboolean
-do_link_enslave (char **argv)
-{
-	int master = parse_ifindex (*argv++);
-	int slave = parse_ifindex (*argv++);
-
-	return nm_platform_link_enslave (NM_PLATFORM_GET, master, slave);
-}
-
-static gboolean
-do_link_release (char **argv)
-{
-	int master = parse_ifindex (*argv++);
-	int slave = parse_ifindex (*argv++);
-
-	return nm_platform_link_release (NM_PLATFORM_GET, master, slave);
-}
-
-LINK_CMD_GET (get_master, decimal)
-
-static gboolean
-do_master_set_option (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	const char *option = *argv++;
-	const char *value = *argv++;
-
-	return nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, option, value);
-}
-
-static gboolean
-do_master_get_option (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	const char *option = *argv++;
-	gs_free char *value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, option);
-
-	printf ("%s\n", value);
-
-	return !!value;
-}
-
-static gboolean
-do_slave_set_option (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	const char *option = *argv++;
-	const char *value = *argv++;
-
-	return nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, option, value);
-}
-
-static gboolean
-do_slave_get_option (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	const char *option = *argv++;
-	gs_free char *value = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex, option);
-
-	printf ("%s\n", value);
-
-	return !!value;
-}
-
-static gboolean
-do_vlan_get_info (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	int parent;
-	int vlanid;
-
-	if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent, &vlanid))
-		return FALSE;
-
-	printf ("%d %d\n", parent, vlanid);
-
-	return TRUE;
-}
-
-static gboolean
-do_vlan_set_ingress_map (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	int from = strtol (*argv++, NULL, 10);
-	int to = strtol (*argv++, NULL, 10);
-
-	return nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, from, to);
-}
-
-static gboolean
-do_vlan_set_egress_map (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	int from = strtol (*argv++, NULL, 10);
-	int to = strtol (*argv++, NULL, 10);
-
-	return nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, from, to);
-}
-
-static gboolean
-do_veth_get_properties (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	NMPlatformVethProperties props;
-
-	if (!nm_platform_veth_get_properties (NM_PLATFORM_GET, ifindex, &props))
-		return FALSE;
-
-	printf ("peer: %d\n", props.peer);
-
-	return TRUE;
-}
-
-static gboolean
-do_tun_get_properties (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	NMPlatformTunProperties props;
-
-	if (!nm_platform_tun_get_properties (NM_PLATFORM_GET, ifindex, &props))
-		return FALSE;
-
-	printf ("mode: %s\n", props.mode);
-	if (props.owner == -1)
-		printf ("owner: none\n");
-	else
-		printf ("owner: %lu\n", (gulong) props.owner);
-	if (props.group == -1)
-		printf ("group: none\n");
-	else
-		printf ("group: %lu\n", (gulong) props.group);
-	printf ("no-pi: ");
-	print_boolean (props.no_pi);
-	printf ("vnet-hdr: ");
-	print_boolean (props.vnet_hdr);
-	printf ("multi-queue: ");
-	print_boolean (props.multi_queue);
-
-	return TRUE;
-}
-
-static gboolean
-do_macvlan_get_properties (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	NMPlatformMacvlanProperties props;
-
-	if (!nm_platform_macvlan_get_properties (NM_PLATFORM_GET, ifindex, &props))
-		return FALSE;
-
-	printf ("parent: %d\n", props.parent_ifindex);
-	printf ("mode: %s\n", props.mode);
-	printf ("no-promisc: ");
-	print_boolean (props.no_promisc);
-	return TRUE;
-}
-
-static gboolean
-do_vxlan_get_properties (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	NMPlatformVxlanProperties props;
-	char addrstr[INET6_ADDRSTRLEN];
-
-	if (!nm_platform_vxlan_get_properties (NM_PLATFORM_GET, ifindex, &props))
-		return FALSE;
-
-	printf ("parent-ifindex: %u\n", props.parent_ifindex);
-	printf ("id: %u\n", props.id);
-	if (props.group)
-		inet_ntop (AF_INET, &props.group, addrstr, sizeof (addrstr));
-	else if (props.group6.s6_addr[0])
-		inet_ntop (AF_INET6, &props.group6, addrstr, sizeof (addrstr));
-	else
-		strcpy (addrstr, "-");
-	printf ("group: %s\n", addrstr);
-	if (props.local)
-		inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr));
-	else if (props.local6.s6_addr[0])
-		inet_ntop (AF_INET6, &props.local6, addrstr, sizeof (addrstr));
-	else
-		strcpy (addrstr, "-");
-	printf ("local: %s\n", addrstr);
-	printf ("tos: %u\n", props.tos);
-	printf ("ttl: %u\n", props.ttl);
-	printf ("learning: ");
-	print_boolean (props.learning);
-	printf ("ageing: %u\n", props.ageing);
-	printf ("limit: %u\n", props.limit);
-	printf ("dst-port: %u\n", props.dst_port);
-	printf ("src-port-min: %u\n", props.src_port_min);
-	printf ("src-port-max: %u\n", props.src_port_max);
-	printf ("proxy: ");
-	print_boolean (props.proxy);
-	printf ("rsc: ");
-	print_boolean (props.rsc);
-	printf ("l2miss: ");
-	print_boolean (props.l2miss);
-	printf ("l3miss: ");
-	print_boolean (props.l3miss);
-
-	return TRUE;
-}
-
-static gboolean
-do_gre_get_properties (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	NMPlatformGreProperties props;
-	char addrstr[INET_ADDRSTRLEN];
-
-	if (!nm_platform_gre_get_properties (NM_PLATFORM_GET, ifindex, &props))
-		return FALSE;
-
-	printf ("parent-ifindex: %u\n", props.parent_ifindex);
-	printf ("input-flags: %u\n", props.input_flags);
-	printf ("output-flags: %u\n", props.input_flags);
-	printf ("input-key: %u\n", props.input_key);
-	printf ("output-key: %u\n", props.output_key);
-	if (props.local)
-		inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr));
-	else
-		strcpy (addrstr, "-");
-	printf ("local: %s\n", addrstr);
-	if (props.remote)
-		inet_ntop (AF_INET, &props.remote, addrstr, sizeof (addrstr));
-	else
-		strcpy (addrstr, "-");
-	printf ("remote: %s\n", addrstr);
-	printf ("ttl: %u\n", props.ttl);
-	printf ("tos: %u\n", props.tos);
-	printf ("path-mtu-discovery: ");
-	print_boolean (props.path_mtu_discovery);
-
-	return TRUE;
-}
-
-static gboolean
-do_ip4_address_get_all (char **argv)
-{
-	int ifindex = parse_ifindex (argv[0]);
-	GArray *addresses;
-	NMPlatformIP4Address *address;
-	char addrstr[INET_ADDRSTRLEN];
-	int i;
-
-	if (ifindex) {
-		addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
-		for (i = 0; i < addresses->len; i++) {
-			address = &g_array_index (addresses, NMPlatformIP4Address, i);
-			inet_ntop (AF_INET, &address->address, addrstr, sizeof (addrstr));
-			printf ("%s/%d\n", addrstr, address->plen);
-		}
-		g_array_unref (addresses);
-	}
-
-	return !!ifindex;
-}
-
-static gboolean
-do_ip6_address_get_all (char **argv)
-{
-	int ifindex = parse_ifindex (argv[0]);
-	GArray *addresses;
-	NMPlatformIP6Address *address;
-	char addrstr[INET6_ADDRSTRLEN];
-	int i;
-
-	if (ifindex) {
-		addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);
-		for (i = 0; i < addresses->len; i++) {
-			address = &g_array_index (addresses, NMPlatformIP6Address, i);
-			inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr));
-			printf ("%s/%d\n", addrstr, address->plen);
-		}
-		g_array_unref (addresses);
-	}
-
-	return !!ifindex;
-}
-
-static gboolean
-parse_ip_address (int family, char *str, gpointer address, int *plen)
-{
-	char *endptr;
-
-	if (plen)
-		*plen = 0;
-
-	if (plen) {
-		char *ptr = strchr (str, '/');
-		if (ptr) {
-			*ptr++ = '\0';
-			*plen = strtol (ptr, &endptr, 10);
-			if (*endptr)
-				ptr = NULL;
-		}
-		if (!ptr) {
-			error ("Bad format of IP address, expected address/plen.\n");
-			return FALSE;
-		}
-	}
-
-	if (inet_pton (family, str, address))
-		return TRUE;
-
-	error ("Bad format of IP address, expected address%s.\n", plen ? "/plen" : "");
-	return FALSE;
-}
-
-typedef in_addr_t ip4_t;
-typedef struct in6_addr ip6_t;
-
-#define parse_ip4_address(s, a, p) parse_ip_address (AF_INET, s, a, p)
-#define parse_ip6_address(s, a, p) parse_ip_address (AF_INET6, s, a, p)
-
-static gboolean
-do_ip4_address_add (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	ip4_t address;
-	int plen;
-
-	if (ifindex && parse_ip4_address (*argv++, &address, &plen)) {
-		guint32 lifetime = strtol (*argv++, NULL, 10);
-		guint32 preferred = strtol (*argv++, NULL, 10);
-
-		gboolean value = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address, 0, plen, lifetime, preferred, NULL);
-		return value;
-	} else
-		return FALSE;
-}
-
-static gboolean
-do_ip6_address_add (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	ip6_t address;
-	int plen;
-
-	if (ifindex && parse_ip6_address (*argv++, &address, &plen)) {
-		guint32 lifetime = strtol (*argv++, NULL, 10);
-		guint32 preferred = strtol (*argv++, NULL, 10);
-		guint flags = (*argv) ? rtnl_addr_str2flags (*argv++) : 0;
-
-		gboolean value = nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, address, in6addr_any, plen, lifetime, preferred, flags);
-		return value;
-	} else
-		return FALSE;
-}
-
-#define ADDR_CMD_FULL(v, cmdname, print, ...) \
-	static gboolean \
-	do_##v##_address_##cmdname (char **argv) \
-	{ \
-		int ifindex = parse_ifindex (*argv++); \
-		v##_t address; \
-		int plen; \
-		if (ifindex && parse_##v##_address (*argv++, &address, &plen)) { \
-			gboolean value = !!nm_platform_##v##_address_##cmdname (NM_PLATFORM_GET, ifindex, address, plen, ##__VA_ARGS__); \
-			if (print) { \
-				print_boolean (value); \
-				return TRUE; \
-			} else \
-				return value; \
-		} else \
-			return FALSE; \
-	}
-#define ADDR_CMD(cmdname) ADDR_CMD_FULL (ip4, cmdname, FALSE, 0) ADDR_CMD_FULL (ip6, cmdname, FALSE)
-#define ADDR_CMD_PRINT(cmdname) ADDR_CMD_FULL (ip4, cmdname, TRUE) ADDR_CMD_FULL (ip6, cmdname, TRUE)
-
-ADDR_CMD (delete)
-ADDR_CMD_PRINT (get)
-
-static gboolean
-do_ip4_route_get_all (char **argv)
-{
-	int ifindex = parse_ifindex (argv[0]);
-	GArray *routes;
-	NMPlatformIP4Route *route;
-	char networkstr[INET_ADDRSTRLEN], gatewaystr[INET_ADDRSTRLEN];
-	int i;
-
-	if (ifindex) {
-		routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
-		for (i = 0; i < routes->len; i++) {
-			route = &g_array_index (routes, NMPlatformIP4Route, i);
-			inet_ntop (AF_INET, &route->network, networkstr, sizeof (networkstr));
-			inet_ntop (AF_INET, &route->gateway, gatewaystr, sizeof (gatewaystr));
-			printf ("%s/%d via %s metric %d\n",
-					networkstr, route->plen, gatewaystr, route->metric);
-		}
-		g_array_unref (routes);
-	}
-
-	return !!ifindex;
-}
-
-static gboolean
-do_ip6_route_get_all (char **argv)
-{
-	int ifindex = parse_ifindex (argv[0]);
-	GArray *routes;
-	NMPlatformIP6Route *route;
-	char networkstr[INET6_ADDRSTRLEN], gatewaystr[INET6_ADDRSTRLEN];
-	int i;
-
-	if (ifindex) {
-		routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
-		for (i = 0; i < routes->len; i++) {
-			route = &g_array_index (routes, NMPlatformIP6Route, i);
-			inet_ntop (AF_INET6, &route->network, networkstr, sizeof (networkstr));
-			inet_ntop (AF_INET6, &route->gateway, gatewaystr, sizeof (gatewaystr));
-			printf ("%s/%d via %s metric %d\n",
-					networkstr, route->plen, gatewaystr, route->metric);
-		}
-		g_array_unref (routes);
-	}
-
-	return !!ifindex;
-}
-
-static gboolean
-do_ip4_route_add (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	in_addr_t network, gateway;
-	int plen, metric, mss;
-
-	parse_ip4_address (*argv++, &network, &plen);
-	parse_ip4_address (*argv++, &gateway, NULL);
-	metric = strtol (*argv++, NULL, 10);
-	mss = strtol (*argv++, NULL, 10);
-
-	return nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER,
-	                                  network, plen, gateway, 0,
-	                                  metric, mss);
-}
-
-static gboolean
-do_ip6_route_add (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	struct in6_addr network, gateway;
-	int plen, metric, mss;
-
-	parse_ip6_address (*argv++, &network, &plen);
-	parse_ip6_address (*argv++, &gateway, NULL);
-	metric = strtol (*argv++, NULL, 10);
-	mss = strtol (*argv++, NULL, 10);
-	return nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER,
-	                                  network, plen, gateway,
-	                                  metric, mss);
-}
-
-static gboolean
-do_ip4_route_delete (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	in_addr_t network;
-	int plen, metric;
-
-	parse_ip4_address (*argv++, &network, &plen);
-	metric = strtol (*argv++, NULL, 10);
-
-	return nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric);
-}
-
-static gboolean
-do_ip6_route_delete (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	struct in6_addr network;
-	int plen, metric;
-
-	parse_ip6_address (*argv++, &network, &plen);
-	metric = strtol (*argv++, NULL, 10);
-
-	return nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric);
-}
-
-static gboolean
-do_ip4_route_get (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	in_addr_t network;
-	int plen, metric;
-
-	parse_ip4_address (*argv++, &network, &plen);
-	metric = strtol (*argv++, NULL, 10);
-
-	print_boolean (!!nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
-	return TRUE;
-}
-
-static gboolean
-do_ip6_route_get (char **argv)
-{
-	int ifindex = parse_ifindex (*argv++);
-	struct in6_addr network;
-	int plen, metric;
-
-	parse_ip6_address (*argv++, &network, &plen);
-	metric = strtol (*argv++, NULL, 10);
-
-	print_boolean (!!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
-	return TRUE;
-}
-
-typedef struct {
-	const char *name;
-	const char *help;
-	int (*handler) (char **argv);
-	int argc;
-	const char *arghelp;
-} command_t;
-
-static const command_t commands[] = {
-	{ "sysctl-set", "get /proc/sys or /sys value", do_sysctl_set, 2, "<path> <value>" },
-	{ "sysctl-get", "get /proc/sys or /sys value", do_sysctl_get, 1, "<value>" },
-	{ "link-get-all", "print all links", do_link_get_all, 0, "" },
-	{ "dummy-add", "add dummy interface", do_dummy_add, 1, "<ifname>" },
-	{ "bridge-add", "add bridge interface", do_bridge_add, 1, "<ifname>" },
-	{ "bond-add", "add bond interface", do_bond_add, 1, "<ifname>" },
-	{ "team-add", "add team interface", do_team_add, 1, "<ifname>" },
-	{ "vlan-add", "add vlan interface", do_vlan_add, 4, "<ifname> <parent> <vlanid> <vlanflags>" },
-	{ "link-exists", "check ifname for existance", do_link_exists, 1, "<ifname>" },
-	{ "link-delete", "delete interface", do_link_delete, 1, "<ifname/ifindex>" },
-	{ "link-get-ifindex>", "get interface index", do_link_get_ifindex, 1, "<ifname>" },
-	{ "link-get-name", "get interface name", do_link_get_name, 1, "<ifindex>" },
-	{ "link-get-type", "get interface type", do_link_get_type, 1, "<ifname/ifindex>" },
-	{ "link-is-software", "check if interface is a software one", do_link_is_software, 1, "<ifname/ifindex>" },
-	{ "link-supports-slaves", "check if interface supports slaves", do_link_supports_slaves, 1, "<ifname/ifindex>" },
-	{ "link-set-up", "set interface up", do_link_set_up, 1, "<ifname/ifindex>" },
-	{ "link-set-down", "set interface down", do_link_set_down, 1, "<ifname/ifindex>" },
-	{ "link-set-arp", "activate interface arp", do_link_set_arp, 1, "<ifname/ifindex>" },
-	{ "link-set-noarp", "deactivate interface arp", do_link_set_noarp, 1, "<ifname/ifindex>" },
-	{ "link-is-up", "check if interface is up", do_link_is_up, 1, "<ifname/ifindex>" },
-	{ "link-is-connected", "check interface carrier", do_link_is_connected, 1, "<ifname/ifindex>" },
-	{ "link-uses-arp", "check whether interface uses arp", do_link_uses_arp, 1, "<ifname/ifindex>" },
-	{ "link-get-address", "print link address", do_link_get_address, 1, "<ifname/ifindex>" },
-	{ "link-set-address", "set link address", do_link_set_address, 2, "<ifname/ifindex> <hex>" },
-	{ "link-get-mtu", "print link mtu", do_link_get_mtu, 1, "<ifname/ifindex>" },
-	{ "link-set-mtu", "set link mtu", do_link_set_mtu, 2, "<ifname/ifindex> <mtu>" },
-	{ "link-supports-carrier-detect", "check whether interface supports carrier detect",
-		do_link_supports_carrier_detect, 1, "<ifname/ifindex>" },
-	{ "link-supports-vlans", "check whether interface supports VLANs",
-		do_link_supports_vlans, 1, "<ifname/ifindex>" },
-	{ "link-enslave", "enslave slave interface with master", do_link_enslave, 2, "<master> <slave>" },
-	{ "link-release", "release save interface from master", do_link_release, 2, "<master> <slave>" },
-	{ "link-get-master", "print master interface of a slave", do_link_get_master, 1, "<ifname/ifindex>" },
-	{ "link-master-set-option", "set master option", do_master_set_option, 3,
-		"<ifname/ifindex> <option> <value>" },
-	{ "link-master-get-option", "get master option", do_master_get_option, 2,
-		"<ifname/ifindex> <option>" },
-	{ "link-slave-set-option", "set slave option", do_slave_set_option, 3,
-		"<ifname/ifindex> <option>" },
-	{ "link-slave-get-option", "get slave option", do_slave_get_option, 2,
-		"<ifname/ifindex> <option>" },
-	{ "vlan-get-info", "get vlan info", do_vlan_get_info, 1, "<ifname/ifindex>" },
-	{ "vlan-set-ingress-map", "set vlan ingress map", do_vlan_set_ingress_map, 3,
-		"<ifname/ifindex> <from> <to>" },
-	{ "vlan-set-egress-map", "set vlan egress map", do_vlan_set_egress_map, 3,
-		"<ifname/ifindex> <from> <to>" },
-	{ "veth-get-properties", "get veth properties", do_veth_get_properties, 1,
-	  "<ifname/ifindex>" },
-	{ "tun-get-properties", "get tun/tap properties", do_tun_get_properties, 1,
-	  "<ifname/ifindex>" },
-	{ "macvlan-get-properties", "get macvlan properties", do_macvlan_get_properties, 1,
-	  "<ifname/ifindex>" },
-	{ "vxlan-get-properties", "get vxlan properties", do_vxlan_get_properties, 1,
-	  "<ifname/ifindex>" },
-	{ "gre-get-properties", "get gre properties", do_gre_get_properties, 1,
-	  "<ifname/ifindex>" },
-	{ "ip4-address-get-all", "print all IPv4 addresses", do_ip4_address_get_all, 1, "<ifname/ifindex>" },
-	{ "ip6-address-get-all", "print all IPv6 addresses", do_ip6_address_get_all, 1, "<ifname/ifindex>" },
-	{ "ip4-address-add", "add IPv4 address", do_ip4_address_add, 4, "<ifname/ifindex> <address>/<plen> <lifetime> <>" },
-	{ "ip6-address-add", "add IPv6 address", do_ip6_address_add, 4, "<ifname/ifindex> <address>/<plen> <lifetime> [<flags>] <>" },
-	{ "ip4-address-delete", "delete IPv4 address", do_ip4_address_delete, 2,
-		"<ifname/ifindex> <address>/<plen>" },
-	{ "ip6-address-delete", "delete IPv6 address", do_ip6_address_delete, 2,
-		"<ifname/ifindex> <address>/<plen>" },
-	{ "ip4-address-exists", "check for existence of IPv4 address", do_ip4_address_get, 2,
-		"<ifname/ifindex> <address>/<plen>" },
-	{ "ip6-address-exists", "check for existence of IPv6 address", do_ip6_address_get, 2,
-		"<ifname/ifindex> <address>/<plen>" },
-	{ "ip4-route-get-all", "print all IPv4 routes", do_ip4_route_get_all, 1, "<ifname/ifindex>" },
-	{ "ip6-route-get-all", "print all IPv6 routes", do_ip6_route_get_all, 1, "<ifname/ifindex>" },
-	{ "ip4-route-add", "add IPv4 route", do_ip4_route_add, 5,
-		"<ifname/ifindex> <network>/<plen> <gateway> <metric> <mss>" },
-	{ "ip6-route-add", "add IPv6 route", do_ip6_route_add, 5,
-		"<ifname/ifindex> <network>/<plen> <gateway> <metric> <mss>" },
-	{ "ip4-route-delete", "delete IPv4 route", do_ip4_route_delete, 3,
-		"<ifname/ifindex> <network>/<plen> <metric>" },
-	{ "ip6-route-delete", "delete IPv6 route", do_ip6_route_delete, 3,
-		"<ifname/ifindex> <network>/<plen> <metric>" },
-	{ "ip4-route-exists", "check for existence of IPv4 route", do_ip4_route_get, 3,
-		"<ifname/ifindex> <network>/<plen> <metric>" },
-	{ "ip6-route-exists", "check for existence of IPv6 route", do_ip6_route_get, 3,
-		"<ifname/ifindex> <network>/<plen> <metric>" },
-	{ NULL, NULL, NULL, 0, NULL },
-};
-
-int
-main (int argc, char **argv)
-{
-	const char *arg0 = *argv++;
-	const command_t *command = NULL;
-	gboolean status = TRUE;
-
-#if !GLIB_CHECK_VERSION (2, 35, 0)
-	g_type_init ();
-#endif
-
-	if (*argv && !g_strcmp0 (argv[1], "--fake")) {
-		nm_fake_platform_setup ();
-	} else
-		nm_linux_platform_setup ();
-
-	if (*argv)
-		for (command = commands; command->name; command++)
-			if (g_str_has_prefix (command->name, *argv))
-				break;
-
-	if (command && command->name) {
-		argv++;
-		if (g_strv_length (argv) == command->argc)
-			status = command->handler (argv);
-		else {
-			error ("Wrong number of arguments to '%s' (expected %d).\n\nUsage: %s %s %s\n-- %s\n",
-					command->name, command->argc,
-					arg0, command->name, command->arghelp, command->help);
-			return EXIT_FAILURE;
-		}
-	} else {
-		error ("Usage: %s COMMAND\n\n", arg0);
-		error ("COMMAND\n");
-		for (command = commands; command->name; command++)
-			error ("  %s %s\n    -- %s\n", command->name, command->arghelp, command->help);
-		error ("\n");
-	}
-
-	return EXIT_SUCCESS;
-}
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index f9645d85..47cbcec1 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -274,10 +274,14 @@ test_slave (int master, int type, SignalData *master_changed)
 	}
 
 	/* Release */
+	ensure_no_signal (link_added);
 	ensure_no_signal (link_changed);
+	ensure_no_signal (link_removed);
 	g_assert (nm_platform_link_release (NM_PLATFORM_GET, master, ifindex));
 	g_assert_cmpint (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex), ==, 0);
+	accept_signals (link_added, 0, 1);
 	accept_signals (link_changed, 1, 3);
+	accept_signals (link_removed, 0, 1);
 	accept_signals (master_changed, 1, 2);
 
 	ensure_no_signal (master_changed);
@@ -289,7 +293,9 @@ test_slave (int master, int type, SignalData *master_changed)
 	ensure_no_signal (master_changed);
 
 	/* Remove */
+	ensure_no_signal (link_added);
 	ensure_no_signal (link_changed);
+	ensure_no_signal (link_removed);
 	g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
 	accept_signals (master_changed, 0, 1);
 	accept_signals (link_changed, 0, 1);
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index 73528aa9..d27b262e 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -865,7 +865,8 @@ create_pppd_cmd_line (NMPPPManager *self,
 		return NULL;
 
 	if (   pppoe
-	    || (adsl && strcmp (nm_setting_adsl_get_protocol (adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE))) {
+	    || (   adsl
+	        && !strcmp (nm_setting_adsl_get_protocol (adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE))) {
 		pppoe_binary = nm_utils_find_helper ("pppoe", NULL, err);
 		if (!pppoe_binary)
 			return NULL;
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index c694ad6f..8d9252a5 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -50,9 +50,8 @@ G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, G_TYPE_OBJECT)
                                          NMAgentManagerPrivate))
 
 typedef struct {
-	gboolean disposed;
-
 	NMDBusManager *dbus_mgr;
+	NMAuthManager *auth_mgr;
 
 	/* Auth chains for checking agent permissions */
 	GSList *chains;
@@ -1559,35 +1558,7 @@ authority_changed_cb (NMAuthManager *auth_manager, NMAgentManager *self)
 
 /*************************************************************/
 
-NMAgentManager *
-nm_agent_manager_get (void)
-{
-	static NMAgentManager *singleton = NULL;
-	NMAgentManagerPrivate *priv;
-
-	if (singleton)
-		return g_object_ref (singleton);
-
-	singleton = (NMAgentManager *) g_object_new (NM_TYPE_AGENT_MANAGER, NULL);
-	g_assert (singleton);
-
-	priv = NM_AGENT_MANAGER_GET_PRIVATE (singleton);
-	priv->dbus_mgr = nm_dbus_manager_get ();
-
-	nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_AGENT_MANAGER, singleton);
-
-	g_signal_connect (priv->dbus_mgr,
-	                  NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
-	                  G_CALLBACK (name_owner_changed_cb),
-	                  singleton);
-
-	g_signal_connect (nm_auth_manager_get (),
-	                  NM_AUTH_MANAGER_SIGNAL_CHANGED,
-	                  G_CALLBACK (authority_changed_cb),
-	                  singleton);
-
-	return singleton;
-}
+NM_DEFINE_SINGLETON_GETTER (NMAgentManager, nm_agent_manager_get, NM_TYPE_AGENT_MANAGER);
 
 static void
 nm_agent_manager_init (NMAgentManager *self)
@@ -1602,23 +1573,57 @@ nm_agent_manager_init (NMAgentManager *self)
 }
 
 static void
-dispose (GObject *object)
+constructed (GObject *object)
 {
 	NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (object);
 
-	if (!priv->disposed) {
-		priv->disposed = TRUE;
+	G_OBJECT_CLASS (nm_agent_manager_parent_class)->constructed (object);
 
-		g_signal_handlers_disconnect_by_func (nm_auth_manager_get (),
-		                                      G_CALLBACK (authority_changed_cb),
-		                                      object);
+	priv->dbus_mgr = g_object_ref (nm_dbus_manager_get ());
+	priv->auth_mgr = g_object_ref (nm_auth_manager_get ());
+
+	nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_AGENT_MANAGER, object);
 
-		g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_unref);
+	g_signal_connect (priv->dbus_mgr,
+	                  NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
+	                  G_CALLBACK (name_owner_changed_cb),
+	                  object);
+
+	g_signal_connect (priv->auth_mgr,
+	                  NM_AUTH_MANAGER_SIGNAL_CHANGED,
+	                  G_CALLBACK (authority_changed_cb),
+	                  object);
+}
 
+static void
+dispose (GObject *object)
+{
+	NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (object);
+
+	g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_unref);
+	priv->chains = NULL;
+
+	if (priv->agents) {
 		g_hash_table_destroy (priv->agents);
+		priv->agents = NULL;
+	}
+	if (priv->requests) {
 		g_hash_table_destroy (priv->requests);
+		priv->requests = NULL;
+	}
 
-		priv->dbus_mgr = NULL;
+	if (priv->auth_mgr) {
+		g_signal_handlers_disconnect_by_func (priv->auth_mgr,
+		                                      G_CALLBACK (authority_changed_cb),
+		                                      object);
+		g_clear_object (&priv->auth_mgr);
+	}
+	if (priv->dbus_mgr) {
+		g_signal_handlers_disconnect_by_func (priv->dbus_mgr,
+		                                      G_CALLBACK (name_owner_changed_cb),
+		                                      object);
+		nm_dbus_manager_unregister_object (priv->dbus_mgr, object);
+		g_clear_object (&priv->dbus_mgr);
 	}
 
 	G_OBJECT_CLASS (nm_agent_manager_parent_class)->dispose (object);
@@ -1632,6 +1637,7 @@ nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class)
 	g_type_class_add_private (agent_manager_class, sizeof (NMAgentManagerPrivate));
 
 	/* virtual methods */
+	object_class->constructed = constructed;
 	object_class->dispose = dispose;
 
 	/* Signals */
diff --git a/src/settings/nm-inotify-helper.c b/src/settings/nm-inotify-helper.c
index 41f0268d..3732e77a 100644
--- a/src/settings/nm-inotify-helper.c
+++ b/src/settings/nm-inotify-helper.c
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <sys/inotify.h>
 #include <glib.h>
+#include <errno.h>
 
 #include "nm-inotify-helper.h"
 #include "nm-logging.h"
@@ -55,9 +56,10 @@ nm_inotify_helper_add_watch (NMInotifyHelper *self, const char *path)
 {
 	NMInotifyHelperPrivate *priv = NM_INOTIFY_HELPER_GET_PRIVATE (self);
 	int wd;
-	guint32 refcount;
+	guint refcount;
 
-	g_return_val_if_fail (priv->ifd >= 0, -1);
+	if (priv->ifd < 0)
+		return -1;
 
 	/* We only care about modifications since we're just trying to get change
 	 * notifications on hardlinks.
@@ -78,9 +80,10 @@ void
 nm_inotify_helper_remove_watch (NMInotifyHelper *self, int wd)
 {
 	NMInotifyHelperPrivate *priv = NM_INOTIFY_HELPER_GET_PRIVATE (self);
-	guint32 refcount;
+	guint refcount;
 
-	g_return_if_fail (priv->ifd >= 0);
+	if (priv->ifd < 0)
+		return;
 
 	refcount = GPOINTER_TO_UINT (g_hash_table_lookup (priv->wd_refs, GINT_TO_POINTER (wd)));
 	if (!refcount)
@@ -128,7 +131,9 @@ init_inotify (NMInotifyHelper *self)
 
 	priv->ifd = inotify_init ();
 	if (priv->ifd == -1) {
-		nm_log_warn (LOGD_SETTINGS, "couldn't initialize inotify");
+		int errsv = errno;
+
+		nm_log_warn (LOGD_SETTINGS, "couldn't initialize inotify: %s (%d)", strerror (errsv), errsv);
 		return FALSE;
 	}
 
@@ -145,24 +150,7 @@ init_inotify (NMInotifyHelper *self)
 	return TRUE;
 }
 
-NMInotifyHelper *
-nm_inotify_helper_get (void)
-{
-	static NMInotifyHelper *singleton_instance = NULL;
-
-	if (!singleton_instance) {
-		singleton_instance = (NMInotifyHelper *) g_object_new (NM_TYPE_INOTIFY_HELPER, NULL);
-
-		if (!init_inotify (singleton_instance)) {
-			g_clear_object (&singleton_instance);
-			return NULL;
-		}
-	} else
-		g_object_ref (singleton_instance);
-
-	g_assert (singleton_instance);
-	return singleton_instance;
-}
+NM_DEFINE_SINGLETON_GETTER (NMInotifyHelper, nm_inotify_helper_get, NM_TYPE_INOTIFY_HELPER);
 
 static void
 nm_inotify_helper_init (NMInotifyHelper *self)
@@ -173,6 +161,14 @@ nm_inotify_helper_init (NMInotifyHelper *self)
 }
 
 static void
+constructed (GObject *object)
+{
+	G_OBJECT_CLASS (nm_inotify_helper_parent_class)->constructed (object);
+
+	init_inotify (NM_INOTIFY_HELPER (object));
+}
+
+static void
 finalize (GObject *object)
 {
 	NMInotifyHelperPrivate *priv = NM_INOTIFY_HELPER_GET_PRIVATE (object);
@@ -193,6 +189,7 @@ nm_inotify_helper_class_init (NMInotifyHelperClass *klass)
 	g_type_class_add_private (klass, sizeof (NMInotifyHelperPrivate));
 
 	/* Virtual methods */
+	object_class->constructed = constructed;
 	object_class->finalize = finalize;
 
 	/* Signals */
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index da5384c0..1fa19237 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -2282,7 +2282,7 @@ nm_settings_connection_init (NMSettingsConnection *self)
 	                                             G_CALLBACK (session_changed_cb),
 	                                             self);
 
-	priv->agent_mgr = nm_agent_manager_get ();
+	priv->agent_mgr = g_object_ref (nm_agent_manager_get ());
 
 	priv->seen_bssids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 4d7d697d..f20bc71b 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -1922,7 +1922,7 @@ nm_settings_init (NMSettings *self)
 	 * transient, and we don't want the agent manager to get destroyed and
 	 * recreated often.
 	 */
-	priv->agent_mgr = nm_agent_manager_get ();
+	priv->agent_mgr = g_object_ref (nm_agent_manager_get ());
 
 	g_signal_connect (priv->agent_mgr, "agent-registered", G_CALLBACK (secret_agent_registered), self);
 }
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c
index 6358c180..083f2ebc 100644
--- a/src/supplicant-manager/nm-supplicant-manager.c
+++ b/src/supplicant-manager/nm-supplicant-manager.c
@@ -318,19 +318,7 @@ on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data)
 
 /*******************************************************************/
 
-NMSupplicantManager *
-nm_supplicant_manager_get (void)
-{
-	static NMSupplicantManager *singleton = NULL;
-
-	if (!singleton)
-		singleton = NM_SUPPLICANT_MANAGER (g_object_new (NM_TYPE_SUPPLICANT_MANAGER, NULL));
-	else
-		g_object_ref (singleton);
-
-	g_assert (singleton);
-	return singleton;
-}
+NM_DEFINE_SINGLETON_GETTER (NMSupplicantManager, nm_supplicant_manager_get, NM_TYPE_SUPPLICANT_MANAGER);
 
 static void
 nm_supplicant_manager_init (NMSupplicantManager *self)
diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c
index 235cfd42..404940d4 100644
--- a/src/tests/test-ip4-config.c
+++ b/src/tests/test-ip4-config.c
@@ -336,6 +336,27 @@ test_merge_subtract_mss_mtu (void)
 	g_object_unref (cfg3);
 }
 
+static void
+test_strip_search_trailing_dot (void)
+{
+	NMIP4Config *config;
+
+	config = nm_ip4_config_new ();
+
+	nm_ip4_config_add_search (config, ".");
+	nm_ip4_config_add_search (config, "foo");
+	nm_ip4_config_add_search (config, "bar.");
+	nm_ip4_config_add_search (config, "baz.com");
+	nm_ip4_config_add_search (config, "baz.com.");
+
+	g_assert_cmpuint (nm_ip4_config_get_num_searches (config), ==, 3);
+	g_assert_cmpstr (nm_ip4_config_get_search (config, 0), ==, "foo");
+	g_assert_cmpstr (nm_ip4_config_get_search (config, 1), ==, "bar");
+	g_assert_cmpstr (nm_ip4_config_get_search (config, 2), ==, "baz.com");
+
+	g_object_unref (config);
+}
+
 /*******************************************/
 
 int
@@ -352,6 +373,7 @@ main (int argc, char **argv)
 	g_test_add_func ("/ip4-config/add-address-with-source", test_add_address_with_source);
 	g_test_add_func ("/ip4-config/add-route-with-source", test_add_route_with_source);
 	g_test_add_func ("/ip4-config/merge-subtract-mss-mtu", test_merge_subtract_mss_mtu);
+	g_test_add_func ("/ip4-config/strip-search-trailing-dot", test_strip_search_trailing_dot);
 
 	return g_test_run ();
 }
diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c
index 9e1d5651..a5397b8a 100644
--- a/src/tests/test-ip6-config.c
+++ b/src/tests/test-ip6-config.c
@@ -321,6 +321,27 @@ test_nm_ip6_config_addresses_sort (void)
 	g_object_unref (config);
 }
 
+static void
+test_strip_search_trailing_dot (void)
+{
+	NMIP6Config *config;
+
+	config = nm_ip6_config_new ();
+
+	nm_ip6_config_add_search (config, ".");
+	nm_ip6_config_add_search (config, "foo");
+	nm_ip6_config_add_search (config, "bar.");
+	nm_ip6_config_add_search (config, "baz.com");
+	nm_ip6_config_add_search (config, "baz.com.");
+
+	g_assert_cmpuint (nm_ip6_config_get_num_searches (config), ==, 3);
+	g_assert_cmpstr (nm_ip6_config_get_search (config, 0), ==, "foo");
+	g_assert_cmpstr (nm_ip6_config_get_search (config, 1), ==, "bar");
+	g_assert_cmpstr (nm_ip6_config_get_search (config, 2), ==, "baz.com");
+
+	g_object_unref (config);
+}
+
 /*******************************************/
 
 NMTST_DEFINE();
@@ -335,6 +356,7 @@ main (int argc, char **argv)
 	g_test_add_func ("/ip6-config/add-address-with-source", test_add_address_with_source);
 	g_test_add_func ("/ip6-config/add-route-with-source", test_add_route_with_source);
 	g_test_add_func ("/ip6-config/test_nm_ip6_config_addresses_sort", test_nm_ip6_config_addresses_sort);
+	g_test_add_func ("/ip6-config/strip-search-trailing-dot", test_strip_search_trailing_dot);
 
 	return g_test_run ();
 }
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index e2d3103b..64e5e2ab 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -1663,7 +1663,6 @@ static void
 really_activate (NMVpnConnection *connection, const char *username)
 {
 	NMVpnConnectionPrivate *priv;
-	NMAgentManager *agent_mgr;
 	GHashTable *details;
 
 	g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
@@ -1702,8 +1701,7 @@ really_activate (NMVpnConnection *connection, const char *username)
 	 * dialog and we won't get the secrets we need.  In this case fall back to
 	 * the old Connect() call.
 	 */
-	agent_mgr = nm_agent_manager_get ();
-	if (nm_agent_manager_all_agents_have_capability (agent_mgr,
+	if (nm_agent_manager_all_agents_have_capability (nm_agent_manager_get (),
 	                                                 nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (connection)),
 	                                                 NM_SECRET_AGENT_CAPABILITY_VPN_HINTS)) {
 		nm_log_dbg (LOGD_VPN, "Allowing interactive secrets as all agents have that capability");
@@ -1719,7 +1717,6 @@ really_activate (NMVpnConnection *connection, const char *username)
 		                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash,
 		                         G_TYPE_INVALID);
 	}
-	g_object_unref (agent_mgr);
 	g_hash_table_destroy (details);
 
 	_set_vpn_state (connection, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c
index 1f3798c7..1de9b753 100644
--- a/src/vpn-manager/nm-vpn-manager.c
+++ b/src/vpn-manager/nm-vpn-manager.c
@@ -200,19 +200,7 @@ vpn_dir_changed (GFileMonitor *monitor,
 
 /******************************************************************************/
 
-NMVpnManager *
-nm_vpn_manager_get (void)
-{
-	static NMVpnManager *singleton = NULL;
-
-	if (!singleton)
-		singleton = NM_VPN_MANAGER (g_object_new (NM_TYPE_VPN_MANAGER, NULL));
-	else
-		g_object_ref (singleton);
-
-	g_assert (singleton);
-	return singleton;
-}
+NM_DEFINE_SINGLETON_GETTER (NMVpnManager, nm_vpn_manager_get, NM_TYPE_VPN_MANAGER);
 
 static void
 nm_vpn_manager_init (NMVpnManager *self)