about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2015-05-05 17:48:57 +0200
committerMichael Biebl <biebl@debian.org>2015-05-05 17:48:57 +0200
commitf408e27bccfacf347605a8d98649975a68f38a17 (patch)
tree654fd6695c31511baf919b1c0870d119a352ed75 /src
parent2c032d8f1c6292c1338a615e6ec40252889ba85c (diff)
Imported Upstream version 1.0.2 upstream/1.0.2
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile.in52
-rw-r--r--src/NetworkManagerUtils.c95
-rw-r--r--src/NetworkManagerUtils.h3
-rw-r--r--src/devices/adsl/Makefile.in30
-rw-r--r--src/devices/bluetooth/Makefile.in30
-rw-r--r--src/devices/bluetooth/nm-device-bt.c7
-rw-r--r--src/devices/nm-device-bond.c3
-rw-r--r--src/devices/nm-device-bridge.c3
-rw-r--r--src/devices/nm-device-private.h3
-rw-r--r--src/devices/nm-device.c429
-rw-r--r--src/devices/nm-device.h67
-rw-r--r--src/devices/team/Makefile.in30
-rw-r--r--src/devices/team/nm-device-team.c333
-rw-r--r--src/devices/wifi/Makefile.in30
-rw-r--r--src/devices/wifi/nm-device-olpc-mesh.c2
-rw-r--r--src/devices/wifi/nm-device-wifi.c82
-rw-r--r--src/devices/wifi/nm-wifi-ap.c2
-rw-r--r--src/devices/wifi/tests/Makefile.am1
-rw-r--r--src/devices/wifi/tests/Makefile.in32
-rw-r--r--src/devices/wifi/tests/test-wifi-ap-utils.c3
-rw-r--r--src/devices/wimax/Makefile.in30
-rw-r--r--src/devices/wimax/nm-device-wimax.c31
-rw-r--r--src/devices/wwan/Makefile.in30
-rw-r--r--src/devices/wwan/nm-device-modem.c71
-rw-r--r--src/devices/wwan/nm-modem-broadband.c385
-rw-r--r--src/devices/wwan/nm-modem.c310
-rw-r--r--src/devices/wwan/nm-modem.h24
-rw-r--r--src/devices/wwan/wwan-exports.ver2
-rw-r--r--src/dhcp-manager/Makefile.in30
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c10
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient-utils.c29
-rw-r--r--src/dhcp-manager/nm-dhcp-utils.c1
-rw-r--r--src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h2
-rw-r--r--src/dhcp-manager/tests/Makefile.am1
-rw-r--r--src/dhcp-manager/tests/Makefile.in34
-rw-r--r--src/dhcp-manager/tests/test-dhcp-dhclient.c79
-rw-r--r--src/dhcp-manager/tests/test-dhcp-utils.c3
-rw-r--r--src/dns-manager/nm-dns-manager.c198
-rw-r--r--src/dns-manager/nm-dns-plugin.c5
-rw-r--r--src/dns-manager/nm-dns-unbound.c2
-rw-r--r--src/dnsmasq-manager/tests/Makefile.am1
-rw-r--r--src/dnsmasq-manager/tests/Makefile.in32
-rw-r--r--src/main-utils.c93
-rw-r--r--src/main-utils.h8
-rw-r--r--src/main.c233
-rw-r--r--src/nm-auth-manager.c22
-rw-r--r--src/nm-auth-subject.c3
-rw-r--r--src/nm-auth-utils.c5
-rw-r--r--src/nm-config.c19
-rw-r--r--src/nm-connectivity.c69
-rw-r--r--src/nm-dbus-manager.c46
-rw-r--r--src/nm-dbus-manager.h1
-rw-r--r--src/nm-default-route-manager.c218
-rw-r--r--src/nm-dispatcher.c8
-rw-r--r--src/nm-enum-types.c18
-rw-r--r--src/nm-iface-helper.c278
-rw-r--r--src/nm-ip4-config.c2
-rw-r--r--src/nm-ip6-config.c4
-rw-r--r--src/nm-logging.c19
-rw-r--r--src/nm-logging.h27
-rw-r--r--src/nm-manager.c112
-rw-r--r--src/nm-properties-changed-signal.c11
-rw-r--r--src/platform/Makefile.in24
-rw-r--r--src/platform/nm-fake-platform.c18
-rw-r--r--src/platform/nm-linux-platform.c150
-rw-r--r--src/platform/nm-platform.c166
-rw-r--r--src/platform/nm-platform.h30
-rw-r--r--src/platform/tests/Makefile.am2
-rw-r--r--src/platform/tests/Makefile.in32
-rw-r--r--src/platform/tests/test-address.c6
-rw-r--r--src/platform/tests/test-cleanup.c6
-rw-r--r--src/platform/tests/test-common.c115
-rw-r--r--src/platform/tests/test-common.h8
-rw-r--r--src/platform/tests/test-link.c8
-rw-r--r--src/platform/tests/test-route.c97
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.c11
-rw-r--r--src/platform/wifi/wifi-utils-wext.c15
-rw-r--r--src/platform/wifi/wifi-utils.h3
-rw-r--r--src/ppp-manager/Makefile.in30
-rw-r--r--src/ppp-manager/nm-ppp-manager.c111
-rw-r--r--src/ppp-manager/nm-ppp-manager.h8
-rw-r--r--src/rdisc/Makefile.in24
-rw-r--r--src/rdisc/nm-fake-rdisc.c394
-rw-r--r--src/rdisc/nm-fake-rdisc.h47
-rw-r--r--src/rdisc/nm-lndp-rdisc.c468
-rw-r--r--src/rdisc/nm-rdisc-private.h36
-rw-r--r--src/rdisc/nm-rdisc.c454
-rw-r--r--src/rdisc/nm-rdisc.h2
-rw-r--r--src/rdisc/tests/Makefile.am17
-rw-r--r--src/rdisc/tests/Makefile.in199
-rw-r--r--src/rdisc/tests/test-rdisc-fake.c453
-rw-r--r--src/rdisc/tests/test-rdisc-linux.c (renamed from src/rdisc/tests/rdisc.c)44
-rw-r--r--src/settings/nm-agent-manager.c9
-rw-r--r--src/settings/nm-inotify-helper.c16
-rw-r--r--src/settings/nm-settings-connection.c141
-rw-r--r--src/settings/nm-settings-connection.h22
-rw-r--r--src/settings/nm-settings.c74
-rw-r--r--src/settings/nm-settings.h11
-rw-r--r--src/settings/plugins/Makefile.in24
-rw-r--r--src/settings/plugins/example/Makefile.in30
-rw-r--r--src/settings/plugins/example/nm-example-connection.c1
-rw-r--r--src/settings/plugins/ibft/Makefile.in30
-rw-r--r--src/settings/plugins/ibft/nm-ibft-connection.c1
-rw-r--r--src/settings/plugins/ibft/plugin.c6
-rw-r--r--src/settings/plugins/ibft/reader.c1
-rw-r--r--src/settings/plugins/ibft/tests/Makefile.am1
-rw-r--r--src/settings/plugins/ibft/tests/Makefile.in32
-rw-r--r--src/settings/plugins/ibft/tests/test-ibft.c7
-rw-r--r--src/settings/plugins/ifcfg-rh/Makefile.in30
-rw-r--r--src/settings/plugins/ifcfg-rh/common.h4
-rw-r--r--src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c217
-rw-r--r--src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.h8
-rw-r--r--src/settings/plugins/ifcfg-rh/plugin.c561
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.c203
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.h17
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.c16
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/Makefile.am1
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/Makefile.in32
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am3
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in27
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-mode-numeric5
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bridge-main2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-open2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp-plus-ip6
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-12
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-23
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-obsolete-gateway-n13
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-shared-plus-ip19
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh-utils.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c2561
-rw-r--r--src/settings/plugins/ifcfg-rh/utils.c24
-rw-r--r--src/settings/plugins/ifcfg-rh/utils.h8
-rw-r--r--src/settings/plugins/ifcfg-rh/writer.c40
-rw-r--r--src/settings/plugins/ifcfg-suse/Makefile.in30
-rw-r--r--src/settings/plugins/ifnet/Makefile.in30
-rw-r--r--src/settings/plugins/ifnet/net_parser.c6
-rw-r--r--src/settings/plugins/ifnet/nm-ifnet-connection.c1
-rw-r--r--src/settings/plugins/ifnet/plugin.c9
-rw-r--r--src/settings/plugins/ifnet/tests/Makefile.in30
-rw-r--r--src/settings/plugins/ifnet/tests/test_all.c3
-rw-r--r--src/settings/plugins/ifupdown/Makefile.in30
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.am2
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.in30
-rw-r--r--src/settings/plugins/keyfile/Makefile.in30
-rw-r--r--src/settings/plugins/keyfile/common.h2
-rw-r--r--src/settings/plugins/keyfile/nm-keyfile-connection.c64
-rw-r--r--src/settings/plugins/keyfile/nm-keyfile-connection.h3
-rw-r--r--src/settings/plugins/keyfile/plugin.c377
-rw-r--r--src/settings/plugins/keyfile/reader.c1
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.am1
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.in32
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.in24
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main2
-rw-r--r--src/settings/plugins/keyfile/tests/test-keyfile.c26
-rw-r--r--src/settings/plugins/keyfile/utils.h7
-rw-r--r--src/settings/plugins/keyfile/writer.c32
-rw-r--r--src/supplicant-manager/nm-supplicant-config.c7
-rw-r--r--src/supplicant-manager/tests/Makefile.am1
-rw-r--r--src/supplicant-manager/tests/Makefile.in32
-rw-r--r--src/supplicant-manager/tests/test-supplicant-config.c9
-rw-r--r--src/tests/Makefile.am1
-rw-r--r--src/tests/Makefile.in34
-rw-r--r--src/tests/config/Makefile.am1
-rw-r--r--src/tests/config/Makefile.in32
-rw-r--r--src/tests/config/nm-test-device.c7
-rw-r--r--src/tests/config/test-config.c25
-rw-r--r--src/tests/test-general-with-expect.c32
-rw-r--r--src/tests/test-wired-defname.c9
169 files changed, 7370 insertions, 4526 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 808e59eb..a24ac6c4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -229,6 +229,7 @@ nm_sources = \
 	rdisc/nm-lndp-rdisc.h \
 	rdisc/nm-rdisc.c \
 	rdisc/nm-rdisc.h \
+	rdisc/nm-rdisc-private.h \
 	\
 	ppp-manager/nm-ppp-manager.c \
 	ppp-manager/nm-ppp-manager.h \
diff --git a/src/Makefile.in b/src/Makefile.in
index 6828f69c..da305209 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -17,7 +17,17 @@
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -115,8 +125,6 @@ sbin_PROGRAMS = NetworkManager$(EXEEXT)
 
 libexec_PROGRAMS = nm-iface-helper$(EXEEXT)
 subdir = src
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -133,6 +141,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -182,11 +191,12 @@ am__libNetworkManager_la_SOURCES_DIST = devices/nm-device-bond.h \
 	platform/wifi/wifi-utils.h rdisc/nm-fake-rdisc.c \
 	rdisc/nm-fake-rdisc.h rdisc/nm-lndp-rdisc.c \
 	rdisc/nm-lndp-rdisc.h rdisc/nm-rdisc.c rdisc/nm-rdisc.h \
-	ppp-manager/nm-ppp-manager.c ppp-manager/nm-ppp-manager.h \
-	ppp-manager/nm-ppp-status.h settings/nm-agent-manager.c \
-	settings/nm-agent-manager.h settings/nm-inotify-helper.c \
-	settings/nm-inotify-helper.h settings/nm-secret-agent.c \
-	settings/nm-secret-agent.h settings/nm-settings-connection.c \
+	rdisc/nm-rdisc-private.h ppp-manager/nm-ppp-manager.c \
+	ppp-manager/nm-ppp-manager.h ppp-manager/nm-ppp-status.h \
+	settings/nm-agent-manager.c settings/nm-agent-manager.h \
+	settings/nm-inotify-helper.c settings/nm-inotify-helper.h \
+	settings/nm-secret-agent.c settings/nm-secret-agent.h \
+	settings/nm-settings-connection.c \
 	settings/nm-settings-connection.h settings/nm-settings.c \
 	settings/nm-settings.h settings/nm-system-config-interface.c \
 	settings/nm-system-config-interface.h \
@@ -487,6 +497,8 @@ DIST_SUBDIRS = . devices/adsl devices/wifi dhcp-manager ppp-manager \
 	settings/plugins devices/wwan devices/bluetooth devices/wimax \
 	devices/team dhcp-manager/tests dnsmasq-manager/tests platform \
 	rdisc supplicant-manager/tests tests
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -538,7 +550,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -573,6 +584,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -946,11 +958,12 @@ nm_sources = $(nm_device_headers) $(nm_dhcp_client_headers) \
 	platform/wifi/wifi-utils.h rdisc/nm-fake-rdisc.c \
 	rdisc/nm-fake-rdisc.h rdisc/nm-lndp-rdisc.c \
 	rdisc/nm-lndp-rdisc.h rdisc/nm-rdisc.c rdisc/nm-rdisc.h \
-	ppp-manager/nm-ppp-manager.c ppp-manager/nm-ppp-manager.h \
-	ppp-manager/nm-ppp-status.h settings/nm-agent-manager.c \
-	settings/nm-agent-manager.h settings/nm-inotify-helper.c \
-	settings/nm-inotify-helper.h settings/nm-secret-agent.c \
-	settings/nm-secret-agent.h settings/nm-settings-connection.c \
+	rdisc/nm-rdisc-private.h ppp-manager/nm-ppp-manager.c \
+	ppp-manager/nm-ppp-manager.h ppp-manager/nm-ppp-status.h \
+	settings/nm-agent-manager.c settings/nm-agent-manager.h \
+	settings/nm-inotify-helper.c settings/nm-inotify-helper.h \
+	settings/nm-secret-agent.c settings/nm-secret-agent.h \
+	settings/nm-settings-connection.c \
 	settings/nm-settings-connection.h settings/nm-settings.c \
 	settings/nm-settings.h settings/nm-system-config-interface.c \
 	settings/nm-system-config-interface.h \
@@ -1121,7 +1134,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -1388,14 +1400,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -2351,6 +2363,8 @@ uninstall-am: uninstall-dbusserviceDATA uninstall-libexecPROGRAMS \
 	tags tags-am uninstall uninstall-am uninstall-dbusserviceDATA \
 	uninstall-libexecPROGRAMS uninstall-sbinPROGRAMS
 
+.PRECIOUS: Makefile
+
 include $(GLIB_MAKEFILE)
 
 @GNOME_CODE_COVERAGE_RULES@
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 2c291cdb..24cb949c 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -71,36 +71,36 @@
 gboolean
 nm_ethernet_address_is_valid (gconstpointer addr, gssize len)
 {
-	guint8 invalid_addr1[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-	guint8 invalid_addr2[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-	guint8 invalid_addr3[ETH_ALEN] = {0x44, 0x44, 0x44, 0x44, 0x44, 0x44};
-	guint8 invalid_addr4[ETH_ALEN] = {0x00, 0x30, 0xb4, 0x00, 0x00, 0x00}; /* prism54 dummy MAC */
-	guchar first_octet;
-
-	g_return_val_if_fail (addr != NULL, FALSE);
-	g_return_val_if_fail (len == ETH_ALEN || len == -1, FALSE);
-
-	/* Compare the AP address the card has with invalid ethernet MAC addresses. */
-	if (nm_utils_hwaddr_matches (addr, len, invalid_addr1, ETH_ALEN))
-		return FALSE;
+	guint8 invalid_addr[4][ETH_ALEN] = {
+	    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+	    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	    {0x44, 0x44, 0x44, 0x44, 0x44, 0x44},
+	    {0x00, 0x30, 0xb4, 0x00, 0x00, 0x00}, /* prism54 dummy MAC */
+	};
+	guint8 addr_bin[ETH_ALEN];
+	guint i;
 
-	if (nm_utils_hwaddr_matches (addr, len, invalid_addr2, ETH_ALEN))
+	if (!addr) {
+		g_return_val_if_fail (len == -1 || len == ETH_ALEN, FALSE);
 		return FALSE;
+	}
 
-	if (nm_utils_hwaddr_matches (addr, len, invalid_addr3, ETH_ALEN))
-		return FALSE;
+	if (len == -1) {
+		if (!nm_utils_hwaddr_aton (addr, addr_bin, ETH_ALEN))
+			return FALSE;
+		addr = addr_bin;
+	} else if (len != ETH_ALEN)
+		g_return_val_if_reached (FALSE);
 
-	if (nm_utils_hwaddr_matches (addr, len, invalid_addr4, ETH_ALEN))
+	/* Check for multicast address */
+	if ((((guint8 *) addr)[0]) & 0x01)
 		return FALSE;
 
-	/* Check for multicast address */
-	if (len == -1)
-		first_octet = strtoul (addr, NULL, 16);
-	else
-		first_octet = ((guint8 *)addr)[0];
-	if (first_octet & 0x01)
+	for (i = 0; i < G_N_ELEMENTS (invalid_addr); i++) {
+		if (nm_utils_hwaddr_matches (addr, ETH_ALEN, invalid_addr[i], ETH_ALEN))
 			return FALSE;
-	
+	}
+
 	return TRUE;
 }
 
@@ -152,27 +152,26 @@ nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_
 
 
 int
-nm_spawn_process (const char *args)
+nm_spawn_process (const char *args, GError **error)
 {
+	GError *local = NULL;
 	gint num_args;
 	char **argv = NULL;
 	int status = -1;
-	GError *error = NULL;
 
 	g_return_val_if_fail (args != NULL, -1);
+	g_return_val_if_fail (!error || !*error, -1);
 
-	if (!g_shell_parse_argv (args, &num_args, &argv, &error)) {
-		nm_log_warn (LOGD_CORE, "could not parse arguments for '%s': %s", args, error->message);
-		g_error_free (error);
-		return -1;
+	if (g_shell_parse_argv (args, &num_args, &argv, &local)) {
+		g_spawn_sync ("/", argv, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, &status, &local);
+		g_strfreev (argv);
 	}
 
-	if (!g_spawn_sync ("/", argv, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, &status, &error)) {
-		nm_log_warn (LOGD_CORE, "could not spawn process '%s': %s", args, error->message);
-		g_error_free (error);
+	if (local) {
+		nm_log_warn (LOGD_CORE, "could not spawn process '%s': %s", args, local->message);
+		g_propagate_error (error, local);
 	}
 
-	g_strfreev (argv);
 	return status;
 }
 
@@ -814,6 +813,7 @@ const char *const NM_PATHS_DEFAULT[] = {
 	"/sbin/",
 	"/usr/sbin/",
 	"/usr/local/sbin/",
+	"/bin/",
 	"/usr/bin/",
 	"/usr/local/bin/",
 	NULL,
@@ -1724,10 +1724,10 @@ nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max
  * Returns a variant3 UUID based on the concatenated C strings.
  * It does not simply concatenate them, but also includes the
  * terminating '\0' character. For example "a", "b", gives
- * "a\0b\0\0".
+ * "a\0b\0".
  *
  * This has the advantage, that the following invocations
- * all give different UUIDs: (""), ("",""), ("","a"), ("a",""),
+ * all give different UUIDs: (NULL), (""), ("",""), ("","a"), ("a",""),
  * ("aa"), ("aa", ""), ("", "aa"), ...
  */
 char *
@@ -2090,9 +2090,9 @@ nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base,
 	connection_diff_are_same = nm_connection_diff (connection, diff_base, NM_SETTING_COMPARE_FLAG_EXACT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, &connection_diff);
 	if (connection_diff_are_same) {
 		if (diff_base)
-			nm_log (level, domain, "%sconnection '%s' (%p and %p): no difference", prefix, name, connection, diff_base);
+			nm_log (level, domain, "%sconnection '%s' (%p/%s and %p/%s): no difference", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base));
 		else
-			nm_log (level, domain, "%sconnection '%s' (%p): no properties set", prefix, name, connection);
+			nm_log (level, domain, "%sconnection '%s' (%p/%s): no properties set", prefix, name, connection, G_OBJECT_TYPE_NAME (connection));
 		g_assert (!connection_diff);
 		return;
 	}
@@ -2127,9 +2127,9 @@ nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base,
 				GError *err_verify = NULL;
 
 				if (diff_base)
-					nm_log (level, domain, "%sconnection '%s' (%p < %p):", prefix, name, connection, diff_base);
+					nm_log (level, domain, "%sconnection '%s' (%p/%s < %p/%s):", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base));
 				else
-					nm_log (level, domain, "%sconnection '%s' (%p):", prefix, name, connection);
+					nm_log (level, domain, "%sconnection '%s' (%p/%s):", prefix, name, connection, G_OBJECT_TYPE_NAME (connection));
 				print_header = FALSE;
 
 				if (!nm_connection_verify (connection, &err_verify)) {
@@ -2312,6 +2312,7 @@ get_gre_eui64_u_bit (guint32 addr)
  * @link_type: the hardware link type
  * @hwaddr: the hardware address of the interface
  * @hwaddr_len: the length (in bytes) of @hwaddr
+ * @dev_id: the device identifier, if any
  * @out_iid: on success, filled with the interface identifier; on failure
  * zeroed out
  *
@@ -2326,6 +2327,7 @@ gboolean
 nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
                                         const guint8 *hwaddr,
                                         guint hwaddr_len,
+                                        guint dev_id,
                                         NMUtilsIPv6IfaceId *out_iid)
 {
 	guint32 addr;
@@ -2360,13 +2362,20 @@ nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
 	default:
 		if (hwaddr_len == ETH_ALEN) {
 			/* Translate 48-bit MAC address to a 64-bit Modified EUI-64.  See
-			 * http://tools.ietf.org/html/rfc4291#appendix-A
+			 * http://tools.ietf.org/html/rfc4291#appendix-A and the Linux
+			 * kernel's net/ipv6/addrconf.c::ipv6_generate_eui64() function.
 			 */
-			out_iid->id_u8[0] = hwaddr[0] ^ 0x02;
+			out_iid->id_u8[0] = hwaddr[0];
 			out_iid->id_u8[1] = hwaddr[1];
 			out_iid->id_u8[2] = hwaddr[2];
-			out_iid->id_u8[3] = 0xff;
-			out_iid->id_u8[4] = 0xfe;
+			if (dev_id) {
+				out_iid->id_u8[3] = (dev_id >> 8) & 0xff;
+				out_iid->id_u8[4] = dev_id & 0xff;
+			} else {
+				out_iid->id_u8[0] ^= 0x02;
+				out_iid->id_u8[3] = 0xff;
+				out_iid->id_u8[4] = 0xfe;
+			}
 			out_iid->id_u8[5] = hwaddr[3];
 			out_iid->id_u8[6] = hwaddr[4];
 			out_iid->id_u8[7] = hwaddr[5];
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 40315c6e..ae1edd82 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -49,7 +49,7 @@ nm_utils_ip6_route_metric_normalize (guint32 metric)
 	return metric ? metric : 1024 /*NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6*/;
 }
 
-int nm_spawn_process (const char *args);
+int nm_spawn_process (const char *args, GError **error);
 
 /* check if @flags has exactly one flag (@check) set. You should call this
  * only with @check being a compile time constant and a power of two. */
@@ -196,6 +196,7 @@ typedef struct {
 gboolean nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
                                                  const guint8 *hwaddr,
                                                  guint len,
+                                                 guint dev_id,
                                                  NMUtilsIPv6IfaceId *out_iid);
 
 void nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr,
diff --git a/src/devices/adsl/Makefile.in b/src/devices/adsl/Makefile.in
index 7942c559..02da85e7 100644
--- a/src/devices/adsl/Makefile.in
+++ b/src/devices/adsl/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/devices/adsl
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -207,6 +216,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -233,7 +244,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -268,6 +278,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -524,7 +535,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/adsl/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/devices/adsl/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -596,14 +606,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -831,6 +841,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 include $(GLIB_MAKEFILE)
 
 @GNOME_CODE_COVERAGE_RULES@
diff --git a/src/devices/bluetooth/Makefile.in b/src/devices/bluetooth/Makefile.in
index 0a285fda..b8e6dcda 100644
--- a/src/devices/bluetooth/Makefile.in
+++ b/src/devices/bluetooth/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -85,8 +95,6 @@ host_triplet = @host@
 
 @WITH_BLUEZ5_DUN_TRUE@am__append_3 = $(BLUEZ5_LIBS)
 subdir = src/devices/bluetooth
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -103,6 +111,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -227,6 +236,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -253,7 +264,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -288,6 +298,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -536,7 +547,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/bluetooth/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/devices/bluetooth/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -614,14 +624,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -849,6 +859,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 include $(GLIB_MAKEFILE)
 
 @GNOME_CODE_COVERAGE_RULES@
diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c
index 689f37c9..61371ddd 100644
--- a/src/devices/bluetooth/nm-device-bt.c
+++ b/src/devices/bluetooth/nm-device-bt.c
@@ -187,6 +187,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 static gboolean
 check_connection_available (NMDevice *device,
                             NMConnection *connection,
+                            NMDeviceCheckConAvailableFlags flags,
                             const char *specific_object)
 {
 	NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
@@ -929,7 +930,7 @@ bluez_device_removed (NMBluezDevice *bdev, gpointer user_data)
 /*****************************************************************************/
 
 static gboolean
-is_available (NMDevice *dev)
+is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags)
 {
 	NMDeviceBt *self = NM_DEVICE_BT (dev);
 	NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
@@ -957,7 +958,7 @@ handle_availability_change (NMDeviceBt *self,
 		return;
 	}
 
-	available = nm_device_is_available (device);
+	available = nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
 	if (available == old_available)
 		return;
 
@@ -987,7 +988,7 @@ set_mm_running (NMDeviceBt *self, gboolean running)
 	_LOGD (LOGD_BT, "ModemManager now %s",
 	       running ? "available" : "unavailable");
 
-	old_available = nm_device_is_available (NM_DEVICE (self));
+	old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
 	priv->mm_running = running;
 	handle_availability_change (self, old_available, NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE);
 
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c
index 9d9fe426..0b2c97d1 100644
--- a/src/devices/nm-device-bond.c
+++ b/src/devices/nm-device-bond.c
@@ -67,7 +67,7 @@ get_generic_capabilities (NMDevice *dev)
 }
 
 static gboolean
-is_available (NMDevice *dev)
+is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags)
 {
 	if (NM_DEVICE_GET_CLASS (dev)->is_up)
 		return NM_DEVICE_GET_CLASS (dev)->is_up (dev);
@@ -77,6 +77,7 @@ is_available (NMDevice *dev)
 static gboolean
 check_connection_available (NMDevice *device,
                             NMConnection *connection,
+                            NMDeviceCheckConAvailableFlags flags,
                             const char *specific_object)
 {
 	/* Connections are always available because the carrier state is determined
diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c
index a70cfd95..a2ed4b41 100644
--- a/src/devices/nm-device-bridge.c
+++ b/src/devices/nm-device-bridge.c
@@ -66,7 +66,7 @@ get_generic_capabilities (NMDevice *dev)
 }
 
 static gboolean
-is_available (NMDevice *dev)
+is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags)
 {
 	if (NM_DEVICE_GET_CLASS (dev)->is_up)
 		return NM_DEVICE_GET_CLASS (dev)->is_up (dev);
@@ -76,6 +76,7 @@ is_available (NMDevice *dev)
 static gboolean
 check_connection_available (NMDevice *device,
                             NMConnection *connection,
+                            NMDeviceCheckConAvailableFlags flags,
                             const char *specific_object)
 {
 	/* Connections are always available because the carrier state is determined
diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h
index 65a9a71a..1f781bbc 100644
--- a/src/devices/nm-device-private.h
+++ b/src/devices/nm-device-private.h
@@ -33,7 +33,8 @@ enum NMActStageReturn {
 	NM_ACT_STAGE_RETURN_SUCCESS,     /* Activation stage done */
 	NM_ACT_STAGE_RETURN_POSTPONE,    /* Long-running operation in progress */
 	NM_ACT_STAGE_RETURN_WAIT,        /* Not ready to start stage; wait */
-	NM_ACT_STAGE_RETURN_STOP         /* Activation stage done; nothing to do */
+	NM_ACT_STAGE_RETURN_STOP,        /* Activation not wanted */
+	NM_ACT_STAGE_RETURN_FINISH       /* Activation stage done; nothing to do */
 };
 
 #define NM_DEVICE_CAP_NONSTANDARD_CARRIER 0x80000000
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index a9899535..47526281 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -201,14 +201,18 @@ typedef struct {
 	char *        hw_addr;
 	guint         hw_addr_len;
 	char *        physical_port_id;
+	guint         dev_id;
 
 	NMUnmanagedFlags        unmanaged_flags;
 	gboolean                is_nm_owned; /* whether the device is a device owned and created by NM */
 	DeleteOnDeactivateData *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */
 
+	GCancellable *deactivating_cancellable;
+
 	guint32         ip4_address;
 
 	NMActRequest *  queued_act_request;
+	gboolean        queued_act_request_is_waiting_for_carrier;
 	NMActRequest *  act_request;
 	guint           act_source_id;
 	gpointer        act_source_func;
@@ -337,6 +341,8 @@ static gboolean addrconf6_start_with_link_ready (NMDevice *self);
 static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection);
 static NMActStageReturn linklocal6_start (NMDevice *self);
 
+static void _carrier_wait_check_queued_act_request (NMDevice *self);
+
 static gboolean nm_device_get_default_unmanaged (NMDevice *self);
 
 static void _set_state_full (NMDevice *self,
@@ -381,6 +387,7 @@ state_to_string (NMDeviceState state)
 }
 
 static const char *reason_table[] = {
+	[NM_DEVICE_STATE_REASON_UNKNOWN]                  = "unknown",
 	[NM_DEVICE_STATE_REASON_NONE]                     = "none",
 	[NM_DEVICE_STATE_REASON_NOW_MANAGED]              = "managed",
 	[NM_DEVICE_STATE_REASON_NOW_UNMANAGED]            = "unmanaged",
@@ -440,6 +447,7 @@ static const char *reason_table[] = {
 	[NM_DEVICE_STATE_REASON_MODEM_FAILED]             = "modem-failed",
 	[NM_DEVICE_STATE_REASON_MODEM_AVAILABLE]          = "modem-available",
 	[NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT]        = "sim-pin-incorrect",
+	[NM_DEVICE_STATE_REASON_NEW_ACTIVATION]           = "new-activation",
 };
 
 static const char *
@@ -588,6 +596,7 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
 static gboolean
 get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
 {
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMLinkType link_type;
 	const guint8 *hwaddr = NULL;
 	size_t hwaddr_len = 0;
@@ -608,6 +617,7 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
 	success = nm_utils_get_ipv6_interface_identifier (link_type,
 	                                                  hwaddr,
 	                                                  hwaddr_len,
+	                                                  priv->dev_id,
 	                                                  out_iid);
 	if (!success) {
 		_LOGW (LOGD_HW, "failed to generate interface identifier "
@@ -692,6 +702,8 @@ nm_device_get_priority (NMDevice *self)
 		return 350;
 	case NM_DEVICE_TYPE_VLAN:
 		return 400;
+	case NM_DEVICE_TYPE_BRIDGE:
+		return 425;
 	case NM_DEVICE_TYPE_MODEM:
 		return 450;
 	case NM_DEVICE_TYPE_BT:
@@ -700,23 +712,37 @@ nm_device_get_priority (NMDevice *self)
 		return 600;
 	case NM_DEVICE_TYPE_OLPC_MESH:
 		return 650;
-	default:
+	case NM_DEVICE_TYPE_GENERIC:
 		return 950;
+	case NM_DEVICE_TYPE_UNKNOWN:
+		return 10000;
+	case NM_DEVICE_TYPE_UNUSED1:
+	case NM_DEVICE_TYPE_UNUSED2:
+		/* omit default: to get compiler warning about missing switch cases */
+		break;
 	}
+	return 11000;
 }
 
 guint32
 nm_device_get_ip4_route_metric (NMDevice *self)
 {
 	NMConnection *connection;
+	NMSettingIPConfig *s_ip = NULL;
 	gint64 route_metric = -1;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32);
 
 	connection = nm_device_get_connection (self);
-
 	if (connection)
-		route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip4_config (connection));
+		s_ip = nm_connection_get_setting_ip4_config (connection);
+
+	/* Slave interfaces don't have IP settings, but we may get here when
+	 * external changes are made or when noticing IP changes when starting
+	 * the slave connection.
+	 */
+	if (s_ip)
+		route_metric = nm_setting_ip_config_get_route_metric (s_ip);
 
 	return route_metric >= 0 ? route_metric : nm_device_get_priority (self);
 }
@@ -725,14 +751,21 @@ guint32
 nm_device_get_ip6_route_metric (NMDevice *self)
 {
 	NMConnection *connection;
+	NMSettingIPConfig *s_ip = NULL;
 	gint64 route_metric = -1;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32);
 
 	connection = nm_device_get_connection (self);
-
 	if (connection)
-		route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip6_config (connection));
+		s_ip = nm_connection_get_setting_ip6_config (connection);
+
+	/* Slave interfaces don't have IP settings, but we may get here when
+	 * external changes are made or when noticing IP changes when starting
+	 * the slave connection.
+	 */
+	if (s_ip)
+		route_metric = nm_setting_ip_config_get_route_metric (s_ip);
 
 	return route_metric >= 0 ? route_metric : nm_device_get_priority (self);
 }
@@ -1128,6 +1161,7 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier)
 			g_source_remove (priv->carrier_wait_id);
 			priv->carrier_wait_id = 0;
 			nm_device_remove_pending_action (self, "carrier wait", TRUE);
+			_carrier_wait_check_queued_act_request (self);
 		}
 	} else if (state <= NM_DEVICE_STATE_DISCONNECTED) {
 		_LOGI (LOGD_DEVICE, "link disconnected");
@@ -1717,16 +1751,24 @@ nm_device_removed (NMDevice *self)
 
 
 static gboolean
-is_available (NMDevice *self)
+is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	return priv->carrier || priv->ignore_carrier;
+	if (priv->carrier || priv->ignore_carrier)
+		return TRUE;
+
+	if (NM_FLAGS_HAS (flags, NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER))
+		return TRUE;
+
+	return FALSE;
 }
 
 /**
  * nm_device_is_available:
  * @self: the #NMDevice
+ * @flags: additional flags to influence the check. Flags have the
+ *   meaning to increase the availability of a device.
  *
  * Checks if @self would currently be capable of activating a
  * connection. In particular, it checks that the device is ready (eg,
@@ -1742,14 +1784,14 @@ is_available (NMDevice *self)
  * Returns: %TRUE or %FALSE
  */
 gboolean
-nm_device_is_available (NMDevice *self)
+nm_device_is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
 	if (priv->firmware_missing)
 		return FALSE;
 
-	return NM_DEVICE_GET_CLASS (self)->is_available (self);
+	return NM_DEVICE_GET_CLASS (self)->is_available (self, flags);
 }
 
 gboolean
@@ -1873,7 +1915,7 @@ can_auto_connect (NMDevice *self,
 	if (!nm_setting_connection_get_autoconnect (s_con))
 		return FALSE;
 
-	return nm_device_connection_is_available (self, connection, FALSE);
+	return nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL);
 }
 
 /**
@@ -3760,7 +3802,7 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason)
 		}
 
 		/* success; already have the LL address; kick off DHCP */
-		g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
+		g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS || ret == NM_ACT_STAGE_RETURN_FINISH);
 	}
 
 	if (!dhcp6_start_with_link_ready (self, connection)) {
@@ -3925,7 +3967,7 @@ linklocal6_start (NMDevice *self)
 	linklocal6_cleanup (self);
 
 	if (have_ip6_address (priv->ip6_config, TRUE))
-		return NM_ACT_STAGE_RETURN_SUCCESS;
+		return NM_ACT_STAGE_RETURN_FINISH;
 
 	connection = nm_device_get_connection (self);
 	g_assert (connection);
@@ -4126,14 +4168,8 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self)
 		}
 	}
 
-	/* hop_limit == 0 is a special value "unspecified", so do not touch
-	 * in this case */
-	if (changed & NM_RDISC_CONFIG_HOP_LIMIT && rdisc->hop_limit > 0) {
-		char val[16];
-
-		g_snprintf (val, sizeof (val), "%d", rdisc->hop_limit);
-		nm_device_ipv6_sysctl_set (self, "hop_limit", val);
-	}
+	if (changed & NM_RDISC_CONFIG_HOP_LIMIT)
+		nm_platform_sysctl_set_ip6_hop_limit_safe (nm_device_get_ip_iface (self), rdisc->hop_limit);
 
 	if (changed & NM_RDISC_CONFIG_MTU) {
 		char val[16];
@@ -4241,7 +4277,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
 	}
 
 	/* success; already have the LL address; kick off router discovery */
-	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
+	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS || ret == NM_ACT_STAGE_RETURN_FINISH);
 	return addrconf6_start_with_link_ready (self);
 }
 
@@ -4345,11 +4381,12 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable)
 		if (enable) {
 			/* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */
 			value = nm_platform_sysctl_get (nm_utils_ip6_property_path (iface, "disable_ipv6"));
-			if (g_strcmp0 (value, "0") == 0) {
+			if (g_strcmp0 (value, "0") == 0)
 				nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1");
-				nm_device_ipv6_sysctl_set (self, "disable_ipv6", "0");
-			}
 			g_free (value);
+
+			/* Ensure IPv6 is enabled */
+			nm_device_ipv6_sysctl_set (self, "disable_ipv6", "0");
 		}
 
 	}
@@ -4445,7 +4482,7 @@ act_stage3_ip6_config_start (NMDevice *self,
 	connection = nm_device_get_connection (self);
 	g_assert (connection);
 
-	if (   connection_ip4_method_requires_carrier (connection, NULL)
+	if (   connection_ip6_method_requires_carrier (connection, NULL)
 	    && priv->is_master
 	    && !priv->carrier) {
 		_LOGI (LOGD_IP6 | LOGD_DEVICE,
@@ -4519,7 +4556,7 @@ act_stage3_ip6_config_start (NMDevice *self,
 			ret = NM_ACT_STAGE_RETURN_POSTPONE;
 	} else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) {
 		ret = linklocal6_start (self);
-		if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
+		if (ret == NM_ACT_STAGE_RETURN_FINISH) {
 			/* New blank config; LL address is already in priv->ext_ip6_config */
 			*out_config = nm_ip6_config_new ();
 			g_assert (*out_config);
@@ -4626,8 +4663,13 @@ nm_device_activate_stage3_ip6_start (NMDevice *self)
 		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		return FALSE;
 	} else if (ret == NM_ACT_STAGE_RETURN_STOP) {
-		/* Early finish */
+		/* Activation not wanted */
 		priv->ip6_state = IP_FAIL;
+	} else if (ret == NM_ACT_STAGE_RETURN_FINISH) {
+		/* Early finish, nothing more to do */
+		priv->ip6_state = IP_DONE;
+		if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
+			nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE);
 	} else if (ret == NM_ACT_STAGE_RETURN_WAIT) {
 		/* Wait for something to try IP config again */
 		priv->ip6_state = IP_WAIT;
@@ -5569,6 +5611,15 @@ disconnect_cb (NMDevice *self,
 }
 
 static void
+_clear_queued_act_request (NMDevicePrivate *priv)
+{
+	if (priv->queued_act_request) {
+		nm_active_connection_set_state ((NMActiveConnection *) priv->queued_act_request, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
+		g_clear_object (&priv->queued_act_request);
+	}
+}
+
+static void
 impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context)
 {
 	NMConnection *connection;
@@ -5670,26 +5721,97 @@ _device_activate (NMDevice *self, NMActRequest *req)
 	nm_device_activate_schedule_stage1_device_prepare (self);
 }
 
+static void
+_carrier_wait_check_queued_act_request (NMDevice *self)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMActRequest *queued_req;
+
+	if (   !priv->queued_act_request
+	    || !priv->queued_act_request_is_waiting_for_carrier)
+		return;
+
+	priv->queued_act_request_is_waiting_for_carrier = FALSE;
+	if (!priv->carrier) {
+		_LOGD (LOGD_DEVICE, "Cancel queued activation request as we have no carrier after timeout");
+		g_clear_object (&priv->queued_act_request);
+	} else {
+		_LOGD (LOGD_DEVICE, "Activate queued activation request as we now have carrier");
+		queued_req = priv->queued_act_request;
+		priv->queued_act_request = NULL;
+		_device_activate (self, queued_req);
+		g_object_unref (queued_req);
+	}
+}
+
+static gboolean
+_carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMConnection *connection;
+
+	/* If we have carrier or if we are not waiting for it, the activation
+	 * request is not blocked waiting for carrier. */
+	if (priv->carrier)
+		return FALSE;
+	if (priv->carrier_wait_id == 0)
+		return FALSE;
+
+	connection = nm_act_request_get_connection (req);
+
+	if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL, NULL)) {
+		/* We passed all @flags we have, and no @specific_object.
+		 * This equals maximal availability, if a connection is not available
+		 * in this case, it is not waiting for carrier.
+		 *
+		 * Actually, why are we even trying to activate it? Strange, but whatever
+		 * the reason, don't wait for carrier.
+		 */
+		return FALSE;
+	}
+
+	if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, NULL)) {
+		/* The connection was available with flags ALL, and it is still available
+		 * if we pretend not to wait for carrier. That means that the
+		 * connection is available now, and does not wait for carrier.
+		 *
+		 * Since the flags increase the availability of a connection, when checking
+		 * ALL&~WAITING_CARRIER, it means that we certainly would wait for carrier. */
+		return FALSE;
+	}
+
+	/* The activation request must wait for carrier. */
+	return TRUE;
+}
+
 void
 nm_device_queue_activation (NMDevice *self, NMActRequest *req)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	gboolean must_queue;
+
+	must_queue = _carrier_wait_check_act_request_must_queue (self, req);
 
-	if (!priv->act_request) {
+	if (!priv->act_request && !must_queue) {
 		/* Just activate immediately */
 		_device_activate (self, req);
 		return;
 	}
 
 	/* supercede any already-queued request */
-	g_clear_object (&priv->queued_act_request);
+	_clear_queued_act_request (priv);
 	priv->queued_act_request = g_object_ref (req);
+	priv->queued_act_request_is_waiting_for_carrier = must_queue;
 
-	/* Deactivate existing activation request first */
-	_LOGI (LOGD_DEVICE, "disconnecting for new activation request.");
-	nm_device_state_changed (self,
-	                         NM_DEVICE_STATE_DEACTIVATING,
-	                         NM_DEVICE_STATE_REASON_NONE);
+	_LOGD (LOGD_DEVICE, "queue activation request waiting for %s", must_queue ? "carrier" : "currently active connection to disconnect");
+
+	if (priv->act_request) {
+		/* Deactivate existing activation request first */
+		_LOGI (LOGD_DEVICE, "disconnecting for new activation request.");
+		nm_device_state_changed (self,
+		                         NM_DEVICE_STATE_DEACTIVATING,
+		                         NM_DEVICE_STATE_REASON_NEW_ACTIVATION);
+	}
 }
 
 /*
@@ -5915,7 +6037,7 @@ nm_device_set_ip6_config (NMDevice *self,
 				nm_ip6_config_export (new_config);
 			}
 
-			_LOGD (LOGD_IP4, "set IP6Config instance (%s)",
+			_LOGD (LOGD_IP6, "set IP6Config instance (%s)",
 			       nm_ip6_config_get_dbus_path (new_config));
 		}
 	} else if (old_config) {
@@ -6231,6 +6353,9 @@ carrier_wait_timeout (gpointer user_data)
 
 	NM_DEVICE_GET_PRIVATE (self)->carrier_wait_id = 0;
 	nm_device_remove_pending_action (self, "carrier wait", TRUE);
+
+	_carrier_wait_check_queued_act_request (self);
+
 	return G_SOURCE_REMOVE;
 }
 
@@ -6295,12 +6420,11 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware)
 	 * a timeout is reached.
 	 */
 	if (device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
-		if (priv->carrier_wait_id) {
+		if (priv->carrier_wait_id)
 			g_source_remove (priv->carrier_wait_id);
-			nm_device_remove_pending_action (self, "carrier wait", TRUE);
-		}
+		else
+			nm_device_add_pending_action (self, "carrier wait", TRUE);
 		priv->carrier_wait_id = g_timeout_add_seconds (5, carrier_wait_timeout, self);
-		nm_device_add_pending_action (self, "carrier wait", TRUE);
 	}
 
 	/* Can only get HW address of some devices when they are up */
@@ -6728,12 +6852,12 @@ nm_device_set_unmanaged_quitting (NMDevice *self)
 
 	/* It's OK to block here because we're quitting */
 	if (nm_device_is_activating (self) || priv->state == NM_DEVICE_STATE_ACTIVATED)
-		_set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_REMOVED, TRUE);
+		_set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_NOW_UNMANAGED, TRUE);
 
 	nm_device_set_unmanaged (self,
 	                         NM_UNMANAGED_INTERNAL,
 	                         TRUE,
-	                         NM_DEVICE_STATE_REASON_REMOVED);
+	                         NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
 }
 
 /**
@@ -6788,48 +6912,45 @@ nm_device_set_dhcp_anycast_address (NMDevice *self, const char *addr)
 }
 
 /**
- * nm_device_connection_is_available():
+ * nm_device_check_connection_available():
  * @self: the #NMDevice
  * @connection: the #NMConnection to check for availability
- * @allow_device_override: set to %TRUE to let the device do specific checks
+ * @flags: flags to affect the decision making of whether a connection
+ *   is available. Adding a flag can only make a connection more available,
+ *   not less.
+ * @specific_object: a device type dependent argument to further
+ *   filter the result. Passing a non %NULL specific object can only reduce
+ *   the availability of a connection.
  *
- * Check if @connection is available to be activated on @self.  Normally this
- * only checks if the connection is in @self's AvailableConnections property.
- * If @allow_device_override is %TRUE then the device is asked to do specific
- * checks that may bypass the AvailableConnections property.
+ * Check if @connection is available to be activated on @self.
  *
  * Returns: %TRUE if @connection can be activated on @self
  */
 gboolean
-nm_device_connection_is_available (NMDevice *self,
-                                   NMConnection *connection,
-                                   gboolean allow_device_override)
+nm_device_check_connection_available (NMDevice *self,
+                                      NMConnection *connection,
+                                      NMDeviceCheckConAvailableFlags flags,
+                                      const char *specific_object)
 {
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	gboolean available = FALSE;
+	NMDeviceState state;
 
-	if (nm_device_get_default_unmanaged (self) && (priv->state == NM_DEVICE_STATE_UNMANAGED)) {
-		/* default-unmanaged  devices in UNMANAGED state have no available connections
-		 * so we must manually check whether the connection is available here.
-		 */
-		if (   nm_device_check_connection_compatible (self, connection)
-		    && NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, NULL))
-			return TRUE;
-	}
+	state = nm_device_get_state (self);
+	if (state < NM_DEVICE_STATE_UNMANAGED)
+		return FALSE;
+	if (   state < NM_DEVICE_STATE_UNAVAILABLE
+	    && nm_device_get_unmanaged_flag (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT))
+		return FALSE;
+	if (   state < NM_DEVICE_STATE_DISCONNECTED
+	    && (   (   !NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
+	            && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE))
+	        || (    NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
+	            && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER))))
+		return FALSE;
 
-	available = !!g_hash_table_lookup (priv->available_connections, connection);
-	if (!available && allow_device_override) {
-		/* FIXME: hack for hidden WiFi becuase clients didn't consistently
-		 * set the 'hidden' property to indicate hidden SSID networks.  If
-		 * activating but the network isn't available let the device recheck
-		 * availability.
-		 */
-		if (   nm_device_check_connection_compatible (self, connection)
-		    && NM_DEVICE_GET_CLASS (self)->check_connection_available_wifi_hidden)
-			available = NM_DEVICE_GET_CLASS (self)->check_connection_available_wifi_hidden (self, connection);
-	}
+	if (!nm_device_check_connection_compatible (self, connection))
+		return FALSE;
 
-	return available;
+	return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object);
 }
 
 static void
@@ -6849,17 +6970,10 @@ _clear_available_connections (NMDevice *self, gboolean do_signal)
 static gboolean
 _try_add_available_connection (NMDevice *self, NMConnection *connection)
 {
-	if (   nm_device_get_state (self) < NM_DEVICE_STATE_DISCONNECTED
-	    && !nm_device_get_default_unmanaged (self))
-		return FALSE;
-
-	if (nm_device_check_connection_compatible (self, connection)) {
-		if (NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, NULL)) {
-			g_hash_table_insert (NM_DEVICE_GET_PRIVATE (self)->available_connections,
-			                     g_object_ref (connection),
-			                     GUINT_TO_POINTER (1));
-			return TRUE;
-		}
+	if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL)) {
+		g_hash_table_add (NM_DEVICE_GET_PRIVATE (self)->available_connections,
+		                  g_object_ref (connection));
+		return TRUE;
 	}
 	return FALSE;
 }
@@ -6873,15 +6987,28 @@ _del_available_connection (NMDevice *self, NMConnection *connection)
 static gboolean
 check_connection_available (NMDevice *self,
                             NMConnection *connection,
+                            NMDeviceCheckConAvailableFlags flags,
                             const char *specific_object)
 {
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+
 	/* Connections which require a network connection are not available when
 	 * the device has no carrier, even with ignore-carrer=TRUE.
 	 */
-	if (NM_DEVICE_GET_PRIVATE (self)->carrier == FALSE)
-		return connection_requires_carrier (connection) ? FALSE : TRUE;
+	if (   priv->carrier
+	    || !connection_requires_carrier (connection))
+		return TRUE;
 
-	return TRUE;
+	if (   NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
+	    && priv->carrier_wait_id != 0) {
+		/* The device has no carrier though the connection requires it.
+		 *
+		 * If we are still waiting for carrier, the connection is available
+		 * for an explicit user-request. */
+		return TRUE;
+	}
+
+	return FALSE;
 }
 
 void
@@ -6933,8 +7060,8 @@ nm_device_get_available_connections (NMDevice *self, const char *specific_object
 			/* If a specific object is given, only include connections that are
 			 * compatible with it.
 			 */
-			if (   !specific_object
-			    || NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, specific_object))
+			if (   !specific_object /* << Optimization: we know that the connection is available without @specific_object.  */
+			    || nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, specific_object))
 				g_ptr_array_add (array, connection);
 		}
 	}
@@ -7190,7 +7317,7 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure)
  *
  */
 static void
-nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason)
+nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, gboolean deconfigure)
 {
 	NMDevicePrivate *priv;
 	int ifindex;
@@ -7205,12 +7332,14 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason)
 	/* Save whether or not we tried IPv6 for later */
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
-	_cleanup_generic_pre (self, TRUE);
+	_cleanup_generic_pre (self, deconfigure);
 
 	/* Turn off kernel IPv6 */
-	set_disable_ipv6 (self, "1");
-	nm_device_ipv6_sysctl_set (self, "accept_ra", "0");
-	nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0");
+	if (deconfigure) {
+		set_disable_ipv6 (self, "1");
+		nm_device_ipv6_sysctl_set (self, "accept_ra", "0");
+		nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0");
+	}
 
 	/* Call device type-specific deactivation */
 	if (NM_DEVICE_GET_CLASS (self)->deactivate)
@@ -7231,7 +7360,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason)
 		nm_platform_address_flush (ifindex);
 	}
 
-	_cleanup_generic_post (self, TRUE);
+	_cleanup_generic_post (self, deconfigure);
 }
 
 static char *
@@ -7332,7 +7461,7 @@ nm_device_spawn_iface_helper (NMDevice *self)
 		}
 
 		hostname = nm_dhcp_client_get_hostname (priv->dhcp4_client);
-		if (client_id) {
+		if (hostname) {
 			g_ptr_array_add (argv, g_strdup ("--dhcp4-hostname"));
 			g_ptr_array_add (argv, g_strdup (hostname));
 		}
@@ -7430,6 +7559,69 @@ ip6_managed_setup (NMDevice *self)
 }
 
 static void
+deactivate_async_ready (NMDevice *self,
+                        GAsyncResult *res,
+                        gpointer user_data)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMDeviceStateReason reason = GPOINTER_TO_UINT (user_data);
+	GError *error = NULL;
+
+	NM_DEVICE_GET_CLASS (self)->deactivate_async_finish (self, res, &error);
+
+	/* If operation cancelled, just return */
+	if (   g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
+	    || (priv->deactivating_cancellable && g_cancellable_is_cancelled (priv->deactivating_cancellable))) {
+		nm_log_warn (LOGD_DEVICE, "Deactivation (%s) cancelled",
+		             nm_device_get_iface (self));
+	}
+	/* In every other case, transition to the DISCONNECTED state */
+	else {
+		if (error)
+			nm_log_warn (LOGD_DEVICE, "Deactivation (%s) failed: %s",
+			             nm_device_get_iface (self),
+			             error->message);
+		nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason);
+	}
+
+	g_clear_object (&priv->deactivating_cancellable);
+	g_clear_error (&error);
+}
+
+static void
+deactivate_dispatcher_complete (guint call_id, gpointer user_data)
+{
+	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMDeviceStateReason reason;
+
+	g_return_if_fail (call_id == priv->dispatcher.call_id);
+	g_return_if_fail (priv->dispatcher.post_state == NM_DEVICE_STATE_DISCONNECTED);
+
+	reason = priv->dispatcher.post_state_reason;
+
+	priv->dispatcher.call_id = 0;
+	priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
+	priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
+
+	if (priv->deactivating_cancellable) {
+		g_warn_if_reached ();
+		g_cancellable_cancel (priv->deactivating_cancellable);
+		g_clear_object (&priv->deactivating_cancellable);
+	}
+
+	if (   NM_DEVICE_GET_CLASS (self)->deactivate_async
+	    && NM_DEVICE_GET_CLASS (self)->deactivate_async_finish) {
+		priv->deactivating_cancellable = g_cancellable_new ();
+		NM_DEVICE_GET_CLASS (self)->deactivate_async (self,
+		                                              priv->deactivating_cancellable,
+		                                              (GAsyncReadyCallback) deactivate_async_ready,
+		                                              GUINT_TO_POINTER (reason));
+	} else
+		nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason);
+}
+
+static void
 _set_state_full (NMDevice *self,
                  NMDeviceState state,
                  NMDeviceStateReason reason,
@@ -7473,13 +7665,15 @@ _set_state_full (NMDevice *self,
 	nm_device_queued_state_clear (self);
 
 	dispatcher_cleanup (self);
+	if (priv->deactivating_cancellable)
+		g_cancellable_cancel (priv->deactivating_cancellable);
 
 	/* Cache the activation request for the dispatcher */
 	req = priv->act_request ? g_object_ref (priv->act_request) : NULL;
 
 	if (state <= NM_DEVICE_STATE_UNAVAILABLE) {
 		_clear_available_connections (self, TRUE);
-		g_clear_object (&priv->queued_act_request);
+		_clear_queued_act_request (priv);
 	}
 
 	/* Update the available connections list when a device first becomes available */
@@ -7494,12 +7688,16 @@ _set_state_full (NMDevice *self,
 	case NM_DEVICE_STATE_UNMANAGED:
 		nm_device_set_firmware_missing (self, FALSE);
 		if (old_state > NM_DEVICE_STATE_UNMANAGED) {
-			/* Clean up if the device is now unmanaged but was activated */
-			if (nm_device_get_act_request (self))
-				nm_device_cleanup (self, reason);
-			nm_device_take_down (self, TRUE);
-			set_nm_ipv6ll (self, FALSE);
-			restore_ip6_properties (self);
+			if (reason == NM_DEVICE_STATE_REASON_REMOVED) {
+				nm_device_cleanup (self, reason, FALSE);
+			} else {
+				/* Clean up if the device is now unmanaged but was activated */
+				if (nm_device_get_act_request (self))
+					nm_device_cleanup (self, reason, TRUE);
+				nm_device_take_down (self, TRUE);
+				set_nm_ipv6ll (self, FALSE);
+				restore_ip6_properties (self);
+			}
 		}
 		break;
 	case NM_DEVICE_STATE_UNAVAILABLE:
@@ -7524,7 +7722,7 @@ _set_state_full (NMDevice *self,
 			 * Note that we "deactivate" the device even when coming from
 			 * UNMANAGED, to ensure that it's in a clean state.
 			 */
-			nm_device_cleanup (self, reason);
+			nm_device_cleanup (self, reason, TRUE);
 		}
 		break;
 	case NM_DEVICE_STATE_DISCONNECTED:
@@ -7534,7 +7732,7 @@ _set_state_full (NMDevice *self,
 			 */
 			set_nm_ipv6ll (self, TRUE);
 
-			nm_device_cleanup (self, reason);
+			nm_device_cleanup (self, reason, TRUE);
 		} else if (old_state < NM_DEVICE_STATE_DISCONNECTED) {
 			if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) {
 				/* Ensure IPv6 is set up as it may not have been done when
@@ -7575,7 +7773,7 @@ _set_state_full (NMDevice *self,
 		 * we can't change states again from the state handler for a variety of
 		 * reasons.
 		 */
-		if (nm_device_is_available (self)) {
+		if (nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) {
 			_LOGD (LOGD_DEVICE, "device is available, will transition to DISCONNECTED");
 			nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
 		} else {
@@ -7597,16 +7795,17 @@ _set_state_full (NMDevice *self,
 			if (!nm_dispatcher_call (DISPATCHER_ACTION_PRE_DOWN,
 			                         nm_act_request_get_connection (req),
 			                         self,
-			                         dispatcher_complete_proceed_state,
+			                         deactivate_dispatcher_complete,
 			                         self,
 			                         &priv->dispatcher.call_id)) {
 				/* Just proceed on errors */
-				dispatcher_complete_proceed_state (0, self);
+				deactivate_dispatcher_complete (0, self);
 			}
 		}
 		break;
 	case NM_DEVICE_STATE_DISCONNECTED:
-		if (priv->queued_act_request) {
+		if (   priv->queued_act_request
+		    && !priv->queued_act_request_is_waiting_for_carrier) {
 			NMActRequest *queued_req;
 
 			queued_req = priv->queued_act_request;
@@ -8057,6 +8256,9 @@ constructor (GType type,
 	g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ip_changed), self);
 	g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self);
 
+	/* trigger initial ip config change to initialize ip-config */
+	priv->queued_ip_config_id = g_idle_add (queued_ip_config_change, self);
+
 	if (nm_platform_check_support_user_ipv6ll ()) {
 		int ip_ifindex = nm_device_get_ip_ifindex (self);
 
@@ -8103,6 +8305,7 @@ constructed (GObject *object)
 	if (priv->ifindex > 0) {
 		priv->is_software = nm_platform_link_is_software (priv->ifindex);
 		priv->physical_port_id = nm_platform_link_get_physical_port_id (priv->ifindex);
+		priv->dev_id = nm_platform_link_get_dev_id (priv->ifindex);
 		priv->mtu = nm_platform_link_get_mtu (priv->ifindex);
 	}
 	/* Indicate software device in capabilities. */
@@ -8164,7 +8367,7 @@ dispose (GObject *object)
 
 	_cleanup_generic_post (self, FALSE);
 
-	g_clear_pointer (&priv->ip6_saved_properties, g_hash_table_unref);
+	g_hash_table_remove_all (priv->ip6_saved_properties);
 
 	if (priv->recheck_assume_id) {
 		g_source_remove (priv->recheck_assume_id);
@@ -8180,15 +8383,14 @@ dispose (GObject *object)
 		priv->con_provider = NULL;
 	}
 
-	g_hash_table_unref (priv->available_connections);
-	priv->available_connections = NULL;
+	g_hash_table_remove_all (priv->available_connections);
 
 	if (priv->carrier_wait_id) {
 		g_source_remove (priv->carrier_wait_id);
 		priv->carrier_wait_id = 0;
 	}
 
-	g_clear_object (&priv->queued_act_request);
+	_clear_queued_act_request (priv);
 
 	platform = nm_platform_get ();
 	g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ip_changed), self);
@@ -8218,6 +8420,9 @@ finalize (GObject *object)
 	g_free (priv->type_desc);
 	g_free (priv->dhcp_anycast_address);
 
+	g_hash_table_unref (priv->ip6_saved_properties);
+	g_hash_table_unref (priv->available_connections);
+
 	G_OBJECT_CLASS (nm_device_parent_class)->finalize (object);
 }
 
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index b3855c74..e204af84 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -23,6 +23,7 @@
 #define __NETWORKMANAGER_DEVICE_H__
 
 #include <glib-object.h>
+#include <gio/gio.h>
 #include <dbus/dbus-glib.h>
 #include <netinet/in.h>
 
@@ -85,10 +86,37 @@ G_BEGIN_DECLS
 
 typedef enum NMActStageReturn NMActStageReturn;
 
+/* These flags affect whether a connection is considered available on a device
+ * (check_connection_available()). The flags should have the meaning of relaxing
+ * a condition, so that adding a flag might make a connection available that would
+ * not be available otherwise. Adding a flag should never make a connection
+ * not available if it would be available otherwise. */
+typedef enum { /*< skip >*/
+	NM_DEVICE_CHECK_CON_AVAILABLE_NONE                                  = 0,
+
+	_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER     = (1L << 0),
+	_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP           = (1L << 1),
+	NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST                      = _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER
+	                                                                    | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP,
+
+	__NM_DEVICE_CHECK_CON_AVAILABLE_ALL,
+	NM_DEVICE_CHECK_CON_AVAILABLE_ALL                                   = (((__NM_DEVICE_CHECK_CON_AVAILABLE_ALL - 1) << 1) - 1),
+} NMDeviceCheckConAvailableFlags;
+
 struct _NMDevice {
 	GObject parent;
 };
 
+/* The flags have an relaxing meaning, that means, specifying more flags, can make
+ * a device appear more available. It can never make a device less available. */
+typedef enum { /*< skip >*/
+	NM_DEVICE_CHECK_DEV_AVAILABLE_NONE                                  = 0,
+	NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER                        = (1L << 0),
+
+	__NM_DEVICE_CHECK_DEV_AVAILABLE_ALL,
+	NM_DEVICE_CHECK_DEV_AVAILABLE_ALL                                   = (((__NM_DEVICE_CHECK_DEV_AVAILABLE_ALL - 1) << 1) - 1),
+} NMDeviceCheckDevAvailableFlags;
+
 typedef struct {
 	GObjectClass parent;
 
@@ -116,7 +144,7 @@ typedef struct {
 
 	guint32		(* get_generic_capabilities)	(NMDevice *self);
 
-	gboolean	(* is_available) (NMDevice *self);
+	gboolean	(* is_available) (NMDevice *self, NMDeviceCheckDevAvailableFlags flags);
 
 	gboolean    (* get_enabled) (NMDevice *self);
 
@@ -136,19 +164,18 @@ typedef struct {
 	 * including any live network information like scan lists.  The connection
 	 * is checked against the object defined by @specific_object, if given.
 	 * Returns TRUE if the connection is available; FALSE if not.
+	 *
+	 * The passed @flags affect whether a connection is considered
+	 * available or not. Adding more flags, means the connection is
+	 * *more* available.
+	 *
+	 * Specifying @specific_object can only reduce the availability of a connection.
 	 */
 	gboolean    (* check_connection_available) (NMDevice *self,
 	                                            NMConnection *connection,
+	                                            NMDeviceCheckConAvailableFlags flags,
 	                                            const char *specific_object);
 
-	/* Same as check_connection_available() but called if the connection
-	 * is not present in the activating-connections array during activation,
-	 * to give the device a chance to allow/deny the activation.  This is a
-	 * hack only meant for hidden WiFi networks.
-	 */
-	gboolean    (* check_connection_available_wifi_hidden) (NMDevice *self,
-	                                                        NMConnection *connection);
-
 	gboolean    (* complete_connection)         (NMDevice *self,
 	                                             NMConnection *connection,
 	                                             const char *specific_object,
@@ -174,6 +201,16 @@ typedef struct {
 	void                (* ip4_config_pre_commit) (NMDevice *self, NMIP4Config *config);
 	void                (* ip6_config_pre_commit) (NMDevice *self, NMIP6Config *config);
 
+	/* Async deactivating (in the DEACTIVATING phase) */
+	void            (* deactivate_async)        (NMDevice *self,
+	                                             GCancellable *cancellable,
+	                                             GAsyncReadyCallback callback,
+	                                             gpointer user_data);
+	gboolean        (* deactivate_async_finish) (NMDevice *self,
+	                                             GAsyncResult *res,
+	                                             GError **error);
+
+	/* Sync deactivating (in the DISCONNECTED phase) */
 	void			(* deactivate)			(NMDevice *self);
 
 	gboolean        (* spec_match_list)     (NMDevice *self, const GSList *specs);
@@ -257,7 +294,7 @@ NMConnection *  nm_device_get_connection	(NMDevice *dev);
 
 void            nm_device_removed        (NMDevice *dev);
 
-gboolean        nm_device_is_available   (NMDevice *dev);
+gboolean        nm_device_is_available   (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags);
 gboolean        nm_device_has_carrier    (NMDevice *dev);
 
 NMConnection * nm_device_generate_connection (NMDevice *self, NMDevice *master);
@@ -316,7 +353,8 @@ typedef enum {
 
 	/* Boundary value */
 	__NM_UNMANAGED_LAST,
-	NM_UNMANAGED_LAST     = __NM_UNMANAGED_LAST - 1,
+	NM_UNMANAGED_LAST          = __NM_UNMANAGED_LAST - 1,
+	NM_UNMANAGED_ALL           = ((NM_UNMANAGED_LAST << 1) - 1),
 } NMUnmanagedFlags;
 
 gboolean nm_device_get_managed (NMDevice *device);
@@ -360,9 +398,10 @@ gboolean nm_device_has_pending_action    (NMDevice *device);
 GPtrArray *nm_device_get_available_connections (NMDevice *device,
                                                 const char *specific_object);
 
-gboolean   nm_device_connection_is_available (NMDevice *device,
-                                              NMConnection *connection,
-                                              gboolean allow_device_override);
+gboolean   nm_device_check_connection_available (NMDevice *device,
+                                                 NMConnection *connection,
+                                                 NMDeviceCheckConAvailableFlags flags,
+                                                 const char *specific_object);
 
 gboolean nm_device_notify_component_added (NMDevice *device, GObject *component);
 
diff --git a/src/devices/team/Makefile.in b/src/devices/team/Makefile.in
index 4ee30e66..29ad0598 100644
--- a/src/devices/team/Makefile.in
+++ b/src/devices/team/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 @WITH_TEAMDCTL_TRUE@am__append_1 = ${LIBTEAMDCTL_CFLAGS}
 @WITH_TEAMDCTL_TRUE@am__append_2 = $(LIBTEAMDCTL_LIBS)
 subdir = src/devices/team
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -211,6 +220,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -237,7 +248,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -272,6 +282,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -523,7 +534,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/team/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/devices/team/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -595,14 +605,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -830,6 +840,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 include $(GLIB_MAKEFILE)
 
 @GNOME_CODE_COVERAGE_RULES@
diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c
index 16f1fcc2..49202c36 100644
--- a/src/devices/team/nm-device-team.c
+++ b/src/devices/team/nm-device-team.c
@@ -41,6 +41,7 @@
 #include "nm-team-enum-types.h"
 #include "nm-posix-signals.h"
 #include "nm-core-internal.h"
+#include "gsystem-local-alloc.h"
 
 #include "nm-device-team-glue.h"
 
@@ -51,8 +52,6 @@ G_DEFINE_TYPE (NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE)
 
 #define NM_DEVICE_TEAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TEAM, NMDeviceTeamPrivate))
 
-static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team);
-
 typedef struct {
 	struct teamdctl *tdc;
 	GPid teamd_pid;
@@ -68,6 +67,8 @@ enum {
 	LAST_PROP
 };
 
+static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team);
+
 /******************************************************************/
 
 static guint32
@@ -77,7 +78,7 @@ get_generic_capabilities (NMDevice *device)
 }
 
 static gboolean
-is_available (NMDevice *device)
+is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
 {
 	if (NM_DEVICE_GET_CLASS (device)->is_up)
 		return NM_DEVICE_GET_CLASS (device)->is_up (device);
@@ -87,6 +88,7 @@ is_available (NMDevice *device)
 static gboolean
 check_connection_available (NMDevice *device,
                             NMConnection *connection,
+                            NMDeviceCheckConAvailableFlags flags,
                             const char *specific_object)
 {
 	/* Connections are always available because the carrier state is determined
@@ -171,6 +173,7 @@ update_connection (NMDevice *device, NMConnection *connection)
 {
 	NMDeviceTeam *self = NM_DEVICE_TEAM (device);
 	NMSettingTeam *s_team = nm_connection_get_setting_team (connection);
+	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
 
 	if (!s_team) {
 		s_team = (NMSettingTeam *) nm_setting_team_new ();
@@ -178,8 +181,7 @@ update_connection (NMDevice *device, NMConnection *connection)
 	}
 	g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_CONFIG, NULL, NULL);
 
-	teamd_start (device, s_team);
-	if (NM_DEVICE_TEAM_GET_PRIVATE (device)->teamd_pid > 0 && ensure_teamd_connection (device)) {
+	if (priv->tdc) {
 		const char *config = NULL;
 		int err;
 
@@ -261,49 +263,30 @@ master_update_slave_connection (NMDevice *self,
 /******************************************************************/
 
 static void
-teamd_timeout_remove (NMDevice *device)
+teamd_cleanup (NMDevice *device, gboolean free_tdc)
 {
 	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device);
 
-	if (priv->teamd_timeout) {
-		g_source_remove (priv->teamd_timeout);
-		priv->teamd_timeout = 0;
-	}
-}
-
-static void
-teamd_cleanup (NMDevice *device, gboolean device_state_failed)
-{
-	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device);
-
-	if (priv->teamd_dbus_watch) {
-		g_bus_unwatch_name (priv->teamd_dbus_watch);
-		priv->teamd_dbus_watch = 0;
-	}
-
 	if (priv->teamd_process_watch) {
 		g_source_remove (priv->teamd_process_watch);
 		priv->teamd_process_watch = 0;
 	}
 
+	if (priv->teamd_timeout) {
+		g_source_remove (priv->teamd_timeout);
+		priv->teamd_timeout = 0;
+	}
+
 	if (priv->teamd_pid > 0) {
 		nm_utils_kill_child_async (priv->teamd_pid, SIGTERM, LOGD_TEAM, "teamd", 2000, NULL, NULL);
 		priv->teamd_pid = 0;
 	}
 
-	if (priv->tdc) {
+	if (priv->tdc && free_tdc) {
 		teamdctl_disconnect (priv->tdc);
 		teamdctl_free (priv->tdc);
 		priv->tdc = NULL;
 	}
-
-	teamd_timeout_remove (device);
-
-	if (device_state_failed) {
-		if (nm_device_is_activating (device) ||
-		    (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED))
-			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED);
-	}
 }
 
 static gboolean
@@ -314,11 +297,18 @@ teamd_timeout_cb (gpointer user_data)
 	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device);
 
 	g_return_val_if_fail (priv->teamd_timeout, FALSE);
+	priv->teamd_timeout = 0;
 
-	_LOGI (LOGD_TEAM, "teamd timed out.");
-	teamd_cleanup (device, TRUE);
+	if (priv->teamd_pid && !priv->tdc) {
+		/* Timed out launching our own teamd process */
+		_LOGW (LOGD_TEAM, "teamd timed out.");
+		teamd_cleanup (device, TRUE);
 
-	return FALSE;
+		g_warn_if_fail (nm_device_is_activating (device));
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED);
+	}
+
+	return G_SOURCE_REMOVE;
 }
 
 static void
@@ -335,43 +325,77 @@ teamd_dbus_appeared (GDBusConnection *connection,
 	g_return_if_fail (priv->teamd_dbus_watch);
 
 	_LOGI (LOGD_TEAM, "teamd appeared on D-Bus");
-	teamd_timeout_remove (device);
+	nm_device_queue_recheck_assume (device);
+
+	/* If another teamd grabbed the bus name while our teamd was starting,
+	 * just ignore the death of our teamd and run with the existing one.
+	 */
+	if (priv->teamd_process_watch) {
+		gs_unref_variant GVariant *ret = NULL;
+		guint32 pid;
+
+		ret = g_dbus_connection_call_sync (connection,
+		                                   "org.freedesktop.DBus",
+		                                   "/org/freedesktop/DBus",
+		                                   "org.freedesktop.DBus",
+		                                   "GetConnectionUnixProcessID",
+		                                   g_variant_new ("(s)", name_owner),
+		                                   NULL,
+		                                   G_DBUS_CALL_FLAGS_NO_AUTO_START,
+		                                   2000,
+		                                   NULL,
+		                                   NULL);
+		g_variant_get (ret, "(u)", &pid);
+
+		if (pid != priv->teamd_pid)
+			teamd_cleanup (device, FALSE);
+	}
 
+	/* Grab a teamd control handle even if we aren't going to use it
+	 * immediately.  But if we are, and grabbing it failed, fail the
+	 * device activation.
+	 */
 	success = ensure_teamd_connection (device);
 	if (nm_device_get_state (device) == NM_DEVICE_STATE_PREPARE) {
 		if (success)
 			nm_device_activate_schedule_stage2_device_config (device);
 		else if (!nm_device_uses_assumed_connection (device))
 			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED);
-		return;
 	}
 }
 
 static void
-teamd_dbus_vanished (GDBusConnection *connection,
+teamd_dbus_vanished (GDBusConnection *dbus_connection,
                      const gchar *name,
                      gpointer user_data)
 {
 	NMDeviceTeam *self = NM_DEVICE_TEAM (user_data);
 	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
 	NMDevice *device = NM_DEVICE (self);
+	NMDeviceState state = nm_device_get_state (device);
 
 	g_return_if_fail (priv->teamd_dbus_watch);
 
-	if (priv->teamd_timeout) {
+	if (!priv->tdc) {
 		/* g_bus_watch_name will always raise an initial signal, to indicate whether the
-		 * name exists/not exists initially. Do not take this as a failure, until the
-		 * startup timeout is over.
-		 *
-		 * Note that g_bus_watch_name is guaranteed to alternate vanished/appeared signals,
-		 * so we won't hit this condition again (because the next signal is either 'appeared'
-		 * or 'timeout'). */
-		_LOGD (LOGD_TEAM, "teamd vanished from D-Bus (ignored)");
+		 * name exists/not exists initially. Do not take this as a failure if it hadn't
+		 * previously appeared.
+		 */
+		_LOGD (LOGD_TEAM, "teamd not on D-Bus (ignored)");
 		return;
 	}
 
 	_LOGI (LOGD_TEAM, "teamd vanished from D-Bus");
 	teamd_cleanup (device, TRUE);
+
+	/* Attempt to respawn teamd */
+	if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_ACTIVATED) {
+		NMConnection *connection = nm_device_get_connection (device);
+
+		g_assert (connection);
+		if (!teamd_start (device, nm_connection_get_setting_team (connection)))
+			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED);
+	}
 }
 
 static void
@@ -380,13 +404,24 @@ teamd_process_watch_cb (GPid pid, gint status, gpointer user_data)
 	NMDeviceTeam *self = NM_DEVICE_TEAM (user_data);
 	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
 	NMDevice *device = NM_DEVICE (self);
+	NMDeviceState state = nm_device_get_state (device);
 
 	g_return_if_fail (priv->teamd_process_watch);
 
-	_LOGI (LOGD_TEAM, "teamd died with status %d", status);
-	priv->teamd_process_watch = 0;
+	_LOGD (LOGD_TEAM, "teamd died with status %d", status);
 	priv->teamd_pid = 0;
-	teamd_cleanup (device, TRUE);
+	priv->teamd_process_watch = 0;
+
+	/* If teamd quit within 5 seconds of starting, it's probably hosed
+	 * and will just die again, so fail the activation.
+	 */
+	if (priv->teamd_timeout &&
+	    (state >= NM_DEVICE_STATE_PREPARE) &&
+	    (state <= NM_DEVICE_STATE_ACTIVATED)) {
+		_LOGW (LOGD_TEAM, "teamd process quit unexpectedly; failing activation");
+		teamd_cleanup (device, TRUE);
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED);
+	}
 }
 
 static void
@@ -407,28 +442,41 @@ teamd_child_setup (gpointer user_data G_GNUC_UNUSED)
 }
 
 static gboolean
+teamd_kill (NMDeviceTeam *self, const char *teamd_binary, GError **error)
+{
+	gs_unref_ptrarray GPtrArray *argv = NULL;
+	gs_free char *tmp_str = NULL;
+
+	if (!teamd_binary) {
+		teamd_binary = nm_utils_find_helper ("teamd", NULL, NULL);
+		if (!teamd_binary) {
+			_LOGW (LOGD_TEAM, "Activation: (team) failed to start teamd: teamd binary not found");
+			return FALSE;
+		}
+	}
+
+	argv = g_ptr_array_new ();
+	g_ptr_array_add (argv, (gpointer) teamd_binary);
+	g_ptr_array_add (argv, (gpointer) "-k");
+	g_ptr_array_add (argv, (gpointer) "-t");
+	g_ptr_array_add (argv, (gpointer) nm_device_get_iface (NM_DEVICE (self)));
+	g_ptr_array_add (argv, NULL);
+
+	_LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata)));
+	return g_spawn_sync ("/", (char **) argv->pdata, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, NULL, error);
+}
+
+static gboolean
 teamd_start (NMDevice *device, NMSettingTeam *s_team)
 {
 	NMDeviceTeam *self = NM_DEVICE_TEAM (device);
 	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
 	const char *iface = nm_device_get_ip_iface (device);
-	char *tmp_str = NULL;
-	const char *config;
+	gs_unref_ptrarray GPtrArray *argv = NULL;
+	gs_free_error GError *error = NULL;
+	gs_free char *tmp_str = NULL;
 	const char *teamd_binary;
-	GPtrArray *argv;
-	GError *error = NULL;
-	gboolean ret;
-	int status;
-
-	if (priv->teamd_dbus_watch ||
-	    priv->teamd_process_watch ||
-	    priv->teamd_pid > 0 ||
-	    priv->tdc ||
-	    priv->teamd_timeout)
-	{
-		/* Just return if teamd_start() was already called */
-		return TRUE;
-	}
+	const char *config;
 
 	teamd_binary = nm_utils_find_helper ("teamd", NULL, NULL);
 	if (!teamd_binary) {
@@ -436,20 +484,12 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team)
 		return FALSE;
 	}
 
-	/* Kill teamd for same named device first if it is there */
-	argv = g_ptr_array_new ();
-	g_ptr_array_add (argv, (gpointer) teamd_binary);
-	g_ptr_array_add (argv, (gpointer) "-k");
-	g_ptr_array_add (argv, (gpointer) "-t");
-	g_ptr_array_add (argv, (gpointer) iface);
-	g_ptr_array_add (argv, NULL);
-
-	_LOGD (LOGD_TEAM, "running: %s",
-	       (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata)));
-	g_clear_pointer (&tmp_str, g_free);
-
-	ret = g_spawn_sync ("/", (char **) argv->pdata, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, &status, &error);
-	g_ptr_array_free (argv, TRUE);
+	if (priv->teamd_process_watch || priv->teamd_pid > 0 || priv->tdc) {
+		g_warn_if_reached ();
+		if (!priv->teamd_pid)
+			teamd_kill (self, teamd_binary, NULL);
+		teamd_cleanup (device, TRUE);
+	}
 
 	/* Start teamd now */
 	argv = g_ptr_array_new ();
@@ -472,83 +512,90 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team)
 		g_ptr_array_add (argv, (gpointer) "-gg");
 	g_ptr_array_add (argv, NULL);
 
-	_LOGD (LOGD_TEAM, "running: %s",
-	       (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata)));
-	g_clear_pointer (&tmp_str, g_free);
-
-	/* Start a timeout for teamd to appear at D-Bus */
-	priv->teamd_timeout = g_timeout_add_seconds (5, teamd_timeout_cb, device);
-
-	/* Register D-Bus name watcher */
-	tmp_str = g_strdup_printf ("org.libteam.teamd.%s", iface);
-	priv->teamd_dbus_watch = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
-	                                           tmp_str,
-	                                           G_BUS_NAME_WATCHER_FLAGS_NONE,
-	                                           teamd_dbus_appeared,
-	                                           teamd_dbus_vanished,
-	                                           device,
-	                                           NULL);
-	g_free (tmp_str);
-
-	ret = g_spawn_async ("/", (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
-	                    &teamd_child_setup, NULL, &priv->teamd_pid, &error);
-	g_ptr_array_free (argv, TRUE);
-	if (!ret) {
+	_LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata)));
+	if (!g_spawn_async ("/", (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
+	                    teamd_child_setup, NULL, &priv->teamd_pid, &error)) {
 		_LOGW (LOGD_TEAM, "Activation: (team) failed to start teamd: %s", error->message);
-		g_clear_error (&error);
-		teamd_cleanup (device, FALSE);
+		teamd_cleanup (device, TRUE);
 		return FALSE;
 	}
 
+	/* Start a timeout for teamd to appear at D-Bus */
+	if (!priv->teamd_timeout)
+		priv->teamd_timeout = g_timeout_add_seconds (5, teamd_timeout_cb, device);
+
 	/* Monitor the child process so we know when it dies */
 	priv->teamd_process_watch = g_child_watch_add (priv->teamd_pid,
 	                                               teamd_process_watch_cb,
 	                                               device);
 
-	_LOGI (LOGD_TEAM, "Activation: (team) started teamd...");
+	_LOGI (LOGD_TEAM, "Activation: (team) started teamd [pid %u]...", (guint) priv->teamd_pid);
 	return TRUE;
 }
 
-static void
-teamd_stop (NMDevice *device)
-{
-	NMDeviceTeam *self = NM_DEVICE_TEAM (device);
-	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
-
-	if (priv->teamd_pid > 0)
-		_LOGI (LOGD_TEAM, "Deactivation: stopping teamd...");
-	else
-		_LOGD (LOGD_TEAM, "Deactivation: stopping teamd (not started)...");
-	teamd_cleanup (device, FALSE);
-}
-
 static NMActStageReturn
 act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 {
+	NMDeviceTeam *self = NM_DEVICE_TEAM (device);
+	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
+	gs_free_error GError *error = NULL;
 	NMConnection *connection;
 	NMSettingTeam *s_team;
+	const char *cfg;
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
 	ret = NM_DEVICE_CLASS (nm_device_team_parent_class)->act_stage1_prepare (device, reason);
-	if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
-		connection = nm_device_get_connection (device);
-		g_assert (connection);
-		s_team = nm_connection_get_setting_team (connection);
-		g_assert (s_team);
-		if (teamd_start (device, s_team))
-			ret = NM_ACT_STAGE_RETURN_POSTPONE;
-		else
-			ret = NM_ACT_STAGE_RETURN_FAILURE;
+	if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
+		return ret;
+
+	connection = nm_device_get_connection (device);
+	g_assert (connection);
+	s_team = nm_connection_get_setting_team (connection);
+	g_assert (s_team);
+
+	if (priv->tdc) {
+		/* If the existing teamd config is the same as we're about to use,
+		 * then we can proceed.  If it's not the same, and we have a PID,
+		 * kill it so we can respawn it with the right config.  If we don't
+		 * have a PID, then we must fail.
+		 */
+		cfg = teamdctl_config_get_raw (priv->tdc);
+		if (cfg && strcmp (cfg,  nm_setting_team_get_config (s_team)) == 0) {
+			_LOGD (LOGD_TEAM, "using existing matching teamd config");
+			return NM_ACT_STAGE_RETURN_SUCCESS;
+		}
+
+		if (!priv->teamd_pid) {
+			_LOGD (LOGD_TEAM, "existing teamd config mismatch; killing existing via teamdctl");
+			if (!teamd_kill (self, NULL, &error)) {
+				_LOGW (LOGD_TEAM, "existing teamd config mismatch; failed to kill existing teamd: %s", error->message);
+				*reason = NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED;
+				return NM_ACT_STAGE_RETURN_FAILURE;
+			}
+		}
+
+		_LOGD (LOGD_TEAM, "existing teamd config mismatch; respawning...");
+		teamd_cleanup (device, TRUE);
 	}
-	return ret;
+
+	return teamd_start (device, s_team) ?
+		NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE;
 }
 
 static void
 deactivate (NMDevice *device)
 {
-	teamd_stop (device);
+	NMDeviceTeam *self = NM_DEVICE_TEAM (device);
+	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
+
+	if (priv->teamd_pid || priv->tdc)
+		_LOGI (LOGD_TEAM, "deactivation: stopping teamd...");
+
+	if (!priv->teamd_pid)
+		teamd_kill (self, NULL, NULL);
+	teamd_cleanup (device, TRUE);
 }
 
 static gboolean
@@ -694,6 +741,27 @@ nm_device_team_init (NMDeviceTeam * self)
 }
 
 static void
+constructed (GObject *object)
+{
+	NMDevice *device = NM_DEVICE (object);
+	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object);
+	char *tmp_str = NULL;
+
+	G_OBJECT_CLASS (nm_device_team_parent_class)->constructed (object);
+
+	/* Register D-Bus name watcher */
+	tmp_str = g_strdup_printf ("org.libteam.teamd.%s", nm_device_get_ip_iface (device));
+	priv->teamd_dbus_watch = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
+	                                           tmp_str,
+	                                           G_BUS_NAME_WATCHER_FLAGS_NONE,
+	                                           teamd_dbus_appeared,
+	                                           teamd_dbus_vanished,
+	                                           NM_DEVICE (device),
+	                                           NULL);
+	g_free (tmp_str);
+}
+
+static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
 {
@@ -730,7 +798,15 @@ set_property (GObject *object, guint prop_id,
 static void
 dispose (GObject *object)
 {
-	teamd_cleanup (NM_DEVICE (object), FALSE);
+	NMDevice *device = NM_DEVICE (object);
+	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object);
+
+	if (priv->teamd_dbus_watch) {
+		g_bus_unwatch_name (priv->teamd_dbus_watch);
+		priv->teamd_dbus_watch = 0;
+	}
+
+	teamd_cleanup (device, TRUE);
 
 	G_OBJECT_CLASS (nm_device_team_parent_class)->dispose (object);
 }
@@ -746,6 +822,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass)
 	parent_class->connection_type = NM_SETTING_TEAM_SETTING_NAME;
 
 	/* virtual methods */
+	object_class->constructed = constructed;
 	object_class->get_property = get_property;
 	object_class->set_property = set_property;
 	object_class->dispose = dispose;
diff --git a/src/devices/wifi/Makefile.in b/src/devices/wifi/Makefile.in
index 175dd900..f5e88007 100644
--- a/src/devices/wifi/Makefile.in
+++ b/src/devices/wifi/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/devices/wifi
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -226,6 +235,8 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -277,7 +288,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -312,6 +322,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -583,7 +594,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wifi/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/devices/wifi/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -658,14 +668,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -968,6 +978,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	tags tags-am uninstall uninstall-am \
 	uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 include $(GLIB_MAKEFILE)
 
 @GNOME_CODE_COVERAGE_RULES@
diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c
index 0f5aa164..dc3dfbc6 100644
--- a/src/devices/wifi/nm-device-olpc-mesh.c
+++ b/src/devices/wifi/nm-device-olpc-mesh.c
@@ -235,7 +235,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 }
 
 static gboolean
-is_available (NMDevice *device)
+is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
 {
 	NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device);
 
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index dd7754b3..ce9a3f75 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -863,10 +863,10 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 
 
 static gboolean
-_internal_check_connection_available (NMDevice *device,
-                                      NMConnection *connection,
-                                      const char *specific_object,
-                                      gboolean ignore_ap_list)
+check_connection_available (NMDevice *device,
+                            NMConnection *connection,
+                            NMDeviceCheckConAvailableFlags flags,
+                            const char *specific_object)
 {
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
 	NMSettingWireless *s_wifi;
@@ -876,6 +876,9 @@ _internal_check_connection_available (NMDevice *device,
 	s_wifi = nm_connection_get_setting_wireless (connection);
 	g_return_val_if_fail (s_wifi, FALSE);
 
+	/* a connection that is available for a certain @specific_object, MUST
+	 * also be available in general (without @specific_object). */
+
 	if (specific_object) {
 		NMAccessPoint *ap;
 
@@ -891,8 +894,15 @@ _internal_check_connection_available (NMDevice *device,
 	    || g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0)
 		return TRUE;
 
-	/* Hidden SSIDs obviously don't always appear in the scan list either */
-	if (nm_setting_wireless_get_hidden (s_wifi) || ignore_ap_list)
+	/* Hidden SSIDs obviously don't always appear in the scan list either.
+	 *
+	 * For an explict user-activation-request, a connection is considered
+	 * available because for hidden Wi-Fi, clients didn't consistently
+	 * set the 'hidden' property to indicate hidden SSID networks.  If
+	 * activating but the network isn't available let the device recheck
+	 * availability.
+	 */
+	if (nm_setting_wireless_get_hidden (s_wifi) || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP))
 		return TRUE;
 
 	/* check if its visible */
@@ -904,24 +914,6 @@ _internal_check_connection_available (NMDevice *device,
 	return FALSE;
 }
 
-static gboolean
-check_connection_available (NMDevice *device,
-                            NMConnection *connection,
-                            const char *specific_object)
-{
-	return _internal_check_connection_available (device, connection, specific_object, FALSE);
-}
-
-/* FIXME: remove this function when we require the 'hidden' property to be
- * set before a hidden connection can be activated.
- */
-static gboolean
-check_connection_available_wifi_hidden (NMDevice *device,
-                                        NMConnection *connection)
-{
-	return _internal_check_connection_available (device, connection, NULL, TRUE);
-}
-
 /*
  * List of manufacturer default SSIDs that are often unchanged by users.
  *
@@ -1143,28 +1135,22 @@ complete_connection (NMDevice *device,
 }
 
 static gboolean
-is_available (NMDevice *device)
+is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
 {
 	NMDeviceWifi *self = NM_DEVICE_WIFI (device);
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	guint32 state;
 
-	if (!priv->enabled) {
-		_LOGD (LOGD_WIFI, "not available because not enabled");
+	if (!priv->enabled)
 		return FALSE;
-	}
 
-	if (!priv->sup_iface) {
-		_LOGD (LOGD_WIFI, "not available because supplicant not running");
+	if (!priv->sup_iface)
 		return FALSE;
-	}
 
 	state = nm_supplicant_interface_get_state (priv->sup_iface);
 	if (   state < NM_SUPPLICANT_INTERFACE_STATE_READY
-	    || state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) {
-		_LOGD (LOGD_WIFI, "not available because supplicant interface not ready");
+	    || state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)
 		return FALSE;
-	}
 
 	return TRUE;
 }
@@ -1522,7 +1508,9 @@ request_wireless_scan (gpointer user_data)
 
 				for (i = 0; i < ssids->len; i++) {
 					ssid = g_ptr_array_index (ssids, i);
-					foo = nm_utils_ssid_to_utf8 (ssid->data, ssid->len);
+					foo = ssid->len > 0
+					      ? nm_utils_ssid_to_utf8 (ssid->data, ssid->len)
+					      : NULL;
 					_LOGD (LOGD_WIFI_SCAN, "(%d) probe scanning SSID '%s'",
 					            i, foo ? foo : "<hidden>");
 					g_free (foo);
@@ -1636,6 +1624,8 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
  *
  */
 
+#define WPAS_REMOVED_TAG "supplicant-removed"
+
 static void
 try_fill_ssid_for_hidden_ap (NMAccessPoint *ap)
 {
@@ -1743,6 +1733,7 @@ merge_scanned_ap (NMDeviceWifi *self,
 		 * fake, since it clearly exists somewhere.
 		 */
 		nm_ap_set_fake (found_ap, FALSE);
+		g_object_set_data (G_OBJECT (found_ap), WPAS_REMOVED_TAG, NULL);
 	} else {
 		/* New entry in the list */
 		_LOGD (LOGD_WIFI_SCAN, "adding new AP '%s' %s (%p)",
@@ -1756,8 +1747,6 @@ merge_scanned_ap (NMDeviceWifi *self,
 	}
 }
 
-#define WPAS_REMOVED_TAG "supplicant-removed"
-
 static gboolean
 cull_scan_list (NMDeviceWifi *self)
 {
@@ -1912,9 +1901,23 @@ supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface,
 	g_return_if_fail (object_path != NULL);
 
 	ap = get_ap_by_supplicant_path (self, object_path);
-	if (ap)
+	if (ap) {
+		gint32 now = nm_utils_get_monotonic_timestamp_s ();
+		gint32 last_seen = nm_ap_get_last_seen (ap);
+
+		/* We don't know when the supplicant last saw the AP's beacons,
+		 * it could be two minutes or it could be 2 seconds.  Because the
+		 * supplicant doesn't send property change notifications if the
+		 * AP's other properties don't change, our last-seen time may be
+		 * much older the supplicant's, and the AP would be immediately
+		 * removed from the list on the next cleanup.  So update the
+		 * last-seen time to ensure the AP sticks around for at least
+		 * one more periodic scan.
+		 */
+		nm_ap_set_last_seen (ap, MAX (last_seen, now - SCAN_INTERVAL_MAX));
 		g_object_set_data (G_OBJECT (ap), WPAS_REMOVED_TAG, GUINT_TO_POINTER (TRUE));
 }
+}
 
 static void
 remove_supplicant_timeouts (NMDeviceWifi *self)
@@ -2169,7 +2172,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
 		/* If the interface can now be activated because the supplicant is now
 		 * available, transition to DISCONNECTED.
 		 */
-		if ((devstate == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device)) {
+		if ((devstate == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) {
 			nm_device_state_changed (device,
 			                         NM_DEVICE_STATE_DISCONNECTED,
 			                         NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE);
@@ -3335,7 +3338,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
 	parent_class->is_available = is_available;
 	parent_class->check_connection_compatible = check_connection_compatible;
 	parent_class->check_connection_available = check_connection_available;
-	parent_class->check_connection_available_wifi_hidden = check_connection_available_wifi_hidden;
 	parent_class->complete_connection = complete_connection;
 	parent_class->set_enabled = set_enabled;
 
diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c
index ee07cf40..66d73563 100644
--- a/src/devices/wifi/nm-wifi-ap.c
+++ b/src/devices/wifi/nm-wifi-ap.c
@@ -808,7 +808,7 @@ nm_ap_set_ssid (NMAccessPoint *ap, const guint8 *ssid, gsize len)
 NM80211ApFlags
 nm_ap_get_flags (NMAccessPoint *ap)
 {
-	g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_SEC_NONE);
+	g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_FLAGS_NONE);
 
 	return NM_AP_GET_PRIVATE (ap)->flags;
 }
diff --git a/src/devices/wifi/tests/Makefile.am b/src/devices/wifi/tests/Makefile.am
index 09c6401f..2a7d7849 100644
--- a/src/devices/wifi/tests/Makefile.am
+++ b/src/devices/wifi/tests/Makefile.am
@@ -23,5 +23,6 @@ test_wifi_ap_utils_SOURCES = \
 
 test_wifi_ap_utils_LDADD = $(top_builddir)/src/libNetworkManager.la
 
+@VALGRIND_RULES@
 TESTS = test-wifi-ap-utils
 
diff --git a/src/devices/wifi/tests/Makefile.in b/src/devices/wifi/tests/Makefile.in
index a8ae2e9d..e3b7c767 100644
--- a/src/devices/wifi/tests/Makefile.in
+++ b/src/devices/wifi/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 noinst_PROGRAMS = test-wifi-ap-utils$(EXEEXT)
 TESTS = test-wifi-ap-utils$(EXEEXT)
 subdir = src/devices/wifi/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -195,6 +204,8 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -221,7 +232,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -256,6 +266,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -494,7 +505,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wifi/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/devices/wifi/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -541,14 +551,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -888,6 +898,10 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
+
+@VALGRIND_RULES@
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/devices/wifi/tests/test-wifi-ap-utils.c b/src/devices/wifi/tests/test-wifi-ap-utils.c
index fb335b89..3c405e26 100644
--- a/src/devices/wifi/tests/test-wifi-ap-utils.c
+++ b/src/devices/wifi/tests/test-wifi-ap-utils.c
@@ -785,6 +785,7 @@ test_priv_ap_leap_connection_1 (gconstpointer add_wifi)
 	COMPARE (src, expected, success, error, 0, 0);
 
 	g_object_unref (src);
+	g_object_unref (expected);
 }
 
 /*******************************************/
@@ -866,6 +867,7 @@ test_priv_ap_dynamic_wep_1 (void)
 	COMPARE (src, expected, success, error, 0, 0);
 
 	g_object_unref (src);
+	g_object_unref (expected);
 }
 
 /*******************************************/
@@ -913,6 +915,7 @@ test_priv_ap_dynamic_wep_2 (void)
 	COMPARE (src, expected, success, error, 0, 0);
 
 	g_object_unref (src);
+	g_object_unref (expected);
 }
 
 /*******************************************/
diff --git a/src/devices/wimax/Makefile.in b/src/devices/wimax/Makefile.in
index f1ffb09c..32800fb7 100644
--- a/src/devices/wimax/Makefile.in
+++ b/src/devices/wimax/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/devices/wimax
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -205,6 +214,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -231,7 +242,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -266,6 +276,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -526,7 +537,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wimax/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/devices/wimax/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -600,14 +610,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -835,6 +845,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 
 nm-wimax-nsp-glue.h: $(top_srcdir)/introspection/nm-wimax-nsp.xml
 	dbus-binding-tool --prefix=nm_wimax_nsp --mode=glib-server --output=$@ $<
diff --git a/src/devices/wimax/nm-device-wimax.c b/src/devices/wimax/nm-device-wimax.c
index 466cd979..0c8f1cbb 100644
--- a/src/devices/wimax/nm-device-wimax.c
+++ b/src/devices/wimax/nm-device-wimax.c
@@ -239,7 +239,7 @@ update_availability (NMDeviceWimax *self, gboolean old_available)
 	NMDeviceState state;
 	gboolean new_available, changed = FALSE;
 
-	new_available = nm_device_is_available (device);
+	new_available = nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
 	if (new_available == old_available)
 		return FALSE;
 
@@ -281,7 +281,7 @@ set_enabled (NMDevice *device, gboolean enabled)
 	if (priv->enabled == enabled)
 		return;
 
-	old_available = nm_device_is_available (NM_DEVICE (device));
+	old_available = nm_device_is_available (NM_DEVICE (device), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
 	priv->enabled = enabled;
 
 	nm_log_dbg (LOGD_WIMAX, "(%s): radio now %s",
@@ -334,12 +334,16 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 static gboolean
 check_connection_available (NMDevice *device,
                             NMConnection *connection,
+                            NMDeviceCheckConAvailableFlags flags,
                             const char *specific_object)
 {
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
 	const GSList *ns_iter = NULL;
 	NMWimaxNsp *nsp;
 
+	/* a connection that is available for a certain @specific_object, MUST
+	 * also be available in general (without @specific_object). */
+
 	if (specific_object) {
 		nsp = get_nsp_by_path (NM_DEVICE_WIMAX (device), specific_object);
 		return nsp ? nm_wimax_nsp_check_compatible (nsp, connection) : FALSE;
@@ -484,30 +488,21 @@ can_auto_connect (NMDevice *device,
 }
 
 static gboolean
-is_available (NMDevice *device)
+is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
 {
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
-	const char *iface = nm_device_get_iface (device);
 
-	if (!priv->enabled) {
-		nm_log_dbg (LOGD_WIMAX, "(%s): not available because not enabled", iface);
+	if (!priv->enabled)
 		return FALSE;
-	}
 
-	if (!priv->wimaxd_enabled) {
-		nm_log_dbg (LOGD_WIMAX, "(%s): not available because not enabled in wimaxd", iface);
+	if (!priv->wimaxd_enabled)
 		return FALSE;
-	}
 
-	if (!nm_wimax_util_sdk_is_initialized ()) {
-		nm_log_dbg (LOGD_WIMAX, "(%s): not available because WiMAX SDK not initialized", iface);
+	if (!nm_wimax_util_sdk_is_initialized ())
 		return FALSE;
-	}
 
-	if (!priv->sdk) {
-		nm_log_dbg (LOGD_WIMAX, "(%s): not available because not known to WiMAX SDK", iface);
+	if (!priv->sdk)
 		return FALSE;
-	}
 
 	return iwmxsdk_status_get (priv->sdk) >= WIMAX_API_DEVICE_STATUS_Ready;
 }
@@ -712,7 +707,7 @@ wmx_state_change_cb (struct wmxsdk *wmxsdk,
 		return;
 
 	state = nm_device_get_state (NM_DEVICE (self));
-	old_available = nm_device_is_available (NM_DEVICE (self));
+	old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
 
 	priv->status = new_status;
 	if (priv->current_nsp)
@@ -1153,7 +1148,7 @@ static gboolean
 sdk_action_defer_cb (gpointer user_data)
 {
 	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
-	gboolean old_available = nm_device_is_available (NM_DEVICE (self));
+	gboolean old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
 
 	NM_DEVICE_WIMAX_GET_PRIVATE (self)->sdk_action_defer_id = 0;
 	update_availability (self, old_available);
diff --git a/src/devices/wwan/Makefile.in b/src/devices/wwan/Makefile.in
index 18cbfdd3..1a8aef3b 100644
--- a/src/devices/wwan/Makefile.in
+++ b/src/devices/wwan/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/devices/wwan
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -216,6 +225,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -242,7 +253,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -277,6 +287,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -553,7 +564,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wwan/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/devices/wwan/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -631,14 +641,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -866,6 +876,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 include $(GLIB_MAKEFILE)
 
 @GNOME_CODE_COVERAGE_RULES@
diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c
index f681e59c..f819d1d7 100644
--- a/src/devices/wwan/nm-device-modem.c
+++ b/src/devices/wwan/nm-device-modem.c
@@ -295,16 +295,19 @@ modem_state_cb (NMModem *modem,
 		 * device's enabled/disabled state.
 		 */
 		nm_modem_set_mm_enabled (priv->modem, priv->rf_enabled);
+
+		/* Now allow connections without a PIN to be available */
+		nm_device_recheck_available_connections (device);
 	}
 
-	if ((dev_state >= NM_DEVICE_STATE_DISCONNECTED) && !nm_device_is_available (device)) {
+	if ((dev_state >= NM_DEVICE_STATE_DISCONNECTED) && !nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) {
 		nm_device_state_changed (device,
 		                         NM_DEVICE_STATE_UNAVAILABLE,
 		                         NM_DEVICE_STATE_REASON_MODEM_FAILED);
 		return;
 	}
 
-	if ((dev_state == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device)) {
+	if ((dev_state == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) {
 		nm_device_state_changed (device,
 		                         NM_DEVICE_STATE_DISCONNECTED,
 		                         NM_DEVICE_STATE_REASON_MODEM_AVAILABLE);
@@ -391,6 +394,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 static gboolean
 check_connection_available (NMDevice *device,
                             NMConnection *connection,
+                            NMDeviceCheckConAvailableFlags flags,
                             const char *specific_object)
 {
 	NMDeviceModem *self = NM_DEVICE_MODEM (device);
@@ -433,6 +437,50 @@ deactivate (NMDevice *device)
 	nm_modem_deactivate (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device);
 }
 
+/***********************************************************/
+
+static gboolean
+deactivate_async_finish (NMDevice *self,
+                         GAsyncResult *res,
+                         GError **error)
+{
+	return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+modem_deactivate_async_ready (NMModem *modem,
+                              GAsyncResult *res,
+                              GSimpleAsyncResult *simple)
+{
+	GError *error = NULL;
+
+	if (!nm_modem_deactivate_async_finish (modem, res, &error))
+		g_simple_async_result_take_error (simple, error);
+	g_simple_async_result_complete (simple);
+	g_object_unref (simple);
+}
+
+static void
+deactivate_async (NMDevice *self,
+                  GCancellable *cancellable,
+                  GAsyncReadyCallback callback,
+                  gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+
+	simple = g_simple_async_result_new (G_OBJECT (self),
+	                                    callback,
+	                                    user_data,
+	                                    deactivate_async);
+	nm_modem_deactivate_async (NM_DEVICE_MODEM_GET_PRIVATE (self)->modem,
+	                           self,
+	                           cancellable,
+	                           (GAsyncReadyCallback) modem_deactivate_async_ready,
+	                           simple);
+}
+
+/***********************************************************/
+
 static NMActStageReturn
 act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 {
@@ -536,24 +584,19 @@ set_enabled (NMDevice *device, gboolean enabled)
 }
 
 static gboolean
-is_available (NMDevice *device)
+is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
 {
 	NMDeviceModem *self = NM_DEVICE_MODEM (device);
-	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device);
+	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self);
 	NMModemState modem_state;
 
-	if (!priv->rf_enabled) {
-		_LOGD (LOGD_MB, "not available because WWAN airplane mode is on");
+	if (!priv->rf_enabled)
 		return FALSE;
-	}
 
 	g_assert (priv->modem);
 	modem_state = nm_modem_get_state (priv->modem);
-	if (modem_state <= NM_MODEM_STATE_INITIALIZING) {
-		_LOGD (LOGD_MB, "not available because modem is not ready (%s)",
-		       nm_modem_state_to_string (modem_state));
+	if (modem_state <= NM_MODEM_STATE_INITIALIZING)
 		return FALSE;
-	}
 
 	return TRUE;
 }
@@ -638,7 +681,7 @@ set_modem (NMDeviceModem *self, NMModem *modem)
 
 static void
 set_property (GObject *object, guint prop_id,
-			  const GValue *value, GParamSpec *pspec)
+              const GValue *value, GParamSpec *pspec)
 {
 	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);
 
@@ -661,7 +704,7 @@ set_property (GObject *object, guint prop_id,
 
 static void
 get_property (GObject *object, guint prop_id,
-			  GValue *value, GParamSpec *pspec)
+              GValue *value, GParamSpec *pspec)
 {
 	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);
 
@@ -711,6 +754,8 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass)
 	device_class->check_connection_compatible = check_connection_compatible;
 	device_class->check_connection_available = check_connection_available;
 	device_class->complete_connection = complete_connection;
+	device_class->deactivate_async = deactivate_async;
+	device_class->deactivate_async_finish = deactivate_async_finish;
 	device_class->deactivate = deactivate;
 	device_class->act_stage1_prepare = act_stage1_prepare;
 	device_class->act_stage2_config = act_stage2_config;
diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c
index f8239b79..4bb72fd1 100644
--- a/src/devices/wwan/nm-modem-broadband.c
+++ b/src/devices/wwan/nm-modem-broadband.c
@@ -42,7 +42,7 @@ struct _NMModemBroadbandPrivate {
 	MMModemSimple *simple_iface;
 
 	/* Connection setup */
-	MMSimpleConnectProperties *connect_properties;
+
 	MMBearer *bearer;
 	MMBearerIpConfig *ipv4_config;
 	MMBearerIpConfig *ipv6_config;
@@ -176,78 +176,6 @@ get_bearer_ip_method (MMBearerIpConfig *config)
 	return NM_MODEM_IP_METHOD_UNKNOWN;
 }
 
-static void
-connect_ready (MMModemSimple *simple_iface,
-               GAsyncResult *res,
-               NMModemBroadband *self)
-{
-	GError *error = NULL;
-	NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN;
-	NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN;
-
-	g_clear_object (&self->priv->connect_properties);
-
-	self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error);
-	if (!self->priv->bearer) {
-		if (g_error_matches (error,
-		                     MM_MOBILE_EQUIPMENT_ERROR,
-		                     MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) ||
-			(g_error_matches (error,
-		                          MM_CORE_ERROR,
-		                          MM_CORE_ERROR_UNAUTHORIZED) &&
-			 mm_modem_get_unlock_required (self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) {
-			/* Request PIN */
-			ask_for_pin (self);
-		} else {
-			/* Strip remote error info before logging it */
-			if (g_dbus_error_is_remote_error (error))
-				g_dbus_error_strip_remote_error (error);
-
-			nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s",
-			             nm_modem_get_uid (NM_MODEM (self)),
-			             error && error->message ? error->message : "(unknown)");
-			g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error));
-		}
-
-		g_clear_error (&error);
-		g_object_unref (self);
-		return;
-	}
-
-	/* Grab IP configurations */
-	self->priv->ipv4_config = mm_bearer_get_ipv4_config (self->priv->bearer);
-	if (self->priv->ipv4_config)
-		ip4_method = get_bearer_ip_method (self->priv->ipv4_config);
-
-	self->priv->ipv6_config = mm_bearer_get_ipv6_config (self->priv->bearer);
-	if (self->priv->ipv6_config)
-		ip6_method = get_bearer_ip_method (self->priv->ipv6_config);
-
-	if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN &&
-	    ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) {
-		nm_log_warn (LOGD_MB, "(%s) failed to connect modem: invalid bearer IP configuration",
-		             nm_modem_get_uid (NM_MODEM (self)));
-
-		error = g_error_new_literal (NM_DEVICE_ERROR,
-		                             NM_DEVICE_ERROR_INVALID_CONNECTION,
-		                             "invalid bearer IP configuration");
-		g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, error);
-		g_error_free (error);
-		g_object_unref (self);
-		return;
-	}
-
-	g_object_set (self,
-	              NM_MODEM_DATA_PORT,  mm_bearer_get_interface (self->priv->bearer),
-	              NM_MODEM_IP4_METHOD, ip4_method,
-	              NM_MODEM_IP6_METHOD, ip6_method,
-	              NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (self->priv->bearer),
-	              NULL);
-
-	g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE);
-	g_object_unref (self);
-}
-
 static MMSimpleConnectProperties *
 create_cdma_connect_properties (NMConnection *connection)
 {
@@ -266,15 +194,12 @@ create_cdma_connect_properties (NMConnection *connection)
 }
 
 static MMSimpleConnectProperties *
-create_gsm_connect_properties (NMModem *modem,
-                               NMConnection *connection,
-                               GError **error)
+create_gsm_connect_properties (NMConnection *connection)
 {
 	NMSettingGsm *setting;
 	NMSettingPpp *s_ppp;
 	MMSimpleConnectProperties *properties;
 	const gchar *str;
-	NMModemIPType ip_type;
 
 	setting = nm_connection_get_setting_gsm (connection);
 	properties = mm_simple_connect_properties_new ();
@@ -329,23 +254,137 @@ create_gsm_connect_properties (NMModem *modem,
 		mm_simple_connect_properties_set_allowed_auth (properties, allowed_auth);
 	}
 
-	/* Determine IP types to use when connecting */
-	ip_type = nm_modem_get_connection_ip_type (modem, connection, error);
-	if (ip_type == NM_MODEM_IP_TYPE_UNKNOWN) {
-		g_object_unref (properties);
-		return NULL;
+	return properties;
+}
+
+typedef struct {
+	NMModemBroadband *self;
+	MMModemCapability caps;
+	MMSimpleConnectProperties *connect_properties;
+	GArray *ip_types;
+	guint ip_types_i;
+	GError *first_error;
+} ActStageContext;
+
+static void
+act_stage_context_free (ActStageContext *ctx)
+{
+	g_clear_error (&ctx->first_error);
+	g_clear_pointer (&ctx->ip_types, (GDestroyNotify) g_array_unref);
+	g_clear_object (&ctx->connect_properties);
+	g_object_unref (ctx->self);
+	g_slice_free (ActStageContext, ctx);
+}
+
+static void act_stage_context_step (ActStageContext *ctx);
+
+static void
+connect_ready (MMModemSimple *simple_iface,
+               GAsyncResult *res,
+               ActStageContext *ctx)
+{
+	GError *error = NULL;
+	NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN;
+	NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN;
+
+	ctx->self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error);
+	if (!ctx->self->priv->bearer) {
+		if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) ||
+		    (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) &&
+		     mm_modem_get_unlock_required (ctx->self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) {
+			/* Request PIN */
+			ask_for_pin (ctx->self);
+			g_error_free (error);
+			act_stage_context_free (ctx);
+			return;
+		}
+
+		/* Save the error, if it's the first one */
+		if (!ctx->first_error) {
+			/* Strip remote error info before saving it */
+			if (g_dbus_error_is_remote_error (error))
+				g_dbus_error_strip_remote_error (error);
+			ctx->first_error = error;
+		} else
+			g_error_free (error);
+
+		/* If the modem/provider lies and the IP type we tried isn't supported,
+		 * retry with the next one, if any.
+		 */
+		ctx->ip_types_i++;
+		act_stage_context_step (ctx);
+		return;
 	}
 
-	if (ip_type == NM_MODEM_IP_TYPE_IPV4)
-		mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV4);
-	else if (ip_type == NM_MODEM_IP_TYPE_IPV6)
-		mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV6);
-	else if (ip_type == NM_MODEM_IP_TYPE_IPV4V6)
-		mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV4V6);
-	else
-		g_assert_not_reached ();
+	/* Grab IP configurations */
+	ctx->self->priv->ipv4_config = mm_bearer_get_ipv4_config (ctx->self->priv->bearer);
+	if (ctx->self->priv->ipv4_config)
+		ip4_method = get_bearer_ip_method (ctx->self->priv->ipv4_config);
 
-	return properties;
+	ctx->self->priv->ipv6_config = mm_bearer_get_ipv6_config (ctx->self->priv->bearer);
+	if (ctx->self->priv->ipv6_config)
+		ip6_method = get_bearer_ip_method (ctx->self->priv->ipv6_config);
+
+	if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN &&
+	    ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) {
+		nm_log_warn (LOGD_MB, "(%s): failed to connect modem: invalid bearer IP configuration",
+		             nm_modem_get_uid (NM_MODEM (ctx->self)));
+		g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+		act_stage_context_free (ctx);
+		return;
+	}
+
+	g_object_set (ctx->self,
+	              NM_MODEM_DATA_PORT,  mm_bearer_get_interface (ctx->self->priv->bearer),
+	              NM_MODEM_IP4_METHOD, ip4_method,
+	              NM_MODEM_IP6_METHOD, ip6_method,
+	              NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (ctx->self->priv->bearer),
+	              NULL);
+
+	g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE);
+	act_stage_context_free (ctx);
+}
+
+static void
+act_stage_context_step (ActStageContext *ctx)
+{
+	if (ctx->ip_types_i < ctx->ip_types->len) {
+		NMModemIPType current;
+
+		current = g_array_index (ctx->ip_types, NMModemIPType, ctx->ip_types_i);
+
+		if (current == NM_MODEM_IP_TYPE_IPV4)
+			mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4);
+		else if (current == NM_MODEM_IP_TYPE_IPV6)
+			mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV6);
+		else if (current == NM_MODEM_IP_TYPE_IPV4V6)
+			mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4V6);
+		else
+			g_assert_not_reached ();
+
+		nm_log_dbg (LOGD_MB, "(%s): launching connection with ip type '%s'",
+		            nm_modem_get_uid (NM_MODEM (ctx->self)),
+		            nm_modem_ip_type_to_string (current));
+
+		mm_modem_simple_connect (ctx->self->priv->simple_iface,
+		                         ctx->connect_properties,
+		                         NULL,
+		                         (GAsyncReadyCallback)connect_ready,
+		                         ctx);
+		return;
+	}
+
+	/* If we have a saved error from a previous attempt, use it */
+	if (!ctx->first_error)
+		ctx->first_error = g_error_new_literal (NM_DEVICE_ERROR,
+		                                        NM_DEVICE_ERROR_INVALID_CONNECTION,
+		                                        "invalid bearer IP configuration");
+
+	nm_log_warn (LOGD_MB, "(%s): failed to connect modem: %s",
+	             nm_modem_get_uid (NM_MODEM (ctx->self)),
+	             ctx->first_error->message);
+	g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (ctx->first_error));
+	act_stage_context_free (ctx);
 }
 
 static NMActStageReturn
@@ -354,42 +393,55 @@ act_stage1_prepare (NMModem *_self,
                     NMDeviceStateReason *reason)
 {
 	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
-	MMModemCapability caps;
+	ActStageContext *ctx;
 	GError *error = NULL;
 
-	g_clear_object (&self->priv->connect_properties);
+	/* Make sure we can get the Simple interface from the modem */
+	if (!self->priv->simple_iface) {
+		self->priv->simple_iface = mm_object_get_modem_simple (self->priv->modem_object);
+		if (!self->priv->simple_iface) {
+			nm_log_warn (LOGD_MB, "(%s) cannot access the Simple mobile broadband modem interface",
+			             nm_modem_get_uid (NM_MODEM (self)));
+			*reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
+			return NM_ACT_STAGE_RETURN_FAILURE;
+		}
+	}
+
+	/* Allocate new context for this activation stage attempt */
+	ctx = g_slice_new0 (ActStageContext);
+	ctx->self = NM_MODEM_BROADBAND (g_object_ref (self));
+	ctx->caps = mm_modem_get_current_capabilities (self->priv->modem_iface);
 
-	caps = mm_modem_get_current_capabilities (self->priv->modem_iface);
-	if (MODEM_CAPS_3GPP (caps))
-		self->priv->connect_properties = create_gsm_connect_properties (_self, connection, &error);
-	else if (MODEM_CAPS_3GPP2 (caps))
-		self->priv->connect_properties = create_cdma_connect_properties (connection);
+	/* Create core connect properties based on the modem capabilities */
+	if (MODEM_CAPS_3GPP (ctx->caps))
+		ctx->connect_properties = create_gsm_connect_properties (connection);
+	else if (MODEM_CAPS_3GPP2 (ctx->caps))
+		ctx->connect_properties = create_cdma_connect_properties (connection);
 	else {
-		nm_log_warn (LOGD_MB, "(%s) not a mobile broadband modem",
-					 nm_modem_get_uid (NM_MODEM (self)));
+		nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': not a mobile broadband modem",
+		             nm_modem_get_uid (NM_MODEM (self)),
+		             nm_connection_get_id (connection));
+		act_stage_context_free (ctx);
 		*reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
 		return NM_ACT_STAGE_RETURN_FAILURE;
 	}
+	g_assert (ctx->connect_properties);
 
-	if (error) {
+	/* Checkout list of IP types that we need to use in the retries */
+	ctx->ip_types = nm_modem_get_connection_ip_type (NM_MODEM (self), connection, &error);
+	if (!ctx->ip_types) {
 		nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': %s",
 		             nm_modem_get_uid (NM_MODEM (self)),
 		             nm_connection_get_id (connection),
-		             error->message);
+		             error ? error->message : "unknown error");
 		g_clear_error (&error);
+		act_stage_context_free (ctx);
 		*reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
 		return NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
-	if (!self->priv->simple_iface)
-		self->priv->simple_iface = mm_object_get_modem_simple (self->priv->modem_object);
-
 	g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (self->priv->simple_iface), MODEM_CONNECT_TIMEOUT_SECS * 1000);
-	mm_modem_simple_connect (self->priv->simple_iface,
-	                         self->priv->connect_properties,
-	                         NULL,
-	                         (GAsyncReadyCallback)connect_ready,
-	                         g_object_ref (self));
+	act_stage_context_step (ctx);
 
 	return NM_ACT_STAGE_RETURN_POSTPONE;
 }
@@ -566,9 +618,9 @@ set_power_state_low_ready (MMModem *modem,
 
 	if (!mm_modem_set_power_state_finish (modem, result, &error)) {
 		/* Log but ignore errors; not all modems support low power state */
-		nm_log_dbg (LOGD_MB, "(%s) failed to set modem low power state: %s",
-		             nm_modem_get_uid (NM_MODEM (self)),
-		             error && error->message ? error->message : "(unknown)");
+		nm_log_dbg (LOGD_MB, "(%s): failed to set modem low power state: %s",
+		            nm_modem_get_uid (NM_MODEM (self)),
+		            error && error->message ? error->message : "(unknown)");
 		g_clear_error (&error);
 	}
 
@@ -591,7 +643,7 @@ modem_disable_ready (MMModem *modem_iface,
 		                          (GAsyncReadyCallback) set_power_state_low_ready,
 		                          g_object_ref (self));
 	} else {
-		nm_log_warn (LOGD_MB, "(%s) failed to disable modem: %s",
+		nm_log_warn (LOGD_MB, "(%s): failed to disable modem: %s",
 		             nm_modem_get_uid (NM_MODEM (self)),
 		             error && error->message ? error->message : "(unknown)");
 		nm_modem_set_prev_state (NM_MODEM (self), "disable failed");
@@ -708,7 +760,7 @@ static_stage3_ip4_done (NMModemBroadband *self)
 
 	/* DNS servers */
 	dns = mm_bearer_ip_config_get_dns (self->priv->ipv4_config);
-	for (i = 0; dns[i]; i++) {
+	for (i = 0; dns && dns[i]; i++) {
 		if (   ip4_string_to_num (dns[i], &address_network)
 		    && address_network > 0) {
 			nm_ip4_config_add_nameserver (config, address_network);
@@ -761,9 +813,9 @@ stage3_ip6_done (NMModemBroadband *self)
 		/* DHCP/SLAAC is allowed to skip addresses; other methods require it */
 		if (ip_method != NM_MODEM_IP_METHOD_AUTO) {
 			error = g_error_new (NM_DEVICE_ERROR,
-				                 NM_DEVICE_ERROR_INVALID_CONNECTION,
-				                 "(%s) retrieving IPv6 configuration failed: no address given",
-				                 nm_modem_get_uid (NM_MODEM (self)));
+			                     NM_DEVICE_ERROR_INVALID_CONNECTION,
+			                     "(%s) retrieving IPv6 configuration failed: no address given",
+			                     nm_modem_get_uid (NM_MODEM (self)));
 		}
 		goto out;
 	}
@@ -792,10 +844,10 @@ stage3_ip6_done (NMModemBroadband *self)
 	if (address_string) {
 		if (!inet_pton (AF_INET6, address_string, (void *) &(address.address))) {
 			error = g_error_new (NM_DEVICE_ERROR,
-				                 NM_DEVICE_ERROR_INVALID_CONNECTION,
-				                 "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'",
-				                 nm_modem_get_uid (NM_MODEM (self)),
-				                 address_string);
+			                     NM_DEVICE_ERROR_INVALID_CONNECTION,
+			                     "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'",
+			                     nm_modem_get_uid (NM_MODEM (self)),
+			                     address_string);
 			goto out;
 		}
 		nm_log_info (LOGD_MB, "  gateway %s", address_string);
@@ -844,20 +896,47 @@ stage3_ip6_config_request (NMModem *_self, NMDeviceStateReason *reason)
 
 typedef struct {
 	NMModemBroadband *self;
+	GSimpleAsyncResult *result;
+	GCancellable *cancellable;
 	gboolean warn;
-} SimpleDisconnectContext;
+} DisconnectContext;
 
 static void
-simple_disconnect_context_free (SimpleDisconnectContext *ctx)
+disconnect_context_complete (DisconnectContext *ctx)
 {
+	g_simple_async_result_complete_in_idle (ctx->result);
+	if (ctx->cancellable)
+		g_object_unref (ctx->cancellable);
+	g_object_unref (ctx->result);
 	g_object_unref (ctx->self);
-	g_slice_free (SimpleDisconnectContext, ctx);
+	g_slice_free (DisconnectContext, ctx);
+}
+
+static gboolean
+disconnect_context_complete_if_cancelled (DisconnectContext *ctx)
+{
+	GError *error = NULL;
+
+	if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) {
+		g_simple_async_result_take_error (ctx->result, error);
+		disconnect_context_complete (ctx);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean
+disconnect_finish (NMModem *self,
+                   GAsyncResult *res,
+                   GError **error)
+{
+	return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
 }
 
 static void
 simple_disconnect_ready (MMModemSimple *modem_iface,
                          GAsyncResult *res,
-                         SimpleDisconnectContext *ctx)
+                         DisconnectContext *ctx)
 {
 	GError *error = NULL;
 
@@ -865,33 +944,48 @@ simple_disconnect_ready (MMModemSimple *modem_iface,
 		if (ctx->warn)
 			nm_log_warn (LOGD_MB, "(%s) failed to disconnect modem: %s",
 			             nm_modem_get_uid (NM_MODEM (ctx->self)),
-			             error && error->message ? error->message : "(unknown)");
-		g_clear_error (&error);
+			             error->message);
+		g_simple_async_result_take_error (ctx->result, error);
 	}
 
-	simple_disconnect_context_free (ctx);
+	disconnect_context_complete (ctx);
 }
 
 static void
-disconnect (NMModem *modem,
-            gboolean warn)
+disconnect (NMModem *self,
+            gboolean warn,
+            GCancellable *cancellable,
+            GAsyncReadyCallback callback,
+            gpointer user_data)
 {
-	NMModemBroadband *self = NM_MODEM_BROADBAND (modem);
-	SimpleDisconnectContext *ctx;
-
-	if (!self->priv->simple_iface)
-		return;
+	DisconnectContext *ctx;
 
-	ctx = g_slice_new (SimpleDisconnectContext);
+	ctx = g_slice_new (DisconnectContext);
 	ctx->self = g_object_ref (self);
-
+	ctx->result = g_simple_async_result_new (G_OBJECT (self),
+	                                         callback,
+	                                         user_data,
+	                                         disconnect);
 	/* Don't bother warning on FAILED since the modem is already gone */
 	ctx->warn = warn;
 
+	/* Setup cancellable */
+	ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	if (disconnect_context_complete_if_cancelled (ctx))
+		return;
+
+	/* If no simple iface, we're done */
+	if (!ctx->self->priv->simple_iface) {
+		disconnect_context_complete (ctx);
+		return;
+	}
+
+	nm_log_dbg (LOGD_MB, "(%s): notifying ModemManager about the modem disconnection",
+	            nm_modem_get_uid (NM_MODEM (ctx->self)));
 	mm_modem_simple_disconnect (
 		ctx->self->priv->simple_iface,
 		NULL, /* bearer path; if NULL given ALL get disconnected */
-		NULL, /* cancellable */
+		cancellable,
 		(GAsyncReadyCallback)simple_disconnect_ready,
 		ctx);
 }
@@ -899,7 +993,7 @@ disconnect (NMModem *modem,
 /*****************************************************************************/
 
 static void
-deactivate (NMModem *_self, NMDevice *device)
+deactivate_cleanup (NMModem *_self, NMDevice *device)
 {
 	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
 
@@ -913,7 +1007,7 @@ deactivate (NMModem *_self, NMDevice *device)
 	self->priv->pin_tries = 0;
 
 	/* Chain up parent's */
-	NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate (_self, device);
+	NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate_cleanup (_self, device);
 }
 
 /*****************************************************************************/
@@ -1027,7 +1121,7 @@ get_sim_ready (MMModem *modem,
 		              NULL);
 		g_object_unref (new_sim);
 	} else {
-		nm_log_warn (LOGD_MB, "(%s) failed to retrieve SIM object: %s",
+		nm_log_warn (LOGD_MB, "(%s): failed to retrieve SIM object: %s",
 		             nm_modem_get_uid (NM_MODEM (self)),
 		             error && error->message ? error->message : "(unknown)");
 	}
@@ -1062,7 +1156,7 @@ nm_modem_broadband_init (NMModemBroadband *self)
 static void
 set_property (GObject *object,
               guint prop_id,
-			  const GValue *value,
+              const GValue *value,
               GParamSpec *pspec)
 {
 	NMModemBroadband *self = NM_MODEM_BROADBAND (object);
@@ -1095,7 +1189,7 @@ set_property (GObject *object,
 static void
 get_property (GObject *object,
               guint prop_id,
-			  GValue *value,
+              GValue *value,
               GParamSpec *pspec)
 {
 	NMModemBroadband *self = NM_MODEM_BROADBAND (object);
@@ -1142,7 +1236,8 @@ nm_modem_broadband_class_init (NMModemBroadbandClass *klass)
 	modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start;
 	modem_class->stage3_ip6_config_request = stage3_ip6_config_request;
 	modem_class->disconnect = disconnect;
-	modem_class->deactivate = deactivate;
+	modem_class->disconnect_finish = disconnect_finish;
+	modem_class->deactivate_cleanup = deactivate_cleanup;
 	modem_class->set_mm_enabled = set_mm_enabled;
 	modem_class->get_user_pass = get_user_pass;
 	modem_class->check_connection_compatible = check_connection_compatible;
diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c
index ba1db8a4..69eaddf3 100644
--- a/src/devices/wwan/nm-modem.c
+++ b/src/devices/wwan/nm-modem.c
@@ -175,23 +175,23 @@ nm_modem_set_mm_enabled (NMModem *self,
 	NMModemState prev_state = priv->state;
 
 	if (enabled && priv->state >= NM_MODEM_STATE_ENABLING) {
-		nm_log_dbg (LOGD_MB, "(%s) cannot enable modem: already enabled",
+		nm_log_dbg (LOGD_MB, "(%s): cannot enable modem: already enabled",
 		            nm_modem_get_uid (self));
 		return;
 	}
 	if (!enabled && priv->state <= NM_MODEM_STATE_DISABLING) {
-		nm_log_dbg (LOGD_MB, "(%s) cannot disable modem: already disabled",
+		nm_log_dbg (LOGD_MB, "(%s): cannot disable modem: already disabled",
 		            nm_modem_get_uid (self));
 		return;
 	}
 
 	if (priv->state <= NM_MODEM_STATE_INITIALIZING) {
-		nm_log_dbg (LOGD_MB, "(%s) cannot enable/disable modem: initializing or failed",
+		nm_log_dbg (LOGD_MB, "(%s): cannot enable/disable modem: initializing or failed",
 		            nm_modem_get_uid (self));
 		return;
 	} else if (priv->state == NM_MODEM_STATE_LOCKED) {
 		/* Don't try to enable if the modem is locked since that will fail */
-		nm_log_warn (LOGD_MB, "(%s) cannot enable/disable modem: locked",
+		nm_log_warn (LOGD_MB, "(%s): cannot enable/disable modem: locked",
 		             nm_modem_get_uid (self));
 
 		/* Try to unlock the modem if it's being enabled */
@@ -221,17 +221,39 @@ nm_modem_get_supported_ip_types (NMModem *self)
 	return NM_MODEM_GET_PRIVATE (self)->ip_types;
 }
 
+const gchar *
+nm_modem_ip_type_to_string (NMModemIPType ip_type)
+{
+	switch (ip_type) {
+	case NM_MODEM_IP_TYPE_IPV4:
+		return "ipv4";
+	case NM_MODEM_IP_TYPE_IPV6:
+		return "ipv6";
+	case NM_MODEM_IP_TYPE_IPV4V6:
+		return "ipv4v6";
+	default:
+		g_return_val_if_reached ("unknown");
+	}
+}
+
+static GArray *
+build_single_ip_type_array (NMModemIPType type)
+{
+	return g_array_append_val (g_array_sized_new (FALSE, FALSE, sizeof (NMModemIPType), 1), type);
+}
+
 /**
  * nm_modem_get_connection_ip_type:
  * @self: the #NMModem
  * @connection: the #NMConnection to determine IP type to use
  *
- * Given a modem and a connection, determine which NMModemIpType to use
+ * Given a modem and a connection, determine which #NMModemIPTypes to use
  * when connecting.
  *
- * Returns: a single %NMModemIpType value
+ * Returns: an array of #NMModemIpType values, in the order in which they
+ * should be tried.
  */
-NMModemIPType
+GArray *
 nm_modem_get_connection_ip_type (NMModem *self,
                                  NMConnection *connection,
                                  GError **error)
@@ -265,9 +287,9 @@ nm_modem_get_connection_ip_type (NMModem *self,
 			                     NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
 			                     "Connection requested IPv4 but IPv4 is "
 			                     "unsuported by the modem.");
-			return NM_MODEM_IP_TYPE_UNKNOWN;
+			return NULL;
 		}
-		return NM_MODEM_IP_TYPE_IPV4;
+		return build_single_ip_type_array (NM_MODEM_IP_TYPE_IPV4);
 	}
 
 	if (ip6 && !ip4) {
@@ -277,38 +299,54 @@ nm_modem_get_connection_ip_type (NMModem *self,
 			                     NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
 			                     "Connection requested IPv6 but IPv6 is "
 			                     "unsuported by the modem.");
-			return NM_MODEM_IP_TYPE_UNKNOWN;
+			return NULL;
 		}
-		return NM_MODEM_IP_TYPE_IPV6;
+		return build_single_ip_type_array (NM_MODEM_IP_TYPE_IPV6);
 	}
 
 	if (ip4 && ip6) {
-		/* Modem supports dual-stack */
-		if (priv->ip_types & NM_MODEM_IP_TYPE_IPV4V6)
-			return NM_MODEM_IP_TYPE_IPV4V6;
+		NMModemIPType type;
+		GArray *out;
 
-		/* Both IPv4 and IPv6 requested, but modem doesn't support dual-stack;
-		 * if one method is marked "may-fail" then use the other.
-		 */
-		if (ip6_may_fail)
-			return NM_MODEM_IP_TYPE_IPV4;
-		else if (ip4_may_fail)
-			return NM_MODEM_IP_TYPE_IPV6;
+		out = g_array_sized_new (FALSE, FALSE, sizeof (NMModemIPType), 3);
 
+		/* Modem supports dual-stack? */
+		if (priv->ip_types & NM_MODEM_IP_TYPE_IPV4V6) {
+			type = NM_MODEM_IP_TYPE_IPV4V6;
+			g_array_append_val (out, type);
+		}
+
+		/* If IPv6 may-fail=false, we should NOT try IPv4 as fallback */
+		if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV4) && ip6_may_fail) {
+			type = NM_MODEM_IP_TYPE_IPV4;
+			g_array_append_val (out, type);
+		}
+
+		/* If IPv4 may-fail=false, we should NOT try IPv6 as fallback */
+		if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV6) && ip4_may_fail) {
+			type = NM_MODEM_IP_TYPE_IPV6;
+			g_array_append_val (out, type);
+		}
+
+		if (out->len > 0)
+			return out;
+
+		/* Error... */
+		g_array_unref (out);
 		g_set_error_literal (error,
 		                     NM_DEVICE_ERROR,
 		                     NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
 		                     "Connection requested both IPv4 and IPv6 "
 		                     "but dual-stack addressing is unsupported "
 		                     "by the modem.");
-		return NM_MODEM_IP_TYPE_UNKNOWN;
+		return NULL;
 	}
 
 	g_set_error_literal (error,
 	                     NM_DEVICE_ERROR,
 	                     NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
 	                     "Connection specified no IP configuration!");
-	return NM_MODEM_IP_TYPE_UNKNOWN;
+	return NULL;
 }
 
 /*****************************************************************************/
@@ -343,9 +381,9 @@ set_data_port (NMModem *self, const char *new_data_port)
 
 static void
 ppp_ip4_config (NMPPPManager *ppp_manager,
-				const char *iface,
-				NMIP4Config *config,
-				gpointer user_data)
+                const char *iface,
+                NMIP4Config *config,
+                gpointer user_data)
 {
 	NMModem *self = NM_MODEM (user_data);
 	guint32 i, num;
@@ -416,9 +454,9 @@ ppp_ip6_config (NMPPPManager *ppp_manager,
 
 static void
 ppp_stats (NMPPPManager *ppp_manager,
-		   guint32 in_bytes,
-		   guint32 out_bytes,
-		   gpointer user_data)
+           guint32 in_bytes,
+           guint32 out_bytes,
+           gpointer user_data)
 {
 	NMModem *self = NM_MODEM (user_data);
 	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
@@ -464,7 +502,8 @@ ppp_stage3_ip_config_start (NMModem *self,
 	/* Check if ModemManager requested a specific IP timeout to be used. If 0 reported,
 	 * use the default one (30s) */
 	if (priv->mm_ip_timeout > 0) {
-		nm_log_info (LOGD_PPP, "using modem-specified IP timeout: %u seconds",
+		nm_log_info (LOGD_PPP, "(%s): using modem-specified IP timeout: %u seconds",
+		             nm_modem_get_uid (self),
 		             priv->mm_ip_timeout);
 		ip_timeout = priv->mm_ip_timeout;
 	}
@@ -486,7 +525,8 @@ ppp_stage3_ip_config_start (NMModem *self,
 
 		ret = NM_ACT_STAGE_RETURN_POSTPONE;
 	} else {
-		nm_log_err (LOGD_PPP, "error starting PPP: (%d) %s",
+		nm_log_err (LOGD_PPP, "(%s): error starting PPP: (%d) %s",
+		            nm_modem_get_uid (self),
 		            error ? error->code : -1,
 		            error && error->message ? error->message : "(unknown)");
 		g_error_free (error);
@@ -705,7 +745,7 @@ modem_secrets_cb (NMActRequest *req,
 	priv->secrets_id = 0;
 
 	if (error)
-		nm_log_warn (LOGD_MB, "%s", error->message);
+		nm_log_warn (LOGD_MB, "(%s): %s", nm_modem_get_uid (self), error->message);
 
 	g_signal_emit (self, signals[AUTH_RESULT], 0, error);
 }
@@ -839,13 +879,12 @@ nm_modem_complete_connection (NMModem *self,
 /*****************************************************************************/
 
 static void
-deactivate (NMModem *self, NMDevice *device)
+deactivate_cleanup (NMModem *self, NMDevice *device)
 {
 	NMModemPrivate *priv;
 	int ifindex;
 
 	g_return_if_fail (NM_IS_MODEM (self));
-	g_return_if_fail (NM_IS_DEVICE (device));
 
 	priv = NM_MODEM_GET_PRIVATE (self);
 
@@ -864,15 +903,19 @@ deactivate (NMModem *self, NMDevice *device)
 		priv->ppp_manager = NULL;
 	}
 
-	if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC ||
-	    priv->ip4_method == NM_MODEM_IP_METHOD_AUTO ||
-	    priv->ip6_method == NM_MODEM_IP_METHOD_STATIC ||
-	    priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) {
-		ifindex = nm_device_get_ip_ifindex (device);
-		if (ifindex > 0) {
-			nm_platform_route_flush (ifindex);
-			nm_platform_address_flush (ifindex);
-			nm_platform_link_set_down (ifindex);
+	if (device) {
+		g_return_if_fail (NM_IS_DEVICE (device));
+
+		if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC ||
+		    priv->ip4_method == NM_MODEM_IP_METHOD_AUTO ||
+		    priv->ip6_method == NM_MODEM_IP_METHOD_STATIC ||
+		    priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) {
+			ifindex = nm_device_get_ip_ifindex (device);
+			if (ifindex > 0) {
+				nm_platform_route_flush (ifindex);
+				nm_platform_address_flush (ifindex);
+				nm_platform_link_set_down (ifindex);
+			}
 		}
 	}
 	priv->ip4_method = NM_MODEM_IP_METHOD_UNKNOWN;
@@ -884,10 +927,176 @@ deactivate (NMModem *self, NMDevice *device)
 
 /*****************************************************************************/
 
+typedef enum {
+	DEACTIVATE_CONTEXT_STEP_FIRST,
+	DEACTIVATE_CONTEXT_STEP_CLEANUP,
+	DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP,
+	DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT,
+	DEACTIVATE_CONTEXT_STEP_LAST
+} DeactivateContextStep;
+
+typedef struct {
+	NMModem *self;
+	NMDevice *device;
+	GCancellable *cancellable;
+	GSimpleAsyncResult *result;
+	DeactivateContextStep step;
+	NMPPPManager *ppp_manager;
+} DeactivateContext;
+
+static void
+deactivate_context_complete (DeactivateContext *ctx)
+{
+	if (ctx->ppp_manager)
+		g_object_unref (ctx->ppp_manager);
+	if (ctx->cancellable)
+		g_object_unref (ctx->cancellable);
+	g_simple_async_result_complete_in_idle (ctx->result);
+	g_object_unref (ctx->result);
+	g_object_unref (ctx->device);
+	g_object_unref (ctx->self);
+	g_slice_free (DeactivateContext, ctx);
+}
+
+gboolean
+nm_modem_deactivate_async_finish (NMModem *self,
+                                  GAsyncResult *res,
+                                  GError **error)
+{
+	return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void deactivate_step (DeactivateContext *ctx);
+
+static void
+disconnect_ready (NMModem *self,
+                  GAsyncResult *res,
+                  DeactivateContext *ctx)
+{
+	GError *error = NULL;
+
+	if (!NM_MODEM_GET_CLASS (self)->disconnect_finish (self, res, &error)) {
+		g_simple_async_result_take_error (ctx->result, error);
+		deactivate_context_complete (ctx);
+		return;
+	}
+
+	/* Go on */
+	ctx->step++;
+	deactivate_step (ctx);
+}
+
+static void
+ppp_manager_stop_ready (NMPPPManager *ppp_manager,
+                        GAsyncResult *res,
+                        DeactivateContext *ctx)
+{
+	GError *error = NULL;
+
+	if (!nm_ppp_manager_stop_finish (ppp_manager, res, &error)) {
+		nm_log_warn (LOGD_MB, "(%s): cannot stop PPP manager: %s",
+		             nm_modem_get_uid (ctx->self),
+		             error->message);
+		g_simple_async_result_take_error (ctx->result, error);
+		deactivate_context_complete (ctx);
+		return;
+	}
+
+	/* Go on */
+	ctx->step++;
+	deactivate_step (ctx);
+}
+
+static void
+deactivate_step (DeactivateContext *ctx)
+{
+	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (ctx->self);
+	GError *error = NULL;
+
+	/* Check cancellable in each step */
+	if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) {
+		g_simple_async_result_take_error (ctx->result, error);
+		deactivate_context_complete (ctx);
+		return;
+	}
+
+	switch (ctx->step) {
+	case DEACTIVATE_CONTEXT_STEP_FIRST:
+		ctx->step++;
+		/* Fall down */
+
+	case DEACTIVATE_CONTEXT_STEP_CLEANUP:
+		/* Make sure we keep a ref to the PPP manager if there is one */
+		if (priv->ppp_manager)
+			ctx->ppp_manager = g_object_ref (priv->ppp_manager);
+		/* Run cleanup */
+		NM_MODEM_GET_CLASS (ctx->self)->deactivate_cleanup (ctx->self, ctx->device);
+		ctx->step++;
+		/* Fall down */
+
+	case DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP:
+		/* If we have a PPP manager, stop it */
+		if (ctx->ppp_manager) {
+			nm_ppp_manager_stop (ctx->ppp_manager,
+			                     ctx->cancellable,
+			                     (GAsyncReadyCallback) ppp_manager_stop_ready,
+			                     ctx);
+			return;
+		}
+		ctx->step++;
+		/* Fall down */
+
+	case DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT:
+		/* Disconnect asynchronously */
+		NM_MODEM_GET_CLASS (ctx->self)->disconnect (ctx->self,
+		                                            FALSE,
+		                                            ctx->cancellable,
+		                                            (GAsyncReadyCallback) disconnect_ready,
+		                                            ctx);
+		return;
+
+	case DEACTIVATE_CONTEXT_STEP_LAST:
+		nm_log_dbg (LOGD_MB, "(%s): modem deactivation finished",
+		            nm_modem_get_uid (ctx->self));
+		deactivate_context_complete (ctx);
+		return;
+	}
+
+	g_assert_not_reached ();
+}
+
+void
+nm_modem_deactivate_async (NMModem *self,
+                           NMDevice *device,
+                           GCancellable *cancellable,
+                           GAsyncReadyCallback callback,
+                           gpointer user_data)
+{
+	DeactivateContext *ctx;
+
+	ctx = g_slice_new0 (DeactivateContext);
+	ctx->self = g_object_ref (self);
+	ctx->device = g_object_ref (device);
+	ctx->result = g_simple_async_result_new (G_OBJECT (self),
+	                                         callback,
+	                                         user_data,
+	                                         nm_modem_deactivate_async);
+	ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+
+	/* Start */
+	ctx->step = DEACTIVATE_CONTEXT_STEP_FIRST;
+	deactivate_step (ctx);
+}
+
+/*****************************************************************************/
+
 void
 nm_modem_deactivate (NMModem *self, NMDevice *device)
 {
-	NM_MODEM_GET_CLASS (self)->deactivate (self, device);
+	/* First cleanup */
+	NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, device);
+	/* Then disconnect without waiting */
+	NM_MODEM_GET_CLASS (self)->disconnect (self, FALSE, NULL, NULL, NULL);
 }
 
 /*****************************************************************************/
@@ -912,7 +1121,6 @@ nm_modem_device_state_changed (NMModem *self,
 	switch (new_state) {
 	case NM_DEVICE_STATE_UNMANAGED:
 	case NM_DEVICE_STATE_UNAVAILABLE:
-	case NM_DEVICE_STATE_DISCONNECTED:
 	case NM_DEVICE_STATE_FAILED:
 		if (priv->act_request) {
 			cancel_get_secrets (self);
@@ -924,7 +1132,9 @@ nm_modem_device_state_changed (NMModem *self,
 			/* Don't bother warning on FAILED since the modem is already gone */
 			if (new_state == NM_DEVICE_STATE_FAILED)
 				warn = FALSE;
-			NM_MODEM_GET_CLASS (self)->disconnect (self, warn);
+			/* First cleanup */
+			NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, NULL);
+			NM_MODEM_GET_CLASS (self)->disconnect (self, warn, NULL, NULL, NULL);
 		}
 		break;
 	default:
@@ -1030,8 +1240,8 @@ nm_modem_init (NMModem *self)
 
 static GObject*
 constructor (GType type,
-			 guint n_construct_params,
-			 GObjectConstructParam *construct_params)
+             guint n_construct_params,
+             GObjectConstructParam *construct_params)
 {
 	GObject *object;
 	NMModemPrivate *priv;
@@ -1056,7 +1266,7 @@ constructor (GType type,
 
 	return object;
 
- err:
+err:
 	g_object_unref (object);
 	return NULL;
 }
@@ -1209,7 +1419,7 @@ nm_modem_class_init (NMModemClass *klass)
 
 	klass->act_stage1_prepare = act_stage1_prepare;
 	klass->stage3_ip6_config_request = stage3_ip6_config_request;
-	klass->deactivate = deactivate;
+	klass->deactivate_cleanup = deactivate_cleanup;
 
 	/* Properties */
 
diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h
index 2a4d9173..2cace890 100644
--- a/src/devices/wwan/nm-modem.h
+++ b/src/devices/wwan/nm-modem.h
@@ -143,9 +143,16 @@ typedef struct {
 
 	void (*set_mm_enabled)                     (NMModem *self, gboolean enabled);
 
-	void (*disconnect)                         (NMModem *self, gboolean warn);
+	void     (*disconnect)                     (NMModem *self,
+	                                            gboolean warn,
+	                                            GCancellable *cancellable,
+	                                            GAsyncReadyCallback callback,
+	                                            gpointer user_data);
+	gboolean (*disconnect_finish)              (NMModem *self,
+	                                            GAsyncResult *res,
+	                                            GError **error);
 
-	void (*deactivate)                         (NMModem *self, NMDevice *device);
+	void     (*deactivate_cleanup)             (NMModem *self, NMDevice *device);
 
 	gboolean (*owns_port)                      (NMModem *self, const char *iface);
 
@@ -218,6 +225,15 @@ gboolean nm_modem_get_secrets (NMModem *modem,
 
 void nm_modem_deactivate (NMModem *modem, NMDevice *device);
 
+void     nm_modem_deactivate_async        (NMModem *self,
+                                           NMDevice *device,
+                                           GCancellable *cancellable,
+                                           GAsyncReadyCallback callback,
+                                           gpointer user_data);
+gboolean nm_modem_deactivate_async_finish (NMModem *self,
+                                           GAsyncResult *res,
+                                           GError **error);
+
 void nm_modem_device_state_changed (NMModem *modem,
                                     NMDeviceState new_state,
                                     NMDeviceState old_state,
@@ -237,7 +253,7 @@ NMModemIPType nm_modem_get_supported_ip_types (NMModem *self);
 /* For the modem-manager only */
 void          nm_modem_emit_removed (NMModem *self);
 
-NMModemIPType nm_modem_get_connection_ip_type (NMModem *self,
+GArray       *nm_modem_get_connection_ip_type (NMModem *self,
                                                NMConnection *connection,
                                                GError **error);
 
@@ -246,6 +262,8 @@ void nm_modem_emit_ip6_config_result (NMModem *self,
                                       NMIP6Config *config,
                                       GError *error);
 
+const gchar *nm_modem_ip_type_to_string (NMModemIPType ip_type);
+
 G_END_DECLS
 
 #endif /* __NETWORKMANAGER_MODEM_H__ */
diff --git a/src/devices/wwan/wwan-exports.ver b/src/devices/wwan/wwan-exports.ver
index c23ab24b..23412de6 100644
--- a/src/devices/wwan/wwan-exports.ver
+++ b/src/devices/wwan/wwan-exports.ver
@@ -5,6 +5,8 @@ global:
 	nm_modem_check_connection_compatible;
 	nm_modem_complete_connection;
 	nm_modem_deactivate;
+	nm_modem_deactivate_async;
+	nm_modem_deactivate_async_finish;
 	nm_modem_device_state_changed;
 	nm_modem_get_capabilities;
 	nm_modem_get_control_port;
diff --git a/src/dhcp-manager/Makefile.in b/src/dhcp-manager/Makefile.in
index 4dea1085..a609e8c6 100644
--- a/src/dhcp-manager/Makefile.in
+++ b/src/dhcp-manager/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -16,7 +16,17 @@
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ build_triplet = @build@
 host_triplet = @host@
 libexec_PROGRAMS = nm-dhcp-helper$(EXEEXT)
 subdir = src/dhcp-manager
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -202,6 +211,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -228,7 +239,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -263,6 +273,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -493,7 +504,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/dhcp-manager/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/dhcp-manager/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -578,14 +588,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -843,6 +853,8 @@ uninstall-am: uninstall-dbusserviceDATA uninstall-libexecPROGRAMS
 	tags tags-am uninstall uninstall-am uninstall-dbusserviceDATA \
 	uninstall-libexecPROGRAMS
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index 47fa5317..a39ffcca 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -767,7 +767,13 @@ nm_dhcp_client_handle_event (gpointer unused,
 				                                                               str_options,
 				                                                               priv->priority);
 			}
-			g_warn_if_fail (ip_config != NULL);
+
+			/* Fail if no valid IP config was received */
+			if (ip_config == NULL) {
+				nm_log_warn (LOGD_DHCP, "(%s): DHCP client bound but IP config not received", iface);
+				new_state = NM_DHCP_STATE_FAIL;
+				g_clear_pointer (&str_options, g_hash_table_unref);
+			}
 		}
 	}
 
@@ -878,6 +884,8 @@ dispose (GObject *object)
 	timeout_cleanup (self);
 
 	g_clear_pointer (&priv->iface, g_free);
+	g_clear_pointer (&priv->hostname, g_free);
+	g_clear_pointer (&priv->uuid, g_free);
 
 	if (priv->hwaddr) {
 		g_byte_array_free (priv->hwaddr, TRUE);
diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
index 46e8e0b8..d1fe0c30 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
@@ -39,8 +39,8 @@
 #define HOSTNAME4_TAG    "send host-name"
 #define HOSTNAME4_FORMAT HOSTNAME4_TAG " \"%s\"; # added by NetworkManager"
 
-#define HOSTNAME6_TAG    "send fqdn.fqdn"
-#define HOSTNAME6_FORMAT HOSTNAME6_TAG " \"%s\"; # added by NetworkManager"
+#define FQDN_TAG    "send fqdn.fqdn"
+#define FQDN_FORMAT FQDN_TAG " \"%s\"; # added by NetworkManager"
 
 #define ALSOREQ_TAG "also request "
 
@@ -57,7 +57,7 @@ add_also_request (GPtrArray *array, const char *item)
 }
 
 static void
-add_hostname (GString *str, const char *format, const char *hostname)
+add_hostname4 (GString *str, const char *format, const char *hostname)
 {
 	char *plain_hostname, *dot;
 
@@ -109,7 +109,7 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname)
 		g_string_append (str, "; # added by NetworkManager\n");
 	}
 
-	add_hostname (str, HOSTNAME4_FORMAT "\n", hostname);
+	add_hostname4 (str, HOSTNAME4_FORMAT "\n", hostname);
 
 	g_string_append_c (str, '\n');
 
@@ -125,13 +125,18 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname)
 }
 
 static void
-add_ip6_config (GString *str, const char *hostname)
+add_hostname6 (GString *str, const char *hostname)
 {
-	add_hostname (str, HOSTNAME6_FORMAT "\n", hostname);
-	g_string_append (str,
-	                 "send fqdn.encoded on;\n"
-	                 "send fqdn.no-client-update on;\n"
-	                 "send fqdn.server-update on;\n");
+	/* dhclient only supports the fqdn.fqdn for DHCPv6 and requires a fully-
+	 * qualified name for this option, so we must require one here too.
+	 */
+	if (hostname && strchr (hostname, '.')) {
+		g_string_append_printf (str, FQDN_FORMAT "\n", hostname);
+		g_string_append (str,
+		                 "send fqdn.encoded on;\n"
+		                 "send fqdn.server-update on;\n");
+		g_string_append_c (str, '\n');
+	}
 }
 
 static GBytes *
@@ -232,7 +237,7 @@ nm_dhcp_dhclient_create_config (const char *interface,
 			if (hostname) {
 				if (strncmp (p, HOSTNAME4_TAG, strlen (HOSTNAME4_TAG)) == 0)
 					continue;
-				if (strncmp (p, HOSTNAME6_TAG, strlen (HOSTNAME6_TAG)) == 0)
+				if (strncmp (p, FQDN_TAG, strlen (FQDN_TAG)) == 0)
 					continue;
 			}
 
@@ -290,7 +295,7 @@ nm_dhcp_dhclient_create_config (const char *interface,
 		g_string_append_c (new_contents, '\n');
 
 	if (is_ip6) {
-		add_ip6_config (new_contents, hostname);
+		add_hostname6 (new_contents, hostname);
 		add_also_request (alsoreq, "dhcp6.name-servers");
 		add_also_request (alsoreq, "dhcp6.domain-search");
 		add_also_request (alsoreq, "dhcp6.client-id");
diff --git a/src/dhcp-manager/nm-dhcp-utils.c b/src/dhcp-manager/nm-dhcp-utils.c
index 5aa25ff0..8cd4359a 100644
--- a/src/dhcp-manager/nm-dhcp-utils.c
+++ b/src/dhcp-manager/nm-dhcp-utils.c
@@ -140,6 +140,7 @@ process_dhclient_rfc3442_route (const char **octets,
 			g_free (str_addr);
 			goto error;
 		}
+		g_free (str_addr);
 		tmp_addr &= nm_utils_ip4_prefix_to_netmask ((guint32) tmp);
 		route->network = tmp_addr;
 	}
diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h
index ce1716b1..c316fb46 100644
--- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h
+++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h
@@ -57,7 +57,7 @@ G_STMT_START { \
 	if (nm_logging_enabled (_l, LOGD_DHCP)) { \
 		const char *_location = strrchr (file "", '/'); \
 		\
-		_nm_log (_location ? _location + 1 : file, line, func, _l, LOGD_DHCP, format, ## __VA_ARGS__); \
+		_nm_log_impl (_location ? _location + 1 : file, line, func, _l, LOGD_DHCP, 0, format, ## __VA_ARGS__); \
 	} \
 } G_STMT_END
 
diff --git a/src/dhcp-manager/tests/Makefile.am b/src/dhcp-manager/tests/Makefile.am
index 9dc5dcb1..8aa79a29 100644
--- a/src/dhcp-manager/tests/Makefile.am
+++ b/src/dhcp-manager/tests/Makefile.am
@@ -37,6 +37,7 @@ test_dhcp_utils_LDADD = \
 
 #################################
 
+@VALGRIND_RULES@
 TESTS = test-dhcp-dhclient test-dhcp-utils
 
 EXTRA_DIST = \
diff --git a/src/dhcp-manager/tests/Makefile.in b/src/dhcp-manager/tests/Makefile.in
index c0324e30..e0a155f1 100644
--- a/src/dhcp-manager/tests/Makefile.in
+++ b/src/dhcp-manager/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 noinst_PROGRAMS = test-dhcp-dhclient$(EXEEXT) test-dhcp-utils$(EXEEXT)
 TESTS = test-dhcp-dhclient$(EXEEXT) test-dhcp-utils$(EXEEXT)
 subdir = src/dhcp-manager/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -200,6 +209,8 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -226,7 +237,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -261,6 +271,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -518,7 +529,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/dhcp-manager/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/dhcp-manager/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -570,14 +580,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -917,6 +927,12 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
+
+#################################
+
+@VALGRIND_RULES@
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/dhcp-manager/tests/test-dhcp-dhclient.c b/src/dhcp-manager/tests/test-dhcp-dhclient.c
index 4f7e96af..e1a96cab 100644
--- a/src/dhcp-manager/tests/test-dhcp-dhclient.c
+++ b/src/dhcp-manager/tests/test-dhcp-dhclient.c
@@ -39,6 +39,7 @@
 static void
 test_config (const char *orig,
              const char *expected,
+             gboolean ipv6,
              const char *hostname,
              const char *dhcp_client_id,
              GBytes *expected_new_client_id,
@@ -55,7 +56,7 @@ test_config (const char *orig,
 	}
 
 	new = nm_dhcp_dhclient_create_config (iface,
-	                                      FALSE,
+	                                      ipv6,
 	                                      client_id,
 	                                      anycast_addr,
 	                                      hostname,
@@ -103,7 +104,7 @@ static const char *orig_missing_expected = \
 static void
 test_orig_missing (void)
 {
-	test_config (NULL, orig_missing_expected, NULL, NULL, NULL, "eth0", NULL);
+	test_config (NULL, orig_missing_expected, FALSE, NULL, NULL, NULL, "eth0", NULL);
 }
 
 /*******************************************/
@@ -132,7 +133,7 @@ static void
 test_override_client_id (void)
 {
 	test_config (override_client_id_orig, override_client_id_expected,
-	             NULL,
+	             FALSE, NULL,
 	             "11:22:33:44:55:66",
 	             NULL,
 	             "eth0",
@@ -161,7 +162,7 @@ static void
 test_quote_client_id (void)
 {
 	test_config (NULL, quote_client_id_expected,
-	             NULL,
+	             FALSE, NULL,
 	             "1234",
 	             NULL,
 	             "eth0",
@@ -190,7 +191,7 @@ static void
 test_ascii_client_id (void)
 {
 	test_config (NULL, ascii_client_id_expected,
-	             NULL,
+	             FALSE, NULL,
 	             "qb:cd:ef:12:34:56",
 	             NULL,
 	             "eth0",
@@ -219,7 +220,7 @@ static void
 test_hex_single_client_id (void)
 {
 	test_config (NULL, hex_single_client_id_expected,
-	             NULL,
+	             FALSE, NULL,
 	             "ab:cd:e:12:34:56",
 	             NULL,
 	             "eth0",
@@ -256,7 +257,7 @@ test_existing_hex_client_id (void)
 
 	new_client_id = g_bytes_new (bytes, sizeof (bytes));
 	test_config (existing_hex_client_id_orig, existing_hex_client_id_expected,
-	             NULL,
+	             FALSE, NULL,
 	             NULL,
 	             new_client_id,
 	             "eth0",
@@ -296,7 +297,7 @@ test_existing_ascii_client_id (void)
 	memcpy (buf + 1, EACID, STRLEN (EACID));
 	new_client_id = g_bytes_new (buf, sizeof (buf));
 	test_config (existing_ascii_client_id_orig, existing_ascii_client_id_expected,
-	             NULL,
+	             FALSE, NULL,
 	             NULL,
 	             new_client_id,
 	             "eth0",
@@ -329,7 +330,58 @@ static void
 test_override_hostname (void)
 {
 	test_config (override_hostname_orig, override_hostname_expected,
-	             "blahblah",
+	             FALSE, "blahblah",
+	             NULL,
+	             NULL,
+	             "eth0",
+	             NULL);
+}
+
+/*******************************************/
+
+static const char *override_hostname6_orig = \
+	"send fqdn.fqdn \"foobar\";\n";
+
+static const char *override_hostname6_expected = \
+	"# Created by NetworkManager\n"
+	"# Merged from /path/to/dhclient.conf\n"
+	"\n"
+	"send fqdn.fqdn \"blahblah.local\"; # added by NetworkManager\n"
+	"send fqdn.encoded on;\n"
+	"send fqdn.server-update on;\n"
+	"\n"
+	"also request dhcp6.name-servers;\n"
+	"also request dhcp6.domain-search;\n"
+	"also request dhcp6.client-id;\n"
+	"\n";
+
+static void
+test_override_hostname6 (void)
+{
+	test_config (override_hostname6_orig, override_hostname6_expected,
+	             TRUE, "blahblah.local",
+	             NULL,
+	             NULL,
+	             "eth0",
+	             NULL);
+}
+
+/*******************************************/
+
+static const char *nonfqdn_hostname6_expected = \
+	"# Created by NetworkManager\n"
+	"\n"
+	"also request dhcp6.name-servers;\n"
+	"also request dhcp6.domain-search;\n"
+	"also request dhcp6.client-id;\n"
+	"\n";
+
+static void
+test_nonfqdn_hostname6 (void)
+{
+	/* Non-FQDN hostname can't be used with dhclient */
+	test_config (NULL, nonfqdn_hostname6_expected,
+	             TRUE, "blahblah",
 	             NULL,
 	             NULL,
 	             "eth0",
@@ -364,7 +416,7 @@ static void
 test_existing_alsoreq (void)
 {
 	test_config (existing_alsoreq_orig, existing_alsoreq_expected,
-	             NULL,
+	             FALSE, NULL,
 	             NULL,
 	             NULL,
 	             "eth0",
@@ -403,7 +455,7 @@ static void
 test_existing_multiline_alsoreq (void)
 {
 	test_config (existing_multiline_alsoreq_orig, existing_multiline_alsoreq_expected,
-	             NULL,
+	             FALSE, NULL,
 	             NULL,
 	             NULL,
 	             "eth0",
@@ -430,6 +482,9 @@ test_one_duid (const char *escaped, const guint8 *unescaped, guint len)
 	g_assert (w);
 	g_assert_cmpint (strlen (escaped), ==, strlen (w));
 	g_assert_cmpstr (escaped, ==, w);
+
+	g_byte_array_free (t, TRUE);
+	g_free (w);
 }
 
 static void
@@ -718,6 +773,8 @@ main (int argc, char **argv)
 	g_test_add_func ("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id);
 	g_test_add_func ("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id);
 	g_test_add_func ("/dhcp/dhclient/override_hostname", test_override_hostname);
+	g_test_add_func ("/dhcp/dhclient/override_hostname6", test_override_hostname6);
+	g_test_add_func ("/dhcp/dhclient/nonfqdn_hostname6", test_nonfqdn_hostname6);
 	g_test_add_func ("/dhcp/dhclient/existing_alsoreq", test_existing_alsoreq);
 	g_test_add_func ("/dhcp/dhclient/existing_multiline_alsoreq", test_existing_multiline_alsoreq);
 	g_test_add_func ("/dhcp/dhclient/duids", test_duids);
diff --git a/src/dhcp-manager/tests/test-dhcp-utils.c b/src/dhcp-manager/tests/test-dhcp-utils.c
index 4ff8caad..53688a5b 100644
--- a/src/dhcp-manager/tests/test-dhcp-utils.c
+++ b/src/dhcp-manager/tests/test-dhcp-utils.c
@@ -694,8 +694,7 @@ NMTST_DEFINE ();
 
 int main (int argc, char **argv)
 {
-	nmtst_init_assert_logging (&argc, &argv);
-	nm_logging_setup ("WARN", "DEFAULT", NULL, NULL);
+	nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT");
 
 	g_test_add_func ("/dhcp/generic-options", test_generic_options);
 	g_test_add_func ("/dhcp/wins-options", test_wins_options);
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index 0d93d8bb..2f8ceab5 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -28,6 +28,8 @@
 #include <resolv.h>
 #include <stdlib.h>
 #include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
 #include <linux/fs.h>
@@ -279,10 +281,10 @@ dispatch_netconfig (char **searches,
                     char **nis_servers,
                     GError **error)
 {
-	char *str, *tmp;
+	char *str;
 	GPid pid;
 	gint fd;
-	int ret;
+	int ret = 1;
 
 	pid = run_netconfig (error, &fd);
 	if (pid < 0)
@@ -321,12 +323,18 @@ dispatch_netconfig (char **searches,
 
  again:
 
-	ret = waitpid (pid, NULL, 0);
-	if (ret < 0 && errno == EINTR)
-		goto again;
-	else if (ret < 0 && errno == ECHILD) {
-		/* When the netconfig exist, the errno is ECHILD, it should return TRUE */
-		return TRUE;
+	if (waitpid (pid, NULL, 0) < 0) {
+		if (errno == EINTR)
+			goto again;
+		else if (errno == ECHILD) {
+			/* child already exited */
+			ret = pid;
+		} else {
+			g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
+			             "Error waiting for netconfig to exit: %s",
+			             strerror (errno));
+			ret = 0;
+		}
 	}
 
 	return ret > 0;
@@ -342,22 +350,12 @@ write_resolv_conf (FILE *f,
 {
 	char *searches_str = NULL;
 	char *nameservers_str = NULL;
-	int i;
 	gboolean retval = FALSE;
+	char *tmp_str;
 	GString *str;
-
-	if (fprintf (f, "%s","# Generated by NetworkManager\n") < 0) {
-		g_set_error (error,
-		             NM_MANAGER_ERROR,
-		             NM_MANAGER_ERROR_FAILED,
-		             "Could not write " _PATH_RESCONF ": %s\n",
-		             g_strerror (errno));
-		return FALSE;
-	}
+	int i;
 
 	if (searches) {
-		char *tmp_str;
-
 		tmp_str = g_strjoinv (" ", searches);
 		searches_str = g_strconcat ("search ", tmp_str, "\n", NULL);
 		g_free (tmp_str);
@@ -385,10 +383,17 @@ write_resolv_conf (FILE *f,
 
 	nameservers_str = g_string_free (str, FALSE);
 
-	if (fprintf (f, "%s%s",
+	if (fprintf (f, "# Generated by NetworkManager\n%s%s",
 	             searches_str ? searches_str : "",
-	             strlen (nameservers_str) ? nameservers_str : "") != -1)
+	             nameservers_str) > 0)
 		retval = TRUE;
+	else {
+		g_set_error (error,
+		             NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_FAILED,
+		             "Could not write " _PATH_RESCONF ": %s\n",
+		             g_strerror (errno));
+	}
 
 	g_free (searches_str);
 	g_free (nameservers_str);
@@ -405,9 +410,15 @@ dispatch_resolvconf (char **searches,
 	char *cmd;
 	FILE *f;
 	gboolean retval = FALSE;
+	int errnosv, err;
 
-	if (! g_file_test (RESOLVCONF_PATH, G_FILE_TEST_IS_EXECUTABLE))
+	if (!g_file_test (RESOLVCONF_PATH, G_FILE_TEST_IS_EXECUTABLE)) {
+		g_set_error_literal (error,
+		                     NM_MANAGER_ERROR,
+		                     NM_MANAGER_ERROR_FAILED,
+		                     RESOLVCONF_PATH " is not executable");
 		return FALSE;
+	}
 
 	if (searches || nameservers) {
 		cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL);
@@ -421,12 +432,21 @@ dispatch_resolvconf (char **searches,
 			             g_strerror (errno));
 		else {
 			retval = write_resolv_conf (f, searches, nameservers, error);
-			retval &= (pclose (f) == 0);
+			err = pclose (f);
+			if (err < 0) {
+				errnosv = errno;
+				g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errnosv),
+				             "Failed to close pipe to resolvconf: %d", errnosv);
+				retval = FALSE;
+			} else if (err > 0) {
+				nm_log_warn (LOGD_DNS, "resolvconf failed with status %d", err);
+				retval = FALSE;
+			}
 		}
 	} else {
 		cmd = g_strconcat (RESOLVCONF_PATH, " -d ", "NetworkManager", NULL);
 		nm_log_info (LOGD_DNS, "Removing DNS information from %s", RESOLVCONF_PATH);
-		if (nm_spawn_process (cmd) == 0)
+		if (nm_spawn_process (cmd, error) == 0)
 			retval = TRUE;
 	}
 
@@ -559,6 +579,42 @@ compute_hash (NMDnsManager *self, guint8 buffer[HASH_LEN])
 	g_checksum_free (sum);
 }
 
+static void
+build_plugin_config_lists (NMDnsManager *self,
+                           GSList **out_vpn_configs,
+                           GSList **out_dev_configs,
+                           GSList **out_other_configs)
+{
+	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+
+	g_return_if_fail (out_vpn_configs && !*out_vpn_configs);
+	g_return_if_fail (out_dev_configs && !*out_dev_configs);
+	g_return_if_fail (out_other_configs && !*out_other_configs);
+
+	/* Build up config lists for plugins; we use the raw configs here, not the
+	 * merged information that we write to resolv.conf so that the plugins can
+	 * still use the domain information in each config to provide split DNS if
+	 * they want to.
+	 */
+	if (priv->ip4_vpn_config)
+		*out_vpn_configs = g_slist_append (*out_vpn_configs, priv->ip4_vpn_config);
+	if (priv->ip6_vpn_config)
+		*out_vpn_configs = g_slist_append (*out_vpn_configs, priv->ip6_vpn_config);
+	if (priv->ip4_device_config)
+		*out_dev_configs = g_slist_append (*out_dev_configs, priv->ip4_device_config);
+	if (priv->ip6_device_config)
+		*out_dev_configs = g_slist_append (*out_dev_configs, priv->ip6_device_config);
+
+	for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
+		if (   (iter->data != priv->ip4_vpn_config)
+		    && (iter->data != priv->ip4_device_config)
+		    && (iter->data != priv->ip6_vpn_config)
+		    && (iter->data != priv->ip6_device_config))
+			*out_other_configs = g_slist_append (*out_other_configs, iter->data);
+	}
+}
+
 static gboolean
 update_dns (NMDnsManager *self,
             gboolean no_caching,
@@ -566,7 +622,7 @@ update_dns (NMDnsManager *self,
 {
 	NMDnsManagerPrivate *priv;
 	NMResolvConfData rc;
-	GSList *iter, *vpn_configs = NULL, *dev_configs = NULL, *other_configs = NULL;
+	GSList *iter;
 	const char *nis_domain = NULL;
 	char **searches = NULL;
 	char **nameservers = NULL;
@@ -574,8 +630,7 @@ update_dns (NMDnsManager *self,
 	int num, i, len;
 	gboolean success = FALSE, caching = FALSE;
 
-	g_return_val_if_fail (error != NULL, FALSE);
-	g_return_val_if_fail (*error == NULL, FALSE);
+	g_return_val_if_fail (!error || !*error, FALSE);
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 
@@ -672,32 +727,11 @@ update_dns (NMDnsManager *self,
 
 	nis_domain = rc.nis_domain;
 
-	/* Build up config lists for plugins; we use the raw configs here, not the
-	 * merged information that we write to resolv.conf so that the plugins can
-	 * still use the domain information in each config to provide split DNS if
-	 * they want to.
-	 */
-	if (priv->ip4_vpn_config)
-		vpn_configs = g_slist_append (vpn_configs, priv->ip4_vpn_config);
-	if (priv->ip6_vpn_config)
-		vpn_configs = g_slist_append (vpn_configs, priv->ip6_vpn_config);
-	if (priv->ip4_device_config)
-		dev_configs = g_slist_append (dev_configs, priv->ip4_device_config);
-	if (priv->ip6_device_config)
-		dev_configs = g_slist_append (dev_configs, priv->ip6_device_config);
-
-	for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
-		if (   (iter->data != priv->ip4_vpn_config)
-		    && (iter->data != priv->ip4_device_config)
-		    && (iter->data != priv->ip6_vpn_config)
-		    && (iter->data != priv->ip6_device_config))
-			other_configs = g_slist_append (other_configs, iter->data);
-	}
-
 	/* Let any plugins do their thing first */
 	if (priv->plugin) {
 		NMDnsPlugin *plugin = priv->plugin;
 		const char *plugin_name = nm_dns_plugin_get_name (plugin);
+		GSList *vpn_configs = NULL, *dev_configs = NULL, *other_configs = NULL;
 
 		if (nm_dns_plugin_is_caching (plugin)) {
 			if (no_caching) {
@@ -708,6 +742,8 @@ update_dns (NMDnsManager *self,
 			caching = TRUE;
 		}
 
+		build_plugin_config_lists (self, &vpn_configs, &dev_configs, &other_configs);
+
 		nm_log_dbg (LOGD_DNS, "DNS: updating plugin %s", plugin_name);
 		if (!nm_dns_plugin_update (plugin,
 		                           vpn_configs,
@@ -721,15 +757,14 @@ update_dns (NMDnsManager *self,
 			 */
 			caching = FALSE;
 		}
+		g_slist_free (vpn_configs);
+		g_slist_free (dev_configs);
+		g_slist_free (other_configs);
 
 	skip:
 		;
 	}
 
-	g_slist_free (vpn_configs);
-	g_slist_free (dev_configs);
-	g_slist_free (other_configs);
-
 	/* If caching was successful, we only send 127.0.0.1 to /etc/resolv.conf
 	 * to ensure that the glibc resolver doesn't try to round-robin nameservers,
 	 * but only uses the local caching nameserver.
@@ -781,9 +816,23 @@ plugin_failed (NMDnsPlugin *plugin, gpointer user_data)
 
 	/* Disable caching until the next DNS update */
 	if (!update_dns (self, TRUE, &error)) {
-		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
+		nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message);
+		g_clear_error (&error);
+	}
+}
+
+static void
+plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data)
+{
+	NMDnsManager *self = NM_DNS_MANAGER (user_data);
+	GError *error = NULL;
+
+	nm_log_warn (LOGD_DNS, "DNS: plugin %s child quit unexpectedly; refreshing DNS",
+	             nm_dns_plugin_get_name (plugin));
+
+	/* Let the plugin try to spawn the child again */
+	if (!update_dns (self, FALSE, &error)) {
+		nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message);
 		g_clear_error (&error);
 	}
 }
@@ -820,9 +869,7 @@ nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
 		priv->configs = g_slist_append (priv->configs, g_object_ref (config));
 
 	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
-		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
+		nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message);
 		g_clear_error (&error);
 	}
 
@@ -854,9 +901,7 @@ nm_dns_manager_remove_ip4_config (NMDnsManager *mgr, NMIP4Config *config)
 	g_object_unref (config);
 
 	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
-		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
+		nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message);
 		g_clear_error (&error);
 	}
 
@@ -897,9 +942,7 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr,
 		priv->configs = g_slist_append (priv->configs, g_object_ref (config));
 
 	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
-		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
+		nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message);
 		g_clear_error (&error);
 	}
 
@@ -931,9 +974,7 @@ nm_dns_manager_remove_ip6_config (NMDnsManager *mgr, NMIP6Config *config)
 	g_object_unref (config);	
 
 	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
-		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
+		nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message);
 		g_clear_error (&error);
 	}
 
@@ -975,9 +1016,7 @@ nm_dns_manager_set_hostname (NMDnsManager *mgr,
 	priv->hostname = g_strdup (filtered);
 
 	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
-		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
+		nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message);
 		g_clear_error (&error);
 	}
 }
@@ -1031,9 +1070,7 @@ nm_dns_manager_end_updates (NMDnsManager *mgr, const char *func)
 	/* Commit all the outstanding changes */
 	nm_log_dbg (LOGD_DNS, "(%s): committing DNS changes (%d)", func, priv->updates_queue);
 	if (!update_dns (mgr, FALSE, &error)) {
-		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
-			         error ? error->code : -1,
-			         error && error->message ? error->message : "(unknown)");
+		nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message);
 		g_clear_error (&error);
 	}
 
@@ -1105,6 +1142,7 @@ nm_dns_manager_init (NMDnsManager *self)
 	if (priv->plugin) {
 		nm_log_info (LOGD_DNS, "DNS: loaded plugin %s", nm_dns_plugin_get_name (priv->plugin));
 		g_signal_connect (priv->plugin, NM_DNS_PLUGIN_FAILED, G_CALLBACK (plugin_failed), self);
+		g_signal_connect (priv->plugin, NM_DNS_PLUGIN_CHILD_QUIT, G_CALLBACK (plugin_child_quit), self);
 	}
 }
 
@@ -1115,7 +1153,11 @@ dispose (GObject *object)
 	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 	GError *error = NULL;
 
-	g_clear_object (&priv->plugin);
+	if (priv->plugin) {
+		g_signal_handlers_disconnect_by_func (priv->plugin, plugin_failed, self);
+		g_signal_handlers_disconnect_by_func (priv->plugin, plugin_child_quit, self);
+		g_clear_object (&priv->plugin);
+	}
 
 	/* If we're quitting, leave a valid resolv.conf in place, not one
 	 * pointing to 127.0.0.1 if any plugins were active.  Thus update
@@ -1123,9 +1165,7 @@ dispose (GObject *object)
 	 * DNS updates yet, there's no reason to touch resolv.conf on shutdown.
 	 */
 	if (priv->dns_touched && !update_dns (self, TRUE, &error)) {
-		nm_log_warn (LOGD_DNS, "could not commit DNS changes on shutdown: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
+		nm_log_warn (LOGD_DNS, "could not commit DNS changes on shutdown: %s", error->message);
 		g_clear_error (&error);
 		priv->dns_touched = FALSE;
 	}
diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c
index b083b105..c684464e 100644
--- a/src/dns-manager/nm-dns-plugin.c
+++ b/src/dns-manager/nm-dns-plugin.c
@@ -198,7 +198,8 @@ nm_dns_plugin_child_spawn (NMDnsPlugin *self,
 	return priv->pid;
 }
 
-gboolean nm_dns_plugin_child_kill (NMDnsPlugin *self)
+gboolean
+nm_dns_plugin_child_kill (NMDnsPlugin *self)
 {
 	NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
 
@@ -208,7 +209,7 @@ gboolean nm_dns_plugin_child_kill (NMDnsPlugin *self)
 	}
 
 	if (priv->pid) {
-		nm_utils_kill_child_async (priv->pid, SIGTERM, LOGD_DNS, priv->progname, 2000, NULL, NULL);
+		nm_utils_kill_child_sync (priv->pid, SIGTERM, LOGD_DNS, priv->progname, NULL, 1000, 0);
 		priv->pid = 0;
 		g_free (priv->progname);
 		priv->progname = NULL;
diff --git a/src/dns-manager/nm-dns-unbound.c b/src/dns-manager/nm-dns-unbound.c
index 533290c1..5723bf82 100644
--- a/src/dns-manager/nm-dns-unbound.c
+++ b/src/dns-manager/nm-dns-unbound.c
@@ -42,7 +42,7 @@ update (NMDnsPlugin *plugin,
 	 * without calling custom scripts. The dnssec-trigger functionality
 	 * may be eventually merged into NetworkManager.
 	 */
-	return nm_spawn_process ("/usr/libexec/dnssec-trigger-script --async --update") == 0;
+	return nm_spawn_process ("/usr/libexec/dnssec-trigger-script --async --update", NULL) == 0;
 }
 
 static gboolean
diff --git a/src/dnsmasq-manager/tests/Makefile.am b/src/dnsmasq-manager/tests/Makefile.am
index c6ce1cda..b51de6aa 100644
--- a/src/dnsmasq-manager/tests/Makefile.am
+++ b/src/dnsmasq-manager/tests/Makefile.am
@@ -19,5 +19,6 @@ test_dnsmasq_utils_SOURCES = \
 test_dnsmasq_utils_LDADD = \
 	$(top_builddir)/src/libNetworkManager.la
 
+@VALGRIND_RULES@
 TESTS = test-dnsmasq-utils
 
diff --git a/src/dnsmasq-manager/tests/Makefile.in b/src/dnsmasq-manager/tests/Makefile.in
index d5f92416..c21629db 100644
--- a/src/dnsmasq-manager/tests/Makefile.in
+++ b/src/dnsmasq-manager/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 noinst_PROGRAMS = test-dnsmasq-utils$(EXEEXT)
 TESTS = test-dnsmasq-utils$(EXEEXT)
 subdir = src/dnsmasq-manager/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -194,6 +203,8 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -220,7 +231,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -255,6 +265,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -490,7 +501,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/dnsmasq-manager/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/dnsmasq-manager/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -535,14 +545,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -854,6 +864,10 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
+
+@VALGRIND_RULES@
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/main-utils.c b/src/main-utils.c
index 0fa3644f..c4d0eeb9 100644
--- a/src/main-utils.c
+++ b/src/main-utils.c
@@ -33,8 +33,10 @@
 #include <glib/gi18n.h>
 #include <gmodule.h>
 
+#include "gsystem-local-alloc.h"
 #include "main-utils.h"
 #include "nm-posix-signals.h"
+#include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
 static sigset_t signal_set;
@@ -152,72 +154,82 @@ nm_main_utils_write_pidfile (const char *pidfile)
 	return success;
 }
 
+void
+nm_main_utils_ensure_rundir ()
+{
+	/* Setup runtime directory */
+	if (g_mkdir_with_parents (NMRUNDIR, 0755) != 0) {
+		fprintf (stderr, _("Cannot create '%s': %s"), NMRUNDIR, strerror (errno));
+		exit (1);
+	}
+}
+
 /**
- * nm_main_utils_check_pidfile:
+ * nm_main_utils_ensure_not_running_pidfile:
  * @pidfile: the pid file
- * @name: the process name
  *
  * Checks whether the pidfile already exists and contains PID of a running
  * process.
  *
- * Returns: %TRUE if the specified pidfile already exists and contains the PID
- *  of a running process named @name, or %FALSE if not
+ * Exits with code 1 if a conflicting process is running.
  */
-gboolean
-nm_main_utils_check_pidfile (const char *pidfile, const char *name)
+void
+nm_main_utils_ensure_not_running_pidfile (const char *pidfile)
 {
-	char *contents = NULL;
+	gs_free char *contents = NULL;
+	gs_free char *proc_cmdline = NULL;
 	gsize len = 0;
 	glong pid;
-	char *proc_cmdline = NULL;
-	gboolean nm_running = FALSE;
 	const char *process_name;
+	const char *prgname = g_get_prgname ();
 
-	/* Setup runtime directory */
-	if (g_mkdir_with_parents (NMRUNDIR, 0755) != 0) {
-		nm_log_err (LOGD_CORE, "Cannot create '%s': %s", NMRUNDIR, strerror (errno));
-		exit (1);
-	}
+	g_return_if_fail (prgname);
 
-	if (!g_file_get_contents (pidfile, &contents, &len, NULL))
-		return FALSE;
+	if (!pidfile || !*pidfile)
+		return;
 
+	if (!g_file_get_contents (pidfile, &contents, &len, NULL))
+		return;
 	if (len <= 0)
-		goto done;
+		return;
 
 	errno = 0;
 	pid = strtol (contents, NULL, 10);
 	if (pid <= 0 || pid > 65536 || errno)
-		goto done;
+		return;
 
-	g_free (contents);
+	g_clear_pointer (&contents, g_free);
 	proc_cmdline = g_strdup_printf ("/proc/%ld/cmdline", pid);
 	if (!g_file_get_contents (proc_cmdline, &contents, &len, NULL))
-		goto done;
+		return;
 
 	process_name = strrchr (contents, '/');
 	if (process_name)
 		process_name++;
 	else
 		process_name = contents;
-	if (strcmp (process_name, name) == 0) {
+	if (strcmp (process_name, prgname) == 0) {
 		/* Check that the process exists */
 		if (kill (pid, 0) == 0) {
-			fprintf (stderr, _("%s is already running (pid %ld)\n"), name, pid);
-			nm_running = TRUE;
+			fprintf (stderr, _("%s is already running (pid %ld)\n"), prgname, pid);
+			exit (1);
 		}
 	}
+}
 
-done:
-	g_free (proc_cmdline);
-	g_free (contents);
-	return nm_running;
+void
+nm_main_utils_ensure_root ()
+{
+	if (getuid () != 0) {
+		fprintf (stderr, _("You must be root to run %s!\n"), str_if_set (g_get_prgname (), ""));
+		exit (1);
+	}
 }
 
 gboolean
 nm_main_utils_early_setup (const char *progname,
-                           char **argv[],
                            int *argc,
+                           char **argv[],
                            GOptionEntry *options,
                            GOptionEntry *more_options,
                            const char *summary)
@@ -226,6 +238,8 @@ nm_main_utils_early_setup (const char *progname,
 	GError *error = NULL;
 	gboolean success = FALSE;
 	int i;
+	const char *opt_fmt_log_level = NULL, *opt_fmt_log_domains = NULL;
+	const char **opt_loc_log_level = NULL, **opt_loc_log_domains = NULL;
 
 	/* Make GIO ignore the remote VFS service; otherwise it tries to use the
 	 * session bus to contact the remote service, and NM shouldn't ever be
@@ -244,16 +258,16 @@ nm_main_utils_early_setup (const char *progname,
 	setlocale (LC_ALL, "");
 	textdomain (GETTEXT_PACKAGE);
 
-	if (getuid () != 0) {
-		fprintf (stderr, _("You must be root to run %s!\n"), progname);
-		exit (1);
-	}
-
 	for (i = 0; options[i].long_name; i++) {
-		if (!strcmp (options[i].long_name, "log-level"))
+		if (!strcmp (options[i].long_name, "log-level")) {
+			opt_fmt_log_level = options[i].description;
+			opt_loc_log_level = &options[i].description;
 			options[i].description = g_strdup_printf (options[i].description, nm_logging_all_levels_to_string ());
-		else if (!strcmp (options[i].long_name, "log-domains"))
+		} else if (!strcmp (options[i].long_name, "log-domains")) {
+			opt_fmt_log_domains = options[i].description;
+			opt_loc_log_domains = &options[i].description;
 			options[i].description = g_strdup_printf (options[i].description, nm_logging_all_domains_to_string ());
+		}
 	}
 
 	/* Parse options */
@@ -274,6 +288,15 @@ nm_main_utils_early_setup (const char *progname,
 	}
 	g_option_context_free (opt_ctx);
 
+	if (opt_loc_log_level) {
+		g_free ((char *) *opt_loc_log_level);
+		*opt_loc_log_level = opt_fmt_log_level;
+	}
+	if (opt_loc_log_domains) {
+		g_free ((char *) *opt_loc_log_domains);
+		*opt_loc_log_domains = opt_fmt_log_domains;
+	}
+
 	return success;
 }
 
diff --git a/src/main-utils.h b/src/main-utils.h
index 472fa5e7..1fceb350 100644
--- a/src/main-utils.h
+++ b/src/main-utils.h
@@ -23,15 +23,19 @@
 
 #include <glib.h>
 
+void     nm_main_utils_ensure_root (void);
+
 gboolean nm_main_utils_setup_signals (GMainLoop *main_loop, gboolean *quit_early_ptr);
 
+void     nm_main_utils_ensure_rundir (void);
+
 gboolean nm_main_utils_write_pidfile (const char *pidfile);
 
-gboolean nm_main_utils_check_pidfile (const char *pidfile, const char *name);
+void     nm_main_utils_ensure_not_running_pidfile (const char *pidfile);
 
 gboolean nm_main_utils_early_setup (const char *progname,
-                                    char **argv[],
                                     int *argc,
+                                    char **argv[],
                                     GOptionEntry *options,
                                     GOptionEntry *more_options,
                                     const char *summary);
diff --git a/src/main.c b/src/main.c
index b3206fb4..53e829cd 100644
--- a/src/main.c
+++ b/src/main.c
@@ -69,6 +69,21 @@
 #define NM_DEFAULT_SYSTEM_STATE_FILE NMSTATEDIR "/NetworkManager.state"
 
 static GMainLoop *main_loop = NULL;
+static gboolean quit_early = FALSE;
+
+static struct {
+	gboolean show_version;
+	gboolean become_daemon;
+	gboolean debug;
+	gboolean g_fatal_warnings;
+	gboolean run_from_build_dir;
+	char *opt_log_level;
+	char *opt_log_domains;
+	char *pidfile;
+	char *state_file;
+} global_opt = {
+	.become_daemon = TRUE,
+};
 
 static gboolean
 parse_state_file (const char *filename,
@@ -149,11 +164,23 @@ parse_state_file (const char *filename,
 }
 
 static void
+_set_g_fatal_warnings ()
+{
+	GLogLevelFlags fatal_mask;
+
+	fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+	fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+	g_log_set_always_fatal (fatal_mask);
+}
+
+static void
 _init_nm_debug (const char *debug)
 {
 	const guint D_RLIMIT_CORE = 1;
+	const guint D_FATAL_WARNINGS = 2;
 	GDebugKey keys[] = {
 		{ "RLIMIT_CORE", D_RLIMIT_CORE },
+		{ "fatal-warnings", D_FATAL_WARNINGS },
 	};
 	guint flags = 0;
 	const char *env = getenv ("NM_DEBUG");
@@ -167,7 +194,7 @@ _init_nm_debug (const char *debug)
 	if (debug && strcasecmp (debug, "help") != 0)
 		flags |= g_parse_debug_string (debug,  keys, G_N_ELEMENTS (keys));
 
-	if (flags & D_RLIMIT_CORE) {
+	if (NM_FLAGS_HAS (flags, D_RLIMIT_CORE)) {
 		/* only enable this, if explicitly requested, because it might
 		 * expose sensitive data. */
 
@@ -177,6 +204,8 @@ _init_nm_debug (const char *debug)
 		};
 		setrlimit (RLIMIT_CORE, &limit);
 	}
+	if (NM_FLAGS_HAS (flags, D_FATAL_WARNINGS))
+		_set_g_fatal_warnings ();
 }
 
 static void
@@ -184,6 +213,37 @@ manager_configure_quit (NMManager *manager, gpointer user_data)
 {
 	nm_log_info (LOGD_CORE, "quitting now that startup is complete");
 	g_main_loop_quit (main_loop);
+	quit_early = TRUE;
+}
+
+static void
+do_early_setup (int *argc, char **argv[])
+{
+	GOptionEntry options[] = {
+		{ "version", 'V', 0, G_OPTION_ARG_NONE, &global_opt.show_version, N_("Print NetworkManager version and exit"), NULL },
+		{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &global_opt.become_daemon, N_("Don't become a daemon"), NULL },
+		{ "debug", 'd', 0, G_OPTION_ARG_NONE, &global_opt.debug, N_("Don't become a daemon, and log to stderr"), NULL },
+		{ "log-level", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_level, N_("Log level: one of [%s]"), "INFO" },
+		{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_domains,
+		  N_("Log domains separated by ',': any combination of [%s]"),
+		  "PLATFORM,RFKILL,WIFI" },
+		{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &global_opt.g_fatal_warnings, N_("Make all warnings fatal"), NULL },
+		{ "pid-file", 'p', 0, G_OPTION_ARG_FILENAME, &global_opt.pidfile, N_("Specify the location of a PID file"), N_("filename") },
+		{ "state-file", 0, 0, G_OPTION_ARG_FILENAME, &global_opt.state_file, N_("State file location"), N_("/path/to/state.file") },
+		{ "run-from-build-dir", 0, 0, G_OPTION_ARG_NONE, &global_opt.run_from_build_dir, "Run from build directory", NULL },
+		{NULL}
+	};
+
+	if (!nm_main_utils_early_setup ("NetworkManager",
+	                                argc,
+	                                argv,
+	                                options,
+	                                nm_config_get_options (),
+	                                _("NetworkManager monitors all network connections and automatically\nchooses the best connection to use.  It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with.")))
+		exit (1);
+
+	global_opt.pidfile = global_opt.pidfile ? global_opt.pidfile : g_strdup (NM_DEFAULT_PID_FILE);
+	global_opt.state_file = global_opt.state_file ? global_opt.state_file : g_strdup (NM_DEFAULT_SYSTEM_STATE_FILE);
 }
 
 /*
@@ -193,19 +253,11 @@ manager_configure_quit (NMManager *manager, gpointer user_data)
 int
 main (int argc, char *argv[])
 {
-	char *opt_log_level = NULL;
-	char *opt_log_domains = NULL;
-	gboolean become_daemon = TRUE, run_from_build_dir = FALSE;
-	gboolean debug = FALSE;
-	gboolean g_fatal_warnings = FALSE;
-	gs_free char *pidfile = NULL;
-	gs_free char *state_file = NULL;
 	gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE;
-	gboolean success, show_version = FALSE;
+	gboolean success = FALSE;
 	NMManager *manager = NULL;
 	gs_unref_object NMVpnManager *vpn_manager = NULL;
 	gs_unref_object NMDnsManager *dns_mgr = NULL;
-	gs_unref_object NMDBusManager *dbus_mgr = NULL;
 	gs_unref_object NMSupplicantManager *sup_mgr = NULL;
 	gs_unref_object NMDhcpManager *dhcp_mgr = NULL;
 	gs_unref_object NMFirewallManager *fw_mgr = NULL;
@@ -215,58 +267,40 @@ main (int argc, char *argv[])
 	GError *error = NULL;
 	gboolean wrote_pidfile = FALSE;
 	char *bad_domains = NULL;
-	gboolean quit_early = FALSE;
 
-	GOptionEntry options[] = {
-		{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Print NetworkManager version and exit"), NULL },
-		{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &become_daemon, N_("Don't become a daemon"), NULL },
-		{ "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, N_("Don't become a daemon, and log to stderr"), NULL },
-		{ "log-level", 0, 0, G_OPTION_ARG_STRING, &opt_log_level, N_("Log level: one of [%s]"), "INFO" },
-		{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &opt_log_domains,
-		  N_("Log domains separated by ',': any combination of [%s]"),
-		  "PLATFORM,RFKILL,WIFI" },
-		{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, N_("Make all warnings fatal"), NULL },
-		{ "pid-file", 'p', 0, G_OPTION_ARG_FILENAME, &pidfile, N_("Specify the location of a PID file"), N_("filename") },
-		{ "state-file", 0, 0, G_OPTION_ARG_FILENAME, &state_file, N_("State file location"), N_("/path/to/state.file") },
-		{ "run-from-build-dir", 0, 0, G_OPTION_ARG_NONE, &run_from_build_dir, "Run from build directory", NULL },
-		{NULL}
-	};
+#if !GLIB_CHECK_VERSION (2, 35, 0)
+	g_type_init ();
+#endif
 
 	_nm_utils_is_manager_process = TRUE;
 
 	main_loop = g_main_loop_new (NULL, FALSE);
 
-	if (!nm_main_utils_early_setup ("NetworkManager",
-	                                &argv,
-	                                &argc,
-	                                options,
-	                                nm_config_get_options (),
-	                                _("NetworkManager monitors all network connections and automatically\nchooses the best connection to use.  It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with.")))
-		exit (1);
+	do_early_setup (&argc, &argv);
+
+	if (global_opt.g_fatal_warnings)
+		_set_g_fatal_warnings ();
 
-	if (show_version) {
+	if (global_opt.show_version) {
 		fprintf (stdout, NM_DIST_VERSION "\n");
 		exit (0);
 	}
 
-	if (!nm_logging_setup (opt_log_level,
-	                       opt_log_domains,
-	                       &bad_domains,
-	                       &error)) {
-		fprintf (stderr,
-		         _("%s.  Please use --help to see a list of valid options.\n"),
-		         error->message);
+	nm_main_utils_ensure_root ();
+
+	nm_main_utils_ensure_not_running_pidfile (global_opt.pidfile);
+
+	/* Ensure state directory exists */
+	if (g_mkdir_with_parents (NMSTATEDIR, 0755) != 0) {
+		fprintf (stderr, "Cannot create '%s': %s", NMSTATEDIR, strerror (errno));
 		exit (1);
-	} else if (bad_domains) {
-		fprintf (stderr,
-		         _("Ignoring unrecognized log domain(s) '%s' passed on command line.\n"),
-		         bad_domains);
-		g_clear_pointer (&bad_domains, g_free);
 	}
 
+	nm_main_utils_ensure_rundir ();
+
 	/* When running from the build directory, determine our build directory
 	 * base and set helper paths in the build tree */
-	if (run_from_build_dir) {
+	if (global_opt.run_from_build_dir) {
 		char *path, *slash;
 		int g;
 
@@ -288,19 +322,21 @@ main (int argc, char *argv[])
 		g_free (path);
 	}
 
-	/* Ensure state directory exists */
-	if (g_mkdir_with_parents (NMSTATEDIR, 0755) != 0) {
-		nm_log_err (LOGD_CORE, "Cannot create '%s': %s", NMSTATEDIR, strerror (errno));
+	if (!nm_logging_setup (global_opt.opt_log_level,
+	                       global_opt.opt_log_domains,
+	                       &bad_domains,
+	                       &error)) {
+		fprintf (stderr,
+		         _("%s.  Please use --help to see a list of valid options.\n"),
+		         error->message);
 		exit (1);
+	} else if (bad_domains) {
+		fprintf (stderr,
+		         _("Ignoring unrecognized log domain(s) '%s' passed on command line.\n"),
+		         bad_domains);
+		g_clear_pointer (&bad_domains, g_free);
 	}
 
-	pidfile = pidfile ? pidfile : g_strdup (NM_DEFAULT_PID_FILE);
-	state_file = state_file ? state_file : g_strdup (NM_DEFAULT_SYSTEM_STATE_FILE);
-
-	/* check pid file */
-	if (nm_main_utils_check_pidfile (pidfile, "NetworkManager"))
-		exit (1);
-
 	/* Read the config file and CLI overrides */
 	config = nm_config_new (&error);
 	if (config == NULL) {
@@ -310,10 +346,12 @@ main (int argc, char *argv[])
 		exit (1);
 	}
 
+	_init_nm_debug (nm_config_get_debug (config));
+
 	/* Initialize logging from config file *only* if not explicitly
 	 * specified by commandline.
 	 */
-	if (opt_log_level == NULL && opt_log_domains == NULL) {
+	if (global_opt.opt_log_level == NULL && global_opt.opt_log_domains == NULL) {
 		if (!nm_logging_setup (nm_config_get_log_level (config),
 		                       nm_config_get_log_domains (config),
 		                       &bad_domains,
@@ -329,17 +367,7 @@ main (int argc, char *argv[])
 		}
 	}
 
-	/* Parse the state file */
-	if (!parse_state_file (state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &wimax_enabled, &error)) {
-		fprintf (stderr, _("State file %s parsing failed: (%d) %s\n"),
-		         state_file,
-		         error ? error->code : -1,
-		         (error && error->message) ? error->message : _("unknown"));
-		/* Not a hard failure */
-	}
-	g_clear_error (&error);
-
-	if (become_daemon && !debug) {
+	if (global_opt.become_daemon && !global_opt.debug) {
 		if (daemon (0, 0) < 0) {
 			int saved_errno;
 
@@ -349,28 +377,26 @@ main (int argc, char *argv[])
 			         saved_errno);
 			exit (1);
 		}
-		wrote_pidfile = nm_main_utils_write_pidfile (pidfile);
+		wrote_pidfile = nm_main_utils_write_pidfile (global_opt.pidfile);
 	}
 
-	_init_nm_debug (nm_config_get_debug (config));
-
 	/* Set up unix signal handling - before creating threads, but after daemonizing! */
 	if (!nm_main_utils_setup_signals (main_loop, &quit_early))
 		exit (1);
 
-	if (g_fatal_warnings) {
-		GLogLevelFlags fatal_mask;
+	nm_logging_syslog_openlog (global_opt.debug);
 
-		fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
-		fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
-		g_log_set_always_fatal (fatal_mask);
-	}
-
-	nm_logging_syslog_openlog (debug);
+	nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");
 
-#if !GLIB_CHECK_VERSION (2, 35, 0)
-	g_type_init ();
-#endif
+	/* Parse the state file */
+	if (!parse_state_file (global_opt.state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &wimax_enabled, &error)) {
+		nm_log_err (LOGD_CORE, "State file %s parsing failed: (%d) %s",
+		            global_opt.state_file,
+		            error ? error->code : -1,
+		            (error && error->message) ? error->message : _("unknown"));
+		/* Not a hard failure */
+	}
+	g_clear_error (&error);
 
 	dbus_threads_init_default ();
 
@@ -379,9 +405,6 @@ main (int argc, char *argv[])
 	 */
 	dbus_glib_global_set_disable_legacy_property_access ();
 
-	nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");
-	success = FALSE;
-
 	nm_log_info (LOGD_CORE, "Read config: %s", nm_config_get_description (config));
 	nm_log_info (LOGD_CORE, "WEXT support is %s",
 #if HAVE_WEXT
@@ -391,15 +414,26 @@ main (int argc, char *argv[])
 #endif
 	             );
 
+	if (!nm_dbus_manager_get_connection (nm_dbus_manager_get ())) {
+#if HAVE_DBUS_GLIB_100
+		nm_log_warn (LOGD_CORE, "Failed to connect to D-Bus; only private bus is available");
+#else
+		nm_log_err (LOGD_CORE, "Failed to connect to D-Bus, exiting...");
+		goto done;
+#endif
+	} else {
+		/* Start our DBus service */
+		if (!nm_dbus_manager_start_service (nm_dbus_manager_get ())) {
+			nm_log_err (LOGD_CORE, "failed to start the dbus service.");
+			goto done;
+		}
+	}
+
 	/* Set up platform interaction layer */
 	nm_linux_platform_setup ();
 
 	nm_auth_manager_setup (nm_config_get_auth_polkit (config));
 
-	/* Initialize our DBus service & connection */
-	dbus_mgr = nm_dbus_manager_get ();
-	g_assert (dbus_mgr != NULL);
-
 	vpn_manager = nm_vpn_manager_get ();
 	g_assert (vpn_manager != NULL);
 
@@ -420,7 +454,7 @@ main (int argc, char *argv[])
 	}
 
 	manager = nm_manager_new (settings,
-	                          state_file,
+	                          global_opt.state_file,
 	                          net_enabled,
 	                          wifi_enabled,
 	                          wwan_enabled,
@@ -444,21 +478,6 @@ main (int argc, char *argv[])
 	session_monitor = nm_session_monitor_get ();
 	g_assert (session_monitor != NULL);
 
-	if (!nm_dbus_manager_get_connection (dbus_mgr)) {
-#if HAVE_DBUS_GLIB_100
-		nm_log_warn (LOGD_CORE, "Failed to connect to D-Bus; only private bus is available");
-#else
-		nm_log_err (LOGD_CORE, "Failed to connect to D-Bus, exiting...");
-		goto done;
-#endif
-	} else {
-		/* Start our DBus service */
-		if (!nm_dbus_manager_start_service (dbus_mgr)) {
-			nm_log_err (LOGD_CORE, "failed to start the dbus service.");
-			goto done;
-		}
-	}
-
 	g_signal_connect (manager, NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config);
 
 	nm_manager_start (manager);
@@ -489,8 +508,8 @@ done:
 
 	nm_logging_syslog_closelog ();
 
-	if (pidfile && wrote_pidfile)
-		unlink (pidfile);
+	if (global_opt.pidfile && wrote_pidfile)
+		unlink (global_opt.pidfile);
 
 	nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error");
 	exit (success ? 0 : 1);
diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c
index fc8f8cda..8bd167ef 100644
--- a/src/nm-auth-manager.c
+++ b/src/nm-auth-manager.c
@@ -37,11 +37,11 @@
         if (nm_logging_enabled ((level), (domain))) { \
             char __prefix[30] = "auth"; \
             \
-            if ((self) != _instance) \
+            if ((self) != singleton_instance) \
                 g_snprintf (__prefix, sizeof (__prefix), "auth[%p]", (self)); \
-            nm_log ((level), (domain), \
-                    "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
-                    __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+            _nm_log ((level), (domain), 0, \
+                     "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+                     __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
         } \
     } G_STMT_END
 
@@ -76,7 +76,7 @@ typedef struct {
 #endif
 } NMAuthManagerPrivate;
 
-static NMAuthManager *_instance = NULL;
+static NMAuthManager *singleton_instance = NULL;
 
 G_DEFINE_TYPE (NMAuthManager, nm_auth_manager, G_TYPE_OBJECT)
 
@@ -485,9 +485,9 @@ _dbus_new_proxy_cb (GObject *source_object,
 NMAuthManager *
 nm_auth_manager_get ()
 {
-	g_return_val_if_fail (_instance, NULL);
+	g_return_val_if_fail (singleton_instance, NULL);
 
-	return _instance;
+	return singleton_instance;
 }
 
 NMAuthManager *
@@ -495,14 +495,14 @@ nm_auth_manager_setup (gboolean polkit_enabled)
 {
 	NMAuthManager *self;
 
-	g_return_val_if_fail (!_instance, _instance);
+	g_return_val_if_fail (!singleton_instance, singleton_instance);
 
 	self = g_object_new (NM_TYPE_AUTH_MANAGER,
 	                     NM_AUTH_MANAGER_POLKIT_ENABLED, polkit_enabled,
 	                     NULL);
 	_LOGD ("set instance");
 
-	return (_instance = self);
+	return (singleton_instance = self);
 }
 
 /*****************************************************************************/
@@ -616,8 +616,8 @@ finalize (GObject *object)
 
 	G_OBJECT_CLASS (nm_auth_manager_parent_class)->finalize (object);
 
-	if (self == _instance) {
-		_instance = NULL;
+	if (self == singleton_instance) {
+		singleton_instance = NULL;
 		_LOGD ("unset instance");
 	}
 }
diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c
index 209f98e1..13133f27 100644
--- a/src/nm-auth-subject.c
+++ b/src/nm-auth-subject.c
@@ -38,6 +38,7 @@
 #include "nm-enum-types.h"
 #include "nm-glib-compat.h"
 #include "NetworkManagerUtils.h"
+#include "gsystem-local-alloc.h"
 
 G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT)
 
@@ -175,7 +176,7 @@ _new_unix_process (DBusGMethodInvocation *context,
 	NMAuthSubject *self;
 	gboolean success = FALSE;
 	gulong pid = 0, uid = 0;
-	char *dbus_sender = NULL;
+	gs_free char *dbus_sender = NULL;
 
 	g_return_val_if_fail (context || (connection && message), NULL);
 
diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c
index 9ace1629..b2ca800c 100644
--- a/src/nm-auth-utils.c
+++ b/src/nm-auth-utils.c
@@ -158,17 +158,18 @@ nm_auth_chain_steal_data (NMAuthChain *self, const char *tag)
 {
 	ChainData *tmp;
 	gpointer value = NULL;
+	void *orig_key;
 
 	g_return_val_if_fail (self != NULL, NULL);
 	g_return_val_if_fail (tag != NULL, NULL);
 
-	tmp = g_hash_table_lookup (self->data, tag);
-	if (tmp) {
+	if (g_hash_table_lookup_extended (self->data, tag, &orig_key, (gpointer)&tmp)) {
 		g_hash_table_steal (self->data, tag);
 		value = tmp->data;
 		/* Make sure the destroy handler isn't called when freeing */
 		tmp->destroy = NULL;
 		free_data (tmp);
+		g_free (orig_key);
 	}
 	return value;
 }
diff --git a/src/nm-config.c b/src/nm-config.c
index e8cb0864..4626ae26 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -275,14 +275,18 @@ merge_no_auto_default_state (NMConfig *config)
 	if (g_file_get_contents (priv->no_auto_default_file, &data, NULL, NULL)) {
 		list = g_strsplit (data, "\n", -1);
 		for (i = 0; list[i]; i++) {
-			if (!*list[i])
+			if (!*list[i]) {
+				g_free (list[i]);
 				continue;
+			}
 			for (j = 0; j < updated->len; j++) {
 				if (!strcmp (list[i], updated->pdata[j]))
 					break;
 			}
 			if (j == updated->len)
 				g_ptr_array_add (updated, list[i]);
+			else
+				g_free (list[i]);
 		}
 		g_free (list);
 		g_free (data);
@@ -403,10 +407,12 @@ read_config (NMConfig *config, const char *path, GError **error)
 			continue;
 		for (k = 0; keys[k]; k++) {
 			int len = strlen (keys[k]);
+			char *v;
+
 			if (keys[k][len - 1] == '+') {
 				char *base_key = g_strndup (keys[k], len - 1);
-				const char *old_val = g_key_file_get_value (priv->keyfile, groups[g], base_key, NULL);
-				const char *new_val = g_key_file_get_value (kf, groups[g], keys[k], NULL);
+				char *old_val = g_key_file_get_value (priv->keyfile, groups[g], base_key, NULL);
+				char *new_val = g_key_file_get_value (kf, groups[g], keys[k], NULL);
 
 				if (old_val && *old_val) {
 					char *combined = g_strconcat (old_val, ",", new_val, NULL);
@@ -417,13 +423,18 @@ read_config (NMConfig *config, const char *path, GError **error)
 					g_key_file_set_value (priv->keyfile, groups[g], base_key, new_val);
 
 				g_free (base_key);
+				g_free (old_val);
+				g_free (new_val);
 				continue;
 			}
 
 			g_key_file_set_value (priv->keyfile, groups[g], keys[k],
-			                      g_key_file_get_value (kf, groups[g], keys[k], NULL));
+			                      v = g_key_file_get_value (kf, groups[g], keys[k], NULL));
+			g_free (v);
 		}
+		g_strfreev (keys);
 	}
+	g_strfreev (groups);
 	g_key_file_free (kf);
 
 	return TRUE;
diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c
index 8a324a5c..85bd70ae 100644
--- a/src/nm-connectivity.c
+++ b/src/nm-connectivity.c
@@ -44,7 +44,7 @@ typedef struct {
 
 #if WITH_CONCHECK
 	SoupSession *soup_session;
-	gboolean running;
+	guint pending_checks;
 	guint check_id;
 #endif
 
@@ -69,12 +69,33 @@ nm_connectivity_get_state (NMConnectivity *connectivity)
 	return NM_CONNECTIVITY_GET_PRIVATE (connectivity)->state;
 }
 
+static const char *
+state_name (NMConnectivityState state)
+{
+	switch (state) {
+	case NM_CONNECTIVITY_UNKNOWN:
+		return "UNKNOWN";
+	case NM_CONNECTIVITY_NONE:
+		return "NONE";
+	case NM_CONNECTIVITY_LIMITED:
+		return "LIMITED";
+	case NM_CONNECTIVITY_PORTAL:
+		return "PORTAL";
+	case NM_CONNECTIVITY_FULL:
+		return "FULL";
+	default:
+		return "???";
+	}
+}
+
 static void
 update_state (NMConnectivity *self, NMConnectivityState state)
 {
 	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
 
 	if (priv->state != state) {
+		nm_log_dbg (LOGD_CONCHECK, "Connectivity state changed from %s to %s",
+		            state_name (priv->state), state_name (state));
 		priv->state = state;
 		g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_STATE);
 	}
@@ -93,6 +114,7 @@ nm_connectivity_check_cb (SoupSession *session, SoupMessage *msg, gpointer user_
 	self = NM_CONNECTIVITY (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
 	g_object_unref (self);
 	priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+	priv->pending_checks--;
 
 	if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
 		nm_log_info (LOGD_CONCHECK, "Connectivity check for uri '%s' failed with '%s'.",
@@ -124,10 +146,11 @@ nm_connectivity_check_cb (SoupSession *session, SoupMessage *msg, gpointer user_
 	}
 
  done:
+	update_state (self, new_state);
+
 	g_simple_async_result_set_op_res_gssize (simple, new_state);
 	g_simple_async_result_complete (simple);
-
-	update_state (self, new_state);
+	g_object_unref (simple);
 }
 
 static void
@@ -136,11 +159,9 @@ run_check_complete (GObject      *object,
                     gpointer      user_data)
 {
 	NMConnectivity *self = NM_CONNECTIVITY (object);
-	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
 	GError *error = NULL;
 
 	nm_connectivity_check_finish (self, result, &error);
-	priv->running = FALSE;
 	if (error) {
 		nm_log_err (LOGD_CONCHECK, "Connectivity check failed: %s", error->message);
 		g_error_free (error);
@@ -151,14 +172,23 @@ static gboolean
 run_check (gpointer user_data)
 {
 	NMConnectivity *self = NM_CONNECTIVITY (user_data);
-	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
 
 	nm_connectivity_check_async (self, run_check_complete, NULL);
-	priv->running = TRUE;
-	nm_log_dbg (LOGD_CONCHECK, "Connectivity check with uri '%s' started.", priv->uri);
-
 	return TRUE;
 }
+
+static gboolean
+idle_start_periodic_checks (gpointer user_data)
+{
+	NMConnectivity *self = user_data;
+	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+	priv->check_id = g_timeout_add_seconds (priv->interval, run_check, self);
+	if (!priv->pending_checks)
+		run_check (self);
+
+	return FALSE;
+}
 #endif
 
 void
@@ -167,12 +197,14 @@ nm_connectivity_set_online (NMConnectivity *self,
 {
 #if WITH_CONCHECK
 	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+#endif
 
+	nm_log_dbg (LOGD_CONCHECK, "nm_connectivity_set_online(%s)", online ? "TRUE" : "FALSE");
+
+#if WITH_CONCHECK
 	if (online && priv->uri && priv->interval) {
 		if (!priv->check_id)
-			priv->check_id = g_timeout_add_seconds (priv->interval, run_check, self);
-		if (!priv->running)
-			run_check (self);
+			priv->check_id = g_timeout_add (0, idle_start_periodic_checks, self);
 
 		return;
 	} else if (priv->check_id) {
@@ -201,6 +233,13 @@ nm_connectivity_check_async (NMConnectivity      *self,
 	g_return_if_fail (NM_IS_CONNECTIVITY (self));
 	priv = NM_CONNECTIVITY_GET_PRIVATE (self);
 
+#if WITH_CONCHECK
+	if (callback == run_check_complete)
+		nm_log_dbg (LOGD_CONCHECK, "Periodic connectivity check started with uri '%s'.", priv->uri);
+	else
+#endif
+		nm_log_dbg (LOGD_CONCHECK, "Connectivity check started with uri '%s'.", priv->uri);
+
 	simple = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
 	                                    nm_connectivity_check_async);
 
@@ -208,10 +247,13 @@ nm_connectivity_check_async (NMConnectivity      *self,
 	if (priv->uri && priv->interval) {
 		msg = soup_message_new ("GET", priv->uri);
 		soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
+		/* Disable HTTP/1.1 keepalive; the connection should not persist */
+		soup_message_headers_append (msg->request_headers, "Connection", "close");
 		soup_session_queue_message (priv->soup_session,
 		                            msg,
 		                            nm_connectivity_check_cb,
 		                            simple);
+		priv->pending_checks++;
 
 		return;
 	}
@@ -219,6 +261,7 @@ nm_connectivity_check_async (NMConnectivity      *self,
 
 	g_simple_async_result_set_op_res_gssize (simple, priv->state);
 	g_simple_async_result_complete_in_idle (simple);
+	g_object_unref (simple);
 }
 
 NMConnectivityState
@@ -291,6 +334,8 @@ set_property (GObject *object, guint property_id,
 				g_free (priv->uri);
 				priv->uri = NULL;
 			}
+			if (uri)
+				soup_uri_free (uri);
 		}
 #endif
 		break;
diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c
index 1cceb9b5..f57eeb8e 100644
--- a/src/nm-dbus-manager.c
+++ b/src/nm-dbus-manager.c
@@ -78,20 +78,33 @@ static void nm_dbus_manager_cleanup (NMDBusManager *self, gboolean dispose);
 static void start_reconnection_timeout (NMDBusManager *self);
 static void object_destroyed (NMDBusManager *self, gpointer object);
 
+NM_DEFINE_SINGLETON_DESTRUCTOR (NMDBusManager);
+NM_DEFINE_SINGLETON_WEAK_REF (NMDBusManager);
+
 NMDBusManager *
 nm_dbus_manager_get (void)
 {
-	static NMDBusManager *singleton = NULL;
-	static gsize once = 0;
-
-	if (g_once_init_enter (&once)) {
-		singleton = (NMDBusManager *) g_object_new (NM_TYPE_DBUS_MANAGER, NULL);
-		g_assert (singleton);
-		if (!nm_dbus_manager_init_bus (singleton))
-			start_reconnection_timeout (singleton);
-		g_once_init_leave (&once, 1);
+	if (G_UNLIKELY (!singleton_instance)) {
+		nm_dbus_manager_setup (g_object_new (NM_TYPE_DBUS_MANAGER, NULL));
+		if (!nm_dbus_manager_init_bus (singleton_instance))
+			start_reconnection_timeout (singleton_instance);
 	}
-	return singleton;
+	return singleton_instance;
+}
+
+void
+nm_dbus_manager_setup (NMDBusManager *instance)
+{
+	static char already_setup = FALSE;
+
+	g_assert (NM_IS_DBUS_MANAGER (instance));
+	g_assert (!already_setup);
+	g_assert (!singleton_instance);
+
+	already_setup = TRUE;
+	singleton_instance = instance;
+	nm_singleton_instance_weak_ref_register ();
+	nm_log_dbg (LOGD_CORE, "create %s singleton (%p)", "NMDBusManager", singleton_instance);
 }
 
 /**************************************************************/
@@ -199,6 +212,7 @@ private_server_new (const char *path,
 		nm_log_warn (LOGD_CORE, "(%s) failed to set up private socket %s: %s",
 		             tag, address, error.message);
 		dbus_error_free (&error);
+		g_free (address);
 		return NULL;
 	}
 
@@ -876,8 +890,11 @@ nm_dbus_manager_register_object (NMDBusManager *self,
 
 	g_assert (G_IS_OBJECT (object));
 
-	g_warn_if_fail (g_hash_table_lookup (priv->exported, object) == NULL);
+	if (g_hash_table_lookup (priv->exported, G_OBJECT (object)))
+		g_return_if_reached ();
+
 	g_hash_table_insert (priv->exported, G_OBJECT (object), g_strdup (path));
+	g_object_weak_ref (G_OBJECT (object), (GWeakNotify) object_destroyed, self);
 
 	if (priv->g_connection)
 		dbus_g_connection_register_g_object (priv->g_connection, path, G_OBJECT (object));
@@ -890,8 +907,6 @@ nm_dbus_manager_register_object (NMDBusManager *self,
 			                                     G_OBJECT (object));
 		}
 	}
-
-	g_object_weak_ref (G_OBJECT (object), (GWeakNotify) object_destroyed, self);
 }
 
 void
@@ -903,7 +918,10 @@ nm_dbus_manager_unregister_object (NMDBusManager *self, gpointer object)
 
 	g_assert (G_IS_OBJECT (object));
 
-	g_hash_table_remove (NM_DBUS_MANAGER_GET_PRIVATE (self)->exported, G_OBJECT (object));
+	if (!g_hash_table_lookup (priv->exported, G_OBJECT (object)))
+		g_return_if_reached ();
+
+	g_hash_table_remove (priv->exported, G_OBJECT (object));
 	g_object_weak_unref (G_OBJECT (object), (GWeakNotify) object_destroyed, self);
 
 	if (priv->g_connection)
diff --git a/src/nm-dbus-manager.h b/src/nm-dbus-manager.h
index cc7f3210..c87ee024 100644
--- a/src/nm-dbus-manager.h
+++ b/src/nm-dbus-manager.h
@@ -73,6 +73,7 @@ typedef struct {
 GType nm_dbus_manager_get_type (void);
 
 NMDBusManager * nm_dbus_manager_get       (void);
+void            nm_dbus_manager_setup     (NMDBusManager *instance);
 
 char * nm_dbus_manager_get_name_owner     (NMDBusManager *self,
                                            const char *name,
diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c
index 5cc1bcd2..153c1de6 100644
--- a/src/nm-default-route-manager.c
+++ b/src/nm-default-route-manager.c
@@ -44,30 +44,41 @@ typedef struct {
 		gboolean has_v4_changes;
 		gboolean has_v6_changes;
 	} resync;
+
+	/* During disposing, we unref the sources of all entries. This happens usually
+	 * during shutdown, which might call the final deletion of the object. That
+	 * again might cause calls back into NMDefaultRouteManager, which finds dangling
+	 * pointers.
+	 * Guard every publicly accessible function to return early if the instance
+	 * is already disposing. */
+	gboolean disposed;
+
+	NMPlatform *platform;
 } NMDefaultRouteManagerPrivate;
 
 #define NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEFAULT_ROUTE_MANAGER, NMDefaultRouteManagerPrivate))
 
 G_DEFINE_TYPE (NMDefaultRouteManager, nm_default_route_manager, G_TYPE_OBJECT)
 
-static NMDefaultRouteManager *_instance;
+static NMDefaultRouteManager *singleton_instance;
 
 #define _LOG(level, addr_family, ...) \
     G_STMT_START { \
-        int __addr_family = (addr_family); \
-        guint64 __domain = __addr_family == AF_INET ? LOGD_IP4 : LOGD_IP6; \
+        const int __addr_family = (addr_family); \
+        const NMLogLevel __level = (level); \
+        const NMLogDomain __domain = __addr_family == AF_INET ? LOGD_IP4 : (__addr_family == AF_INET6 ? LOGD_IP6 : LOGD_IP); \
         \
-        if (nm_logging_enabled ((level), (__domain))) { \
+        if (nm_logging_enabled (__level, __domain)) { \
             char __ch = __addr_family == AF_INET ? '4' : (__addr_family == AF_INET6 ? '6' : '-'); \
             char __prefix[30] = "default-route"; \
             \
-            if ((self) != _instance) \
+            if ((self) != singleton_instance) \
                 g_snprintf (__prefix, sizeof (__prefix), "default-route%c[%p]", __ch, (self)); \
             else \
                 __prefix[STRLEN ("default-route")] = __ch; \
-            nm_log ((level), (__domain), \
-                    "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
-                    __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+            _nm_log (__level, __domain, 0, \
+                     "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+                     __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
         } \
     } G_STMT_END
 
@@ -131,22 +142,16 @@ typedef struct {
 } Entry;
 
 typedef struct {
-	int addr_family;
+	const NMPlatformVTableRoute *vt;
 	GPtrArray *(*get_entries) (NMDefaultRouteManagerPrivate *priv);
-	const char *(*platform_route_to_string) (const NMPlatformIPRoute *route);
-	GArray *(*platform_route_get_all) (int ifindex, NMPlatformGetRouteMode mode);
-	gboolean (*platform_route_delete_default) (int ifindex, guint32 metric);
-	guint32 (*route_metric_normalize) (guint32 metric);
 } VTableIP;
 
 static const VTableIP vtable_ip4, vtable_ip6;
 
-#define VTABLE_IS_IP4 (vtable->addr_family == AF_INET)
-
 static NMPlatformIPRoute *
 _vt_route_index (const VTableIP *vtable, GArray *routes, guint index)
 {
-	if (VTABLE_IS_IP4)
+	if (vtable->vt->is_ip4)
 		return (NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP4Route, index);
 	else
 		return (NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP6Route, index);
@@ -160,7 +165,7 @@ _vt_routes_has_entry (const VTableIP *vtable, GArray *routes, const Entry *entry
 
 	route.rx.metric = entry->effective_metric;
 
-	if (VTABLE_IS_IP4) {
+	if (vtable->vt->is_ip4) {
 		for (i = 0; i < routes->len; i++) {
 			NMPlatformIP4Route *r = &g_array_index (routes, NMPlatformIP4Route, i);
 
@@ -250,7 +255,7 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g
 	if (!entry)
 		return FALSE;
 
-	if (VTABLE_IS_IP4) {
+	if (vtable->vt->is_ip4) {
 		success = nm_platform_ip4_route_add (entry->route.rx.ifindex,
 		                                     entry->route.rx.source,
 		                                     0,
@@ -269,8 +274,8 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g
 		                                     entry->route.rx.mss);
 	}
 	if (!success) {
-		_LOGW (vtable->addr_family, "failed to add default route %s with effective metric %u",
-		       vtable->platform_route_to_string (&entry->route.rx), (guint) entry->effective_metric);
+		_LOGW (vtable->vt->addr_family, "failed to add default route %s with effective metric %u",
+		       vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric);
 	}
 	return TRUE;
 }
@@ -285,7 +290,7 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self,
 	gboolean changed = FALSE;
 
 	/* prune all other default routes from this device. */
-	routes = vtable->platform_route_get_all (0, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
+	routes = vtable->vt->route_get_all (0, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
 
 	for (i = 0; i < routes->len; i++) {
 		const NMPlatformIPRoute *route;
@@ -317,7 +322,7 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self,
 		 */
 		if (   !entry
 		    && (has_ifindex_synced || ifindex_to_flush == route->ifindex)) {
-			vtable->platform_route_delete_default (route->ifindex, route->metric);
+			vtable->vt->route_delete_default (route->ifindex, route->metric);
 			changed = TRUE;
 		}
 	}
@@ -401,7 +406,7 @@ _get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *s
 		}
 
 		if (!ifindex_has_synced_entry)
-			g_hash_table_add (result, GUINT_TO_POINTER (vtable->route_metric_normalize (route->metric)));
+			g_hash_table_add (result, GUINT_TO_POINTER (vtable->vt->metric_normalize (route->metric)));
 	}
 
 	return result;
@@ -437,7 +442,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
 	priv->resync.guard++;
 
 	if (!external_change) {
-		if (VTABLE_IS_IP4)
+		if (vtable->vt->is_ip4)
 			priv->resync.has_v4_changes = FALSE;
 		else
 			priv->resync.has_v6_changes = FALSE;
@@ -447,7 +452,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
 
 	entries = vtable->get_entries (priv);
 
-	routes = vtable->platform_route_get_all (0, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
+	routes = vtable->vt->route_get_all (0, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
 
 	assumed_metrics = _get_assumed_interface_metrics (vtable, self, routes);
 
@@ -517,24 +522,24 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
 			 * or none. Hence, we only have to remember what is going to change. */
 			g_array_append_val (changed_metrics, expected_metric);
 			if (old_entry) {
-				_LOGD (vtable->addr_family, LOG_ENTRY_FMT": update %s (%u -> %u)", LOG_ENTRY_ARGS (i, entry),
-				       vtable->platform_route_to_string (&entry->route.rx), (guint) old_entry->effective_metric,
+				_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": update %s (%u -> %u)", LOG_ENTRY_ARGS (i, entry),
+				       vtable->vt->route_to_string (&entry->route), (guint) old_entry->effective_metric,
 				       (guint) expected_metric);
 			} else {
-				_LOGD (vtable->addr_family, LOG_ENTRY_FMT": add %s (%u)", LOG_ENTRY_ARGS (i, entry),
-				       vtable->platform_route_to_string (&entry->route.rx), (guint) expected_metric);
+				_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": add %s (%u)", LOG_ENTRY_ARGS (i, entry),
+				       vtable->vt->route_to_string (&entry->route), (guint) expected_metric);
 			}
 		} else if (entry->effective_metric != expected_metric) {
 			g_array_append_val (changed_metrics, entry->effective_metric);
 			g_array_append_val (changed_metrics, expected_metric);
-			_LOGD (vtable->addr_family, LOG_ENTRY_FMT": resync metric %s (%u -> %u)", LOG_ENTRY_ARGS (i, entry),
-			       vtable->platform_route_to_string (&entry->route.rx), (guint) entry->effective_metric,
+			_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": resync metric %s (%u -> %u)", LOG_ENTRY_ARGS (i, entry),
+			       vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric,
 			       (guint) expected_metric);
 		} else {
 			if (!_vt_routes_has_entry (vtable, routes, entry)) {
 				g_array_append_val (changed_metrics, entry->effective_metric);
-				_LOGD (vtable->addr_family, LOG_ENTRY_FMT": readd route %s (%u -> %u)", LOG_ENTRY_ARGS (i, entry),
-				       vtable->platform_route_to_string (&entry->route.rx), (guint) entry->effective_metric,
+				_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": readd route %s (%u -> %u)", LOG_ENTRY_ARGS (i, entry),
+				       vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric,
 				       (guint) entry->effective_metric);
 			}
 		}
@@ -598,10 +603,10 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint
 	if (!entry->synced && !entry->never_default)
 		entry->effective_metric = entry->route.rx.metric;
 
-	_LOGD (vtable->addr_family, LOG_ENTRY_FMT": %s %s",
+	_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": %s %s",
 	       LOG_ENTRY_ARGS (entry_idx, entry),
 	       old_entry ? "update" : "add",
-	       vtable->platform_route_to_string (&entry->route.rx));
+	       vtable->vt->route_to_string (&entry->route));
 
 	g_ptr_array_sort_with_data (entries, _sort_entries_cmp, NULL);
 
@@ -621,8 +626,8 @@ _entry_at_idx_remove (const VTableIP *vtable, NMDefaultRouteManager *self, guint
 
 	entry = g_ptr_array_index (entries, entry_idx);
 
-	_LOGD (vtable->addr_family, LOG_ENTRY_FMT": remove %s (%u)", LOG_ENTRY_ARGS (entry_idx, entry),
-	       vtable->platform_route_to_string (&entry->route.rx), (guint) entry->effective_metric);
+	_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": remove %s (%u)", LOG_ENTRY_ARGS (entry_idx, entry),
+	       vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric);
 
 	/* Remove the entry from the list (but don't free it yet) */
 	g_ptr_array_index (entries, entry_idx) = NULL;
@@ -651,6 +656,11 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
 	gboolean synced = FALSE;
 
 	g_return_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self));
+
+	priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
+	if (priv->disposed)
+		return;
+
 	if (NM_IS_DEVICE (source))
 		device = source;
 	else if (NM_IS_VPN_CONNECTION (source))
@@ -671,15 +681,13 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
 		}
 	}
 
-	priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
 	entries = vtable->get_entries (priv);
 	entry = _entry_find_by_source (entries, source, &entry_idx);
 
 	if (   entry
 	    && entry->route.rx.ifindex != ip_ifindex) {
 		/* Strange... the ifindex changed... Remove the device and start again. */
-		_LOGD (vtable->addr_family, "ifindex of "LOG_ENTRY_FMT" changed: %d -> %d",
+		_LOGD (vtable->vt->addr_family, "ifindex of "LOG_ENTRY_FMT" changed: %d -> %d",
 		       LOG_ENTRY_ARGS (entry_idx, entry),
 		       entry->route.rx.ifindex, ip_ifindex);
 
@@ -696,7 +704,7 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
 		if (device) {
 			gboolean is_assumed;
 
-			if (VTABLE_IS_IP4)
+			if (vtable->vt->is_ip4)
 				default_route = (const NMPlatformIPRoute *) nm_device_get_ip4_default_route (device, &is_assumed);
 			else
 				default_route = (const NMPlatformIPRoute *) nm_device_get_ip6_default_route (device, &is_assumed);
@@ -724,7 +732,7 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
 			    && nm_vpn_connection_get_vpn_state (vpn) == NM_VPN_CONNECTION_STATE_ACTIVATED) {
 
 				memset (&rt, 0, sizeof (rt));
-				if (VTABLE_IS_IP4) {
+				if (vtable->vt->is_ip4) {
 					NMIP4Config *vpn_config;
 
 					vpn_config = nm_vpn_connection_get_ip4_config (vpn);
@@ -766,13 +774,13 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
 		entry = g_slice_new0 (Entry);
 		entry->source.object = g_object_ref (source);
 
-		if (VTABLE_IS_IP4)
+		if (vtable->vt->is_ip4)
 			entry->route.r4 = *((const NMPlatformIP4Route *) default_route);
 		else
 			entry->route.r6 = *((const NMPlatformIP6Route *) default_route);
 
 		/* only use normalized metrics */
-		entry->route.rx.metric = vtable->route_metric_normalize (entry->route.rx.metric);
+		entry->route.rx.metric = vtable->vt->metric_normalize (entry->route.rx.metric);
 		entry->route.rx.ifindex = ip_ifindex;
 		entry->never_default = never_default;
 		entry->effective_metric = entry->route.rx.metric;
@@ -785,12 +793,12 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
 		Entry old_entry, new_entry;
 
 		new_entry = *entry;
-		if (VTABLE_IS_IP4)
+		if (vtable->vt->is_ip4)
 			new_entry.route.r4 = *((const NMPlatformIP4Route *) default_route);
 		else
 			new_entry.route.r6 = *((const NMPlatformIP6Route *) default_route);
 		/* only use normalized metrics */
-		new_entry.route.rx.metric = vtable->route_metric_normalize (new_entry.route.rx.metric);
+		new_entry.route.rx.metric = vtable->vt->metric_normalize (new_entry.route.rx.metric);
 		new_entry.route.rx.ifindex = ip_ifindex;
 		new_entry.never_default = never_default;
 		new_entry.synced = synced;
@@ -830,14 +838,14 @@ _ipx_connection_has_default_route (const VTableIP *vtable, NMDefaultRouteManager
 	g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), FALSE);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
 
-	if (VTABLE_IS_IP4)
+	if (vtable->vt->is_ip4)
 		s_ip = nm_connection_get_setting_ip4_config (connection);
 	else
 		s_ip = nm_connection_get_setting_ip6_config (connection);
 	if (!s_ip || nm_setting_ip_config_get_never_default (s_ip))
 		return FALSE;
 
-	if (VTABLE_IS_IP4) {
+	if (vtable->vt->is_ip4) {
 		method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
 		if (   !method
 		    || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)
@@ -881,10 +889,13 @@ _ipx_get_best_device (const VTableIP *vtable, NMDefaultRouteManager *self, const
 		return NULL;
 
 	priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
+	if (priv->disposed)
+		return NULL;
 	entries = vtable->get_entries (priv);
 
 	for (i = 0; i < entries->len; i++) {
 		Entry *entry = g_ptr_array_index (entries, i);
+		NMDeviceState state;
 
 		if (!NM_IS_DEVICE (entry->source.pointer))
 			continue;
@@ -892,8 +903,22 @@ _ipx_get_best_device (const VTableIP *vtable, NMDefaultRouteManager *self, const
 		if (entry->never_default)
 			continue;
 
-		if (g_slist_find ((GSList *) devices, entry->source.device))
+		state = nm_device_get_state (entry->source.device);
+		if (   state <= NM_DEVICE_STATE_DISCONNECTED
+		    || state >= NM_DEVICE_STATE_DEACTIVATING) {
+			/* FIXME: we also track unmanaged devices with assumed default routes.
+			 * Skip them, they are (currently) no candidates for best-device.
+			 *
+			 * Later we also want to properly assume connections for unmanaged devices.
+			 *
+			 * Also, we don't want to have DEACTIVATING devices returned as best_device(). */
+			continue;
+		}
+
+		if (g_slist_find ((GSList *) devices, entry->source.device)) {
+			g_return_val_if_fail (nm_device_get_act_request (entry->source.pointer), entry->source.pointer);
 			return entry->source.pointer;
+		}
 	}
 	return NULL;
 }
@@ -920,6 +945,8 @@ _ipx_get_best_activating_device (const VTableIP *vtable, NMDefaultRouteManager *
 	g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), NULL);
 
 	priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
+	if (priv->disposed)
+		return NULL;
 
 	best_activated_device = _ipx_get_best_device (vtable, self, devices);
 
@@ -948,7 +975,7 @@ _ipx_get_best_activating_device (const VTableIP *vtable, NMDefaultRouteManager *
 
 			prio = nm_device_get_ip4_route_metric (device);
 		}
-		prio = vtable->route_metric_normalize (prio);
+		prio = vtable->vt->metric_normalize (prio);
 
 		if (   !best_device
 		    || prio < best_prio
@@ -1013,6 +1040,8 @@ _ipx_get_best_config (const VTableIP *vtable,
 		*out_vpn = NULL;
 
 	priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
+	if (priv->disposed)
+		return NULL;
 
 	g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), NULL);
 
@@ -1028,7 +1057,7 @@ _ipx_get_best_config (const VTableIP *vtable,
 			if (entry->never_default && !ignore_never_default)
 				continue;
 
-			if (VTABLE_IS_IP4)
+			if (vtable->vt->is_ip4)
 				config_result = nm_vpn_connection_get_ip4_config (vpn);
 			else
 				config_result = nm_vpn_connection_get_ip6_config (vpn);
@@ -1043,11 +1072,25 @@ _ipx_get_best_config (const VTableIP *vtable,
 		} else {
 			NMDevice *device = entry->source.device;
 			NMActRequest *req;
+			NMDeviceState state;
 
 			if (entry->never_default)
 				continue;
 
-			if (VTABLE_IS_IP4)
+			state = nm_device_get_state (device);
+			if (   state <= NM_DEVICE_STATE_DISCONNECTED
+			    || state >= NM_DEVICE_STATE_DEACTIVATING) {
+				/* FIXME: the device has a default route, but we ignore it due to
+				 * unexpected state. That happens for example for unmanaged devices.
+				 *
+				 * In the future, we want unmanaged devices also assume a connection
+				 * if they are activated externally.
+				 *
+				 * Also, we don't want to have DEACTIVATING devices returned as best_config(). */
+				continue;
+			}
+
+			if (vtable->vt->is_ip4)
 				config_result = nm_device_get_ip4_config (device);
 			else
 				config_result = nm_device_get_ip6_config (device);
@@ -1116,40 +1159,14 @@ _v6_get_entries (NMDefaultRouteManagerPrivate *priv)
 	return priv->entries_ip6;
 }
 
-static gboolean
-_v4_platform_route_delete_default (int ifindex, guint32 metric)
-{
-	return nm_platform_ip4_route_delete (ifindex, 0, 0, metric);
-}
-
-static gboolean
-_v6_platform_route_delete_default (int ifindex, guint32 metric)
-{
-	return nm_platform_ip6_route_delete (ifindex, in6addr_any, 0, metric);
-}
-
-static guint32
-_v4_route_metric_normalize (guint32 metric)
-{
-	return metric;
-}
-
 static const VTableIP vtable_ip4 = {
-	.addr_family                    = AF_INET,
+	.vt                             = &nm_platform_vtable_route_v4,
 	.get_entries                    = _v4_get_entries,
-	.platform_route_to_string       = (const char *(*)(const NMPlatformIPRoute *)) nm_platform_ip4_route_to_string,
-	.platform_route_get_all         = nm_platform_ip4_route_get_all,
-	.platform_route_delete_default  = _v4_platform_route_delete_default,
-	.route_metric_normalize         = _v4_route_metric_normalize,
 };
 
 static const VTableIP vtable_ip6 = {
-	.addr_family                    = AF_INET6,
+	.vt                             = &nm_platform_vtable_route_v6,
 	.get_entries                    = _v6_get_entries,
-	.platform_route_to_string       = (const char *(*)(const NMPlatformIPRoute *)) nm_platform_ip6_route_to_string,
-	.platform_route_get_all         = nm_platform_ip6_route_get_all,
-	.platform_route_delete_default  = _v6_platform_route_delete_default,
-	.route_metric_normalize         = nm_utils_ip6_route_metric_normalize,
 };
 
 /***********************************************************************************/
@@ -1157,11 +1174,11 @@ static const VTableIP vtable_ip6 = {
 NMDefaultRouteManager *
 nm_default_route_manager_get ()
 {
-	if (G_UNLIKELY (!_instance)) {
-		_instance = NM_DEFAULT_ROUTE_MANAGER (g_object_new (NM_TYPE_DEFAULT_ROUTE_MANAGER, NULL));
-		g_object_add_weak_pointer (G_OBJECT (_instance), (gpointer *) &_instance);
+	if (G_UNLIKELY (!singleton_instance)) {
+		singleton_instance = NM_DEFAULT_ROUTE_MANAGER (g_object_new (NM_TYPE_DEFAULT_ROUTE_MANAGER, NULL));
+		g_object_add_weak_pointer (G_OBJECT (singleton_instance), (gpointer *) &singleton_instance);
 	}
-	return _instance;
+	return singleton_instance;
 }
 
 /***********************************************************************************/
@@ -1260,7 +1277,7 @@ _platform_ipx_route_changed_cb (const VTableIP *vtable,
 		return;
 	}
 
-	if (VTABLE_IS_IP4)
+	if (vtable->vt->is_ip4)
 		priv->resync.has_v4_changes = TRUE;
 	else
 		priv->resync.has_v6_changes = TRUE;
@@ -1318,16 +1335,15 @@ static void
 nm_default_route_manager_init (NMDefaultRouteManager *self)
 {
 	NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-	NMPlatform *platform;
 
 	priv->entries_ip4 = g_ptr_array_new_full (0, (GDestroyNotify) _entry_free);
 	priv->entries_ip6 = g_ptr_array_new_full (0, (GDestroyNotify) _entry_free);
 
-	platform = nm_platform_get ();
-	g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (_platform_ip4_address_changed_cb), self);
-	g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (_platform_ip6_address_changed_cb), self);
-	g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_platform_ip4_route_changed_cb), self);
-	g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_platform_ip6_route_changed_cb), self);
+	priv->platform = g_object_ref (nm_platform_get ());
+	g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (_platform_ip4_address_changed_cb), self);
+	g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (_platform_ip6_address_changed_cb), self);
+	g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_platform_ip4_route_changed_cb), self);
+	g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_platform_ip6_route_changed_cb), self);
 }
 
 static void
@@ -1336,6 +1352,22 @@ dispose (GObject *object)
 	NMDefaultRouteManager *self = NM_DEFAULT_ROUTE_MANAGER (object);
 	NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
 
+	priv->disposed = TRUE;
+
+	if (priv->platform) {
+		g_signal_handlers_disconnect_by_data (priv->platform, self);
+		g_clear_object (&priv->platform);
+	}
+
+	_resync_idle_cancel (self);
+
+	/* g_ptr_array_free() invokes the free function for all entries without actually
+	 * removing them and having dangling pointers in the process. _entry_free()
+	 * will unref the source, which might cause the destruction of the object, which
+	 * might trigger calling into @self again. This is guarded by priv->dispose.
+	 * If you remove priv->dispose, you must refactor the lines below to remove enties
+	 * one-by-one.
+	 */
 	if (priv->entries_ip4) {
 		g_ptr_array_free (priv->entries_ip4, TRUE);
 		priv->entries_ip4 = NULL;
@@ -1345,10 +1377,6 @@ dispose (GObject *object)
 		priv->entries_ip6 = NULL;
 	}
 
-	_resync_idle_cancel (self);
-
-	g_signal_handlers_disconnect_by_data (nm_platform_get (), self);
-
 	G_OBJECT_CLASS (nm_default_route_manager_parent_class)->dispose (object);
 }
 
diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c
index ae451768..4e200266 100644
--- a/src/nm-dispatcher.c
+++ b/src/nm-dispatcher.c
@@ -37,6 +37,7 @@
 #include "nm-dhcp6-config.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-glib-compat.h"
+#include "nm-settings-connection.h"
 
 #define CALL_TIMEOUT (1000 * 60 * 10)  /* 10 minutes for all scripts */
 
@@ -474,6 +475,7 @@ _dispatcher_call (DispatcherAction action,
 
 	if (connection) {
 		GVariant *connection_dict;
+		const char *filename;
 
 		connection_dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_NO_SECRETS);
 		connection_hash = nm_utils_connection_dict_to_hash (connection_dict);
@@ -483,6 +485,12 @@ _dispatcher_call (DispatcherAction action,
 		value_hash_add_object_path (connection_props,
 		                            NMD_CONNECTION_PROPS_PATH,
 		                            nm_connection_get_path (connection));
+		filename = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection));
+		if (filename) {
+			value_hash_add_str (connection_props,
+			                    NMD_CONNECTION_PROPS_FILENAME,
+			                    filename);
+		}
 	} else {
 		connection_hash = value_hash_create ();
 		connection_props = value_hash_create ();
diff --git a/src/nm-enum-types.c b/src/nm-enum-types.c
index ee1df59f..c3f15f38 100644
--- a/src/nm-enum-types.c
+++ b/src/nm-enum-types.c
@@ -45,6 +45,7 @@
 #include "nm-fake-rdisc.h" 
 #include "nm-lndp-rdisc.h" 
 #include "nm-rdisc.h" 
+#include "nm-rdisc-private.h" 
 #include "nm-ppp-manager.h" 
 #include "nm-ppp-status.h" 
 #include "nm-agent-manager.h" 
@@ -96,8 +97,7 @@
 #include "nm-sleep-monitor.h" 
 #include "nm-types.h" 
 #include "NetworkManagerUtils.h" 
-#include "wifi-utils-wext.h" 
-#include "nm-device-wimax.h"
+#include "wifi-utils-wext.h"
 
 GType
 nm_vlan_error_get_type (void)
@@ -126,7 +126,7 @@ nm_unmanaged_flags_get_type (void)
 
   if (g_once_init_enter (&g_define_type_id__volatile))
     {
-      static const GEnumValue values[] = {
+      static const GFlagsValue values[] = {
         { NM_UNMANAGED_NONE, "NM_UNMANAGED_NONE", "nm-unmanaged-none" },
         { NM_UNMANAGED_DEFAULT, "NM_UNMANAGED_DEFAULT", "nm-unmanaged-default" },
         { NM_UNMANAGED_INTERNAL, "NM_UNMANAGED_INTERNAL", "nm-unmanaged-internal" },
@@ -135,10 +135,11 @@ nm_unmanaged_flags_get_type (void)
         { NM_UNMANAGED_EXTERNAL_DOWN, "NM_UNMANAGED_EXTERNAL_DOWN", "nm-unmanaged-external-down" },
         { __NM_UNMANAGED_LAST, "__NM_UNMANAGED_LAST", "--nm-unmanaged-last" },
         { NM_UNMANAGED_LAST, "NM_UNMANAGED_LAST", "nm-unmanaged-last" },
+        { NM_UNMANAGED_ALL, "NM_UNMANAGED_ALL", "nm-unmanaged-all" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
-        g_enum_register_static (g_intern_static_string ("NMUnmanagedFlags"), values);
+        g_flags_register_static (g_intern_static_string ("NMUnmanagedFlags"), values);
       g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
     }
 
@@ -260,10 +261,11 @@ nm_platform_reason_get_type (void)
   if (g_once_init_enter (&g_define_type_id__volatile))
     {
       static const GEnumValue values[] = {
-        { NM_PLATFORM_REASON_NONE, "NM_PLATFORM_REASON_NONE", "none" },
-        { NM_PLATFORM_REASON_INTERNAL, "NM_PLATFORM_REASON_INTERNAL", "internal" },
-        { NM_PLATFORM_REASON_EXTERNAL, "NM_PLATFORM_REASON_EXTERNAL", "external" },
-        { NM_PLATFORM_REASON_CACHE_CHECK, "NM_PLATFORM_REASON_CACHE_CHECK", "cache-check" },
+        { NM_PLATFORM_REASON_NONE, "NM_PLATFORM_REASON_NONE", "nm-platform-reason-none" },
+        { NM_PLATFORM_REASON_INTERNAL, "NM_PLATFORM_REASON_INTERNAL", "nm-platform-reason-internal" },
+        { NM_PLATFORM_REASON_EXTERNAL, "NM_PLATFORM_REASON_EXTERNAL", "nm-platform-reason-external" },
+        { NM_PLATFORM_REASON_CACHE_CHECK, "NM_PLATFORM_REASON_CACHE_CHECK", "nm-platform-reason-cache-check" },
+        { _NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL, "_NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL", "-nm-platform-reason-cache-check-internal" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 9d5cdc05..97e1708e 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -34,6 +34,10 @@
 #include <sys/stat.h>
 #include <signal.h>
 
+/* Cannot include <net/if.h> due to conflict with <linux/if.h>.
+ * Forward declare if_nametoindex. */
+extern unsigned int if_nametoindex (const char *__ifname);
+
 #include "gsystem-local-alloc.h"
 #include "NetworkManagerUtils.h"
 #include "nm-linux-platform.h"
@@ -51,13 +55,32 @@
 #define NMIH_PID_FILE_FMT NMRUNDIR "/nm-iface-helper-%d.pid"
 
 static GMainLoop *main_loop = NULL;
-static char *ifname = NULL;
 static int ifindex = -1;
-static gboolean slaac_required = FALSE;
-static gboolean dhcp4_required = FALSE;
-static int tempaddr = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
-static guint32 priority_v4 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4;
-static guint32 priority_v6 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6;
+
+static struct {
+	gboolean slaac;
+	gboolean show_version;
+	gboolean become_daemon;
+	gboolean debug;
+	gboolean g_fatal_warnings;
+	gboolean slaac_required;
+	gboolean dhcp4_required;
+	int tempaddr;
+	char *ifname;
+	char *uuid;
+	char *dhcp4_address;
+	char *dhcp4_clientid;
+	char *dhcp4_hostname;
+	char *iid_str;
+	char *opt_log_level;
+	char *opt_log_domains;
+	guint32 priority_v4;
+	guint32 priority_v6;
+} global_opt = {
+	.tempaddr = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN,
+	.priority_v4 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4,
+	.priority_v6 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
+};
 
 static void
 dhcp4_state_changed (NMDhcpClient *client,
@@ -71,7 +94,7 @@ dhcp4_state_changed (NMDhcpClient *client,
 
 	g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config));
 
-	nm_log_dbg (LOGD_DHCP4, "(%s): new DHCPv4 client state %d", ifname, state);
+	nm_log_dbg (LOGD_DHCP4, "(%s): new DHCPv4 client state %d", global_opt.ifname, state);
 
 	switch (state) {
 	case NM_DHCP_STATE_BOUND:
@@ -81,23 +104,22 @@ dhcp4_state_changed (NMDhcpClient *client,
 			nm_ip4_config_subtract (existing, last_config);
 
 		nm_ip4_config_merge (existing, ip4_config);
-		if (!nm_ip4_config_commit (existing, ifindex, priority_v4))
-			nm_log_warn (LOGD_DHCP4, "(%s): failed to apply DHCPv4 config", ifname);
+		if (!nm_ip4_config_commit (existing, ifindex, global_opt.priority_v4))
+			nm_log_warn (LOGD_DHCP4, "(%s): failed to apply DHCPv4 config", global_opt.ifname);
 
-		if (last_config) {
+		if (last_config)
 			g_object_unref (last_config);
-			last_config = nm_ip4_config_new ();
-			nm_ip4_config_replace (last_config, ip4_config, NULL);
-		}
+		last_config = nm_ip4_config_new ();
+		nm_ip4_config_replace (last_config, ip4_config, NULL);
 		break;
 	case NM_DHCP_STATE_TIMEOUT:
 	case NM_DHCP_STATE_DONE:
 	case NM_DHCP_STATE_FAIL:
-		if (dhcp4_required) {
-			nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed, quitting...", ifname);
+		if (global_opt.dhcp4_required) {
+			nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed, quitting...", global_opt.ifname);
 			g_main_loop_quit (main_loop);
 		} else
-			nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed", ifname);
+			nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed", global_opt.ifname);
 		break;
 	default:
 		break;
@@ -128,8 +150,8 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
 
 	if (system_support)
 		ifa_flags = IFA_F_NOPREFIXROUTE;
-	if (tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
-	    || tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
+	if (global_opt.tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
+	    || global_opt.tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
 	{
 		/* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */
 		ifa_flags |= IFA_F_MANAGETEMPADDR;
@@ -193,7 +215,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
 				route.plen = discovered_route->plen;
 				route.gateway = discovered_route->gateway;
 				route.source = NM_IP_CONFIG_SOURCE_RDISC;
-				route.metric = priority_v6;
+				route.metric = global_opt.priority_v6;
 
 				nm_ip6_config_add_route (ip6_config, &route);
 			}
@@ -204,45 +226,38 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
 		/* Unsupported until systemd DHCPv6 is ready */
 	}
 
-	/* hop_limit == 0 is a special value "unspecified", so do not touch
-	 * in this case */
-	if (changed & NM_RDISC_CONFIG_HOP_LIMIT && rdisc->hop_limit > 0) {
-		char val[16];
-
-		g_snprintf (val, sizeof (val), "%d", rdisc->hop_limit);
-		nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "hop_limit"), val);
-	}
+	if (changed & NM_RDISC_CONFIG_HOP_LIMIT)
+		nm_platform_sysctl_set_ip6_hop_limit_safe (global_opt.ifname, rdisc->hop_limit);
 
 	if (changed & NM_RDISC_CONFIG_MTU) {
 		char val[16];
 
 		g_snprintf (val, sizeof (val), "%d", rdisc->mtu);
-		nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "mtu"), val);
+		nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "mtu"), val);
 	}
 
-	existing = nm_ip6_config_capture (ifindex, FALSE, tempaddr);
+	existing = nm_ip6_config_capture (ifindex, FALSE, global_opt.tempaddr);
 	if (last_config)
 		nm_ip6_config_subtract (existing, last_config);
 
 	nm_ip6_config_merge (existing, ip6_config);
 	if (!nm_ip6_config_commit (existing, ifindex))
-		nm_log_warn (LOGD_IP6, "(%s): failed to apply IPv6 config", ifname);
+		nm_log_warn (LOGD_IP6, "(%s): failed to apply IPv6 config", global_opt.ifname);
 
-	if (last_config) {
+	if (last_config)
 		g_object_unref (last_config);
-		last_config = nm_ip6_config_new ();
-		nm_ip6_config_replace (last_config, ip6_config, NULL);
-	}
+	last_config = nm_ip6_config_new ();
+	nm_ip6_config_replace (last_config, ip6_config, NULL);
 }
 
 static void
 rdisc_ra_timeout (NMRDisc *rdisc, gpointer user_data)
 {
-	if (slaac_required) {
-		nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed, quitting...", ifname);
+	if (global_opt.slaac_required) {
+		nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed, quitting...", global_opt.ifname);
 		g_main_loop_quit (main_loop);
 	} else
-		nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed", ifname);
+		nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed", global_opt.ifname);
 }
 
 static gboolean
@@ -268,78 +283,108 @@ setup_signals (gboolean *quit_early_ptr)
 	g_unix_signal_add (SIGTERM, quit_handler, quit_early_ptr);
 }
 
-int
-main (int argc, char *argv[])
+static void
+do_early_setup (int *argc, char **argv[])
 {
-	char *opt_log_level = NULL;
-	char *opt_log_domains = NULL;
-	gboolean debug = FALSE, g_fatal_warnings = FALSE, become_daemon = FALSE;
-	gboolean show_version = FALSE, slaac = FALSE;
-	char *bad_domains = NULL, *dhcp4_hostname = NULL, *uuid = NULL;
-	char *iid_str = NULL, *dhcp4_clientid = NULL, *dhcp4_address = NULL;
-	gs_unref_object NMDhcpManager *dhcp_mgr = NULL;
-	GError *error = NULL;
-	gboolean wrote_pidfile = FALSE;
-	gs_free char *pidfile = NULL;
-	gboolean quit_early = FALSE;
-	gs_unref_object NMDhcpClient *dhcp4_client = NULL;
-	gs_unref_object NMRDisc *rdisc = NULL;
-	GByteArray *hwaddr = NULL;
-	size_t hwaddr_len = 0;
-	gconstpointer tmp;
-	gs_free NMUtilsIPv6IfaceId *iid = NULL;
 	gint64 priority64_v4 = -1;
 	gint64 priority64_v6 = -1;
-
 	GOptionEntry options[] = {
 		/* Interface/IP config */
-		{ "ifname", 'i', 0, G_OPTION_ARG_STRING, &ifname, N_("The interface to manage"), N_("eth0") },
-		{ "uuid", 'u', 0, G_OPTION_ARG_STRING, &uuid, N_("Connection UUID"), N_("661e8cd0-b618-46b8-9dc9-31a52baaa16b") },
-		{ "slaac", 's', 0, G_OPTION_ARG_NONE, &slaac, N_("Whether to manage IPv6 SLAAC"), NULL },
-		{ "slaac-required", '6', 0, G_OPTION_ARG_NONE, &slaac_required, N_("Whether SLAAC must be successful"), NULL },
-		{ "slaac-tempaddr", 't', 0, G_OPTION_ARG_INT, &tempaddr, N_("Use an IPv6 temporary privacy address"), NULL },
-		{ "dhcp4", 'd', 0, G_OPTION_ARG_STRING, &dhcp4_address, N_("Current DHCPv4 address"), NULL },
-		{ "dhcp4-required", '4', 0, G_OPTION_ARG_NONE, &dhcp4_required, N_("Whether DHCPv4 must be successful"), NULL },
-		{ "dhcp4-clientid", 'c', 0, G_OPTION_ARG_STRING, &dhcp4_clientid, N_("Hex-encoded DHCPv4 client ID"), NULL },
-		{ "dhcp4-hostname", 'h', 0, G_OPTION_ARG_STRING, &dhcp4_hostname, N_("Hostname to send to DHCP server"), N_("barbar") },
+		{ "ifname", 'i', 0, G_OPTION_ARG_STRING, &global_opt.ifname, N_("The interface to manage"), N_("eth0") },
+		{ "uuid", 'u', 0, G_OPTION_ARG_STRING, &global_opt.uuid, N_("Connection UUID"), N_("661e8cd0-b618-46b8-9dc9-31a52baaa16b") },
+		{ "slaac", 's', 0, G_OPTION_ARG_NONE, &global_opt.slaac, N_("Whether to manage IPv6 SLAAC"), NULL },
+		{ "slaac-required", '6', 0, G_OPTION_ARG_NONE, &global_opt.slaac_required, N_("Whether SLAAC must be successful"), NULL },
+		{ "slaac-tempaddr", 't', 0, G_OPTION_ARG_INT, &global_opt.tempaddr, N_("Use an IPv6 temporary privacy address"), NULL },
+		{ "dhcp4", 'd', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_address, N_("Current DHCPv4 address"), NULL },
+		{ "dhcp4-required", '4', 0, G_OPTION_ARG_NONE, &global_opt.dhcp4_required, N_("Whether DHCPv4 must be successful"), NULL },
+		{ "dhcp4-clientid", 'c', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_clientid, N_("Hex-encoded DHCPv4 client ID"), NULL },
+		{ "dhcp4-hostname", 'h', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_hostname, N_("Hostname to send to DHCP server"), N_("barbar") },
 		{ "priority4", '\0', 0, G_OPTION_ARG_INT64, &priority64_v4, N_("Route priority for IPv4"), N_("0") },
 		{ "priority6", '\0', 0, G_OPTION_ARG_INT64, &priority64_v6, N_("Route priority for IPv6"), N_("1024") },
-		{ "iid", 'e', 0, G_OPTION_ARG_STRING, &iid_str, N_("Hex-encoded Interface Identifier"), N_("") },
+		{ "iid", 'e', 0, G_OPTION_ARG_STRING, &global_opt.iid_str, N_("Hex-encoded Interface Identifier"), "" },
 
 		/* Logging/debugging */
-		{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Print NetworkManager version and exit"), NULL },
-		{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &become_daemon, N_("Don't become a daemon"), NULL },
-		{ "debug", 'b', 0, G_OPTION_ARG_NONE, &debug, N_("Don't become a daemon, and log to stderr"), NULL },
-		{ "log-level", 0, 0, G_OPTION_ARG_STRING, &opt_log_level, N_("Log level: one of [%s]"), "INFO" },
-		{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &opt_log_domains,
+		{ "version", 'V', 0, G_OPTION_ARG_NONE, &global_opt.show_version, N_("Print NetworkManager version and exit"), NULL },
+		{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &global_opt.become_daemon, N_("Don't become a daemon"), NULL },
+		{ "debug", 'b', 0, G_OPTION_ARG_NONE, &global_opt.debug, N_("Don't become a daemon, and log to stderr"), NULL },
+		{ "log-level", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_level, N_("Log level: one of [%s]"), "INFO" },
+		{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_domains,
 		  N_("Log domains separated by ',': any combination of [%s]"),
 		  "PLATFORM,RFKILL,WIFI" },
-		{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, N_("Make all warnings fatal"), NULL },
+		{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &global_opt.g_fatal_warnings, N_("Make all warnings fatal"), NULL },
 		{NULL}
 	};
 
-	setpgid (getpid (), getpid ());
-
 	if (!nm_main_utils_early_setup ("nm-iface-helper",
-	                                &argv,
-	                                &argc,
+	                                argc,
+	                                argv,
 	                                options,
 	                                NULL,
 	                                _("nm-iface-helper is a small, standalone process that manages a single network interface.")))
 		exit (1);
 
-	if (show_version) {
+	if (priority64_v4 >= 0 && priority64_v4 <= G_MAXUINT32)
+		global_opt.priority_v4 = (guint32) priority64_v4;
+	if (priority64_v6 >= 0 && priority64_v6 <= G_MAXUINT32)
+		global_opt.priority_v6 = (guint32) priority64_v6;
+}
+
+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;
+	gboolean quit_early = FALSE;
+	gs_unref_object NMDhcpClient *dhcp4_client = NULL;
+	gs_unref_object NMRDisc *rdisc = NULL;
+	GByteArray *hwaddr = NULL;
+	size_t hwaddr_len = 0;
+	gconstpointer tmp;
+	gs_free NMUtilsIPv6IfaceId *iid = NULL;
+
+#if !GLIB_CHECK_VERSION (2, 35, 0)
+	g_type_init ();
+#endif
+
+	setpgid (getpid (), getpid ());
+
+	do_early_setup (&argc, &argv);
+
+	if (global_opt.g_fatal_warnings) {
+		GLogLevelFlags fatal_mask;
+
+		fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+		fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+		g_log_set_always_fatal (fatal_mask);
+	}
+
+	if (global_opt.show_version) {
 		fprintf (stdout, NM_DIST_VERSION "\n");
 		exit (0);
 	}
 
-	if (!ifname || !uuid) {
+	nm_main_utils_ensure_root ();
+
+	if (!global_opt.ifname || !global_opt.uuid) {
 		fprintf (stderr, _("An interface name and UUID are required\n"));
 		exit (1);
 	}
 
-	if (!nm_logging_setup (opt_log_level,
-	                       opt_log_domains,
+	ifindex = if_nametoindex (global_opt.ifname);
+	if (ifindex <= 0) {
+		fprintf (stderr, _("Failed to find interface index for %s (%s)\n"), global_opt.ifname, strerror (errno));
+		exit (1);
+	}
+	pidfile = g_strdup_printf (NMIH_PID_FILE_FMT, ifindex);
+	nm_main_utils_ensure_not_running_pidfile (pidfile);
+
+	nm_main_utils_ensure_rundir ();
+
+	if (!nm_logging_setup (global_opt.opt_log_level,
+	                       global_opt.opt_log_domains,
 	                       &bad_domains,
 	                       &error)) {
 		fprintf (stderr,
@@ -353,14 +398,7 @@ main (int argc, char *argv[])
 		g_clear_pointer (&bad_domains, g_free);
 	}
 
-	pidfile = g_strdup_printf (NMIH_PID_FILE_FMT, ifindex);
-	g_assert (pidfile);
-
-	/* check pid file */
-	if (nm_main_utils_check_pidfile (pidfile, "nm-iface-helper"))
-		exit (1);
-
-	if (become_daemon && !debug) {
+	if (global_opt.become_daemon && !global_opt.debug) {
 		if (daemon (0, 0) < 0) {
 			int saved_errno;
 
@@ -378,74 +416,50 @@ main (int argc, char *argv[])
 	main_loop = g_main_loop_new (NULL, FALSE);
 	setup_signals (&quit_early);
 
-	if (g_fatal_warnings) {
-		GLogLevelFlags fatal_mask;
-
-		fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
-		fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
-		g_log_set_always_fatal (fatal_mask);
-	}
-
-	nm_logging_syslog_openlog (debug);
-
-#if !GLIB_CHECK_VERSION (2, 35, 0)
-	g_type_init ();
-#endif
+	nm_logging_syslog_openlog (global_opt.debug);
 
 	nm_log_info (LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting...");
 
 	/* Set up platform interaction layer */
 	nm_linux_platform_setup ();
 
-	ifindex = nm_platform_link_get_ifindex (ifname);
-	if (ifindex <= 0) {
-		fprintf (stderr, _("Failed to find interface index for %s\n"), ifname);
-		exit (1);
-	}
-
 	tmp = nm_platform_link_get_address (ifindex, &hwaddr_len);
 	if (tmp) {
 		hwaddr = g_byte_array_sized_new (hwaddr_len);
 		g_byte_array_append (hwaddr, tmp, hwaddr_len);
 	}
 
-	if (iid_str) {
+	if (global_opt.iid_str) {
 		GBytes *bytes;
 		gsize ignored = 0;
 
-		bytes = nm_utils_hexstr2bin (iid_str);
+		bytes = nm_utils_hexstr2bin (global_opt.iid_str);
 		if (!bytes || g_bytes_get_size (bytes) != sizeof (*iid)) {
-			fprintf (stderr, _("(%s): Invalid IID %s\n"), ifname, iid_str);
+			fprintf (stderr, _("(%s): Invalid IID %s\n"), global_opt.ifname, global_opt.iid_str);
 			exit (1);
 		}
 		iid = g_bytes_unref_to_data (bytes, &ignored);
 	}
 
-	if (priority64_v4 >= 0 && priority64_v4 <= G_MAXUINT32)
-		priority_v4 = (guint32) priority64_v4;
-
-	if (priority64_v6 >= 0 && priority64_v6 <= G_MAXUINT32)
-		priority_v6 = (guint32) priority64_v6;
-
-	if (dhcp4_address) {
-		nm_platform_sysctl_set (nm_utils_ip4_property_path (ifname, "promote_secondaries"), "1");
+	if (global_opt.dhcp4_address) {
+		nm_platform_sysctl_set (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,
-		                                          ifname,
+		                                          global_opt.ifname,
 		                                          ifindex,
 		                                          hwaddr,
-		                                          uuid,
-		                                          priority_v4,
-		                                          !!dhcp4_hostname,
-		                                          dhcp4_hostname,
-		                                          dhcp4_clientid,
+		                                          global_opt.uuid,
+		                                          global_opt.priority_v4,
+		                                          !!global_opt.dhcp4_hostname,
+		                                          global_opt.dhcp4_hostname,
+		                                          global_opt.dhcp4_clientid,
 		                                          45,
 		                                          NULL,
-		                                          dhcp4_address);
+		                                          global_opt.dhcp4_address);
 		g_assert (dhcp4_client);
 		g_signal_connect (dhcp4_client,
 		                  NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
@@ -453,19 +467,19 @@ main (int argc, char *argv[])
 		                  NULL);
 	}
 
-	if (slaac) {
+	if (global_opt.slaac) {
 		nm_platform_link_set_user_ipv6ll_enabled (ifindex, TRUE);
 
-		rdisc = nm_lndp_rdisc_new (ifindex, ifname);
+		rdisc = nm_lndp_rdisc_new (ifindex, global_opt.ifname);
 		g_assert (rdisc);
 
 		if (iid)
 			nm_rdisc_set_iid (rdisc, *iid);
 
-		nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra"), "1");
-		nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra_defrtr"), "0");
-		nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra_pinfo"), "0");
-		nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra_rtr_pref"), "0");
+		nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra"), "1");
+		nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_defrtr"), "0");
+		nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_pinfo"), "0");
+		nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_rtr_pref"), "0");
 
 		g_signal_connect (rdisc,
 		                  NM_RDISC_CONFIG_CHANGED,
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index fd466780..db2ef158 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -1721,6 +1721,8 @@ finalize (GObject *object)
 {
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
 
+	g_free (priv->path);
+
 	g_array_unref (priv->addresses);
 	g_array_unref (priv->routes);
 	g_array_unref (priv->nameservers);
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index db64e726..cf8d74be 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -375,7 +375,7 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex)
 	g_return_val_if_fail (config != NULL, FALSE);
 
 	/* Addresses */
-	nm_platform_ip6_address_sync (ifindex, priv->addresses);
+	nm_platform_ip6_address_sync (ifindex, priv->addresses, TRUE);
 
 	/* Routes */
 	{
@@ -1584,6 +1584,8 @@ finalize (GObject *object)
 {
 	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
 
+	g_free (priv->path);
+
 	g_array_unref (priv->addresses);
 	g_array_unref (priv->routes);
 	g_array_unref (priv->nameservers);
diff --git a/src/nm-logging.c b/src/nm-logging.c
index f1291fa7..fa770344 100644
--- a/src/nm-logging.c
+++ b/src/nm-logging.c
@@ -357,13 +357,14 @@ nm_logging_enabled (NMLogLevel level, NMLogDomain domain)
 }
 
 void
-_nm_log (const char *file,
-         guint line,
-         const char *func,
-         NMLogLevel level,
-         NMLogDomain domain,
-         const char *fmt,
-         ...)
+_nm_log_impl (const char *file,
+              guint line,
+              const char *func,
+              NMLogLevel level,
+              NMLogDomain domain,
+              int error,
+              const char *fmt,
+              ...)
 {
 	va_list args;
 	char *msg;
@@ -379,6 +380,10 @@ _nm_log (const char *file,
 	if (!(logging[level] & domain))
 		return;
 
+	/* Make sure that %m maps to the specified error */
+	if (error != 0)
+		errno = error;
+
 	va_start (args, fmt);
 	msg = g_strdup_vprintf (fmt, args);
 	va_end (args);
diff --git a/src/nm-logging.h b/src/nm-logging.h
index 4ab2db3a..00d429b0 100644
--- a/src/nm-logging.h
+++ b/src/nm-logging.h
@@ -100,12 +100,20 @@ typedef enum  { /*< skip >*/
 #define nm_log_dbg(domain, ...)     nm_log (LOGL_DEBUG, (domain), __VA_ARGS__)
 #define nm_log_trace(domain, ...)   nm_log (LOGL_TRACE, (domain), __VA_ARGS__)
 
+/* A wrapper for the _nm_log_impl() function that adds call site information.
+ * Contrary to nm_log(), it unconditionally calls the function without
+ * checking whether logging for the given level and domain is enabled. */
+#define _nm_log(level, domain, error, ...) \
+    G_STMT_START { \
+        _nm_log_impl (__FILE__, __LINE__, G_STRFUNC, (level), (domain), (error), ""__VA_ARGS__); \
+    } G_STMT_END
+
 /* nm_log() only evaluates it's argument list after checking
  * whether logging for the given level/domain is enabled.  */
 #define nm_log(level, domain, ...) \
     G_STMT_START { \
         if (nm_logging_enabled ((level), (domain))) { \
-            _nm_log (__FILE__, __LINE__, G_STRFUNC, (level), (domain), __VA_ARGS__); \
+            _nm_log (level, domain, 0, __VA_ARGS__); \
         } \
     } G_STMT_END
 
@@ -116,11 +124,13 @@ typedef enum  { /*< skip >*/
 /* log a message for an object (with providing a generic @self pointer) */
 #define nm_log_ptr(level, domain, self, ...) \
     G_STMT_START { \
+        NM_PRAGMA_WARNING_DISABLE("-Wtautological-compare") \
         if ((level) <= LOGL_DEBUG) { \
             _nm_log_ptr ((level), (domain), (self), __VA_ARGS__); \
         } else { \
             nm_log ((level), (domain), __VA_ARGS__); \
         } \
+        NM_PRAGMA_WARNING_REENABLE \
     } G_STMT_END
 
 
@@ -134,13 +144,14 @@ typedef enum  { /*< skip >*/
     nm_log_ptr ((level), (domain), (self), __VA_ARGS__)
 
 
-void _nm_log (const char *file,
-              guint line,
-              const char *func,
-              NMLogLevel level,
-              NMLogDomain domain,
-              const char *fmt,
-              ...) __attribute__((__format__ (__printf__, 6, 7)));
+void _nm_log_impl (const char *file,
+                   guint line,
+                   const char *func,
+                   NMLogLevel level,
+                   NMLogDomain domain,
+                   int error,
+                   const char *fmt,
+                   ...) __attribute__((__format__ (__printf__, 7, 8)));
 
 const char *nm_logging_level_to_string (void);
 const char *nm_logging_domains_to_string (void);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 7e81afa5..0fa88d1d 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -578,7 +578,7 @@ checked_connectivity (GObject *object, GAsyncResult *result, gpointer user_data)
 }
 
 static NMState
-find_best_device_state (NMManager *manager, gboolean *want_connectivity_check)
+find_best_device_state (NMManager *manager)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	NMState best_state = NM_STATE_DISCONNECTED;
@@ -592,14 +592,10 @@ find_best_device_state (NMManager *manager, gboolean *want_connectivity_check)
 		case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
 			if (   nm_active_connection_get_default (ac)
 			    || nm_active_connection_get_default6 (ac)) {
-				nm_connectivity_set_online (priv->connectivity, TRUE);
-				if (nm_connectivity_get_state (priv->connectivity) == NM_CONNECTIVITY_FULL) {
-					*want_connectivity_check = FALSE;
+				if (nm_connectivity_get_state (priv->connectivity) == NM_CONNECTIVITY_FULL)
 					return NM_STATE_CONNECTED_GLOBAL;
-				}
 
-				best_state = NM_STATE_CONNECTING;
-				*want_connectivity_check = TRUE;
+				best_state = NM_STATE_CONNECTED_SITE;
 			} else {
 				if (best_state < NM_STATE_CONNECTING)
 					best_state = NM_STATE_CONNECTED_LOCAL;
@@ -630,7 +626,6 @@ nm_manager_update_state (NMManager *manager)
 {
 	NMManagerPrivate *priv;
 	NMState new_state = NM_STATE_DISCONNECTED;
-	gboolean want_connectivity_check = FALSE;
 
 	g_return_if_fail (NM_IS_MANAGER (manager));
 
@@ -639,16 +634,16 @@ nm_manager_update_state (NMManager *manager)
 	if (manager_sleeping (manager))
 		new_state = NM_STATE_ASLEEP;
 	else
-		new_state = find_best_device_state (manager, &want_connectivity_check);
+		new_state = find_best_device_state (manager);
+
+	nm_connectivity_set_online (priv->connectivity, new_state >= NM_STATE_CONNECTED_LOCAL);
 
-	if (new_state == NM_STATE_CONNECTING && want_connectivity_check) {
+	if (new_state == NM_STATE_CONNECTED_SITE) {
 		nm_connectivity_check_async (priv->connectivity,
 		                             checked_connectivity,
 		                             g_object_ref (manager));
-		return;
 	}
 
-	nm_connectivity_set_online (priv->connectivity, new_state >= NM_STATE_CONNECTED_LOCAL);
 	set_state (manager, new_state);
 }
 
@@ -687,6 +682,11 @@ check_if_startup_complete (NMManager *self)
 	if (!priv->startup)
 		return;
 
+	if (!nm_settings_get_startup_complete (priv->settings)) {
+		nm_log_dbg (LOGD_CORE, "check_if_startup_complete returns FALSE because of NMSettings");
+		return;
+	}
+
 	for (iter = priv->devices; iter; iter = iter->next) {
 		NMDevice *dev = iter->data;
 
@@ -722,6 +722,14 @@ device_has_pending_action_changed (NMDevice *device,
 }
 
 static void
+settings_startup_complete_changed (NMSettings *settings,
+                                   GParamSpec *pspec,
+                                   NMManager *self)
+{
+	check_if_startup_complete (self);
+}
+
+static void
 remove_device (NMManager *manager,
                NMDevice *device,
                gboolean quitting,
@@ -1020,6 +1028,7 @@ get_virtual_iface_name (NMManager *self,
  * system_create_virtual_device:
  * @self: the #NMManager
  * @connection: the connection which might require a virtual device
+ * @error: the error set when return value is NULL
  *
  * If @connection requires a virtual device and one does not yet exist for it,
  * creates that device.
@@ -1027,19 +1036,27 @@ get_virtual_iface_name (NMManager *self,
  * Returns: the #NMDevice if successfully created, %NULL if not
  */
 static NMDevice *
-system_create_virtual_device (NMManager *self, NMConnection *connection)
+system_create_virtual_device (NMManager *self, NMConnection *connection, GError **error)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	GError *error = NULL;
+	GError *local_err = NULL;
 	GSList *iter;
 	char *iface = NULL;
 	NMDevice *device = NULL, *parent = NULL;
 	gboolean nm_owned = FALSE;
 
+	g_return_val_if_fail (NM_IS_MANAGER (self), NULL);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
 	iface = get_virtual_iface_name (self, connection, &parent);
 	if (!iface) {
 		nm_log_dbg (LOGD_DEVICE, "(%s) failed to determine virtual interface name",
 		            nm_connection_get_id (connection));
+		g_set_error_literal (error,
+		                     NM_MANAGER_ERROR,
+		                     NM_MANAGER_ERROR_FAILED,
+		                     "failed to determine virtual interface name");
 		return NULL;
 	}
 
@@ -1048,8 +1065,15 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 		NMDevice *candidate = iter->data;
 
 		if (   g_strcmp0 (nm_device_get_iface (candidate), iface) == 0
-		    || nm_device_check_connection_compatible (candidate, connection))
+		    || nm_device_check_connection_compatible (candidate, connection)) {
+			nm_log_dbg (LOGD_DEVICE, "(%s) already created virtual interface name %s",
+			            nm_connection_get_id (connection), iface);
+			g_set_error (error,
+			             NM_MANAGER_ERROR,
+			             NM_MANAGER_ERROR_FAILED,
+			             "interface name '%s' already created", iface);
 			goto out;
+		}
 	}
 
 	/* Block notification of link added since we're creating the device
@@ -1064,14 +1088,15 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 		device = nm_device_factory_create_virtual_device_for_connection (NM_DEVICE_FACTORY (iter->data),
 		                                                                 connection,
 		                                                                 parent,
-		                                                                 &error);
-		if (device || error) {
+		                                                                 &local_err);
+		if (device || local_err) {
 			if (device)
-				g_assert_no_error (error);
+				g_assert_no_error (local_err);
 			else {
 				nm_log_err (LOGD_DEVICE, "(%s) failed to create virtual device: %s",
-				            nm_connection_get_id (connection), error ? error->message : "(unknown error)");
-				g_clear_error (&error);
+				            nm_connection_get_id (connection),
+				            local_err ? local_err->message : "(unknown error)");
+				g_propagate_error (error, local_err);
 			}
 			break;
 		}
@@ -1087,6 +1112,16 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 		add_device (self, device, !nm_owned);
 
 		g_object_unref (device);
+	} else {
+		if (error && !*error)
+			nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable",
+			            nm_connection_get_id (connection), iface,
+			            nm_connection_get_connection_type (connection));
+			g_set_error (error,
+			             NM_MANAGER_ERROR,
+			             NM_MANAGER_ERROR_FAILED,
+			             "NetworkManager plugin for '%s' unavailable",
+			             nm_connection_get_connection_type (connection));
 	}
 
 	priv->ignore_link_added_cb--;
@@ -1111,7 +1146,7 @@ system_create_virtual_devices (NMManager *self)
 		/* We only create a virtual interface if the connection can autoconnect */
 		if (   nm_connection_is_virtual (connection)
 		    && nm_settings_connection_can_autoconnect (NM_SETTINGS_CONNECTION (connection)))
-			system_create_virtual_device (self, connection);
+			system_create_virtual_device (self, connection, NULL);
 	}
 	g_slist_free (connections);
 }
@@ -1128,7 +1163,7 @@ connection_added (NMSettings *settings,
 
 		g_assert (s_con);
 		if (nm_setting_connection_get_autoconnect (s_con))
-			system_create_virtual_device (manager, connection);
+			system_create_virtual_device (manager, connection, NULL);
 	}
 }
 
@@ -1498,6 +1533,9 @@ done:
 static gboolean
 match_connection_filter (NMConnection *connection, gpointer user_data)
 {
+	if (nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection)))
+		return FALSE;
+
 	return nm_device_check_connection_compatible (NM_DEVICE (user_data), connection);
 }
 
@@ -2491,7 +2529,7 @@ ensure_master_active_connection (NMManager *self,
 				if (!is_compatible_with_slave (candidate, connection))
 					continue;
 
-				if (nm_device_connection_is_available (master_device, candidate, TRUE)) {
+				if (nm_device_check_connection_available (master_device, candidate, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) {
 					master_ac = nm_manager_activate_connection (self,
 					                                            candidate,
 					                                            NULL,
@@ -2532,7 +2570,7 @@ ensure_master_active_connection (NMManager *self,
 				continue;
 			}
 
-			if (!nm_device_connection_is_available (candidate, master_connection, TRUE))
+			if (!nm_device_check_connection_available (candidate, master_connection, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL))
 				continue;
 
 			found_device = TRUE;
@@ -2601,6 +2639,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 	NMConnection *connection;
 	NMConnection *master_connection = NULL;
 	NMActiveConnection *master_ac = NULL;
+	GError *local_err = NULL;
 
 	g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE);
@@ -2625,12 +2664,14 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 			return FALSE;
 		}
 
-		device = system_create_virtual_device (self, connection);
+		device = system_create_virtual_device (self, connection, &local_err);
 		if (!device) {
-			g_set_error_literal (error,
-			                     NM_MANAGER_ERROR,
-			                     NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-			                     "Failed to create virtual interface");
+			g_set_error (error,
+			             NM_MANAGER_ERROR,
+			             NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+			             "Failed to create virtual interface: %s",
+			             local_err ? local_err->message : "(unknown)");
+			g_clear_error (&local_err);
 			return FALSE;
 		}
 
@@ -2646,7 +2687,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 		 * in the UNAVAILABLE state here.  To ensure it can be activated
 		 * immediately, we transition it to DISCONNECTED.
 		 */
-		if (   nm_device_is_available (device)
+		if (   nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)
 			&& (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) {
 			nm_device_state_changed (device,
 			                         NM_DEVICE_STATE_DISCONNECTED,
@@ -2680,7 +2721,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 	}
 
 	/* Final connection must be available on device */
-	if (!nm_device_connection_is_available (device, connection, TRUE)) {
+	if (!nm_device_check_connection_available (device, connection, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) {
 		g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
 		             "Connection '%s' is not available on the device %s at this time.",
 		             nm_connection_get_id (connection), nm_device_get_iface (device));
@@ -3589,7 +3630,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 	waking_from_suspend = sleeping_changed && !priv->sleeping;
 
 	if (manager_sleeping (self)) {
-		nm_log_info (LOGD_SUSPEND, suspending ? "sleeping..." : "disabling...");
+		nm_log_info (LOGD_SUSPEND, "%s...", suspending ? "sleeping" : "disabling");
 
 		/* FIXME: are there still hardware devices that need to be disabled around
 		 * suspend/resume?
@@ -3607,7 +3648,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 			nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
 		}
 	} else {
-		nm_log_info (LOGD_SUSPEND, waking_from_suspend ? "waking up..." : "re-enabling...");
+		nm_log_info (LOGD_SUSPEND, "%s...", waking_from_suspend ? "waking up" : "re-enabling");
 
 		if (waking_from_suspend) {
 			/* Belatedly take down Wake-on-LAN devices; ideally we wouldn't have to do this
@@ -4721,6 +4762,8 @@ nm_manager_new (NMSettings *settings,
 	priv->prop_filter_added = TRUE;
 
 	priv->settings = g_object_ref (settings);
+	g_signal_connect (priv->settings, "notify::" NM_SETTINGS_STARTUP_COMPLETE,
+	                  G_CALLBACK (settings_startup_complete_changed), singleton);
 
 	priv->state_file = g_strdup (state_file);
 
@@ -4795,7 +4838,7 @@ nm_manager_init (NMManager *manager)
 	priv->radio_states[RFKILL_TYPE_WWAN].rtype = RFKILL_TYPE_WWAN;
 
 	priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = TRUE;
-	priv->radio_states[RFKILL_TYPE_WIMAX].key = "WiMAXEnabled";
+	priv->radio_states[RFKILL_TYPE_WIMAX].key = "WimaxEnabled";
 	priv->radio_states[RFKILL_TYPE_WIMAX].prop = NM_MANAGER_WIMAX_ENABLED;
 	priv->radio_states[RFKILL_TYPE_WIMAX].hw_prop = NM_MANAGER_WIMAX_HARDWARE_ENABLED;
 	priv->radio_states[RFKILL_TYPE_WIMAX].desc = "WiMAX";
@@ -5038,6 +5081,7 @@ dispose (GObject *object)
 	}
 
 	g_clear_object (&priv->settings);
+	g_free (priv->state_file);
 	g_clear_object (&priv->vpn_manager);
 
 	/* Unregister property filter */
diff --git a/src/nm-properties-changed-signal.c b/src/nm-properties-changed-signal.c
index 7ba62aa2..c6dbb3d5 100644
--- a/src/nm-properties-changed-signal.c
+++ b/src/nm-properties-changed-signal.c
@@ -148,8 +148,8 @@ notify (GObject *object, GParamSpec *pspec)
 			break;
 	}
 	if (!dbus_property_name) {
-		nm_log_dbg (LOGD_DBUS_PROPS, "ignoring notification for prop %s on type %s",
-		            pspec->name, G_OBJECT_TYPE_NAME (object));
+		nm_log_trace (LOGD_DBUS_PROPS, "ignoring notification for prop %s on type %s",
+		              pspec->name, G_OBJECT_TYPE_NAME (object));
 		return;
 	}
 
@@ -228,16 +228,21 @@ nm_properties_changed_signal_add_property (GType       type,
 	if (!classinfo)
 		classinfo = nm_properties_changed_signal_setup_type (type);
 
+	g_assert (!g_hash_table_contains (classinfo->exported_props, (char *) gobject_property_name));
 	g_hash_table_insert (classinfo->exported_props,
 	                     (char *) gobject_property_name,
 	                     (char *) dbus_property_name);
 
+	if (!strchr (gobject_property_name, '_'))
+		return;
 	hyphen_name = g_strdup (gobject_property_name);
 	for (p = hyphen_name; *p; p++) {
 		if (*p == '_')
 			*p = '-';
 	}
+	g_assert (!g_hash_table_contains (classinfo->exported_props, hyphen_name));
 	g_hash_table_insert (classinfo->exported_props,
-	                     hyphen_name,
+	                     (char *) g_intern_string (hyphen_name),
 	                     (char *) dbus_property_name);
+	g_free (hyphen_name);
 }
diff --git a/src/platform/Makefile.in b/src/platform/Makefile.in
index d4c8ade7..a41de1ae 100644
--- a/src/platform/Makefile.in
+++ b/src/platform/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,7 +88,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/platform
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -95,6 +104,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -154,6 +164,7 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -205,7 +216,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -240,6 +250,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -456,7 +467,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/platform/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/platform/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -751,6 +761,8 @@ uninstall-am:
 	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
 	ps ps-am tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c
index a5eb7d4e..7b0d2d64 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -456,6 +456,15 @@ link_get_physical_port_id (NMPlatform *platform, int ifindex)
 	return NULL;
 }
 
+static guint
+link_get_dev_id (NMPlatform *platform, int ifindex)
+{
+	/* We call link_get just to cause an error to be set if @ifindex is bad. */
+	link_get (platform, ifindex);
+
+	return 0;
+}
+
 static gboolean
 link_get_wake_on_lan (NMPlatform *platform, int ifindex)
 {
@@ -1076,6 +1085,8 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
 			continue;
 		if (item->plen != route.plen)
 			continue;
+		if (item->metric != metric)
+			continue;
 
 		memcpy (item, &route, sizeof (route));
 		g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
@@ -1097,6 +1108,8 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
 	NMPlatformIP6Route route;
 	guint i;
 
+	metric = nm_utils_ip6_route_metric_normalize (metric);
+
 	memset (&route, 0, sizeof (route));
 	route.source = NM_IP_CONFIG_SOURCE_KERNEL;
 	route.ifindex = ifindex;
@@ -1116,6 +1129,8 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
 			continue;
 		if (item->plen != route.plen)
 			continue;
+		if (item->metric != metric)
+			continue;
 
 		memcpy (item, &route, sizeof (route));
 		g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
@@ -1153,6 +1168,8 @@ ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int p
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
 	int i;
 
+	metric = nm_utils_ip6_route_metric_normalize (metric);
+
 	for (i = 0; i < priv->ip6_routes->len; i++) {
 		NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
 
@@ -1301,6 +1318,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
 	platform_class->link_set_mtu = link_set_mtu;
 
 	platform_class->link_get_physical_port_id = link_get_physical_port_id;
+	platform_class->link_get_dev_id = link_get_dev_id;
 	platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
 
 	platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 5d1522ce..c337ee9c 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -127,7 +127,7 @@ _nl_get_vtable (void)
 	if (G_UNLIKELY (!vtable.f_nl_has_capability)) {
 		void *handle;
 
-		handle = dlopen ("libnl-3.so", RTLD_LAZY | RTLD_NOLOAD);
+		handle = dlopen ("libnl-3.so.200", RTLD_LAZY | RTLD_NOLOAD);
 		if (handle) {
 			vtable.handle = handle;
 			vtable.f_nl_has_capability = dlsym (handle, "nl_has_capability");
@@ -872,16 +872,15 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, const char
 		if (!ifname)
 			return_type (NM_LINK_TYPE_UNKNOWN, type);
 
+		driver = ethtool_get_driver (ifname);
 		if (arptype == 256) {
 			/* Some s390 CTC-type devices report 256 for the encapsulation type
-			 * for some reason, but we need to call them Ethernet. FIXME: use
-			 * something other than interface name to detect CTC here.
+			 * for some reason, but we need to call them Ethernet.
 			 */
-			if (g_str_has_prefix (ifname, "ctc"))
+			if (!g_strcmp0 (driver, "ctcm"))
 				return_type (NM_LINK_TYPE_ETHERNET, "ethernet");
 		}
 
-		driver = ethtool_get_driver (ifname);
 		if (!g_strcmp0 (driver, "openvswitch"))
 			return_type (NM_LINK_TYPE_OPENVSWITCH, "openvswitch");
 
@@ -1008,7 +1007,7 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin
 	if (udev_device) {
 		info->driver = udev_get_driver (platform, udev_device, info->ifindex);
 		if (!info->driver)
-			info->driver = rtnl_link_get_type (rtnllink);
+			info->driver = g_intern_string (rtnl_link_get_type (rtnllink));
 		if (!info->driver)
 			info->driver = ethtool_get_driver (info->name);
 		if (!info->driver)
@@ -1392,7 +1391,6 @@ static char to_string_buffer[255];
 #define SET_AND_RETURN_STRING_BUFFER(...) \
 	G_STMT_START { \
 		g_snprintf (to_string_buffer, sizeof (to_string_buffer), ## __VA_ARGS__); \
-		g_return_val_if_reached (to_string_buffer); \
 		return to_string_buffer; \
 	} G_STMT_END
 
@@ -1668,6 +1666,9 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
 		{
 			NMPlatformIP4Route route;
 
+			if (reason == _NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL)
+				return;
+
 			if (!_route_match ((struct rtnl_route *) object, AF_INET, 0, FALSE)) {
 				nm_log_dbg (LOGD_PLATFORM, "skip announce unmatching IP4 route %s", to_string_ip4_route ((struct rtnl_route *) object));
 				return;
@@ -1680,6 +1681,9 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
 		{
 			NMPlatformIP6Route route;
 
+			if (reason == _NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL)
+				return;
+
 			if (!_route_match ((struct rtnl_route *) object, AF_INET6, 0, FALSE)) {
 				nm_log_dbg (LOGD_PLATFORM, "skip announce unmatching IP6 route %s", to_string_ip6_route ((struct rtnl_route *) object));
 				return;
@@ -1719,9 +1723,15 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed
 			announce_object (platform, cached_object, NM_PLATFORM_SIGNAL_REMOVED, reason);
 		}
 	} else {
+		ObjectType type;
+
 		if (!kernel_object)
 			return FALSE;
 
+		/* Unsupported object types should never have reached the caches */
+		type = object_type_from_nl_object (kernel_object);
+		g_assert (type != OBJECT_TYPE_UNKNOWN);
+
 		hack_empty_master_iff_lower_up (platform, kernel_object);
 
 		if (cached_object)
@@ -1735,7 +1745,7 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed
 		announce_object (platform, kernel_object, cached_object ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, reason);
 
 		/* Refresh the master device (even on enslave/release) */
-		if (object_type_from_nl_object (kernel_object) == OBJECT_TYPE_LINK) {
+		if (type == OBJECT_TYPE_LINK) {
 			int kernel_master = rtnl_link_get_master ((struct rtnl_link *) kernel_object);
 			int cached_master = cached_object ? rtnl_link_get_master ((struct rtnl_link *) cached_object) : 0;
 			struct nl_object *master_object;
@@ -1763,10 +1773,6 @@ add_object (NMPlatform *platform, struct nl_object *obj)
 	auto_nl_object struct nl_object *object = obj;
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
 	int nle;
-	struct nl_dump_params dp = {
-		.dp_type = NL_DUMP_DETAILS,
-		.dp_fd = stderr,
-	};
 
 	g_return_val_if_fail (object, FALSE);
 
@@ -1782,7 +1788,18 @@ add_object (NMPlatform *platform, struct nl_object *obj)
 		break;
 	default:
 		error ("Netlink error adding %s: %s", to_string_object (platform, object),  nl_geterror (nle));
-		nl_object_dump (object, &dp);
+		if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
+			char buf[256];
+			struct nl_dump_params dp = {
+				.dp_type = NL_DUMP_DETAILS,
+				.dp_buf = buf,
+				.dp_buflen = sizeof (buf),
+			};
+
+			nl_object_dump (object, &dp);
+			buf[sizeof (buf) - 1] = '\0';
+			debug ("netlink object:\n%s", buf);
+		}
 		return FALSE;
 	}
 
@@ -1997,6 +2014,11 @@ event_notification (struct nl_msg *msg, gpointer user_data)
 		 */
 		if (!kernel_object)
 			return NL_OK;
+
+		/* Ignore unsupported object types (e.g. AF_PHONET family addresses) */
+		if (type == OBJECT_TYPE_UNKNOWN)
+			return NL_OK;
+
 		/* Handle external addition */
 		if (!cached_object) {
 			nle = nl_cache_add (cache, kernel_object);
@@ -2690,6 +2712,30 @@ link_get_physical_port_id (NMPlatform *platform, int ifindex)
 	return id;
 }
 
+static guint
+link_get_dev_id (NMPlatform *platform, int ifindex)
+{
+	const char *ifname;
+	gs_free char *path = NULL, *id = NULL;
+	gint64 int_val;
+
+	ifname = nm_platform_link_get_name (ifindex);
+	if (!ifname)
+		return 0;
+
+	ifname = ASSERT_VALID_PATH_COMPONENT (ifname);
+
+	path = g_strdup_printf ("/sys/class/net/%s/dev_id", ifname);
+	id = sysctl_get (platform, path);
+	if (!id || !*id)
+		return 0;
+
+	/* Value is reported as hex */
+	int_val = nm_utils_ascii_str_to_int64 (id, 16, 0, G_MAXUINT16, 0);
+
+	return errno ? 0 : (int) int_val;
+}
+
 static int
 vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags)
 {
@@ -3507,7 +3553,7 @@ build_rtnl_addr (int family,
                  guint flags,
                  const char *label)
 {
-	auto_nl_addr struct rtnl_addr *rtnladdr = _nm_rtnl_addr_alloc (ifindex);
+	auto_nl_object struct rtnl_addr *rtnladdr = _nm_rtnl_addr_alloc (ifindex);
 	struct rtnl_addr *rtnladdr_copy;
 	int addrlen = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
 	auto_nl_addr struct nl_addr *nladdr = _nm_nl_addr_build (family, addr, addrlen);
@@ -3698,6 +3744,7 @@ _route_match (struct rtnl_route *rtnlroute, int family, int ifindex, gboolean in
 
 	if (rtnl_route_get_type (rtnlroute) != RTN_UNICAST ||
 	    rtnl_route_get_table (rtnlroute) != RT_TABLE_MAIN ||
+	    rtnl_route_get_tos (rtnlroute) != 0 ||
 	    (!include_proto_kernel && rtnl_route_get_protocol (rtnlroute) == RTPROT_KERNEL) ||
 	    rtnl_route_get_family (rtnlroute) != family ||
 	    rtnl_route_get_nnexthops (rtnlroute) != 1 ||
@@ -3845,6 +3892,8 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
                struct in6_addr network, int plen, struct in6_addr gateway,
                guint32 metric, guint32 mss)
 {
+	metric = nm_utils_ip6_route_metric_normalize (metric);
+
 	return add_object (platform, build_rtnl_route (AF_INET6, ifindex, source, &network, plen, &gateway, NULL, metric, mss));
 }
 
@@ -3863,7 +3912,7 @@ route_search_cache (struct nl_cache *cache, int family, int ifindex, const void
 		if (!_route_match (rtnlroute, family, ifindex, FALSE))
 			continue;
 
-		if (metric && metric != rtnl_route_get_priority (rtnlroute))
+		if (metric != rtnl_route_get_priority (rtnlroute))
 			continue;
 
 		dst = rtnl_route_get_dst (rtnlroute);
@@ -3872,7 +3921,14 @@ route_search_cache (struct nl_cache *cache, int family, int ifindex, const void
 		    || nl_addr_get_prefixlen (dst) != plen)
 			continue;
 
-		clear_host_address (family, nl_addr_get_binary_addr (dst), plen, dst_clean);
+		/* plen = 0 means all host bits, so all bits should be cleared.
+		 * Likewise if the binary address is not present or all zeros.
+		 */
+		if (plen == 0 || nl_addr_iszero (dst))
+			memset (dst_clean, 0, sizeof (dst_clean));
+		else
+			clear_host_address (family, nl_addr_get_binary_addr (dst), plen, dst_clean);
+
 		if (memcmp (dst_clean, network_clean,
 		            family == AF_INET ? sizeof (guint32) : sizeof (struct in6_addr)) != 0)
 			continue;
@@ -3884,7 +3940,7 @@ route_search_cache (struct nl_cache *cache, int family, int ifindex, const void
 }
 
 static gboolean
-refresh_route (NMPlatform *platform, int family, int ifindex, const void *network, int plen, int metric)
+refresh_route (NMPlatform *platform, int family, int ifindex, const void *network, int plen, guint32 metric)
 {
 	struct nl_cache *cache;
 	auto_nl_object struct rtnl_route *cached_object = NULL;
@@ -3910,6 +3966,19 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen
 
 	cache = choose_cache_by_type (platform, OBJECT_TYPE_IP4_ROUTE);
 
+	if (metric == 0) {
+		/* Deleting an IPv4 route with metric 0 does not only delete an exectly matching route.
+		 * If no route with metric 0 exists, it might delete another route to the same destination.
+		 * For nm_platform_ip4_route_delete() we don't want this semantic.
+		 *
+		 * Instead, re-fetch the route from kernel, and if that fails, there is nothing to do.
+		 * On success, there is still a race that we might end up deleting the wrong route. */
+		if (!refresh_object (platform, (struct nl_object *) route, FALSE, _NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL)) {
+			rtnl_route_put ((struct rtnl_route *) route);
+			return TRUE;
+		}
+	}
+
 	/* when deleting an IPv4 route, several fields of the provided route must match.
 	 * Lookup in the cache so that we hopefully get the right values. */
 	cached_object = (struct rtnl_route *) nl_cache_search (cache, route);
@@ -3943,8 +4012,8 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen
 	}
 	rtnl_route_set_scope ((struct rtnl_route *) route, scope);
 
-	if (cached_object)
-		rtnl_route_set_tos ((struct rtnl_route *) route, rtnl_route_get_tos (cached_object));
+	/* we only support routes with TOS zero. As such, delete_route() is also only able to delete
+	 * routes with tos==0. build_rtnl_route() already initializes tos properly. */
 
 	/* The following fields are also relevant when comparing the route, but the default values
 	 * are already as we want them:
@@ -3962,6 +4031,8 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, in
 {
 	struct in6_addr gateway = IN6ADDR_ANY_INIT;
 
+	metric = nm_utils_ip6_route_metric_normalize (metric);
+
 	return delete_object (platform, build_rtnl_route (AF_INET6, ifindex, NM_IP_CONFIG_SOURCE_UNKNOWN ,&network, plen, &gateway, NULL, metric, 0), FALSE) &&
 	    refresh_route (platform, AF_INET6, ifindex, &network, plen, metric);
 }
@@ -3989,6 +4060,8 @@ ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen
 static gboolean
 ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
 {
+	metric = nm_utils_ip6_route_metric_normalize (metric);
+
 	return ip_route_exists (platform, AF_INET6, ifindex, &network, plen, metric);
 }
 
@@ -4061,6 +4134,33 @@ cache_announce_changes (NMPlatform *platform, struct nl_cache *new, struct nl_ca
 	nl_cache_free (old);
 }
 
+/* The cache should always avoid containing objects not handled by NM, like
+ * e.g. addresses of the AF_PHONET family. */
+static void
+cache_remove_unknown (struct nl_cache *cache)
+{
+	GPtrArray *objects_to_remove = NULL;
+	struct nl_object *object;
+
+	for (object = nl_cache_get_first (cache); object; object = nl_cache_get_next (object)) {
+		if (object_type_from_nl_object (object) == OBJECT_TYPE_UNKNOWN) {
+			if (!objects_to_remove)
+				objects_to_remove = g_ptr_array_new_with_free_func ((GDestroyNotify) nl_object_put);
+			nl_object_get (object);
+			g_ptr_array_add (objects_to_remove, object);
+		}
+	}
+
+	if (objects_to_remove) {
+		guint i;
+
+		for (i = 0; i < objects_to_remove->len; i++)
+			nl_cache_remove (g_ptr_array_index (objects_to_remove, i));
+
+		g_ptr_array_free (objects_to_remove, TRUE);
+	}
+}
+
 /* Creates and populates the netlink object caches. Called upon platform init and
  * when we run out of sync (out of buffer space, netlink congestion control). In case
  * the caches already exist, it finds changed, added and removed objects, announces
@@ -4082,6 +4182,11 @@ cache_repopulate_all (NMPlatform *platform)
 	rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache);
 	g_assert (priv->link_cache && priv->address_cache && priv->route_cache);
 
+	/* Remove all unknown objects from the caches */
+	cache_remove_unknown (priv->link_cache);
+	cache_remove_unknown (priv->address_cache);
+	cache_remove_unknown (priv->route_cache);
+
 	for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) {
 		_rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object);
 	}
@@ -4139,7 +4244,13 @@ event_handler (GIOChannel *channel,
 			 * like to free up some space. We'll read in the status synchronously. */
 			nl_socket_modify_cb (priv->nlh_event, NL_CB_VALID, NL_CB_DEFAULT, NULL, NULL);
 			do {
+				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))
+					nle = -NLE_AGAIN;
 			} while (nle != -NLE_AGAIN);
 			nl_socket_modify_cb (priv->nlh_event, NL_CB_VALID, NL_CB_CUSTOM, event_notification, user_data);
 			cache_repopulate_all (platform);
@@ -4473,6 +4584,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
 	platform_class->link_set_mtu = link_set_mtu;
 
 	platform_class->link_get_physical_port_id = link_get_physical_port_id;
+	platform_class->link_get_dev_id = link_get_dev_id;
 	platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
 
 	platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 14fc44c5..ba7708d6 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -258,6 +258,38 @@ nm_platform_sysctl_set (const char *path, const char *value)
 	return klass->sysctl_set (platform, path, value);
 }
 
+gboolean
+nm_platform_sysctl_set_ip6_hop_limit_safe (const char *iface, int value)
+{
+	const char *path;
+	gint64 cur;
+
+	/* the hop-limit provided via RA is uint8. */
+	if (value > 0xFF)
+		return FALSE;
+
+	/* don't allow unreasonable small values */
+	if (value < 10)
+		return FALSE;
+
+	path = nm_utils_ip6_property_path (iface, "hop_limit");
+	cur = nm_platform_sysctl_get_int_checked (path, 10, 1, G_MAXINT32, -1);
+
+	/* only allow increasing the hop-limit to avoid DOS by an attacker
+	 * setting a low hop-limit (CVE-2015-2924, rh#1209902) */
+
+	if (value < cur)
+		return FALSE;
+	if (value != cur) {
+		char svalue[20];
+
+		sprintf (svalue, "%d", value);
+		nm_platform_sysctl_set (path, svalue);
+	}
+
+	return TRUE;
+}
+
 /**
  * nm_platform_sysctl_get:
  * @path: Absolute path to sysctl
@@ -963,9 +995,15 @@ nm_platform_link_get_mtu (int ifindex)
 }
 
 /**
- * nm_platform_link_get_mtu:
+ * nm_platform_link_get_physical_port_id:
  * @ifindex: Interface index
  *
+ * The physical port ID, if present, indicates some unique identifier of
+ * the parent interface (eg, the physical port of which this link is a child).
+ * Two links that report the same physical port ID can be assumed to be
+ * children of the same physical port and may share resources that limit
+ * their abilities.
+ *
  * Returns: physical port ID for the interface, or %NULL on error
  * or if the interface has no physical port ID.
  */
@@ -981,6 +1019,28 @@ nm_platform_link_get_physical_port_id (int ifindex)
 }
 
 /**
+ * nm_platform_link_get_dev_id:
+ * @ifindex: Interface index
+ *
+ * In contrast to the physical device ID (which indicates which parent a
+ * child has) the device ID differentiates sibling devices that may share
+ * the same MAC address.
+ *
+ * Returns: device ID for the interface, or 0 on error or if the
+ * interface has no device ID.
+ */
+guint
+nm_platform_link_get_dev_id (int ifindex)
+{
+	reset_error ();
+
+	g_return_val_if_fail (ifindex >= 0, 0);
+	g_return_val_if_fail (klass->link_get_dev_id, 0);
+
+	return klass->link_get_dev_id (platform, ifindex);
+}
+
+/**
  * nm_platform_link_get_wake_onlan:
  * @ifindex: Interface index
  *
@@ -1826,6 +1886,7 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint3
  * nm_platform_ip6_address_sync:
  * @ifindex: Interface index
  * @known_addresses: List of addresses
+ * @keep_link_local: Don't remove link-local address
  *
  * A convenience function to synchronize addresses for a specific interface
  * with the least possible disturbance. It simply removes addresses that are
@@ -1834,7 +1895,7 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint3
  * Returns: %TRUE on success.
  */
 gboolean
-nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses)
+nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses, gboolean keep_link_local)
 {
 	GArray *addresses;
 	NMPlatformIP6Address *address;
@@ -1847,7 +1908,7 @@ nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses)
 		address = &g_array_index (addresses, NMPlatformIP6Address, i);
 
 		/* Leave link local address management to the kernel */
-		if (IN6_IS_ADDR_LINKLOCAL (&address->address))
+		if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address))
 			continue;
 
 		if (!array_contains_ip6_address (known_addresses, address))
@@ -1880,7 +1941,7 @@ gboolean
 nm_platform_address_flush (int ifindex)
 {
 	return nm_platform_ip4_address_sync (ifindex, NULL, 0)
-			&& nm_platform_ip6_address_sync (ifindex, NULL);
+			&& nm_platform_ip6_address_sync (ifindex, NULL, FALSE);
 }
 
 /******************************************************************/
@@ -2100,7 +2161,8 @@ nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes)
 			if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route))
 				continue;
 
-			if ((known_route->gateway == 0) ^ (i_type != 0)) {
+			if (   (i_type == 0 && known_route->gateway != 0)
+			    || (i_type == 1 && known_route->gateway == 0)) {
 				/* Make two runs over the list of routes. On the first, only add
 				 * device routes, on the second the others (gateway routes). */
 				continue;
@@ -2174,7 +2236,8 @@ nm_platform_ip6_route_sync (int ifindex, const GArray *known_routes)
 			if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route))
 				continue;
 
-			if (IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway) ^ (i_type != 0)) {
+			if (   (i_type == 0 && !IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway))
+			    || (i_type == 1 && IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway))) {
 				/* Make two runs over the list of routes. On the first, only add
 				 * device routes, on the second the others (gateway routes). */
 				continue;
@@ -2738,6 +2801,97 @@ log_ip6_route (NMPlatform *p, int ifindex, NMPlatformIP6Route *route, NMPlatform
 
 /******************************************************************/
 
+static gboolean
+_vtr_v4_route_add (int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src)
+{
+	return nm_platform_ip4_route_add (ifindex > 0 ? ifindex : route->rx.ifindex,
+	                                  route->rx.source,
+	                                  route->r4.network,
+	                                  route->rx.plen,
+	                                  route->r4.gateway,
+	                                  v4_pref_src,
+	                                  route->rx.metric,
+	                                  route->rx.mss);
+}
+
+static gboolean
+_vtr_v6_route_add (int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src)
+{
+	return nm_platform_ip6_route_add (ifindex > 0 ? ifindex : route->rx.ifindex,
+	                                  route->rx.source,
+	                                  route->r6.network,
+	                                  route->rx.plen,
+	                                  route->r6.gateway,
+	                                  route->rx.metric,
+	                                  route->rx.mss);
+}
+
+static gboolean
+_vtr_v4_route_delete (int ifindex, const NMPlatformIPXRoute *route)
+{
+	return nm_platform_ip4_route_delete (ifindex > 0 ? ifindex : route->rx.ifindex,
+	                                     route->r4.network,
+	                                     route->rx.plen,
+	                                     route->rx.metric);
+}
+
+static gboolean
+_vtr_v6_route_delete (int ifindex, const NMPlatformIPXRoute *route)
+{
+	return nm_platform_ip6_route_delete (ifindex > 0 ? ifindex : route->rx.ifindex,
+	                                     route->r6.network,
+	                                     route->rx.plen,
+	                                     route->rx.metric);
+}
+
+static guint32
+_vtr_v4_metric_normalize (guint32 metric)
+{
+	return metric;
+}
+
+static gboolean
+_vtr_v4_route_delete_default (int ifindex, guint32 metric)
+{
+	return nm_platform_ip4_route_delete (ifindex, 0, 0, metric);
+}
+
+static gboolean
+_vtr_v6_route_delete_default (int ifindex, guint32 metric)
+{
+	return nm_platform_ip6_route_delete (ifindex, in6addr_any, 0, metric);
+}
+
+/******************************************************************/
+
+const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
+	.is_ip4                         = TRUE,
+	.addr_family                    = AF_INET,
+	.sizeof_route                   = sizeof (NMPlatformIP4Route),
+	.route_cmp                      = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip4_route_cmp,
+	.route_to_string                = (const char *(*) (const NMPlatformIPXRoute *route)) nm_platform_ip4_route_to_string,
+	.route_get_all                  = nm_platform_ip4_route_get_all,
+	.route_add                      = _vtr_v4_route_add,
+	.route_delete                   = _vtr_v4_route_delete,
+	.route_delete_default           = _vtr_v4_route_delete_default,
+	.metric_normalize               = _vtr_v4_metric_normalize,
+};
+
+const NMPlatformVTableRoute nm_platform_vtable_route_v6 = {
+	.is_ip4                         = FALSE,
+	.addr_family                    = AF_INET6,
+	.sizeof_route                   = sizeof (NMPlatformIP6Route),
+	.route_cmp                      = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip6_route_cmp,
+	.route_to_string                = (const char *(*) (const NMPlatformIPXRoute *route)) nm_platform_ip6_route_to_string,
+	.route_get_all                  = nm_platform_ip6_route_get_all,
+	.route_add                      = _vtr_v6_route_add,
+	.route_delete                   = _vtr_v6_route_delete,
+	.route_delete_default           = _vtr_v6_route_delete_default,
+	.metric_normalize               = nm_utils_ip6_route_metric_normalize,
+};
+
+/******************************************************************/
+
 static void
 nm_platform_init (NMPlatform *object)
 {
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 848f78e4..a49e0f11 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -69,7 +69,10 @@ typedef enum {
 	/* Event came from the kernel. */
 	NM_PLATFORM_REASON_EXTERNAL,
 	/* Event is a result of cache checking and cleanups. */
-	NM_PLATFORM_REASON_CACHE_CHECK
+	NM_PLATFORM_REASON_CACHE_CHECK,
+
+	/* Internal reason to suppress announcing change events */
+	_NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL,
 } NMPlatformReason;
 
 #define __NMPlatformObject_COMMON \
@@ -244,6 +247,23 @@ typedef union {
 
 
 typedef struct {
+	gboolean is_ip4;
+	int addr_family;
+	gsize sizeof_route;
+	int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b);
+	const char *(*route_to_string) (const NMPlatformIPXRoute *route);
+	GArray *(*route_get_all) (int ifindex, NMPlatformGetRouteMode mode);
+	gboolean (*route_add) (int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src);
+	gboolean (*route_delete) (int ifindex, const NMPlatformIPXRoute *route);
+	gboolean (*route_delete_default) (int ifindex, guint32 metric);
+	guint32 (*metric_normalize) (guint32 metric);
+} NMPlatformVTableRoute;
+
+extern const NMPlatformVTableRoute nm_platform_vtable_route_v4;
+extern const NMPlatformVTableRoute nm_platform_vtable_route_v6;
+
+
+typedef struct {
 	int peer;
 } NMPlatformVethProperties;
 
@@ -367,7 +387,8 @@ typedef struct {
 	guint32 (*link_get_mtu) (NMPlatform *, int ifindex);
 	gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
 
-	char * (*link_get_physical_port_id) (NMPlatform *, int ifindex);
+	char *   (*link_get_physical_port_id) (NMPlatform *, int ifindex);
+	guint    (*link_get_dev_id) (NMPlatform *, int ifindex);
 	gboolean (*link_get_wake_on_lan) (NMPlatform *, int ifindex);
 
 	gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex);
@@ -480,6 +501,8 @@ char *nm_platform_sysctl_get (const char *path);
 gint32 nm_platform_sysctl_get_int32 (const char *path, gint32 fallback);
 gint64 nm_platform_sysctl_get_int_checked (const char *path, guint base, gint64 min, gint64 max, gint64 fallback);
 
+gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (const char *iface, int value);
+
 gboolean nm_platform_link_get (int ifindex, NMPlatformLink *link);
 GArray *nm_platform_link_get_all (void);
 gboolean nm_platform_dummy_add (const char *name);
@@ -514,6 +537,7 @@ guint32 nm_platform_link_get_mtu (int ifindex);
 gboolean nm_platform_link_set_mtu (int ifindex, guint32 mtu);
 
 char    *nm_platform_link_get_physical_port_id (int ifindex);
+guint    nm_platform_link_get_dev_id (int ifindex);
 gboolean nm_platform_link_get_wake_on_lan (int ifindex);
 
 gboolean nm_platform_link_supports_carrier_detect (int ifindex);
@@ -569,7 +593,7 @@ gboolean nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, i
 gboolean nm_platform_ip4_address_exists (int ifindex, in_addr_t address, int plen);
 gboolean nm_platform_ip6_address_exists (int ifindex, struct in6_addr address, int plen);
 gboolean nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint32 device_route_metric);
-gboolean nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses);
+gboolean nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses, gboolean keep_link_local);
 gboolean nm_platform_address_flush (int ifindex);
 
 gboolean nm_platform_ip4_check_reinstall_device_route (int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric);
diff --git a/src/platform/tests/Makefile.am b/src/platform/tests/Makefile.am
index b06e25e0..c10600eb 100644
--- a/src/platform/tests/Makefile.am
+++ b/src/platform/tests/Makefile.am
@@ -109,7 +109,7 @@ test_cleanup_linux_CPPFLAGS = \
 	-DKERNEL_HACKS=1
 test_cleanup_linux_LDADD = $(PLATFORM_LDADD)
 
-#@VALGRIND_RULES@
+@VALGRIND_RULES@
 TESTS = test-link-fake test-address-fake test-route-fake test-cleanup-fake test-address-linux test-route-linux test-cleanup-linux
 
 
diff --git a/src/platform/tests/Makefile.in b/src/platform/tests/Makefile.in
index 052636ab..16a48430 100644
--- a/src/platform/tests/Makefile.in
+++ b/src/platform/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -89,8 +99,6 @@ TESTS = test-link-fake$(EXEEXT) test-address-fake$(EXEEXT) \
 	test-address-linux$(EXEEXT) test-route-linux$(EXEEXT) \
 	test-cleanup-linux$(EXEEXT)
 subdir = src/platform/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -107,6 +115,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -289,6 +298,8 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -315,7 +326,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -350,6 +360,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -647,7 +658,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/platform/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/platform/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -777,14 +787,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -1698,9 +1708,13 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @GNOME_CODE_COVERAGE_RULES@
 
+@VALGRIND_RULES@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c
index 3ef13b8e..5561038d 100644
--- a/src/platform/tests/test-address.c
+++ b/src/platform/tests/test-address.c
@@ -247,6 +247,12 @@ test_ip6_address_external (void)
 }
 
 void
+init_tests (int *argc, char ***argv)
+{
+	nmtst_init_with_logging (argc, argv, NULL, "ALL");
+}
+
+void
 setup_tests (void)
 {
 	SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c
index afbb438c..0d0f3f63 100644
--- a/src/platform/tests/test-cleanup.c
+++ b/src/platform/tests/test-cleanup.c
@@ -87,6 +87,12 @@ test_cleanup_internal (void)
 }
 
 void
+init_tests (int *argc, char ***argv)
+{
+	nmtst_init_with_logging (argc, argv, NULL, "ALL");
+}
+
+void
 setup_tests (void)
 {
 	nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index ab40f652..1980282d 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -125,6 +125,113 @@ link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, NMPl
 		g_error ("Added/changed link not found in the local cache.");
 }
 
+gboolean
+ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric)
+{
+	gs_free char *arg_network = NULL;
+	const char *argv[] = {
+		NULL,
+		"route",
+		"list",
+		"dev",
+		ifname,
+		"exact",
+		NULL,
+		NULL,
+	};
+	int exit_status;
+	gs_free char *std_out = NULL, *std_err = NULL;
+	char *out;
+	gboolean success;
+	gs_free_error GError *error = NULL;
+	gs_free char *metric_pattern = NULL;
+
+	g_assert (ifname && nm_utils_iface_valid_name (ifname));
+	g_assert (!strstr (ifname, " metric "));
+	g_assert (plen >= 0 && plen <= 32);
+
+	if (!NM_IS_LINUX_PLATFORM (nm_platform_get ())) {
+		/* If we don't test against linux-platform, we don't actually configure any
+		 * routes in the system. */
+		return -1;
+	}
+
+	argv[0] = nm_utils_file_search_in_paths ("ip", NULL,
+	                                         (const char *[]) { "/sbin", "/usr/sbin", NULL },
+	                                         G_FILE_TEST_IS_EXECUTABLE, NULL, NULL, NULL);
+	argv[6] = arg_network = g_strdup_printf ("%s/%d", nm_utils_inet4_ntop (network, NULL), plen);
+
+	if (!argv[0]) {
+		/* Hm. There is no 'ip' binary. Return *unknown* */
+		return -1;
+	}
+
+	success = g_spawn_sync (NULL,
+	                        (char **) argv,
+	                        (char *[]) { NULL },
+	                        0,
+	                        NULL,
+	                        NULL,
+	                        &std_out,
+	                        &std_err,
+	                        &exit_status,
+	                        &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_assert_cmpstr (std_err, ==, "");
+	g_assert (std_out);
+
+	metric_pattern = g_strdup_printf (" metric %u", metric);
+	out = std_out;
+	while (out) {
+		char *eol = strchr (out, '\n');
+		gs_free char *line = eol ? g_strndup (out, eol - out) : g_strdup (out);
+		const char *p;
+
+		out = eol ? &eol[1] : NULL;
+		if (!line[0])
+			continue;
+
+		if (metric == 0) {
+			if (!strstr (line, " metric "))
+				return TRUE;
+		}
+		p = strstr (line, metric_pattern);
+		if (p && NM_IN_SET (p[strlen (metric_pattern)], ' ', '\0'))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+void
+_assert_ip4_route_exists (const char *file, guint line, const char *func, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric)
+{
+	int ifindex;
+	gboolean exists_checked;
+
+	/* Check for existance of the route by spawning iproute2. Do this because platform
+	 * code might be entirely borked, but we expect ip-route to give a correct result.
+	 * If the ip command cannot be found, we accept this as success. */
+	exists_checked = ip4_route_exists (ifname, network, plen, metric);
+	if (exists_checked != -1 && !exists_checked != !exists) {
+		g_error ("[%s:%u] %s(): We expect the ip4 route %s/%d metric %u %s, but it %s",
+		         file, line, func,
+		         nm_utils_inet4_ntop (network, NULL), plen, metric,
+		         exists ? "to exist" : "not to exist",
+		         exists ? "doesn't" : "does");
+	}
+
+	ifindex = nm_platform_link_get_ifindex (ifname);
+	g_assert (ifindex > 0);
+	if (!nm_platform_ip4_route_exists (ifindex, network, plen, metric) != !exists) {
+		g_error ("[%s:%u] %s(): The ip4 route %s/%d metric %u %s, but platform thinks %s",
+		         file, line, func,
+		         nm_utils_inet4_ntop (network, NULL), plen, metric,
+		         exists ? "exists" : "does not exist",
+		         exists ? "it doesn't" : "it does");
+	}
+}
+
 void
 run_command (const char *format, ...)
 {
@@ -148,20 +255,22 @@ main (int argc, char **argv)
 	int result;
 	const char *program = *argv;
 
-	nmtst_init_with_logging (&argc, &argv, NULL, "ALL");
+	init_tests (&argc, &argv);
 
+	NM_PRAGMA_WARNING_DISABLE("-Wtautological-compare")
 	if (SETUP == nm_linux_platform_setup && getuid() != 0) {
 		/* Try to exec as sudo, this function does not return, if a sudo-cmd is set. */
 		nmtst_reexec_sudo ();
 
 #ifdef REQUIRE_ROOT_TESTS
-		g_message ("Fail test: requires root privileges (%s)", program);
+		g_print ("Fail test: requires root privileges (%s)\n", program);
 		return EXIT_FAILURE;
 #else
-		g_message ("Skipping test: requires root privileges (%s)", program);
+		g_print ("Skipping test: requires root privileges (%s)\n", program);
 		return 77;
 #endif
 	}
+	NM_PRAGMA_WARNING_REENABLE
 
 	SETUP ();
 
diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h
index 8f6b3912..367833d1 100644
--- a/src/platform/tests/test-common.h
+++ b/src/platform/tests/test-common.h
@@ -9,6 +9,8 @@
 #include "nm-fake-platform.h"
 #include "nm-linux-platform.h"
 
+#include "nm-test-utils.h"
+
 #define DEVICE_NAME "nm-test-device"
 
 #define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__)
@@ -34,9 +36,15 @@ void accept_signal (SignalData *data);
 void wait_signal (SignalData *data);
 void free_signal (SignalData *data);
 
+gboolean ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric);
+
+void _assert_ip4_route_exists (const char *file, guint line, const char *func, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric);
+#define assert_ip4_route_exists(exists, ifname, network, plen, metric) _assert_ip4_route_exists (__FILE__, __LINE__, G_STRFUNC, exists, ifname, network, plen, metric)
+
 void link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data);
 
 void run_command (const char *format, ...);
 
+void init_tests (int *argc, char ***argv);
 void setup_tests (void);
 
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 8bd2ef44..99556e0a 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -365,12 +365,14 @@ test_bridge (void)
 static void
 test_bond (void)
 {
+	NM_PRAGMA_WARNING_DISABLE("-Wtautological-compare")
 	if (SETUP == nm_linux_platform_setup &&
 	    !g_file_test ("/proc/1/net/bonding", G_FILE_TEST_IS_DIR) &&
 	    system("modprobe --show bonding") != 0) {
 		g_test_skip ("Skipping test for bonding: bonding module not available");
 		return;
 	}
+	NM_PRAGMA_WARNING_REENABLE
 
 	test_software (NM_LINK_TYPE_BOND, "bond");
 }
@@ -538,6 +540,12 @@ test_external (void)
 }
 
 void
+init_tests (int *argc, char ***argv)
+{
+	nmtst_init_with_logging (argc, argv, NULL, "ALL");
+}
+
+void
 setup_tests (void)
 {
 	nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c
index 2c70b412..2d3caaf1 100644
--- a/src/platform/tests/test-route.c
+++ b/src/platform/tests/test-route.c
@@ -2,6 +2,7 @@
 
 #include "test-common.h"
 #include "nm-test-utils.h"
+#include "NetworkManagerUtils.h"
 
 #define DEVICE_NAME "nm-test-device"
 
@@ -50,6 +51,75 @@ ip6_route_callback (NMPlatform *platform, int ifindex, NMPlatformIP6Route *recei
 }
 
 static void
+test_ip4_route_metric0 (void)
+{
+	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_route_callback);
+	SignalData *route_changed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip4_route_callback);
+	SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_route_callback);
+	in_addr_t network = nmtst_inet4_from_string ("192.0.2.5"); /* from 192.0.2.0/24 (TEST-NET-1) (rfc5737) */
+	int plen = 32;
+	int metric = 22987;
+	int mss = 1000;
+
+	/* No routes initially */
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, metric);
+
+	/* add the first route */
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss));
+	no_error ();
+	accept_signal (route_added);
+
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
+	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
+
+	/* Deleting route with metric 0 does nothing */
+	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, 0));
+	no_error ();
+	g_assert (!route_removed->received);
+
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
+	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
+
+	/* add the second route */
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss));
+	no_error ();
+	accept_signal (route_added);
+
+	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, 0);
+	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
+
+	/* Delete route with metric 0 */
+	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, 0));
+	no_error ();
+	accept_signal (route_removed);
+
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
+	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
+
+	/* Delete route with metric 0 again (we expect nothing to happen) */
+	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, 0));
+	no_error ();
+	g_assert (!route_removed->received);
+
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
+	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
+
+	/* Delete the other route */
+	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, metric));
+	no_error ();
+	accept_signal (route_removed);
+
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, metric);
+
+	free_signal (route_added);
+	free_signal (route_changed);
+	free_signal (route_removed);
+}
+
+static void
 test_ip4_route (void)
 {
 	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
@@ -74,11 +144,11 @@ test_ip4_route (void)
 	accept_signal (route_added);
 
 	/* Add route */
-	g_assert (!nm_platform_ip4_route_exists (ifindex, network, plen, metric));
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, metric);
 	no_error ();
 	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
 	no_error ();
-	g_assert (nm_platform_ip4_route_exists (ifindex, network, plen, metric));
+	assert_ip4_route_exists (TRUE, DEVICE_NAME, network, plen, metric);
 	no_error ();
 	accept_signal (route_added);
 
@@ -88,11 +158,11 @@ test_ip4_route (void)
 	accept_signal (route_changed);
 
 	/* Add default route */
-	g_assert (!nm_platform_ip4_route_exists (ifindex, 0, 0, metric));
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, 0, 0, metric);
 	no_error ();
 	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
 	no_error ();
-	g_assert (nm_platform_ip4_route_exists (ifindex, 0, 0, metric));
+	assert_ip4_route_exists (TRUE, DEVICE_NAME, 0, 0, metric);
 	no_error ();
 	accept_signal (route_added);
 
@@ -127,13 +197,13 @@ test_ip4_route (void)
 	rts[2].mss = mss;
 	g_assert_cmpint (routes->len, ==, 3);
 	g_assert (!memcmp (routes->data, rts, sizeof (rts)));
-	nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len);
+	nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE);
 	g_array_unref (routes);
 
 	/* Remove route */
 	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, metric));
 	no_error ();
-	g_assert (!nm_platform_ip4_route_exists (ifindex, network, plen, metric));
+	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, metric);
 	accept_signal (route_removed);
 
 	/* Remove route again */
@@ -205,25 +275,25 @@ test_ip6_route (void)
 	rts[0].plen = 128;
 	rts[0].ifindex = ifindex;
 	rts[0].gateway = in6addr_any;
-	rts[0].metric = metric;
+	rts[0].metric = nm_utils_ip6_route_metric_normalize (metric);
 	rts[0].mss = mss;
 	rts[1].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[1].network = network;
 	rts[1].plen = plen;
 	rts[1].ifindex = ifindex;
 	rts[1].gateway = gateway;
-	rts[1].metric = metric;
+	rts[1].metric = nm_utils_ip6_route_metric_normalize (metric);
 	rts[1].mss = mss;
 	rts[2].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[2].network = in6addr_any;
 	rts[2].plen = 0;
 	rts[2].ifindex = ifindex;
 	rts[2].gateway = gateway;
-	rts[2].metric = metric;
+	rts[2].metric = nm_utils_ip6_route_metric_normalize (metric);
 	rts[2].mss = mss;
 	g_assert_cmpint (routes->len, ==, 3);
 	g_assert (!memcmp (routes->data, rts, sizeof (rts)));
-	nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len);
+	nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len, TRUE);
 	g_array_unref (routes);
 
 	/* Remove route */
@@ -242,6 +312,12 @@ test_ip6_route (void)
 }
 
 void
+init_tests (int *argc, char ***argv)
+{
+	nmtst_init_with_logging (argc, argv, NULL, "ALL");
+}
+
+void
 setup_tests (void)
 {
 	SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
@@ -256,4 +332,5 @@ setup_tests (void)
 
 	g_test_add_func ("/route/ip4", test_ip4_route);
 	g_test_add_func ("/route/ip6", test_ip6_route);
+	g_test_add_func ("/route/ip4_metric0", test_ip4_route_metric0);
 }
diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c
index 752da926..b31ffa1c 100644
--- a/src/platform/wifi/wifi-utils-nl80211.c
+++ b/src/platform/wifi/wifi-utils-nl80211.c
@@ -738,6 +738,7 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 		}
 	}
 
+	/* Find number of supported frequencies */
 	info->num_freqs = 0;
 
 	nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) {
@@ -757,6 +758,7 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 		}
 	}
 
+	/* Read supported frequencies */
 	info->freqs = g_malloc0 (sizeof (guint32) * info->num_freqs);
 
 	freq_idx = 0;
@@ -775,10 +777,19 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 
 			info->freqs[freq_idx] =
 				nla_get_u32 (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+
+			info->caps |= NM_WIFI_DEVICE_CAP_FREQ_VALID;
+
+			if (info->freqs[freq_idx] > 2400 && info->freqs[freq_idx] < 2500)
+				info->caps |= NM_WIFI_DEVICE_CAP_FREQ_2GHZ;
+			if (info->freqs[freq_idx] > 4900 && info->freqs[freq_idx] < 6000)
+				info->caps |= NM_WIFI_DEVICE_CAP_FREQ_5GHZ;
+
 			freq_idx++;
 		}
 	}
 
+	/* Read security/encryption support */
 	if (tb[NL80211_ATTR_CIPHER_SUITES]) {
 		int num;
 		int i;
diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c
index e0331de7..8428010a 100644
--- a/src/platform/wifi/wifi-utils-wext.c
+++ b/src/platform/wifi/wifi-utils-wext.c
@@ -569,6 +569,7 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	guint32 response_len = 0;
 	struct iw_range_with_scan_capa *scan_capa_range;
 	int i;
+	gboolean freq_valid = FALSE, has_5ghz = FALSE, has_2ghz = FALSE;
 
 	wext = wifi_data_new (iface, ifindex, sizeof (*wext));
 	wext->parent.get_mode = wifi_wext_get_mode;
@@ -609,8 +610,14 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	wext->max_qual.updated = range.max_qual.updated;
 
 	wext->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES);
-	for (i = 0; i < wext->num_freqs; i++)
+	for (i = 0; i < wext->num_freqs; i++) {
 		wext->freqs[i] = iw_freq_to_uint32 (&range.freq[i]);
+		freq_valid = TRUE;
+		if (wext->freqs[i] > 2400 && wext->freqs[i] < 2500)
+			has_2ghz = TRUE;
+		else if (wext->freqs[i] > 4900 && wext->freqs[i] < 6000)
+			has_5ghz = TRUE;
+	}
 
 	/* Check for scanning capability; cards that can't scan are not supported */
 	if (check_scan && (wext_can_scan (wext) == FALSE)) {
@@ -638,6 +645,12 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	}
 
 	wext->parent.caps = wext_get_caps (wext, &range);
+	if (freq_valid)
+		wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_VALID;
+	if (has_2ghz)
+		wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_2GHZ;
+	if (has_5ghz)
+		wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_5GHZ;
 
 	nm_log_info (LOGD_HW | LOGD_WIFI,
 	             "(%s): using WEXT for WiFi device control",
diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h
index f1b57ace..eb37bc22 100644
--- a/src/platform/wifi/wifi-utils.h
+++ b/src/platform/wifi/wifi-utils.h
@@ -44,7 +44,8 @@ gboolean wifi_utils_set_mode (WifiData *data, const NM80211Mode mode);
 /* Returns frequency in MHz */
 guint32 wifi_utils_get_freq (WifiData *data);
 
-/* Return the first supported frequency in the zero-terminated list */
+/* Return the first supported frequency in the zero-terminated list.
+ * Frequencies are specified in MHz. */
 guint32 wifi_utils_find_freq (WifiData *data, const guint32 *freqs);
 
 /* Caller must free returned byte array */
diff --git a/src/ppp-manager/Makefile.in b/src/ppp-manager/Makefile.in
index 775e4b5a..ddbb7de0 100644
--- a/src/ppp-manager/Makefile.in
+++ b/src/ppp-manager/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/ppp-manager
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -205,6 +214,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -231,7 +242,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -266,6 +276,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -503,7 +514,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/ppp-manager/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/ppp-manager/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -573,14 +583,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -802,6 +812,8 @@ uninstall-am: uninstall-pppd_pluginLTLIBRARIES
 	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
 	uninstall-pppd_pluginLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index 4fac96dc..65993deb 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -68,6 +68,7 @@ static gboolean impl_ppp_manager_set_ip6_config (NMPPPManager *manager,
 #include "nm-ppp-manager-glue.h"
 
 static void _ppp_cleanup  (NMPPPManager *manager);
+static void _ppp_kill (NMPPPManager *manager);
 
 #define NM_PPPD_PLUGIN PPPD_PLUGIN_DIR "/nm-pppd-plugin.so"
 #define PPP_MANAGER_SECRET_TRIES "ppp-manager-secret-tries"
@@ -139,6 +140,7 @@ dispose (GObject *object)
 	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (object);
 
 	_ppp_cleanup (NM_PPP_MANAGER (object));
+	_ppp_kill (NM_PPP_MANAGER (object));
 
 	g_clear_object (&priv->act_req);
 
@@ -836,6 +838,7 @@ pppd_timed_out (gpointer data)
 
 	nm_log_warn (LOGD_PPP, "pppd timed out or didn't initialize our dbus module");
 	_ppp_cleanup (manager);
+	_ppp_kill (manager);
 
 	g_signal_emit (manager, signals[STATE_CHANGED], 0, NM_PPP_STATUS_DEAD);
 
@@ -1160,6 +1163,21 @@ out:
 }
 
 static void
+_ppp_kill (NMPPPManager *manager)
+{
+	NMPPPManagerPrivate *priv;
+
+	g_return_if_fail (NM_IS_PPP_MANAGER (manager));
+
+	priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
+
+	if (priv->pid) {
+		nm_utils_kill_child_async (priv->pid, SIGTERM, LOGD_PPP, "pppd", 2000, NULL, NULL);
+		priv->pid = 0;
+	}
+}
+
+static void
 _ppp_cleanup (NMPPPManager *manager)
 {
 	NMPPPManagerPrivate *priv;
@@ -1191,9 +1209,96 @@ _ppp_cleanup (NMPPPManager *manager)
 		g_source_remove (priv->ppp_watch_id);
 		priv->ppp_watch_id = 0;
 	}
+}
 
-	if (priv->pid) {
-		nm_utils_kill_child_async (priv->pid, SIGTERM, LOGD_PPP, "pppd", 2000, NULL, NULL);
-		priv->pid = 0;
+/***********************************************************/
+
+typedef struct {
+	NMPPPManager *manager;
+	GSimpleAsyncResult *result;
+	GCancellable *cancellable;
+} StopContext;
+
+static void
+stop_context_complete (StopContext *ctx)
+{
+	if (ctx->cancellable)
+		g_object_unref (ctx->cancellable);
+	g_simple_async_result_complete_in_idle (ctx->result);
+	g_object_unref (ctx->result);
+	g_object_unref (ctx->manager);
+	g_slice_free (StopContext, ctx);
+}
+
+static gboolean
+stop_context_complete_if_cancelled (StopContext *ctx)
+{
+	GError *error = NULL;
+
+	if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) {
+		g_simple_async_result_take_error (ctx->result, error);
+		stop_context_complete (ctx);
+		return TRUE;
 	}
+	return FALSE;
+}
+
+gboolean
+nm_ppp_manager_stop_finish (NMPPPManager *manager,
+                            GAsyncResult *res,
+                            GError **error)
+{
+	return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+kill_child_ready  (pid_t pid,
+                   gboolean success,
+                   int child_status,
+                   StopContext *ctx)
+{
+	if (stop_context_complete_if_cancelled (ctx))
+		return;
+	stop_context_complete (ctx);
+}
+
+void
+nm_ppp_manager_stop (NMPPPManager *manager,
+                     GCancellable *cancellable,
+                     GAsyncReadyCallback callback,
+                     gpointer user_data)
+{
+	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
+	StopContext *ctx;
+
+	ctx = g_slice_new0 (StopContext);
+	ctx->manager = g_object_ref (manager);
+	ctx->result = g_simple_async_result_new (G_OBJECT (manager),
+	                                         callback,
+	                                         user_data,
+	                                         nm_ppp_manager_stop);
+
+	/* Setup cancellable */
+	ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	if (stop_context_complete_if_cancelled (ctx))
+		return;
+
+	/* Cleanup internals */
+	_ppp_cleanup (manager);
+
+	/* If no pppd running, we're done */
+	if (!priv->pid) {
+		stop_context_complete (ctx);
+		return;
+	}
+
+	/* No cancellable operation, so just wait until it returns always */
+	nm_utils_kill_child_async (priv->pid,
+	                           SIGTERM,
+	                           LOGD_PPP,
+	                           "pppd",
+	                           2000,
+	                           (NMUtilsKillChildAsyncCb) kill_child_ready,
+	                           ctx);
+	priv->pid = 0;
 }
diff --git a/src/ppp-manager/nm-ppp-manager.h b/src/ppp-manager/nm-ppp-manager.h
index 84be76d0..f8cbda13 100644
--- a/src/ppp-manager/nm-ppp-manager.h
+++ b/src/ppp-manager/nm-ppp-manager.h
@@ -24,6 +24,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
+#include <gio/gio.h>
 
 #include "nm-ppp-status.h"
 #include "nm-activation-request.h"
@@ -69,5 +70,12 @@ gboolean nm_ppp_manager_start (NMPPPManager *manager,
                                guint32 timeout_secs,
                                GError **err);
 
+void     nm_ppp_manager_stop        (NMPPPManager *manager,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data);
+gboolean nm_ppp_manager_stop_finish (NMPPPManager *manager,
+                                     GAsyncResult *res,
+                                     GError **error);
 
 #endif /* __NETWORKMANAGER_PPP_MANAGER_H__ */
diff --git a/src/rdisc/Makefile.in b/src/rdisc/Makefile.in
index 47a71931..349616f7 100644
--- a/src/rdisc/Makefile.in
+++ b/src/rdisc/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,7 +88,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/rdisc
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -95,6 +104,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -154,6 +164,7 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -205,7 +216,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -240,6 +250,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -456,7 +467,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/rdisc/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/rdisc/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -751,6 +761,8 @@ uninstall-am:
 	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
 	ps ps-am tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/rdisc/nm-fake-rdisc.c b/src/rdisc/nm-fake-rdisc.c
index e631f28d..68f43c0e 100644
--- a/src/rdisc/nm-fake-rdisc.c
+++ b/src/rdisc/nm-fake-rdisc.c
@@ -24,6 +24,7 @@
 #include <arpa/inet.h>
 
 #include "nm-fake-rdisc.h"
+#include "nm-rdisc-private.h"
 
 #include "nm-logging.h"
 
@@ -31,10 +32,314 @@
 #define warning(...) nm_log_warn (LOGD_IP6, __VA_ARGS__)
 #define error(...) nm_log_err (LOGD_IP6, __VA_ARGS__)
 
+typedef struct {
+	guint id;
+	guint when;
+
+	NMRDiscDHCPLevel dhcp_level;
+	GArray *gateways;
+	GArray *addresses;
+	GArray *routes;
+	GArray *dns_servers;
+	GArray *dns_domains;
+	int hop_limit;
+	guint32 mtu;
+} FakeRa;
+
+typedef struct {
+	guint receive_ra_id;
+	GSList *ras;
+} NMFakeRDiscPrivate;
+
 #define NM_FAKE_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_RDISC, NMFakeRDiscPrivate))
 
 G_DEFINE_TYPE (NMFakeRDisc, nm_fake_rdisc, NM_TYPE_RDISC)
 
+enum {
+	RS_SENT,
+	LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/******************************************************************/
+
+static void
+fake_ra_free (gpointer data)
+{
+	FakeRa *ra = data;
+
+	g_array_free (ra->gateways, TRUE);
+	g_array_free (ra->addresses, TRUE);
+	g_array_free (ra->routes, TRUE);
+	g_array_free (ra->dns_servers, TRUE);
+	g_array_free (ra->dns_domains, TRUE);
+	g_free (ra);
+}
+
+static void
+ra_dns_domain_free (gpointer data)
+{
+	g_free (((NMRDiscDNSDomain *)(data))->domain);
+}
+
+static FakeRa *
+find_ra (GSList *ras, guint id)
+{
+	GSList *iter;
+
+	for (iter = ras; iter; iter = iter->next) {
+		if (((FakeRa *) iter->data)->id == id)
+			return iter->data;
+	}
+	return NULL;
+}
+
+guint
+nm_fake_rdisc_add_ra (NMFakeRDisc *self,
+                      guint seconds_after_previous,
+                      NMRDiscDHCPLevel dhcp_level,
+                      int hop_limit,
+                      guint32 mtu)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	static guint counter = 1;
+	FakeRa *ra;
+
+	ra = g_malloc0 (sizeof (*ra));
+	ra->id = counter++;
+	ra->when = seconds_after_previous;
+	ra->dhcp_level = dhcp_level;
+	ra->hop_limit = hop_limit;
+	ra->mtu = mtu;
+	ra->gateways = g_array_new (FALSE, FALSE, sizeof (NMRDiscGateway));
+	ra->addresses = g_array_new (FALSE, FALSE, sizeof (NMRDiscAddress));
+	ra->routes = g_array_new (FALSE, FALSE, sizeof (NMRDiscRoute));
+	ra->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSServer));
+	ra->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSDomain));
+	g_array_set_clear_func (ra->dns_domains, ra_dns_domain_free);
+
+	priv->ras = g_slist_append (priv->ras, ra);
+	return ra->id;
+}
+
+void
+nm_fake_rdisc_add_gateway (NMFakeRDisc *self,
+                           guint ra_id,
+                           const char *addr,
+                           guint32 timestamp,
+                           guint32 lifetime,
+                           NMRDiscPreference preference)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscGateway *gw;
+
+	g_assert (ra);
+	g_array_set_size (ra->gateways, ra->gateways->len + 1);
+	gw = &g_array_index (ra->gateways, NMRDiscGateway, ra->gateways->len - 1);
+	g_assert (inet_pton (AF_INET6, addr, &gw->address) == 1);
+	gw->timestamp = timestamp;
+	gw->lifetime = lifetime;
+	gw->preference = preference;
+}
+
+void
+nm_fake_rdisc_add_address (NMFakeRDisc *self,
+                           guint ra_id,
+                           const char *addr,
+                           guint32 timestamp,
+                           guint32 lifetime,
+                           guint32 preferred)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscAddress *a;
+
+	g_assert (ra);
+	g_array_set_size (ra->addresses, ra->addresses->len + 1);
+	a = &g_array_index (ra->addresses, NMRDiscAddress, ra->addresses->len - 1);
+	g_assert (inet_pton (AF_INET6, addr, &a->address) == 1);
+	a->timestamp = timestamp;
+	a->lifetime = lifetime;
+	a->preferred = preferred;
+}
+
+void
+nm_fake_rdisc_add_route (NMFakeRDisc *self,
+                         guint ra_id,
+                         const char *network,
+                         guint plen,
+                         const char *gateway,
+                         guint32 timestamp,
+                         guint32 lifetime,
+                         NMRDiscPreference preference)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscRoute *route;
+
+	g_assert (ra);
+	g_array_set_size (ra->routes, ra->routes->len + 1);
+	route = &g_array_index (ra->routes, NMRDiscRoute, ra->routes->len - 1);
+	g_assert (inet_pton (AF_INET6, network, &route->network) == 1);
+	g_assert (inet_pton (AF_INET6, gateway, &route->gateway) == 1);
+	route->plen = plen;
+	route->timestamp = timestamp;
+	route->lifetime = lifetime;
+	route->preference = preference;
+}
+
+void
+nm_fake_rdisc_add_dns_server (NMFakeRDisc *self,
+                              guint ra_id,
+                              const char *address,
+                              guint32 timestamp,
+                              guint32 lifetime)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscDNSServer *dns;
+
+	g_assert (ra);
+	g_array_set_size (ra->dns_servers, ra->dns_servers->len + 1);
+	dns = &g_array_index (ra->dns_servers, NMRDiscDNSServer, ra->dns_servers->len - 1);
+	g_assert (inet_pton (AF_INET6, address, &dns->address) == 1);
+	dns->timestamp = timestamp;
+	dns->lifetime = lifetime;
+}
+
+void
+nm_fake_rdisc_add_dns_domain (NMFakeRDisc *self,
+                              guint ra_id,
+                              const char *domain,
+                              guint32 timestamp,
+                              guint32 lifetime)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscDNSDomain *dns;
+
+	g_assert (ra);
+	g_array_set_size (ra->dns_domains, ra->dns_domains->len + 1);
+	dns = &g_array_index (ra->dns_domains, NMRDiscDNSDomain, ra->dns_domains->len - 1);
+	dns->domain = g_strdup (domain);
+	dns->timestamp = timestamp;
+	dns->lifetime = lifetime;
+}
+
+gboolean
+nm_fake_rdisc_done (NMFakeRDisc *self)
+{
+	return !NM_FAKE_RDISC_GET_PRIVATE (self)->ras;
+}
+
+/******************************************************************/
+
+static gboolean
+send_rs (NMRDisc *rdisc)
+{
+	g_signal_emit (rdisc, signals[RS_SENT], 0);
+	return TRUE;
+}
+
+static gboolean
+receive_ra (gpointer user_data)
+{
+	NMFakeRDisc *self = user_data;
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	NMRDisc *rdisc = NM_RDISC (self);
+	FakeRa *ra = priv->ras->data;
+	NMRDiscConfigMap changed = 0;
+	guint32 now = nm_utils_get_monotonic_timestamp_s ();
+	guint i;
+
+	priv->receive_ra_id = 0;
+
+	if (rdisc->dhcp_level != ra->dhcp_level) {
+		rdisc->dhcp_level = ra->dhcp_level;
+		changed |= NM_RDISC_CONFIG_DHCP_LEVEL;
+	}
+
+	for (i = 0; i < ra->gateways->len; i++) {
+		NMRDiscGateway *item = &g_array_index (ra->gateways, NMRDiscGateway, i);
+
+		if (nm_rdisc_add_gateway (rdisc, item))
+			changed |= NM_RDISC_CONFIG_GATEWAYS;
+	}
+
+	for (i = 0; i < ra->addresses->len; i++) {
+		NMRDiscAddress *item = &g_array_index (ra->addresses, NMRDiscAddress, i);
+
+		if (nm_rdisc_add_address (rdisc, item))
+			changed |= NM_RDISC_CONFIG_ADDRESSES;
+	}
+
+	for (i = 0; i < ra->routes->len; i++) {
+		NMRDiscRoute *item = &g_array_index (ra->routes, NMRDiscRoute, i);
+
+		if (nm_rdisc_add_route (rdisc, item))
+			changed |= NM_RDISC_CONFIG_ROUTES;
+	}
+
+	for (i = 0; i < ra->dns_servers->len; i++) {
+		NMRDiscDNSServer *item = &g_array_index (ra->dns_servers, NMRDiscDNSServer, i);
+
+		if (nm_rdisc_add_dns_server (rdisc, item))
+			changed |= NM_RDISC_CONFIG_DNS_SERVERS;
+	}
+
+	for (i = 0; i < ra->dns_domains->len; i++) {
+		NMRDiscDNSDomain *item = &g_array_index (ra->dns_domains, NMRDiscDNSDomain, i);
+
+		if (nm_rdisc_add_dns_domain (rdisc, item))
+			changed |= NM_RDISC_CONFIG_DNS_DOMAINS;
+	}
+
+	if (rdisc->mtu != ra->mtu) {
+		rdisc->mtu = ra->mtu;
+		changed |= NM_RDISC_CONFIG_MTU;
+	}
+
+	if (rdisc->hop_limit != ra->hop_limit) {
+		rdisc->hop_limit = ra->hop_limit;
+		changed |= NM_RDISC_CONFIG_HOP_LIMIT;
+	}
+
+	priv->ras = g_slist_remove (priv->ras, priv->ras->data);
+	fake_ra_free (ra);
+
+	nm_rdisc_ra_received (NM_RDISC (self), now, changed);
+
+	/* Schedule next RA */
+	if (priv->ras) {
+		ra = priv->ras->data;
+		priv->receive_ra_id = g_timeout_add_seconds (ra->when, receive_ra, self);
+	}
+
+	return G_SOURCE_REMOVE;
+}
+
+static void
+start (NMRDisc *rdisc)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (rdisc);
+	FakeRa *ra;
+
+	/* Queue up the first fake RA */
+	g_assert (priv->ras);
+	ra = NM_FAKE_RDISC_GET_PRIVATE (rdisc)->ras->data;
+
+	g_assert (!priv->receive_ra_id);
+	priv->receive_ra_id = g_timeout_add_seconds (ra->when, receive_ra, rdisc);
+}
+
+void
+nm_fake_rdisc_emit_new_ras (NMFakeRDisc *self)
+{
+	if (!NM_FAKE_RDISC_GET_PRIVATE (self)->receive_ra_id)
+		start (NM_RDISC (self));
+}
+
 /******************************************************************/
 
 NMRDisc *
@@ -52,85 +357,42 @@ nm_fake_rdisc_new (int ifindex, const char *ifname)
 }
 
 static void
-delayed_start (NMRDisc *rdisc)
+nm_fake_rdisc_init (NMFakeRDisc *fake_rdisc)
 {
-	int changed =
-		NM_RDISC_CONFIG_GATEWAYS | NM_RDISC_CONFIG_ADDRESSES | NM_RDISC_CONFIG_ROUTES |
-		NM_RDISC_CONFIG_DNS_SERVERS | NM_RDISC_CONFIG_DNS_DOMAINS;
-	debug ("%d", rdisc->dhcp_level);
-
-	g_signal_emit_by_name (
-			rdisc, NM_RDISC_CONFIG_CHANGED, changed);
 }
 
 static void
-start (NMRDisc *rdisc)
+dispose (GObject *object)
 {
-	g_idle_add ((GSourceFunc) (delayed_start), rdisc);
-}
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (object);
 
-/******************************************************************/
+	if (priv->receive_ra_id) {
+		g_source_remove (priv->receive_ra_id);
+		priv->receive_ra_id = 0;
+	}
 
-static void
-nm_fake_rdisc_init (NMFakeRDisc *fake_rdisc)
-{
-	NMRDisc *rdisc = NM_RDISC (fake_rdisc);
-	NMRDiscGateway gateway;
-	NMRDiscAddress address;
-	NMRDiscRoute route;
-	NMRDiscDNSServer dns_server;
-	NMRDiscDNSDomain dns_domain;
-
-	rdisc->dhcp_level = NM_RDISC_DHCP_LEVEL_NONE;
-
-	memset (&gateway, 0, sizeof (gateway));
-	inet_pton (AF_INET6, "fe80::1", &gateway.address);
-	g_array_append_val (rdisc->gateways, gateway);
-	inet_pton (AF_INET6, "fe80::2", &gateway.address);
-	g_array_append_val (rdisc->gateways, gateway);
-	inet_pton (AF_INET6, "fe80::3", &gateway.address);
-	g_array_append_val (rdisc->gateways, gateway);
-
-	memset (&address, 0, sizeof (address));
-	inet_pton (AF_INET6, "2001:db8:a:a::1", &address.address);
-	g_array_append_val (rdisc->addresses, address);
-	inet_pton (AF_INET6, "2001:db8:a:a::2", &address.address);
-	g_array_append_val (rdisc->addresses, address);
-	inet_pton (AF_INET6, "2001:db8:f:f::1", &address.address);
-	g_array_append_val (rdisc->addresses, address);
-
-	memset (&route, 0, sizeof (route));
-	route.plen = 64;
-	inet_pton (AF_INET6, "2001:db8:a:a::", &route.network);
-	g_array_append_val (rdisc->routes, route);
-	inet_pton (AF_INET6, "2001:db8:b:b::", &route.network);
-	g_array_append_val (rdisc->routes, route);
-
-	memset (&dns_server, 0, sizeof (dns_server));
-	inet_pton (AF_INET6, "2001:db8:c:c::1", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-	inet_pton (AF_INET6, "2001:db8:c:c::2", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-	inet_pton (AF_INET6, "2001:db8:c:c::3", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-	inet_pton (AF_INET6, "2001:db8:c:c::4", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-	inet_pton (AF_INET6, "2001:db8:c:c::5", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-
-	memset (&dns_domain, 0, sizeof (dns_domain));
-	dns_domain.domain = g_strdup ("example.net");
-	g_array_append_val (rdisc->dns_domains, dns_domain);
-	dns_domain.domain = g_strdup ("example.com");
-	g_array_append_val (rdisc->dns_domains, dns_domain);
-	dns_domain.domain = g_strdup ("example.org");
-	g_array_append_val (rdisc->dns_domains, dns_domain);
+	g_slist_free_full (priv->ras, fake_ra_free);
+	priv->ras = NULL;
+
+	G_OBJECT_CLASS (nm_fake_rdisc_parent_class)->dispose (object);
 }
 
 static void
 nm_fake_rdisc_class_init (NMFakeRDiscClass *klass)
 {
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	NMRDiscClass *rdisc_class = NM_RDISC_CLASS (klass);
 
+	g_type_class_add_private (klass, sizeof (NMFakeRDiscPrivate));
+
+	object_class->dispose = dispose;
 	rdisc_class->start = start;
+	rdisc_class->send_rs = send_rs;
+
+	signals[RS_SENT] = g_signal_new (
+			NM_FAKE_RDISC_RS_SENT,
+			G_OBJECT_CLASS_TYPE (klass),
+			G_SIGNAL_RUN_FIRST,
+			0,  NULL, NULL, NULL,
+			G_TYPE_NONE, 0);
 }
diff --git a/src/rdisc/nm-fake-rdisc.h b/src/rdisc/nm-fake-rdisc.h
index b4eff7ec..74f74897 100644
--- a/src/rdisc/nm-fake-rdisc.h
+++ b/src/rdisc/nm-fake-rdisc.h
@@ -30,7 +30,7 @@
 #define NM_IS_FAKE_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_FAKE_RDISC))
 #define NM_FAKE_RDISC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_FAKE_RDISC, NMFakeRDiscClass))
 
-/******************************************************************/
+#define NM_FAKE_RDISC_RS_SENT "rs-sent"
 
 typedef struct {
 	NMRDisc parent;
@@ -46,4 +46,49 @@ GType nm_fake_rdisc_get_type (void);
 
 NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname);
 
+guint nm_fake_rdisc_add_ra (NMFakeRDisc *self,
+                            guint seconds,
+                            NMRDiscDHCPLevel dhcp_level,
+                            int hop_limit,
+                            guint32 mtu);
+
+void nm_fake_rdisc_add_gateway    (NMFakeRDisc *self,
+                                   guint ra_id,
+                                   const char *addr,
+                                   guint32 timestamp,
+                                   guint32 lifetime,
+                                   NMRDiscPreference preference);
+
+void nm_fake_rdisc_add_address    (NMFakeRDisc *self,
+                                   guint ra_id,
+                                   const char *addr,
+                                   guint32 timestamp,
+                                   guint32 lifetime,
+                                   guint32 preferred);
+
+void nm_fake_rdisc_add_route      (NMFakeRDisc *self,
+                                   guint ra_id,
+                                   const char *network,
+                                   guint plen,
+                                   const char *gateway,
+                                   guint32 timestamp,
+                                   guint32 lifetime,
+                                   NMRDiscPreference preference);
+
+void nm_fake_rdisc_add_dns_server (NMFakeRDisc *self,
+                                   guint ra_id,
+                                   const char *address,
+                                   guint32 timestamp,
+                                   guint32 lifetime);
+
+void nm_fake_rdisc_add_dns_domain (NMFakeRDisc *self,
+                                   guint ra_id,
+                                   const char *domain,
+                                   guint32 timestamp,
+                                   guint32 lifetime);
+
+void nm_fake_rdisc_emit_new_ras (NMFakeRDisc *self);
+
+gboolean nm_fake_rdisc_done (NMFakeRDisc *self);
+
 #endif /* __NETWORKMANAGER_FAKE_RDISC_H__ */
diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c
index ff1bd33d..cadbfdfa 100644
--- a/src/rdisc/nm-lndp-rdisc.c
+++ b/src/rdisc/nm-lndp-rdisc.c
@@ -27,6 +27,7 @@
 #include <ndp.h>
 
 #include "nm-lndp-rdisc.h"
+#include "nm-rdisc-private.h"
 
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
@@ -39,13 +40,9 @@
 typedef struct {
 	struct ndp *ndp;
 
-	guint send_rs_id;
 	GIOChannel *event_channel;
 	guint event_id;
-	guint timeout_id;   /* prefix/dns/etc lifetime timeout */
 	guint ra_timeout_id;  /* first RA timeout */
-
-	int solicitations_left;
 } NMLNDPRDiscPrivate;
 
 #define NM_LNDP_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LNDP_RDISC, NMLNDPRDiscPrivate))
@@ -54,185 +51,6 @@ G_DEFINE_TYPE (NMLNDPRDisc, nm_lndp_rdisc, NM_TYPE_RDISC)
 
 /******************************************************************/
 
-static inline gint32
-ipv6_sysctl_get (const char *ifname, const char *property, gint32 defval)
-{
-	return nm_platform_sysctl_get_int32 (nm_utils_ip6_property_path (ifname, property), defval);
-}
-
-NMRDisc *
-nm_lndp_rdisc_new (int ifindex, const char *ifname)
-{
-	NMRDisc *rdisc;
-	NMLNDPRDiscPrivate *priv;
-	int error;
-
-	rdisc = g_object_new (NM_TYPE_LNDP_RDISC, NULL);
-
-	rdisc->ifindex = ifindex;
-	rdisc->ifname = g_strdup (ifname);
-
-	rdisc->max_addresses = ipv6_sysctl_get (ifname, "max_addresses",
-	                                        NM_RDISC_MAX_ADDRESSES_DEFAULT);
-	rdisc->rtr_solicitations = ipv6_sysctl_get (ifname, "router_solicitations",
-	                                            NM_RDISC_RTR_SOLICITATIONS_DEFAULT);
-	rdisc->rtr_solicitation_interval = ipv6_sysctl_get (ifname, "router_solicitation_interval",
-	                                                    NM_RDISC_RTR_SOLICITATION_INTERVAL_DEFAULT);
-
-	priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
-	error = ndp_open (&priv->ndp);
-	if (error != 0) {
-		g_object_unref (rdisc);
-		debug ("(%s): error creating socket for NDP; errno=%d", ifname, -error);
-		return NULL;
-	}
-	return rdisc;
-}
-
-static gboolean
-add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new)
-{
-	int i;
-
-	for (i = 0; i < rdisc->gateways->len; i++) {
-		NMRDiscGateway *item = &g_array_index (rdisc->gateways, NMRDiscGateway, i);
-
-		if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) {
-			if (item->preference != new->preference) {
-				g_array_remove_index (rdisc->gateways, i--);
-				continue;
-			}
-			memcpy (item, new, sizeof (*new));
-			return FALSE;
-		}
-
-		/* Put before less preferable gateways. */
-		if (item->preference < new->preference)
-			break;
-	}
-
-	g_array_insert_val (rdisc->gateways, i, *new);
-	return TRUE;
-}
-
-static gboolean
-add_address (NMRDisc *rdisc, const NMRDiscAddress *new)
-{
-	int i;
-
-	for (i = 0; i < rdisc->addresses->len; i++) {
-		NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i);
-
-		if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) {
-			gboolean changed = item->timestamp + item->lifetime  != new->timestamp + new->lifetime ||
-			                   item->timestamp + item->preferred != new->timestamp + new->preferred;
-
-			*item = *new;
-			return changed;
-		}
-	}
-
-	/* we create at most max_addresses autoconf addresses. This is different from
-	 * what the kernel does, because it considers *all* addresses (including
-	 * static and other temporary addresses).
-	 **/
-	if (rdisc->max_addresses && rdisc->addresses->len >= rdisc->max_addresses)
-		return FALSE;
-
-	g_array_insert_val (rdisc->addresses, i, *new);
-	return TRUE;
-}
-
-static gboolean
-add_route (NMRDisc *rdisc, const NMRDiscRoute *new)
-{
-	int i;
-
-	for (i = 0; i < rdisc->routes->len; i++) {
-		NMRDiscRoute *item = &g_array_index (rdisc->routes, NMRDiscRoute, i);
-
-		if (IN6_ARE_ADDR_EQUAL (&item->network, &new->network) && item->plen == new->plen) {
-			if (item->preference != new->preference) {
-				g_array_remove_index (rdisc->routes, i--);
-				continue;
-			}
-			memcpy (item, new, sizeof (*new));
-			return FALSE;
-		}
-
-		/* Put before less preferable routes. */
-		if (item->preference < new->preference)
-			break;
-	}
-
-	g_array_insert_val (rdisc->routes, i, *new);
-	return TRUE;
-}
-
-static gboolean
-add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new)
-{
-	int i;
-
-	for (i = 0; i < rdisc->dns_servers->len; i++) {
-		NMRDiscDNSServer *item = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i);
-
-		if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) {
-			gboolean changed;
-
-			if (new->lifetime == 0) {
-				g_array_remove_index (rdisc->dns_servers, i);
-				return TRUE;
-			}
-
-			changed = (item->timestamp != new->timestamp ||
-			           item->lifetime != new->lifetime);
-			if (changed) {
-				item->timestamp = new->timestamp;
-				item->lifetime = new->lifetime;
-			}
-			return changed;
-		}
-	}
-
-	g_array_insert_val (rdisc->dns_servers, i, *new);
-	return TRUE;
-}
-
-/* Copies new->domain if 'new' is added to the dns_domains list */
-static gboolean
-add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new)
-{
-	NMRDiscDNSDomain *item;
-	int i;
-
-	for (i = 0; i < rdisc->dns_domains->len; i++) {
-		item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i);
-
-		if (!g_strcmp0 (item->domain, new->domain)) {
-			gboolean changed;
-
-			if (new->lifetime == 0) {
-				g_array_remove_index (rdisc->dns_domains, i);
-				return TRUE;
-			}
-
-			changed = (item->timestamp != new->timestamp ||
-			           item->lifetime != new->lifetime);
-			if (changed) {
-				item->timestamp = new->timestamp;
-				item->lifetime = new->lifetime;
-			}
-			return changed;
-		}
-	}
-
-	g_array_insert_val (rdisc->dns_domains, i, *new);
-	item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i);
-	item->domain = g_strdup (new->domain);
-	return TRUE;
-}
-
 static gboolean
 send_rs (NMRDisc *rdisc)
 {
@@ -244,185 +62,12 @@ send_rs (NMRDisc *rdisc)
 	g_assert (!error);
 	ndp_msg_ifindex_set (msg, rdisc->ifindex);
 
-	debug ("(%s): sending router solicitation", rdisc->ifname);
-
 	error = ndp_msg_send (priv->ndp, msg);
-	if (error)
-		error ("(%s): cannot send router solicitation: %d.", rdisc->ifname, error);
-	else
-		priv->solicitations_left--;
-
 	ndp_msg_destroy (msg);
-
-	if (priv->solicitations_left > 0) {
-		debug ("(%s): scheduling router solicitation retry in %d seconds.",
-		       rdisc->ifname, rdisc->rtr_solicitation_interval);
-		priv->send_rs_id = g_timeout_add_seconds (rdisc->rtr_solicitation_interval,
-		                                          (GSourceFunc) send_rs, rdisc);
-	} else {
-		debug ("(%s): did not receive a router advertisement after %d solicitations.",
-		       rdisc->ifname, rdisc->rtr_solicitations);
-		priv->send_rs_id = 0;
-	}
-
-	return G_SOURCE_REMOVE;
-}
-
-static void
-solicit (NMRDisc *rdisc)
-{
-	NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
-
-	if (!priv->send_rs_id) {
-		debug ("(%s): scheduling router solicitation.", rdisc->ifname);
-		priv->send_rs_id = g_idle_add ((GSourceFunc) send_rs, rdisc);
-		priv->solicitations_left = rdisc->rtr_solicitations;
-	}
-}
-
-static void
-clean_gateways (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
-{
-	int i;
-
-	for (i = 0; i < rdisc->gateways->len; i++) {
-		NMRDiscGateway *item = &g_array_index (rdisc->gateways, NMRDiscGateway, i);
-		guint64 expiry = (guint64) item->timestamp + item->lifetime;
-
-		if (item->lifetime == G_MAXUINT32)
-			continue;
-
-		if (now >= expiry) {
-			g_array_remove_index (rdisc->gateways, i--);
-			*changed |= NM_RDISC_CONFIG_GATEWAYS;
-		} else if (*nextevent > expiry)
-			*nextevent = expiry;
-	}
-}
-
-static void
-clean_addresses (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
-{
-	int i;
-
-	for (i = 0; i < rdisc->addresses->len; i++) {
-		NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i);
-		guint64 expiry = (guint64) item->timestamp + item->lifetime;
-
-		if (item->lifetime == G_MAXUINT32)
-			continue;
-
-		if (now >= expiry) {
-			g_array_remove_index (rdisc->addresses, i--);
-			*changed |= NM_RDISC_CONFIG_ADDRESSES;
-		} else if (*nextevent > expiry)
-			*nextevent = expiry;
-	}
-}
-
-static void
-clean_routes (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
-{
-	int i;
-
-	for (i = 0; i < rdisc->routes->len; i++) {
-		NMRDiscRoute *item = &g_array_index (rdisc->routes, NMRDiscRoute, i);
-		guint64 expiry = (guint64) item->timestamp + item->lifetime;
-
-		if (item->lifetime == G_MAXUINT32)
-			continue;
-
-		if (now >= expiry) {
-			g_array_remove_index (rdisc->routes, i--);
-			*changed |= NM_RDISC_CONFIG_ROUTES;
-		} else if (*nextevent > expiry)
-			*nextevent = expiry;
-	}
-}
-
-static void
-clean_dns_servers (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
-{
-	int i;
-
-	for (i = 0; i < rdisc->dns_servers->len; i++) {
-		NMRDiscDNSServer *item = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i);
-		guint64 expiry = (guint64) item->timestamp + item->lifetime;
-		guint64 refresh = (guint64) item->timestamp + item->lifetime / 2;
-
-		if (item->lifetime == G_MAXUINT32)
-			continue;
-
-		if (now >= expiry) {
-			g_array_remove_index (rdisc->dns_servers, i--);
-			*changed |= NM_RDISC_CONFIG_DNS_SERVERS;
-		} else if (now >= refresh)
-			solicit (rdisc);
-		else if (*nextevent > refresh)
-			*nextevent = refresh;
-	}
-}
-
-static void
-clean_dns_domains (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
-{
-	int i;
-
-	for (i = 0; i < rdisc->dns_domains->len; i++) {
-		NMRDiscDNSDomain *item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i);
-		guint64 expiry = (guint64) item->timestamp + item->lifetime;
-		guint64 refresh = (guint64) item->timestamp + item->lifetime / 2;
-
-		if (item->lifetime == G_MAXUINT32)
-			continue;
-
-		if (now >= expiry) {
-			g_free (item->domain);
-			g_array_remove_index (rdisc->dns_domains, i--);
-			*changed |= NM_RDISC_CONFIG_DNS_DOMAINS;
-		} else if (now >= refresh)
-			solicit (rdisc);
-		else if (*nextevent > refresh)
-			*nextevent = refresh;
-	}
-}
-
-static gboolean timeout_cb (gpointer user_data);
-
-static void
-check_timestamps (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed)
-{
-	NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
-	/* Use a magic date in the distant future (~68 years) */
-	guint32 never = G_MAXINT32;
-	guint32 nextevent = never;
-
-	if (priv->timeout_id) {
-		g_source_remove (priv->timeout_id);
-		priv->timeout_id = 0;
-	}
-
-	clean_gateways (rdisc, now, &changed, &nextevent);
-	clean_addresses (rdisc, now, &changed, &nextevent);
-	clean_routes (rdisc, now, &changed, &nextevent);
-	clean_dns_servers (rdisc, now, &changed, &nextevent);
-	clean_dns_domains (rdisc, now, &changed, &nextevent);
-
-	if (changed)
-		g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, changed);
-
-	if (nextevent != never) {
-		g_return_if_fail (nextevent > now);
-		debug ("(%s): scheduling next now/lifetime check: %u seconds",
-		       rdisc->ifname, nextevent - now);
-		priv->timeout_id = g_timeout_add_seconds (nextevent - now, timeout_cb, rdisc);
+	if (error) {
+		error ("(%s): cannot send router solicitation: %d.", rdisc->ifname, error);
+		return FALSE;
 	}
-}
-
-static gboolean
-timeout_cb (gpointer user_data)
-{
-	check_timestamps (user_data, nm_utils_get_monotonic_timestamp_s (), 0);
 
 	return TRUE;
 }
@@ -442,28 +87,6 @@ translate_preference (enum ndp_route_preference preference)
 	}
 }
 
-static void
-clear_rs_timeout (NMLNDPRDisc *rdisc)
-{
-	NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
-
-	if (priv->send_rs_id) {
-		g_source_remove (priv->send_rs_id);
-		priv->send_rs_id = 0;
-	}
-}
-
-static void
-clear_ra_timeout (NMLNDPRDisc *rdisc)
-{
-	NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
-
-	if (priv->ra_timeout_id) {
-		g_source_remove (priv->ra_timeout_id);
-		priv->ra_timeout_id = 0;
-	}
-}
-
 static int
 receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 {
@@ -488,9 +111,6 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 	 */
 	debug ("(%s): received router advertisement at %u", rdisc->ifname, now);
 
-	clear_ra_timeout (NM_LNDP_RDISC (rdisc));
-	clear_rs_timeout (NM_LNDP_RDISC (rdisc));
-
 	/* DHCP level:
 	 *
 	 * The problem with DHCP level is what to do if subsequent
@@ -524,7 +144,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 	gateway.timestamp = now;
 	gateway.lifetime = ndp_msgra_router_lifetime (msgra);
 	gateway.preference = translate_preference (ndp_msgra_route_preference (msgra));
-	if (add_gateway (rdisc, &gateway))
+	if (nm_rdisc_add_gateway (rdisc, &gateway))
 		changed |= NM_RDISC_CONFIG_GATEWAYS;
 
 	/* Addresses & Routes */
@@ -539,7 +159,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 		route.timestamp = now;
 		if (ndp_msg_opt_prefix_flag_on_link (msg, offset)) {
 			route.lifetime = ndp_msg_opt_prefix_valid_time (msg, offset);
-			if (add_route (rdisc, &route))
+			if (nm_rdisc_add_route (rdisc, &route))
 				changed |= NM_RDISC_CONFIG_ROUTES;
 		}
 
@@ -557,7 +177,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 				/* Add the Interface Identifier to the lower 64 bits */
 				nm_utils_ipv6_addr_set_interface_identfier (&address.address, rdisc->iid);
 
-				if (add_address (rdisc, &address))
+				if (nm_rdisc_add_address (rdisc, &address))
 					changed |= NM_RDISC_CONFIG_ADDRESSES;
 			}
 		}
@@ -573,7 +193,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 		route.timestamp = now;
 		route.lifetime = ndp_msg_opt_route_lifetime (msg, offset);
 		route.preference = translate_preference (ndp_msg_opt_route_preference (msg, offset));
-		if (add_route (rdisc, &route))
+		if (nm_rdisc_add_route (rdisc, &route))
 			changed |= NM_RDISC_CONFIG_ROUTES;
 	}
 
@@ -596,7 +216,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 			 */
 			if (dns_server.lifetime && dns_server.lifetime < 7200)
 				dns_server.lifetime = 7200;
-			if (add_dns_server (rdisc, &dns_server))
+			if (nm_rdisc_add_dns_server (rdisc, &dns_server))
 				changed |= NM_RDISC_CONFIG_DNS_SERVERS;
 		}
 	}
@@ -618,7 +238,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 			 */
 			if (dns_domain.lifetime && dns_domain.lifetime < 7200)
 				dns_domain.lifetime = 7200;
-			if (add_dns_domain (rdisc, &dns_domain))
+			if (nm_rdisc_add_dns_domain (rdisc, &dns_domain))
 				changed |= NM_RDISC_CONFIG_DNS_DOMAINS;
 		}
 	}
@@ -644,8 +264,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 		}
 	}
 
-	check_timestamps (rdisc, now, changed);
-
+	nm_rdisc_ra_received (rdisc, now, changed);
 	return 0;
 }
 
@@ -659,41 +278,58 @@ event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc)
 	return G_SOURCE_CONTINUE;
 }
 
-static gboolean
-rdisc_ra_timeout_cb (gpointer user_data)
-{
-	NMLNDPRDisc *rdisc = NM_LNDP_RDISC (user_data);
-	NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
-
-	priv->ra_timeout_id = 0;
-	g_signal_emit_by_name (rdisc, NM_RDISC_RA_TIMEOUT);
-	return G_SOURCE_REMOVE;
-}
-
 static void
 start (NMRDisc *rdisc)
 {
 	NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
 	int fd = ndp_get_eventfd (priv->ndp);
-	guint ra_wait_secs;
 
 	priv->event_channel = g_io_channel_unix_new (fd);
 	priv->event_id = g_io_add_watch (priv->event_channel, G_IO_IN, (GIOFunc) event_ready, rdisc);
 
-	clear_ra_timeout (NM_LNDP_RDISC (rdisc));
-	ra_wait_secs = CLAMP (rdisc->rtr_solicitations * rdisc->rtr_solicitation_interval, 30, 120);
-	priv->ra_timeout_id = g_timeout_add_seconds (ra_wait_secs, rdisc_ra_timeout_cb, rdisc);
-	debug ("(%s): scheduling RA timeout in %d seconds", rdisc->ifname, ra_wait_secs);
-
 	/* Flush any pending messages to avoid using obsolete information */
 	event_ready (priv->event_channel, 0, rdisc);
 
 	ndp_msgrcv_handler_register (priv->ndp, receive_ra, NDP_MSG_RA, rdisc->ifindex, rdisc);
-	solicit (rdisc);
 }
 
 /******************************************************************/
 
+static inline gint32
+ipv6_sysctl_get (const char *ifname, const char *property, gint32 defval)
+{
+	return nm_platform_sysctl_get_int32 (nm_utils_ip6_property_path (ifname, property), defval);
+}
+
+NMRDisc *
+nm_lndp_rdisc_new (int ifindex, const char *ifname)
+{
+	NMRDisc *rdisc;
+	NMLNDPRDiscPrivate *priv;
+	int error;
+
+	rdisc = g_object_new (NM_TYPE_LNDP_RDISC, NULL);
+
+	rdisc->ifindex = ifindex;
+	rdisc->ifname = g_strdup (ifname);
+
+	rdisc->max_addresses = ipv6_sysctl_get (ifname, "max_addresses",
+	                                        NM_RDISC_MAX_ADDRESSES_DEFAULT);
+	rdisc->rtr_solicitations = ipv6_sysctl_get (ifname, "router_solicitations",
+	                                            NM_RDISC_RTR_SOLICITATIONS_DEFAULT);
+	rdisc->rtr_solicitation_interval = ipv6_sysctl_get (ifname, "router_solicitation_interval",
+	                                                    NM_RDISC_RTR_SOLICITATION_INTERVAL_DEFAULT);
+
+	priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
+	error = ndp_open (&priv->ndp);
+	if (error != 0) {
+		g_object_unref (rdisc);
+		debug ("(%s): error creating socket for NDP; errno=%d", ifname, -error);
+		return NULL;
+	}
+	return rdisc;
+}
+
 static void
 nm_lndp_rdisc_init (NMLNDPRDisc *lndp_rdisc)
 {
@@ -705,14 +341,6 @@ dispose (GObject *object)
 	NMLNDPRDisc *rdisc = NM_LNDP_RDISC (object);
 	NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
 
-	clear_rs_timeout (rdisc);
-	clear_ra_timeout (rdisc);
-
-	if (priv->timeout_id) {
-		g_source_remove (priv->timeout_id);
-		priv->timeout_id = 0;
-	}
-
 	if (priv->event_id) {
 		g_source_remove (priv->event_id);
 		priv->event_id = 0;
@@ -720,9 +348,12 @@ dispose (GObject *object)
 	g_clear_pointer (&priv->event_channel, g_io_channel_unref);
 
 	if (priv->ndp) {
+		ndp_msgrcv_handler_unregister (priv->ndp, receive_ra, NDP_MSG_RA, NM_RDISC (rdisc)->ifindex, rdisc);
 		ndp_close (priv->ndp);
 		priv->ndp = NULL;
 	}
+
+	G_OBJECT_CLASS (nm_lndp_rdisc_parent_class)->dispose (object);
 }
 
 static void
@@ -735,4 +366,5 @@ nm_lndp_rdisc_class_init (NMLNDPRDiscClass *klass)
 
 	object_class->dispose = dispose;
 	rdisc_class->start = start;
+	rdisc_class->send_rs = send_rs;
 }
diff --git a/src/rdisc/nm-rdisc-private.h b/src/rdisc/nm-rdisc-private.h
new file mode 100644
index 00000000..f95949de
--- /dev/null
+++ b/src/rdisc/nm-rdisc-private.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-rdisc.h - Perform IPv6 router discovery
+ *
+ * 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 2015 Red Hat, Inc.
+ */
+
+#ifndef __NETWORKMANAGER_RDISC_PRIVATE_H__
+#define __NETWORKMANAGER_RDISC_PRIVATE_H__
+
+#include "nm-rdisc.h"
+
+/* Functions only used by rdisc implementations */
+
+void nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed);
+
+gboolean nm_rdisc_add_gateway    (NMRDisc *rdisc, const NMRDiscGateway *new);
+gboolean nm_rdisc_add_address    (NMRDisc *rdisc, const NMRDiscAddress *new);
+gboolean nm_rdisc_add_route      (NMRDisc *rdisc, const NMRDiscRoute *new);
+gboolean nm_rdisc_add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new);
+gboolean nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new);
+
+#endif /* __NETWORKMANAGER_RDISC_PRIVATE_H__ */
diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c
index 8729fa63..07271a89 100644
--- a/src/rdisc/nm-rdisc.c
+++ b/src/rdisc/nm-rdisc.c
@@ -22,14 +22,26 @@
 
 #include <stdlib.h>
 #include <arpa/inet.h>
+#include <string.h>
 
 #include "nm-rdisc.h"
+#include "nm-rdisc-private.h"
 
 #include "nm-logging.h"
 #include "nm-utils.h"
 
 #define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__)
 
+typedef struct {
+	int solicitations_left;
+	guint send_rs_id;
+	gint64 last_rs;
+	guint ra_timeout_id;  /* first RA timeout */
+	guint timeout_id;   /* prefix/dns/etc lifetime timeout */
+} NMRDiscPrivate;
+
+#define NM_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_RDISC, NMRDiscPrivate))
+
 G_DEFINE_TYPE (NMRDisc, nm_rdisc, G_TYPE_OBJECT)
 
 enum {
@@ -42,6 +54,193 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 /******************************************************************/
 
+gboolean
+nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new)
+{
+	int i, insert_idx = -1;
+
+	for (i = 0; i < rdisc->gateways->len; i++) {
+		NMRDiscGateway *item = &g_array_index (rdisc->gateways, NMRDiscGateway, i);
+
+		if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) {
+			if (new->lifetime == 0) {
+				g_array_remove_index (rdisc->gateways, i--);
+				return TRUE;
+			}
+
+			if (item->preference != new->preference) {
+				g_array_remove_index (rdisc->gateways, i--);
+				continue;
+			}
+
+			memcpy (item, new, sizeof (*new));
+			return FALSE;
+		}
+
+		/* Put before less preferable gateways. */
+		if (item->preference < new->preference && insert_idx < 0)
+			insert_idx = i;
+	}
+
+	if (new->lifetime)
+		g_array_insert_val (rdisc->gateways, CLAMP (insert_idx, 0, G_MAXINT), *new);
+	return !!new->lifetime;
+}
+
+gboolean
+nm_rdisc_add_address (NMRDisc *rdisc, const NMRDiscAddress *new)
+{
+	int i;
+
+	for (i = 0; i < rdisc->addresses->len; i++) {
+		NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i);
+
+		if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) {
+			gboolean changed;
+
+			if (new->lifetime == 0) {
+				g_array_remove_index (rdisc->addresses, i--);
+				return TRUE;
+			}
+
+			changed = item->timestamp + item->lifetime  != new->timestamp + new->lifetime ||
+			          item->timestamp + item->preferred != new->timestamp + new->preferred;
+			*item = *new;
+			return changed;
+		}
+	}
+
+	/* we create at most max_addresses autoconf addresses. This is different from
+	 * what the kernel does, because it considers *all* addresses (including
+	 * static and other temporary addresses).
+	 **/
+	if (rdisc->max_addresses && rdisc->addresses->len >= rdisc->max_addresses)
+		return FALSE;
+
+	if (new->lifetime)
+		g_array_insert_val (rdisc->addresses, i, *new);
+	return !!new->lifetime;
+}
+
+gboolean
+nm_rdisc_add_route (NMRDisc *rdisc, const NMRDiscRoute *new)
+{
+	int i, insert_idx = -1;
+
+	for (i = 0; i < rdisc->routes->len; i++) {
+		NMRDiscRoute *item = &g_array_index (rdisc->routes, NMRDiscRoute, i);
+
+		if (IN6_ARE_ADDR_EQUAL (&item->network, &new->network) && item->plen == new->plen) {
+			if (new->lifetime == 0) {
+				g_array_remove_index (rdisc->routes, i--);
+				return TRUE;
+			}
+
+			if (item->preference != new->preference) {
+				g_array_remove_index (rdisc->routes, i--);
+				continue;
+			}
+
+			memcpy (item, new, sizeof (*new));
+			return FALSE;
+		}
+
+		/* Put before less preferable routes. */
+		if (item->preference < new->preference && insert_idx < 0)
+			insert_idx = i;
+	}
+
+	if (new->lifetime)
+		g_array_insert_val (rdisc->routes, CLAMP (insert_idx, 0, G_MAXINT), *new);
+	return !!new->lifetime;
+}
+
+gboolean
+nm_rdisc_add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new)
+{
+	int i;
+
+	for (i = 0; i < rdisc->dns_servers->len; i++) {
+		NMRDiscDNSServer *item = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i);
+
+		if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) {
+			if (new->lifetime == 0) {
+				g_array_remove_index (rdisc->dns_servers, i);
+				return TRUE;
+			}
+			if (item->timestamp != new->timestamp || item->lifetime != new->lifetime) {
+				*item = *new;
+				return TRUE;
+			}
+			return FALSE;
+		}
+	}
+
+	if (new->lifetime)
+		g_array_insert_val (rdisc->dns_servers, i, *new);
+	return !!new->lifetime;
+}
+
+/* Copies new->domain if 'new' is added to the dns_domains list */
+gboolean
+nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new)
+{
+	NMRDiscDNSDomain *item;
+	int i;
+
+	for (i = 0; i < rdisc->dns_domains->len; i++) {
+		item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i);
+
+		if (!g_strcmp0 (item->domain, new->domain)) {
+			gboolean changed;
+
+			if (new->lifetime == 0) {
+				g_array_remove_index (rdisc->dns_domains, i);
+				return TRUE;
+			}
+
+			changed = (item->timestamp != new->timestamp ||
+			           item->lifetime != new->lifetime);
+			if (changed) {
+				item->timestamp = new->timestamp;
+				item->lifetime = new->lifetime;
+			}
+			return changed;
+		}
+	}
+
+	if (new->lifetime) {
+		g_array_insert_val (rdisc->dns_domains, i, *new);
+		item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i);
+		item->domain = g_strdup (new->domain);
+	}
+	return !!new->lifetime;
+}
+
+/******************************************************************/
+
+static void
+clear_ra_timeout (NMRDisc *rdisc)
+{
+	NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
+
+	if (priv->ra_timeout_id) {
+		g_source_remove (priv->ra_timeout_id);
+		priv->ra_timeout_id = 0;
+	}
+}
+
+static void
+clear_rs_timeout (NMRDisc *rdisc)
+{
+	NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
+
+	if (priv->send_rs_id) {
+		g_source_remove (priv->send_rs_id);
+		priv->send_rs_id = 0;
+	}
+}
+
 void
 nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid)
 {
@@ -50,17 +249,79 @@ nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid)
 	rdisc->iid = iid;
 }
 
+static gboolean
+send_rs (NMRDisc *rdisc)
+{
+	NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc);
+	NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
+
+	debug ("(%s): sending router solicitation", rdisc->ifname);
+
+	if (klass->send_rs (rdisc))
+		priv->solicitations_left--;
+
+	priv->last_rs = nm_utils_get_monotonic_timestamp_s ();
+	if (priv->solicitations_left > 0) {
+		debug ("(%s): scheduling router solicitation retry in %d seconds.",
+		       rdisc->ifname, rdisc->rtr_solicitation_interval);
+		priv->send_rs_id = g_timeout_add_seconds (rdisc->rtr_solicitation_interval,
+		                                          (GSourceFunc) send_rs, rdisc);
+	} else {
+		debug ("(%s): did not receive a router advertisement after %d solicitations.",
+		       rdisc->ifname, rdisc->rtr_solicitations);
+		priv->send_rs_id = 0;
+	}
+
+	return G_SOURCE_REMOVE;
+}
+
+static void
+solicit (NMRDisc *rdisc)
+{
+	NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
+	guint32 now = nm_utils_get_monotonic_timestamp_s ();
+	gint64 next;
+
+	if (!priv->send_rs_id) {
+		priv->solicitations_left = rdisc->rtr_solicitations;
+
+		next = CLAMP (priv->last_rs + rdisc->rtr_solicitation_interval - now, 0, G_MAXINT32);
+		debug ("(%s): scheduling explicit router solicitation request in %" G_GINT64_FORMAT " seconds.",
+		       rdisc->ifname, next);
+		priv->send_rs_id = g_timeout_add_seconds ((guint32) next, (GSourceFunc) send_rs, rdisc);
+	}
+}
+
+static gboolean
+rdisc_ra_timeout_cb (gpointer user_data)
+{
+	NMRDisc *rdisc = NM_RDISC (user_data);
+
+	NM_RDISC_GET_PRIVATE (rdisc)->ra_timeout_id = 0;
+	g_signal_emit_by_name (rdisc, NM_RDISC_RA_TIMEOUT);
+	return G_SOURCE_REMOVE;
+}
+
 void
 nm_rdisc_start (NMRDisc *rdisc)
 {
+	NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
 	NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc);
+	guint ra_wait_secs;
 
 	g_assert (klass->start);
 
 	debug ("(%s): starting router discovery: %d", rdisc->ifname, rdisc->ifindex);
 
+	clear_ra_timeout (rdisc);
+	ra_wait_secs = CLAMP (rdisc->rtr_solicitations * rdisc->rtr_solicitation_interval, 30, 120);
+	priv->ra_timeout_id = g_timeout_add_seconds (ra_wait_secs, rdisc_ra_timeout_cb, rdisc);
+	debug ("(%s): scheduling RA timeout in %d seconds", rdisc->ifname, ra_wait_secs);
+
 	if (klass->start)
 		klass->start (rdisc);
+
+	solicit (rdisc);
 }
 
 #define CONFIG_MAP_MAX_STR 7
@@ -145,21 +406,206 @@ config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed)
 	}
 }
 
+static void
+clean_gateways (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
+{
+	int i;
+
+	for (i = 0; i < rdisc->gateways->len; i++) {
+		NMRDiscGateway *item = &g_array_index (rdisc->gateways, NMRDiscGateway, i);
+		guint64 expiry = (guint64) item->timestamp + item->lifetime;
+
+		if (item->lifetime == G_MAXUINT32)
+			continue;
+
+		if (now >= expiry) {
+			g_array_remove_index (rdisc->gateways, i--);
+			*changed |= NM_RDISC_CONFIG_GATEWAYS;
+		} else if (*nextevent > expiry)
+			*nextevent = expiry;
+	}
+}
+
+static void
+clean_addresses (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
+{
+	int i;
+
+	for (i = 0; i < rdisc->addresses->len; i++) {
+		NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i);
+		guint64 expiry = (guint64) item->timestamp + item->lifetime;
+
+		if (item->lifetime == G_MAXUINT32)
+			continue;
+
+		if (now >= expiry) {
+			g_array_remove_index (rdisc->addresses, i--);
+			*changed |= NM_RDISC_CONFIG_ADDRESSES;
+		} else if (*nextevent > expiry)
+			*nextevent = expiry;
+	}
+}
+
+static void
+clean_routes (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
+{
+	int i;
+
+	for (i = 0; i < rdisc->routes->len; i++) {
+		NMRDiscRoute *item = &g_array_index (rdisc->routes, NMRDiscRoute, i);
+		guint64 expiry = (guint64) item->timestamp + item->lifetime;
+
+		if (item->lifetime == G_MAXUINT32)
+			continue;
+
+		if (now >= expiry) {
+			g_array_remove_index (rdisc->routes, i--);
+			*changed |= NM_RDISC_CONFIG_ROUTES;
+		} else if (*nextevent > expiry)
+			*nextevent = expiry;
+	}
+}
+
+static void
+clean_dns_servers (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
+{
+	int i;
+
+	for (i = 0; i < rdisc->dns_servers->len; i++) {
+		NMRDiscDNSServer *item = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i);
+		guint64 expiry = (guint64) item->timestamp + item->lifetime;
+		guint64 refresh = (guint64) item->timestamp + item->lifetime / 2;
+
+		if (item->lifetime == G_MAXUINT32)
+			continue;
+
+		if (now >= expiry) {
+			g_array_remove_index (rdisc->dns_servers, i--);
+			*changed |= NM_RDISC_CONFIG_DNS_SERVERS;
+		} else if (now >= refresh)
+			solicit (rdisc);
+		else if (*nextevent > refresh)
+			*nextevent = refresh;
+	}
+}
+
+static void
+clean_dns_domains (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent)
+{
+	int i;
+
+	for (i = 0; i < rdisc->dns_domains->len; i++) {
+		NMRDiscDNSDomain *item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i);
+		guint64 expiry = (guint64) item->timestamp + item->lifetime;
+		guint64 refresh = (guint64) item->timestamp + item->lifetime / 2;
+
+		if (item->lifetime == G_MAXUINT32)
+			continue;
+
+		if (now >= expiry) {
+			g_array_remove_index (rdisc->dns_domains, i--);
+			*changed |= NM_RDISC_CONFIG_DNS_DOMAINS;
+		} else if (now >= refresh)
+			solicit (rdisc);
+		else if (*nextevent > refresh)
+			*nextevent = refresh;
+	}
+}
+
+static gboolean timeout_cb (gpointer user_data);
+
+static void
+check_timestamps (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed)
+{
+	NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
+	/* Use a magic date in the distant future (~68 years) */
+	guint32 never = G_MAXINT32;
+	guint32 nextevent = never;
+
+	if (priv->timeout_id) {
+		g_source_remove (priv->timeout_id);
+		priv->timeout_id = 0;
+	}
+
+	clean_gateways (rdisc, now, &changed, &nextevent);
+	clean_addresses (rdisc, now, &changed, &nextevent);
+	clean_routes (rdisc, now, &changed, &nextevent);
+	clean_dns_servers (rdisc, now, &changed, &nextevent);
+	clean_dns_domains (rdisc, now, &changed, &nextevent);
+
+	if (changed)
+		g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, changed);
+
+	if (nextevent != never) {
+		g_return_if_fail (nextevent > now);
+		debug ("(%s): scheduling next now/lifetime check: %u seconds",
+		       rdisc->ifname, nextevent - now);
+		priv->timeout_id = g_timeout_add_seconds (nextevent - now, timeout_cb, rdisc);
+	}
+}
+
+static gboolean
+timeout_cb (gpointer user_data)
+{
+	NM_RDISC_GET_PRIVATE (user_data)->timeout_id = 0;
+	check_timestamps (NM_RDISC (user_data), nm_utils_get_monotonic_timestamp_s (), 0);
+	return G_SOURCE_REMOVE;
+}
+
+void
+nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed)
+{
+	clear_ra_timeout (rdisc);
+	clear_rs_timeout (rdisc);
+	check_timestamps (rdisc, now, changed);
+}
+
 /******************************************************************/
 
 static void
+dns_domain_free (gpointer data)
+{
+	g_free (((NMRDiscDNSDomain *)(data))->domain);
+}
+
+static void
 nm_rdisc_init (NMRDisc *rdisc)
 {
+	NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
+
 	rdisc->gateways = g_array_new (FALSE, FALSE, sizeof (NMRDiscGateway));
 	rdisc->addresses = g_array_new (FALSE, FALSE, sizeof (NMRDiscAddress));
 	rdisc->routes = g_array_new (FALSE, FALSE, sizeof (NMRDiscRoute));
 	rdisc->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSServer));
 	rdisc->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSDomain));
+	g_array_set_clear_func (rdisc->dns_domains, dns_domain_free);
 	rdisc->hop_limit = 64;
+
+	/* Start at very low number so that last_rs - rtr_solicitation_interval
+	 * is much lower than nm_utils_get_monotonic_timestamp_s() at startup.
+	 */
+	priv->last_rs = G_MININT32;
 }
 
 static void
-nm_rdisc_finalize (GObject *object)
+dispose (GObject *object)
+{
+	NMRDisc *rdisc = NM_RDISC (object);
+	NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
+
+	clear_ra_timeout (rdisc);
+	clear_rs_timeout (rdisc);
+
+	if (priv->timeout_id) {
+		g_source_remove (priv->timeout_id);
+		priv->timeout_id = 0;
+	}
+
+	G_OBJECT_CLASS (nm_rdisc_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
 {
 	NMRDisc *rdisc = NM_RDISC (object);
 
@@ -169,6 +615,8 @@ nm_rdisc_finalize (GObject *object)
 	g_array_unref (rdisc->routes);
 	g_array_unref (rdisc->dns_servers);
 	g_array_unref (rdisc->dns_domains);
+
+	G_OBJECT_CLASS (nm_rdisc_parent_class)->finalize (object);
 }
 
 static void
@@ -176,8 +624,10 @@ nm_rdisc_class_init (NMRDiscClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-	object_class->finalize = nm_rdisc_finalize;
+	g_type_class_add_private (klass, sizeof (NMRDiscPrivate));
 
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
 	klass->config_changed = config_changed;
 
 	signals[CONFIG_CHANGED] = g_signal_new (
diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h
index 2d83f0f0..a79e6c96 100644
--- a/src/rdisc/nm-rdisc.h
+++ b/src/rdisc/nm-rdisc.h
@@ -133,7 +133,9 @@ typedef struct {
 	GObjectClass parent;
 
 	void (*start) (NMRDisc *rdisc);
+	gboolean (*send_rs) (NMRDisc *rdisc);
 	void (*config_changed) (NMRDisc *rdisc, NMRDiscConfigMap changed);
+	void (*ra_process) (NMRDisc *rdisc);
 	void (*ra_timeout) (NMRDisc *rdisc);
 } NMRDiscClass;
 
diff --git a/src/rdisc/tests/Makefile.am b/src/rdisc/tests/Makefile.am
index e6fe1369..5d6f8b5b 100644
--- a/src/rdisc/tests/Makefile.am
+++ b/src/rdisc/tests/Makefile.am
@@ -20,11 +20,18 @@ AM_LDFLAGS = \
 
 @GNOME_CODE_COVERAGE_RULES@
 
-noinst_PROGRAMS = \
-	rdisc
+noinst_PROGRAMS = test-rdisc-linux test-rdisc-fake
 
-rdisc_SOURCES = \
-	rdisc.c
-rdisc_LDADD = \
+test_rdisc_linux_SOURCES = \
+	test-rdisc-linux.c
+test_rdisc_linux_LDADD = \
 	$(top_builddir)/src/libNetworkManager.la
 
+test_rdisc_fake_SOURCES = \
+	test-rdisc-fake.c
+test_rdisc_fake_LDADD = \
+	$(top_builddir)/src/libNetworkManager.la
+
+@VALGRIND_RULES@
+TESTS = test-rdisc-fake
+
diff --git a/src/rdisc/tests/Makefile.in b/src/rdisc/tests/Makefile.in
index b2ea3c74..f241fcbf 100644
--- a/src/rdisc/tests/Makefile.in
+++ b/src/rdisc/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,10 +88,9 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-noinst_PROGRAMS = rdisc$(EXEEXT)
+noinst_PROGRAMS = test-rdisc-linux$(EXEEXT) test-rdisc-fake$(EXEEXT)
+TESTS = test-rdisc-fake$(EXEEXT)
 subdir = src/rdisc/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -98,18 +107,24 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
-am_rdisc_OBJECTS = rdisc.$(OBJEXT)
-rdisc_OBJECTS = $(am_rdisc_OBJECTS)
-rdisc_DEPENDENCIES = $(top_builddir)/src/libNetworkManager.la
+am_test_rdisc_fake_OBJECTS = test-rdisc-fake.$(OBJEXT)
+test_rdisc_fake_OBJECTS = $(am_test_rdisc_fake_OBJECTS)
+test_rdisc_fake_DEPENDENCIES =  \
+	$(top_builddir)/src/libNetworkManager.la
 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_test_rdisc_linux_OBJECTS = test-rdisc-linux.$(OBJEXT)
+test_rdisc_linux_OBJECTS = $(am_test_rdisc_linux_OBJECTS)
+test_rdisc_linux_DEPENDENCIES =  \
+	$(top_builddir)/src/libNetworkManager.la
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -144,8 +159,8 @@ 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 = $(rdisc_SOURCES)
-DIST_SOURCES = $(rdisc_SOURCES)
+SOURCES = $(test_rdisc_fake_SOURCES) $(test_rdisc_linux_SOURCES)
+DIST_SOURCES = $(test_rdisc_fake_SOURCES) $(test_rdisc_linux_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -170,6 +185,30 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -196,7 +235,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -231,6 +269,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -451,10 +490,16 @@ AM_LDFLAGS = \
 	$(DBUS_LIBS) \
 	$(CODE_COVERAGE_LDFLAGS)
 
-rdisc_SOURCES = \
-	rdisc.c
+test_rdisc_linux_SOURCES = \
+	test-rdisc-linux.c
 
-rdisc_LDADD = \
+test_rdisc_linux_LDADD = \
+	$(top_builddir)/src/libNetworkManager.la
+
+test_rdisc_fake_SOURCES = \
+	test-rdisc-fake.c
+
+test_rdisc_fake_LDADD = \
 	$(top_builddir)/src/libNetworkManager.la
 
 all: all-am
@@ -473,7 +518,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/rdisc/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/rdisc/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -501,9 +545,13 @@ clean-noinstPROGRAMS:
 	echo " rm -f" $$list; \
 	rm -f $$list
 
-rdisc$(EXEEXT): $(rdisc_OBJECTS) $(rdisc_DEPENDENCIES) $(EXTRA_rdisc_DEPENDENCIES) 
-	@rm -f rdisc$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(rdisc_OBJECTS) $(rdisc_LDADD) $(LIBS)
+test-rdisc-fake$(EXEEXT): $(test_rdisc_fake_OBJECTS) $(test_rdisc_fake_DEPENDENCIES) $(EXTRA_test_rdisc_fake_DEPENDENCIES) 
+	@rm -f test-rdisc-fake$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_rdisc_fake_OBJECTS) $(test_rdisc_fake_LDADD) $(LIBS)
+
+test-rdisc-linux$(EXEEXT): $(test_rdisc_linux_OBJECTS) $(test_rdisc_linux_DEPENDENCIES) $(EXTRA_test_rdisc_linux_DEPENDENCIES) 
+	@rm -f test-rdisc-linux$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_rdisc_linux_OBJECTS) $(test_rdisc_linux_LDADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -511,21 +559,22 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdisc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-rdisc-fake.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-rdisc-linux.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -592,6 +641,99 @@ cscopelist-am: $(am__tagged_files)
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list=' $(TESTS) '; \
+	$(am__tty_colors); \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=XPASS; \
+	      ;; \
+	      *) \
+		col=$$grn; res=PASS; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xfail=`expr $$xfail + 1`; \
+		col=$$lgn; res=XFAIL; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=FAIL; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      col=$$blu; res=SKIP; \
+	    fi; \
+	    echo "$${col}$$res$${std}: $$tst"; \
+	  done; \
+	  if test "$$all" -eq 1; then \
+	    tests="test"; \
+	    All=""; \
+	  else \
+	    tests="tests"; \
+	    All="All "; \
+	  fi; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="$$All$$all $$tests passed"; \
+	    else \
+	      if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+	      banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all $$tests failed"; \
+	    else \
+	      if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+	      banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    if test "$$skip" -eq 1; then \
+	      skipped="($$skip test was not run)"; \
+	    else \
+	      skipped="($$skip tests were not run)"; \
+	    fi; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  if test "$$failed" -eq 0; then \
+	    col="$$grn"; \
+	  else \
+	    col="$$red"; \
+	  fi; \
+	  echo "$${col}$$dashes$${std}"; \
+	  echo "$${col}$$banner$${std}"; \
+	  test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+	  test -z "$$report" || echo "$${col}$$report$${std}"; \
+	  echo "$${col}$$dashes$${std}"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
 distdir: $(DISTFILES)
 	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
 	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
@@ -623,6 +765,7 @@ distdir: $(DISTFILES)
 	  fi; \
 	done
 check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
 check: check-am
 all-am: Makefile $(PROGRAMS)
 installdirs:
@@ -727,11 +870,11 @@ ps-am:
 
 uninstall-am:
 
-.MAKE: install-am install-strip
+.MAKE: check-am install-am install-strip
 
-.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
-	clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \
-	ctags-am distclean distclean-compile distclean-generic \
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
 	distclean-libtool distclean-tags distdir dvi dvi-am html \
 	html-am info info-am install install-am install-data \
 	install-data-am install-dvi install-dvi-am install-exec \
@@ -743,9 +886,13 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @GNOME_CODE_COVERAGE_RULES@
 
+@VALGRIND_RULES@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/rdisc/tests/test-rdisc-fake.c b/src/rdisc/tests/test-rdisc-fake.c
new file mode 100644
index 00000000..8b7bd37a
--- /dev/null
+++ b/src/rdisc/tests/test-rdisc-fake.c
@@ -0,0 +1,453 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* rdisc.c - test program
+ *
+ * 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) 2015 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <syslog.h>
+
+#include "nm-rdisc.h"
+#include "nm-fake-rdisc.h"
+#include "nm-logging.h"
+
+#include "nm-fake-platform.h"
+
+#include "nm-test-utils.h"
+
+static NMFakeRDisc *
+rdisc_new (void)
+{
+	NMRDisc *rdisc;
+	const int ifindex = 1;
+	const char *ifname = nm_platform_link_get_name (ifindex);
+
+	rdisc = nm_fake_rdisc_new (ifindex, ifname);
+	g_assert (rdisc);
+	return NM_FAKE_RDISC (rdisc);
+}
+
+static void
+match_gateway (GArray *array, guint idx, const char *addr, guint32 ts, guint32 lt, NMRDiscPreference pref)
+{
+	NMRDiscGateway *gw = &g_array_index (array, NMRDiscGateway, idx);
+	char buf[INET6_ADDRSTRLEN];
+
+	g_assert_cmpstr (inet_ntop (AF_INET6, &gw->address, buf, sizeof (buf)), ==, addr);
+	g_assert_cmpint (gw->timestamp, ==, ts);
+	g_assert_cmpint (gw->lifetime, ==, lt);
+	g_assert_cmpint (gw->preference, ==, pref);
+}
+
+static void
+match_address (GArray *array, guint idx, const char *addr, guint32 ts, guint32 lt, guint32 preferred)
+{
+	NMRDiscAddress *a = &g_array_index (array, NMRDiscAddress, idx);
+	char buf[INET6_ADDRSTRLEN];
+
+	g_assert_cmpstr (inet_ntop (AF_INET6, &a->address, buf, sizeof (buf)), ==, addr);
+	g_assert_cmpint (a->timestamp, ==, ts);
+	g_assert_cmpint (a->lifetime, ==, lt);
+	g_assert_cmpint (a->preferred, ==, preferred);
+}
+
+static void
+match_route (GArray *array, guint idx, const char *nw, int plen, const char *gw, guint32 ts, guint32 lt, NMRDiscPreference pref)
+{
+	NMRDiscRoute *route = &g_array_index (array, NMRDiscRoute, idx);
+	char buf[INET6_ADDRSTRLEN];
+
+	g_assert_cmpstr (inet_ntop (AF_INET6, &route->network, buf, sizeof (buf)), ==, nw);
+	g_assert_cmpint (route->plen, ==, plen);
+	g_assert_cmpstr (inet_ntop (AF_INET6, &route->gateway, buf, sizeof (buf)), ==, gw);
+	g_assert_cmpint (route->timestamp, ==, ts);
+	g_assert_cmpint (route->lifetime, ==, lt);
+	g_assert_cmpint (route->preference, ==, pref);
+}
+
+static void
+match_dns_server (GArray *array, guint idx, const char *addr, guint32 ts, guint32 lt)
+{
+	NMRDiscDNSServer *dns = &g_array_index (array, NMRDiscDNSServer, idx);
+	char buf[INET6_ADDRSTRLEN];
+
+	g_assert_cmpstr (inet_ntop (AF_INET6, &dns->address, buf, sizeof (buf)), ==, addr);
+	g_assert_cmpint (dns->timestamp, ==, ts);
+	g_assert_cmpint (dns->lifetime, ==, lt);
+}
+
+static void
+match_dns_domain (GArray *array, guint idx, const char *domain, guint32 ts, guint32 lt)
+{
+	NMRDiscDNSDomain *dns = &g_array_index (array, NMRDiscDNSDomain, idx);
+
+	g_assert_cmpstr (dns->domain, ==, domain);
+	g_assert_cmpint (dns->timestamp, ==, ts);
+	g_assert_cmpint (dns->lifetime, ==, lt);
+}
+
+typedef struct {
+	GMainLoop *loop;
+	guint counter;
+	guint rs_counter;
+	guint32 timestamp1;
+	guint32 first_solicit;
+	guint32 timeout_id;
+} TestData;
+
+static void
+test_simple_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *data)
+{
+	g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_DHCP_LEVEL |
+	                              NM_RDISC_CONFIG_GATEWAYS |
+	                              NM_RDISC_CONFIG_ADDRESSES |
+	                              NM_RDISC_CONFIG_ROUTES |
+	                              NM_RDISC_CONFIG_DNS_SERVERS |
+	                              NM_RDISC_CONFIG_DNS_DOMAINS |
+	                              NM_RDISC_CONFIG_HOP_LIMIT |
+	                              NM_RDISC_CONFIG_MTU);
+	g_assert_cmpint (rdisc->dhcp_level, ==, NM_RDISC_DHCP_LEVEL_OTHERCONF);
+	match_gateway (rdisc->gateways, 0, "fe80::1", data->timestamp1, 10, NM_RDISC_PREFERENCE_MEDIUM);
+	match_address (rdisc->addresses, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
+	match_route (rdisc->routes, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 10);
+	match_dns_server (rdisc->dns_servers, 0, "2001:db8:c:c::1", data->timestamp1, 10);
+	match_dns_domain (rdisc->dns_domains, 0, "foobar.com", data->timestamp1, 10);
+
+	g_assert (nm_fake_rdisc_done (NM_FAKE_RDISC (rdisc)));
+	data->counter++;
+	g_main_loop_quit (data->loop);
+}
+
+static void
+test_simple (void)
+{
+	NMFakeRDisc *rdisc = rdisc_new ();
+	guint32 now = nm_utils_get_monotonic_timestamp_s ();
+	TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now };
+	guint id;
+
+	id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_OTHERCONF, 4, 1500);
+	g_assert (id);
+	nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_MEDIUM);
+	nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10);
+	nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10);
+	nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 10);
+	nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar.com", now, 10);
+
+	g_signal_connect (rdisc,
+	                  NM_RDISC_CONFIG_CHANGED,
+	                  G_CALLBACK (test_simple_changed),
+	                  &data);
+
+	nm_rdisc_start (NM_RDISC (rdisc));
+	g_main_loop_run (data.loop);
+	g_assert_cmpint (data.counter, ==, 1);
+
+	g_object_unref (rdisc);
+	g_main_loop_unref (data.loop);
+}
+
+static void
+test_everything_rs_sent (NMRDisc *rdisc, TestData *data)
+{
+	g_assert_cmpint (data->rs_counter, ==, 0);
+	data->rs_counter++;
+}
+
+static void
+test_everything_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *data)
+{
+	if (data->counter == 0) {
+		g_assert_cmpint (data->rs_counter, ==, 1);
+		g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_DHCP_LEVEL |
+			                          NM_RDISC_CONFIG_GATEWAYS |
+			                          NM_RDISC_CONFIG_ADDRESSES |
+			                          NM_RDISC_CONFIG_ROUTES |
+			                          NM_RDISC_CONFIG_DNS_SERVERS |
+			                          NM_RDISC_CONFIG_DNS_DOMAINS |
+			                          NM_RDISC_CONFIG_HOP_LIMIT |
+			                          NM_RDISC_CONFIG_MTU);
+		match_gateway (rdisc->gateways, 0, "fe80::1", data->timestamp1, 10, NM_RDISC_PREFERENCE_MEDIUM);
+		match_address (rdisc->addresses, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
+		match_route (rdisc->routes, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 10);
+		match_dns_server (rdisc->dns_servers, 0, "2001:db8:c:c::1", data->timestamp1, 10);
+		match_dns_domain (rdisc->dns_domains, 0, "foobar.com", data->timestamp1, 10);
+	} else if (data->counter == 1) {
+		g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_GATEWAYS |
+			                          NM_RDISC_CONFIG_ADDRESSES |
+			                          NM_RDISC_CONFIG_ROUTES |
+			                          NM_RDISC_CONFIG_DNS_SERVERS |
+			                          NM_RDISC_CONFIG_DNS_DOMAINS);
+
+		g_assert_cmpint (rdisc->gateways->len, ==, 1);
+		match_gateway (rdisc->gateways, 0, "fe80::2", data->timestamp1, 10, NM_RDISC_PREFERENCE_MEDIUM);
+		g_assert_cmpint (rdisc->addresses->len, ==, 1);
+		match_address (rdisc->addresses, 0, "2001:db8:a:a::2", data->timestamp1, 10, 10);
+		g_assert_cmpint (rdisc->routes->len, ==, 1);
+		match_route (rdisc->routes, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1, 10, 10);
+		g_assert_cmpint (rdisc->dns_servers->len, ==, 1);
+		match_dns_server (rdisc->dns_servers, 0, "2001:db8:c:c::2", data->timestamp1, 10);
+		g_assert_cmpint (rdisc->dns_domains->len, ==, 1);
+		match_dns_domain (rdisc->dns_domains, 0, "foobar2.com", data->timestamp1, 10);
+
+		g_assert (nm_fake_rdisc_done (NM_FAKE_RDISC (rdisc)));
+		g_main_loop_quit (data->loop);
+	} else
+		g_assert_not_reached ();
+
+	data->counter++;
+}
+
+static void
+test_everything (void)
+{
+	NMFakeRDisc *rdisc = rdisc_new ();
+	guint32 now = nm_utils_get_monotonic_timestamp_s ();
+	TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now };
+	guint id;
+
+	id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500);
+	g_assert (id);
+	nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_MEDIUM);
+	nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10);
+	nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10);
+	nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 10);
+	nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar.com", now, 10);
+
+	/* expire everything from the first RA in the second */
+	id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500);
+	g_assert (id);
+	nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 0, NM_RDISC_PREFERENCE_MEDIUM);
+	nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 0, 0);
+	nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 0, 0);
+	nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 0);
+	nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar.com", now, 0);
+
+	/* and add some new stuff */
+	nm_fake_rdisc_add_gateway (rdisc, id, "fe80::2", now, 10, NM_RDISC_PREFERENCE_MEDIUM);
+	nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::2", now, 10, 10);
+	nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10);
+	nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::2", now, 10);
+	nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar2.com", now, 10);
+
+	g_signal_connect (rdisc,
+	                  NM_RDISC_CONFIG_CHANGED,
+	                  G_CALLBACK (test_everything_changed),
+	                  &data);
+	g_signal_connect (rdisc,
+	                  NM_FAKE_RDISC_RS_SENT,
+	                  G_CALLBACK (test_everything_rs_sent),
+	                  &data);
+
+	nm_rdisc_start (NM_RDISC (rdisc));
+	g_main_loop_run (data.loop);
+	g_assert_cmpint (data.counter, ==, 2);
+	g_assert_cmpint (data.rs_counter, ==, 1);
+
+	g_object_unref (rdisc);
+	g_main_loop_unref (data.loop);
+}
+
+static void
+test_preference_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *data)
+{
+	if (data->counter == 1) {
+		g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_GATEWAYS |
+			                          NM_RDISC_CONFIG_ADDRESSES |
+			                          NM_RDISC_CONFIG_ROUTES);
+		g_assert_cmpint (rdisc->gateways->len, ==, 2);
+		match_gateway (rdisc->gateways, 0, "fe80::2", data->timestamp1 + 1, 10, NM_RDISC_PREFERENCE_MEDIUM);
+		match_gateway (rdisc->gateways, 1, "fe80::1", data->timestamp1, 10, NM_RDISC_PREFERENCE_LOW);
+		g_assert_cmpint (rdisc->addresses->len, ==, 2);
+		match_address (rdisc->addresses, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
+		match_address (rdisc->addresses, 1, "2001:db8:a:a::2", data->timestamp1 + 1, 10, 10);
+		g_assert_cmpint (rdisc->routes->len, ==, 2);
+		match_route (rdisc->routes, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10);
+		match_route (rdisc->routes, 1, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 5);
+	} else if (data->counter == 2) {
+		g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_GATEWAYS |
+			                          NM_RDISC_CONFIG_ADDRESSES |
+			                          NM_RDISC_CONFIG_ROUTES);
+
+		g_assert_cmpint (rdisc->gateways->len, ==, 2);
+		match_gateway (rdisc->gateways, 0, "fe80::1", data->timestamp1 + 2, 10, NM_RDISC_PREFERENCE_HIGH);
+		match_gateway (rdisc->gateways, 1, "fe80::2", data->timestamp1 + 1, 10, NM_RDISC_PREFERENCE_MEDIUM);
+		g_assert_cmpint (rdisc->addresses->len, ==, 2);
+		match_address (rdisc->addresses, 0, "2001:db8:a:a::1", data->timestamp1 + 2, 10, 10);
+		match_address (rdisc->addresses, 1, "2001:db8:a:a::2", data->timestamp1 + 1, 10, 10);
+		g_assert_cmpint (rdisc->routes->len, ==, 2);
+		match_route (rdisc->routes, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1 + 2, 10, 15);
+		match_route (rdisc->routes, 1, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10);
+
+		g_assert (nm_fake_rdisc_done (NM_FAKE_RDISC (rdisc)));
+		g_main_loop_quit (data->loop);
+	}
+
+	data->counter++;
+}
+
+static void
+test_preference (void)
+{
+	NMFakeRDisc *rdisc = rdisc_new ();
+	guint32 now = nm_utils_get_monotonic_timestamp_s ();
+	TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now };
+	guint id;
+
+	/* Test that when a low-preference and medium gateway send advertisements,
+	 * that if the low-preference gateway switches to high-preference, we do
+	 * not get duplicates in the gateway list.
+	 */
+
+	id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500);
+	g_assert (id);
+	nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_LOW);
+	nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10);
+	nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 5);
+
+	id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500);
+	g_assert (id);
+	nm_fake_rdisc_add_gateway (rdisc, id, "fe80::2", ++now, 10, NM_RDISC_PREFERENCE_MEDIUM);
+	nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::2", now, 10, 10);
+	nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10);
+
+	id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500);
+	g_assert (id);
+	nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", ++now, 10, NM_RDISC_PREFERENCE_HIGH);
+	nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10);
+	nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 15);
+
+	g_signal_connect (rdisc,
+	                  NM_RDISC_CONFIG_CHANGED,
+	                  G_CALLBACK (test_preference_changed),
+	                  &data);
+
+	nm_rdisc_start (NM_RDISC (rdisc));
+	g_main_loop_run (data.loop);
+	g_assert_cmpint (data.counter, ==, 3);
+
+	g_object_unref (rdisc);
+	g_main_loop_unref (data.loop);
+}
+
+static void
+test_dns_solicit_loop_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *data)
+{
+	data->counter++;
+}
+
+static gboolean
+success_timeout (TestData *data)
+{
+	data->timeout_id = 0;
+	g_main_loop_quit (data->loop);
+	return G_SOURCE_REMOVE;
+}
+
+static void
+test_dns_solicit_loop_rs_sent (NMFakeRDisc *rdisc, TestData *data)
+{
+	guint32 now = nm_utils_get_monotonic_timestamp_s ();
+	guint id;
+
+	if (data->rs_counter > 0 && data->rs_counter < 6) {
+		if (data->rs_counter == 1) {
+			data->first_solicit = now;
+			/* Kill the test after 10 seconds if it hasn't failed yet */
+			data->timeout_id = g_timeout_add_seconds (10, (GSourceFunc) success_timeout, data);
+		}
+
+		/* On all but the first solicitation, which should be triggered by the
+		 * DNS servers reaching 1/2 lifetime, emit a new RA without the DNS
+		 * servers again.
+		 */
+		id = nm_fake_rdisc_add_ra (rdisc, 0, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500);
+		g_assert (id);
+		nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_MEDIUM);
+		nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10);
+
+		nm_fake_rdisc_emit_new_ras (rdisc);
+	} else if (data->rs_counter >= 6) {
+		/* Fail if we've sent too many solicitations in the past 4 seconds */
+		g_assert_cmpint (now - data->first_solicit, >, 4);
+		g_source_remove (data->timeout_id);
+		g_main_loop_quit (data->loop);
+	}
+	data->rs_counter++;
+}
+
+static void
+test_dns_solicit_loop (void)
+{
+	NMFakeRDisc *rdisc = rdisc_new ();
+	guint32 now = nm_utils_get_monotonic_timestamp_s ();
+	TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now, 0 };
+	guint id;
+
+	/* Ensure that no solicitation loop happens when DNS servers or domains
+	 * stop being sent in advertisements.  This can happen if two routers
+	 * send RAs, but the one sending DNS info stops responding, or if one
+	 * router removes the DNS info from the RA without zero-lifetiming them
+	 * first.
+	 */
+
+	id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500);
+	g_assert (id);
+	nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_LOW);
+	nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10);
+	nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 6);
+
+	g_signal_connect (rdisc,
+	                  NM_RDISC_CONFIG_CHANGED,
+	                  G_CALLBACK (test_dns_solicit_loop_changed),
+	                  &data);
+	g_signal_connect (rdisc,
+	                  NM_FAKE_RDISC_RS_SENT,
+	                  G_CALLBACK (test_dns_solicit_loop_rs_sent),
+	                  &data);
+
+	nm_rdisc_start (NM_RDISC (rdisc));
+	g_main_loop_run (data.loop);
+	g_assert_cmpint (data.counter, ==, 3);
+
+	g_object_unref (rdisc);
+	g_main_loop_unref (data.loop);
+}
+
+NMTST_DEFINE ();
+
+int
+main (int argc, char **argv)
+{
+	nmtst_init_with_logging (&argc, &argv, NULL, "DEFAULT");
+
+	if (nmtst_test_quick ()) {
+		g_print ("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n", str_if_set (g_get_prgname (), "test-rdisc-fake"));
+		return EXIT_SKIP;
+	}
+
+	nm_fake_platform_setup ();
+
+	g_test_add_func ("/rdisc/simple", test_simple);
+	g_test_add_func ("/rdisc/everything-changed", test_everything);
+	g_test_add_func ("/rdisc/preference-changed", test_preference);
+	g_test_add_func ("/rdisc/dns-solicit-loop", test_dns_solicit_loop);
+
+	return g_test_run ();
+}
diff --git a/src/rdisc/tests/rdisc.c b/src/rdisc/tests/test-rdisc-linux.c
index d577a63a..9b2ccafd 100644
--- a/src/rdisc/tests/rdisc.c
+++ b/src/rdisc/tests/test-rdisc-linux.c
@@ -24,51 +24,47 @@
 #include <syslog.h>
 
 #include "nm-rdisc.h"
-#include "nm-fake-rdisc.h"
 #include "nm-lndp-rdisc.h"
 #include "nm-logging.h"
 
-#include "nm-fake-platform.h"
 #include "nm-linux-platform.h"
 
+#include "nm-test-utils.h"
+
+NMTST_DEFINE ();
+
 int
 main (int argc, char **argv)
 {
 	GMainLoop *loop;
 	NMRDisc *rdisc;
-	NMRDisc *(*new) (int ifindex, const char *ifname);
 	int ifindex = 1;
 	const char *ifname;
 
-#if !GLIB_CHECK_VERSION (2, 35, 0)
-	g_type_init ();
-#endif
+	nmtst_init_with_logging (&argc, &argv, NULL, "DEFAULT");
 
-	loop = g_main_loop_new (NULL, FALSE);
-	nm_logging_setup ("debug", "ip6", NULL, NULL);
-	openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR, LOG_DAEMON);
-
-	argv++;
-	if (!g_strcmp0 (argv[0], "--fake")) {
-		new = nm_fake_rdisc_new;
-		nm_fake_platform_setup ();
-		argv++;
-	} else {
-		new = nm_lndp_rdisc_new;
-		nm_linux_platform_setup ();
+	if (getuid () != 0) {
+		g_print ("Missing permission: must run as root\n");
+		return EXIT_FAILURE;
 	}
 
-	if (argv[0]) {
-		ifname = argv[0];
+	loop = g_main_loop_new (NULL, FALSE);
+
+	nm_linux_platform_setup ();
+
+	if (argv[1]) {
+		ifname = argv[1];
 		ifindex = nm_platform_link_get_ifindex (ifname);
 	} else {
-		ifindex = 1;
-		ifname = nm_platform_link_get_name (ifindex);
+		g_print ("Missing command line argument \"interface-name\"\n");
+		return EXIT_FAILURE;
 	}
 
-	rdisc = new (ifindex, ifname);
-	if (!rdisc)
+	rdisc = nm_lndp_rdisc_new (ifindex, ifname);
+	if (!rdisc) {
+		g_print ("Failed to create NMRDisc instance\n");
 		return EXIT_FAILURE;
+	}
 
 	nm_rdisc_start (rdisc);
 	g_main_loop_run (loop);
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index cc4b1943..8dcda06d 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -330,6 +330,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
 
 		priv->chains = g_slist_append (priv->chains, chain);
 	} else {
+		g_object_unref (agent);
 		error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
 		                             NM_AGENT_MANAGER_ERROR_FAILED,
 		                             "Unable to start agent authentication.");
@@ -602,11 +603,12 @@ request_next_agent (Request *req)
 {
 	GError *error = NULL;
 
+	req->current_call_id = NULL;
+	if (req->current)
+		g_object_unref (req->current);
+
 	if (req->pending) {
 		/* Send the request to the next agent */
-		req->current_call_id = NULL;
-		if (req->current)
-			g_object_unref (req->current);
 		req->current = req->pending->data;
 		req->pending = g_slist_remove (req->pending, req->current);
 
@@ -616,7 +618,6 @@ request_next_agent (Request *req)
 
 		req->next_callback (req);
 	} else {
-		req->current_call_id = NULL;
 		req->current = NULL;
 
 		/* No more secret agents are available to fulfill this secrets request */
diff --git a/src/settings/nm-inotify-helper.c b/src/settings/nm-inotify-helper.c
index 85b3c400..41f0268d 100644
--- a/src/settings/nm-inotify-helper.c
+++ b/src/settings/nm-inotify-helper.c
@@ -148,20 +148,20 @@ init_inotify (NMInotifyHelper *self)
 NMInotifyHelper *
 nm_inotify_helper_get (void)
 {
-	static NMInotifyHelper *singleton = NULL;
+	static NMInotifyHelper *singleton_instance = NULL;
 
-	if (!singleton) {
-		singleton = (NMInotifyHelper *) g_object_new (NM_TYPE_INOTIFY_HELPER, NULL);
+	if (!singleton_instance) {
+		singleton_instance = (NMInotifyHelper *) g_object_new (NM_TYPE_INOTIFY_HELPER, NULL);
 
-		if (!init_inotify (singleton)) {
-			g_clear_object (&singleton);
+		if (!init_inotify (singleton_instance)) {
+			g_clear_object (&singleton_instance);
 			return NULL;
 		}
 	} else
-		g_object_ref (singleton);
+		g_object_ref (singleton_instance);
 
-	g_assert (singleton);
-	return singleton;
+	g_assert (singleton_instance);
+	return singleton_instance;
 }
 
 static void
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index 529f4d8f..ec2052f0 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -82,7 +82,9 @@ enum {
 	PROP_0 = 0,
 	PROP_VISIBLE,
 	PROP_UNSAVED,
+	PROP_READY,
 	PROP_FLAGS,
+	PROP_FILENAME,
 };
 
 enum {
@@ -99,6 +101,7 @@ typedef struct {
 	guint session_changed_id;
 
 	NMSettingsConnectionFlags flags;
+	gboolean ready;
 
 	guint updated_idle_id;
 
@@ -129,6 +132,8 @@ typedef struct {
 	gint32 autoconnect_retry_time;
 	NMDeviceStateReason autoconnect_blocked_reason;
 
+	char *filename;
+
 } NMSettingsConnectionPrivate;
 
 /**************************************************************/
@@ -442,6 +447,7 @@ gboolean
 nm_settings_connection_replace_settings (NMSettingsConnection *self,
                                          NMConnection *new_connection,
                                          gboolean update_unsaved,
+                                         const char *log_diff_name,
                                          GError **error)
 {
 	NMSettingsConnectionPrivate *priv;
@@ -455,6 +461,15 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
 	if (!nm_connection_normalize (new_connection, NULL, NULL, error))
 		return FALSE;
 
+	if (   nm_connection_get_path (NM_CONNECTION (self))
+	    && g_strcmp0 (nm_connection_get_uuid (NM_CONNECTION (self)), nm_connection_get_uuid (new_connection)) != 0) {
+		/* Updating the UUID is not allowed once the path is exported. */
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+		             "connection %s cannot change the UUID from %s to %s", nm_connection_get_id (NM_CONNECTION (self)),
+		             nm_connection_get_uuid (NM_CONNECTION (self)), nm_connection_get_uuid (new_connection));
+		return FALSE;
+	}
+
 	/* Do nothing if there's nothing to update */
 	if (nm_connection_compare (NM_CONNECTION (self),
 	                           new_connection,
@@ -467,7 +482,8 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
 	 */
 	g_signal_handlers_block_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE));
 
-	nm_utils_log_connection_diff (new_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, "update connection", "++ ");
+	if (log_diff_name)
+		nm_utils_log_connection_diff (new_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ ");
 
 	nm_connection_replace_settings_from_connection (NM_CONNECTION (self), new_connection);
 	nm_settings_connection_set_flags (self,
@@ -519,24 +535,34 @@ ignore_cb (NMSettingsConnection *connection,
  * subsystems watching this connection. Before returning, 'callback' is run
  * with the given 'user_data' along with any errors encountered.
  */
+static void
+replace_and_commit (NMSettingsConnection *self,
+                    NMConnection *new_connection,
+                    NMSettingsConnectionCommitFunc callback,
+                    gpointer user_data)
+{
+	GError *error = NULL;
+
+	if (nm_settings_connection_replace_settings (self, new_connection, TRUE, "replace-and-commit-disk", &error))
+		nm_settings_connection_commit_changes (self, callback, user_data);
+	else {
+		g_assert (error);
+		if (callback)
+			callback (self, error, user_data);
+		g_clear_error (&error);
+	}
+}
+
 void
 nm_settings_connection_replace_and_commit (NMSettingsConnection *self,
                                            NMConnection *new_connection,
                                            NMSettingsConnectionCommitFunc callback,
                                            gpointer user_data)
 {
-	GError *error = NULL;
-
 	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self));
 	g_return_if_fail (NM_IS_CONNECTION (new_connection));
 
-	if (nm_settings_connection_replace_settings (self, new_connection, TRUE, &error)) {
-		nm_settings_connection_commit_changes (self, callback, user_data);
-	} else {
-		if (callback)
-			callback (self, error, user_data);
-		g_clear_error (&error);
-	}
+	NM_SETTINGS_CONNECTION_GET_CLASS (self)->replace_and_commit (self, new_connection, callback, user_data);
 }
 
 static void
@@ -1350,11 +1376,8 @@ update_auth_cb (NMSettingsConnection *self,
 		                                           con_update_cb,
 		                                           info);
 	} else {
-		/* Do nothing if there's nothing to update */
-		if (!nm_connection_compare (NM_CONNECTION (self), info->new_settings, NM_SETTING_COMPARE_FLAG_EXACT)) {
-			if (!nm_settings_connection_replace_settings (self, info->new_settings, TRUE, &local))
-				g_assert (local);
-		}
+		if (!nm_settings_connection_replace_settings (self, info->new_settings, TRUE, "replace-and-commit-memory", &local))
+			g_assert (local);
 		con_update_cb (self, local, info);
 		g_clear_error (&local);
 	}
@@ -2166,6 +2189,64 @@ nm_settings_connection_get_nm_generated_assumed (NMSettingsConnection *connectio
 	return NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED);
 }
 
+gboolean
+nm_settings_connection_get_ready (NMSettingsConnection *connection)
+{
+	return NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->ready;
+}
+
+void
+nm_settings_connection_set_ready (NMSettingsConnection *connection,
+                                  gboolean ready)
+{
+	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
+
+	ready = !!ready;
+	if (priv->ready != ready) {
+		priv->ready = ready;
+		g_object_notify (G_OBJECT (connection), NM_SETTINGS_CONNECTION_READY);
+	}
+}
+
+/**
+ * nm_settings_connection_set_filename:
+ * @connection: an #NMSettingsConnection
+ * @filename: @connection's filename
+ *
+ * Called by a backend to sets the filename that @connection is read
+ * from/written to.
+ */
+void
+nm_settings_connection_set_filename (NMSettingsConnection *connection,
+                                     const char *filename)
+{
+	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
+
+	if (g_strcmp0 (filename, priv->filename) != 0) {
+		g_free (priv->filename);
+		priv->filename = g_strdup (filename);
+		g_object_notify (G_OBJECT (connection), NM_SETTINGS_CONNECTION_FILENAME);
+	}
+}
+
+/**
+ * nm_settings_connection_get_filename:
+ * @connection: an #NMSettingsConnection
+ *
+ * Gets the filename that @connection was read from/written to.  This may be
+ * %NULL if @connection is unsaved, or if it is associated with a backend that
+ * does not store each connection in a separate file.
+ *
+ * Returns: @connection's filename.
+ */
+const char *
+nm_settings_connection_get_filename (NMSettingsConnection *connection)
+{
+	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
+
+	return priv->filename;
+}
+
 /**************************************************************/
 
 static void
@@ -2174,6 +2255,7 @@ nm_settings_connection_init (NMSettingsConnection *self)
 	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
 
 	priv->visible = FALSE;
+	priv->ready = TRUE;
 
 	priv->session_monitor = nm_session_monitor_get ();
 	priv->session_changed_id = g_signal_connect (priv->session_monitor,
@@ -2235,6 +2317,8 @@ dispose (GObject *object)
 	}
 	g_clear_object (&priv->agent_mgr);
 
+	g_clear_pointer (&priv->filename, g_free);
+
 	G_OBJECT_CLASS (nm_settings_connection_parent_class)->dispose (object);
 }
 
@@ -2252,9 +2336,15 @@ get_property (GObject *object, guint prop_id,
 	case PROP_UNSAVED:
 		g_value_set_boolean (value, nm_settings_connection_get_unsaved (self));
 		break;
+	case PROP_READY:
+		g_value_set_boolean (value, nm_settings_connection_get_ready (self));
+		break;
 	case PROP_FLAGS:
 		g_value_set_uint (value, nm_settings_connection_get_flags (self));
 		break;
+	case PROP_FILENAME:
+		g_value_set_string (value, nm_settings_connection_get_filename (self));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -2268,9 +2358,15 @@ set_property (GObject *object, guint prop_id,
 	NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object);
 
 	switch (prop_id) {
+	case PROP_READY:
+		nm_settings_connection_set_ready (self, g_value_get_boolean (value));
+		break;
 	case PROP_FLAGS:
 		nm_settings_connection_set_flags_all (self, g_value_get_uint (value));
 		break;
+	case PROP_FILENAME:
+		nm_settings_connection_set_filename (self, g_value_get_string (value));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -2289,6 +2385,7 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class)
 	object_class->get_property = get_property;
 	object_class->set_property = set_property;
 
+	class->replace_and_commit = replace_and_commit;
 	class->commit_changes = commit_changes;
 	class->delete = do_delete;
 	class->supports_secrets = supports_secrets;
@@ -2309,6 +2406,13 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class)
 		                       G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
+		(object_class, PROP_READY,
+		 g_param_spec_boolean (NM_SETTINGS_CONNECTION_READY, "", "",
+		                       TRUE,
+		                       G_PARAM_READWRITE |
+		                       G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property
 	    (object_class, PROP_FLAGS,
 	     g_param_spec_uint (NM_SETTINGS_CONNECTION_FLAGS, "", "",
 	                        NM_SETTINGS_CONNECTION_FLAGS_NONE,
@@ -2317,6 +2421,13 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class)
 	                        G_PARAM_READWRITE |
 	                        G_PARAM_STATIC_STRINGS));
 
+	g_object_class_install_property
+		(object_class, PROP_FILENAME,
+		 g_param_spec_string (NM_SETTINGS_CONNECTION_FILENAME, "", "",
+		                      NULL,
+		                      G_PARAM_READWRITE |
+		                      G_PARAM_STATIC_STRINGS));
+
 	/* Signals */
 
 	/* Emitted when the connection is changed for any reason */
diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h
index 254e927b..49661f38 100644
--- a/src/settings/nm-settings-connection.h
+++ b/src/settings/nm-settings-connection.h
@@ -46,9 +46,11 @@ G_BEGIN_DECLS
 #define NM_SETTINGS_CONNECTION_UPDATED_BY_USER "updated-by-user"
 
 /* Properties */
-#define NM_SETTINGS_CONNECTION_VISIBLE "visible"
-#define NM_SETTINGS_CONNECTION_UNSAVED "unsaved"
-#define NM_SETTINGS_CONNECTION_FLAGS   "flags"
+#define NM_SETTINGS_CONNECTION_VISIBLE  "visible"
+#define NM_SETTINGS_CONNECTION_UNSAVED  "unsaved"
+#define NM_SETTINGS_CONNECTION_READY    "ready"
+#define NM_SETTINGS_CONNECTION_FLAGS    "flags"
+#define NM_SETTINGS_CONNECTION_FILENAME "filename"
 
 
 /**
@@ -95,6 +97,11 @@ struct _NMSettingsConnectionClass {
 	GObjectClass parent;
 
 	/* virtual methods */
+	void (*replace_and_commit) (NMSettingsConnection *connection,
+	                            NMConnection *new_connection,
+	                            NMSettingsConnectionCommitFunc callback,
+	                            gpointer user_data);
+
 	void (*commit_changes) (NMSettingsConnection *connection,
 	                        NMSettingsConnectionCommitFunc callback,
 	                        gpointer user_data);
@@ -116,6 +123,7 @@ void nm_settings_connection_commit_changes (NMSettingsConnection *connection,
 gboolean nm_settings_connection_replace_settings (NMSettingsConnection *self,
                                                   NMConnection *new_connection,
                                                   gboolean update_unsaved,
+                                                  const char *log_diff_name,
                                                   GError **error);
 
 void nm_settings_connection_replace_and_commit (NMSettingsConnection *self,
@@ -196,6 +204,14 @@ gboolean nm_settings_connection_can_autoconnect (NMSettingsConnection *connectio
 gboolean nm_settings_connection_get_nm_generated (NMSettingsConnection *connection);
 gboolean nm_settings_connection_get_nm_generated_assumed (NMSettingsConnection *connection);
 
+gboolean nm_settings_connection_get_ready (NMSettingsConnection *connection);
+void     nm_settings_connection_set_ready (NMSettingsConnection *connection,
+                                           gboolean ready);
+
+void        nm_settings_connection_set_filename (NMSettingsConnection *connection,
+                                                 const char *filename);
+const char *nm_settings_connection_get_filename (NMSettingsConnection *connection);
+
 G_END_DECLS
 
 #endif /* __NETWORKMANAGER_SETTINGS_CONNECTION_H__ */
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 9ed03f69..9d40b06e 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -151,6 +151,8 @@ typedef struct {
 	GSList *unmanaged_specs;
 	GSList *unrecognized_specs;
 	GSList *get_connections_cache;
+
+	gboolean startup_complete;
 } NMSettingsPrivate;
 
 #define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate))
@@ -175,11 +177,43 @@ enum {
 	PROP_HOSTNAME,
 	PROP_CAN_MODIFY,
 	PROP_CONNECTIONS,
+	PROP_STARTUP_COMPLETE,
 
 	LAST_PROP
 };
 
 static void
+check_startup_complete (NMSettings *self)
+{
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	GHashTableIter iter;
+	NMSettingsConnection *conn;
+
+	if (priv->startup_complete)
+		return;
+
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn)) {
+		if (!nm_settings_connection_get_ready (conn))
+			return;
+	}
+
+	priv->startup_complete = TRUE;
+	g_object_notify (G_OBJECT (self), NM_SETTINGS_STARTUP_COMPLETE);
+}
+
+static void
+connection_ready_changed (NMSettingsConnection *conn,
+                          GParamSpec *pspec,
+                          gpointer user_data)
+{
+	NMSettings *self = NM_SETTINGS (user_data);
+
+	if (nm_settings_connection_get_ready (conn))
+		check_startup_complete (self);
+}
+
+static void
 plugin_connection_added (NMSystemConfigInterface *config,
                          NMSettingsConnection *connection,
                          gpointer user_data)
@@ -772,6 +806,7 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated), self);
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated_by_user), self);
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_visibility_changed), self);
+	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self);
 
 	/* Forget about the connection internally */
 	g_hash_table_remove (NM_SETTINGS_GET_PRIVATE (user_data)->connections,
@@ -784,6 +819,8 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 	g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_REMOVED, connection);
 	g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS);
 
+	check_startup_complete (self);
+
 	g_object_unref (connection);
 }
 
@@ -850,6 +887,7 @@ claim_connection (NMSettings *self,
 	GHashTableIter iter;
 	gpointer data;
 	char *path;
+	NMSettingsConnection *existing;
 
 	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
 	g_return_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL);
@@ -868,6 +906,23 @@ claim_connection (NMSettings *self,
 		return;
 	}
 
+	existing = nm_settings_get_connection_by_uuid (self, nm_connection_get_uuid (NM_CONNECTION (connection)));
+	if (existing) {
+		/* Cannot add duplicate connections per UUID. Just return without action and
+		 * log a warning.
+		 *
+		 * This means, that plugins must not provide duplicate connections (UUID).
+		 * In fact, none of the plugins currently would do that.
+		 *
+		 * But globaly, over different setting plugins, there could be duplicates
+		 * without the individual plugins being aware. Don't handle that at all, just
+		 * error out. That should not happen unless the admin misconfigured the system
+		 * to create conflicting connections. */
+		nm_log_warn (LOGD_SETTINGS, "plugin provided duplicate connection with UUID %s",
+		             nm_connection_get_uuid (NM_CONNECTION (connection)));
+		return;
+	}
+
 	/* Read timestamp from look-aside file and put it into the connection's data */
 	nm_settings_connection_read_and_fill_timestamp (connection);
 
@@ -889,6 +944,11 @@ claim_connection (NMSettings *self,
 	g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_VISIBLE,
 	                  G_CALLBACK (connection_visibility_changed),
 	                  self);
+	if (!priv->startup_complete) {
+		g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_READY,
+		                  G_CALLBACK (connection_ready_changed),
+		                  self);
+	}
 
 	/* Export the connection over D-Bus */
 	g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL);
@@ -1780,6 +1840,16 @@ cp_get_connection_by_uuid (NMConnectionProvider *provider, const char *uuid)
 
 /***************************************************************/
 
+gboolean
+nm_settings_get_startup_complete (NMSettings *self)
+{
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+
+	return priv->startup_complete;
+}
+
+/***************************************************************/
+
 NMSettings *
 nm_settings_new (GError **error)
 {
@@ -1800,6 +1870,7 @@ nm_settings_new (GError **error)
 	}
 
 	load_connections (self);
+	check_startup_complete (self);
 
 	nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_SETTINGS, self);
 	return self;
@@ -1900,6 +1971,9 @@ get_property (GObject *object, guint prop_id,
 			g_ptr_array_add (array, g_strdup (path));
 		g_value_take_boxed (value, array);
 		break;
+	case PROP_STARTUP_COMPLETE:
+		g_value_set_boolean (value, nm_settings_get_startup_complete (self));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h
index 520c4ec3..9c0a4c83 100644
--- a/src/settings/nm-settings.h
+++ b/src/settings/nm-settings.h
@@ -37,10 +37,11 @@
 #define NM_IS_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_SETTINGS))
 #define NM_SETTINGS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_SETTINGS, NMSettingsClass))
 
-#define NM_SETTINGS_UNMANAGED_SPECS "unmanaged-specs"
-#define NM_SETTINGS_HOSTNAME        "hostname"
-#define NM_SETTINGS_CAN_MODIFY      "can-modify"
-#define NM_SETTINGS_CONNECTIONS     "connections"
+#define NM_SETTINGS_UNMANAGED_SPECS  "unmanaged-specs"
+#define NM_SETTINGS_HOSTNAME         "hostname"
+#define NM_SETTINGS_CAN_MODIFY       "can-modify"
+#define NM_SETTINGS_CONNECTIONS      "connections"
+#define NM_SETTINGS_STARTUP_COMPLETE "connections"
 
 #define NM_SETTINGS_SIGNAL_CONNECTION_ADDED              "connection-added"
 #define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED            "connection-updated"
@@ -120,4 +121,6 @@ void nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean qu
 
 gint nm_settings_sort_connections (gconstpointer a, gconstpointer b);
 
+gboolean nm_settings_get_startup_complete (NMSettings *self);
+
 #endif  /* __NM_SETTINGS_H__ */
diff --git a/src/settings/plugins/Makefile.in b/src/settings/plugins/Makefile.in
index 1e9b0fdd..ea45e2a5 100644
--- a/src/settings/plugins/Makefile.in
+++ b/src/settings/plugins/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -83,7 +93,6 @@ host_triplet = @host@
 @CONFIG_PLUGIN_IFUPDOWN_TRUE@am__append_4 = ifupdown
 @CONFIG_PLUGIN_IFNET_TRUE@am__append_5 = ifnet
 subdir = src/settings/plugins
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -100,6 +109,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -159,6 +169,7 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = keyfile example ibft ifcfg-rh ifcfg-suse ifupdown ifnet
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -210,7 +221,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -245,6 +255,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -462,7 +473,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -757,6 +767,8 @@ uninstall-am:
 	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
 	ps ps-am tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @GNOME_CODE_COVERAGE_RULES@
 
diff --git a/src/settings/plugins/example/Makefile.in b/src/settings/plugins/example/Makefile.in
index baa5c698..dabbdc74 100644
--- a/src/settings/plugins/example/Makefile.in
+++ b/src/settings/plugins/example/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/example
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp README
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -175,6 +184,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp README
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -201,7 +212,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -236,6 +246,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -483,7 +494,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/example/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/example/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -532,14 +542,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -757,6 +767,8 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/settings/plugins/example/nm-example-connection.c b/src/settings/plugins/example/nm-example-connection.c
index 2f0b20a0..e1259611 100644
--- a/src/settings/plugins/example/nm-example-connection.c
+++ b/src/settings/plugins/example/nm-example-connection.c
@@ -82,6 +82,7 @@ nm_example_connection_new (const char *full_path,
 	if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
 	                                              tmp,
 	                                              TRUE,
+	                                              NULL,
 	                                              error)) {
 		g_object_unref (object);
 		object = NULL;
diff --git a/src/settings/plugins/ibft/Makefile.in b/src/settings/plugins/ibft/Makefile.in
index 415961df..405c213b 100644
--- a/src/settings/plugins/ibft/Makefile.in
+++ b/src/settings/plugins/ibft/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/ibft
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -225,6 +234,8 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -276,7 +287,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -311,6 +321,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -558,7 +569,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ibft/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ibft/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -644,14 +654,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -948,6 +958,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 
 @GNOME_CODE_COVERAGE_RULES@
 
diff --git a/src/settings/plugins/ibft/nm-ibft-connection.c b/src/settings/plugins/ibft/nm-ibft-connection.c
index 5459a705..c6a9054e 100644
--- a/src/settings/plugins/ibft/nm-ibft-connection.c
+++ b/src/settings/plugins/ibft/nm-ibft-connection.c
@@ -46,6 +46,7 @@ nm_ibft_connection_new (const GPtrArray *block, GError **error)
 	if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
 	                                              source,
 	                                              FALSE,
+	                                              NULL,
 	                                              error))
 		g_clear_object (&object);
 
diff --git a/src/settings/plugins/ibft/plugin.c b/src/settings/plugins/ibft/plugin.c
index 303971e0..632c4df1 100644
--- a/src/settings/plugins/ibft/plugin.c
+++ b/src/settings/plugins/ibft/plugin.c
@@ -63,7 +63,7 @@ read_connections (SCPluginIbft *self)
 	NMIbftConnection *connection;
 
 	if (!read_ibft_blocks ("/sbin/iscsiadm", &blocks, &error)) {
-		nm_log_dbg (LOGD_SETTINGS, _("ibft: failed to read iscsiadm records: %s"), error->message);
+		nm_log_dbg (LOGD_SETTINGS, "ibft: failed to read iscsiadm records: %s", error->message);
 		g_error_free (error);
 		return;
 	}
@@ -71,13 +71,13 @@ read_connections (SCPluginIbft *self)
 	for (iter = blocks; iter; iter = iter->next) {
 		connection = nm_ibft_connection_new (iter->data, &error);
 		if (connection) {
-			nm_log_info (LOGD_SETTINGS, _("ibft: read connection '%s'"),
+			nm_log_info (LOGD_SETTINGS, "ibft: read connection '%s'",
 			             nm_connection_get_id (NM_CONNECTION (connection)));
 			g_hash_table_insert (priv->connections,
 			                     g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection))),
 			                     connection);
 		} else {
-			nm_log_warn (LOGD_SETTINGS, _("ibft: failed to read iscsiadm record: %s"), error->message);
+			nm_log_warn (LOGD_SETTINGS, "ibft: failed to read iscsiadm record: %s", error->message);
 			g_clear_error (&error);
 		}
 	}
diff --git a/src/settings/plugins/ibft/reader.c b/src/settings/plugins/ibft/reader.c
index 066a79f2..e89d9b08 100644
--- a/src/settings/plugins/ibft/reader.c
+++ b/src/settings/plugins/ibft/reader.c
@@ -186,6 +186,7 @@ done:
 	if (lines)
 		g_strfreev (lines);
 	g_free (out);
+	g_free (err);
 	if (success)
 		*out_blocks = blocks;
 	else
diff --git a/src/settings/plugins/ibft/tests/Makefile.am b/src/settings/plugins/ibft/tests/Makefile.am
index dd72220a..3c7c94ac 100644
--- a/src/settings/plugins/ibft/tests/Makefile.am
+++ b/src/settings/plugins/ibft/tests/Makefile.am
@@ -32,6 +32,7 @@ test_ibft_SOURCES = \
 test_ibft_LDADD = \
 	$(top_builddir)/src/libNetworkManager.la
 
+@VALGRIND_RULES@
 TESTS = test-ibft
 
 endif
diff --git a/src/settings/plugins/ibft/tests/Makefile.in b/src/settings/plugins/ibft/tests/Makefile.in
index e2f06169..d682318a 100644
--- a/src/settings/plugins/ibft/tests/Makefile.in
+++ b/src/settings/plugins/ibft/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 @ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-ibft$(EXEEXT)
 @ENABLE_TESTS_TRUE@TESTS = test-ibft$(EXEEXT)
 subdir = src/settings/plugins/ibft/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -196,6 +205,8 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -222,7 +233,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -257,6 +267,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -512,7 +523,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ibft/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ibft/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -558,14 +568,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -891,9 +901,13 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_TESTS_TRUE@@GNOME_CODE_COVERAGE_RULES@
 
+@ENABLE_TESTS_TRUE@@VALGRIND_RULES@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/settings/plugins/ibft/tests/test-ibft.c b/src/settings/plugins/ibft/tests/test-ibft.c
index 2ff249af..980a9cee 100644
--- a/src/settings/plugins/ibft/tests/test-ibft.c
+++ b/src/settings/plugins/ibft/tests/test-ibft.c
@@ -63,7 +63,7 @@ read_block (const char *iscsiadm_path, const char *expected_mac)
 	}
 	g_assert (block);
 
-	g_slist_foreach (blocks, (GFunc) g_ptr_array_unref, NULL);
+	g_slist_free_full (blocks, (GDestroyNotify) g_ptr_array_unref);
 	return block;
 }
 
@@ -110,6 +110,7 @@ test_read_ibft_dhcp (void)
 	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
 
 	g_object_unref (connection);
+	g_ptr_array_unref (block);
 }
 
 static void
@@ -266,7 +267,7 @@ test_read_ibft_vlan (void)
 	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, NULL);
 
 	g_object_unref (connection);
-	g_ptr_array_ref (block);
+	g_ptr_array_unref (block);
 }
 
 NMTST_DEFINE ();
@@ -275,7 +276,7 @@ NMTST_DEFINE ();
 
 int main (int argc, char **argv)
 {
-	nmtst_init_assert_logging (&argc, &argv);
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
 
 	g_test_add_func (TPATH "ibft/dhcp", test_read_ibft_dhcp);
 	g_test_add_func (TPATH "ibft/static", test_read_ibft_static);
diff --git a/src/settings/plugins/ifcfg-rh/Makefile.in b/src/settings/plugins/ifcfg-rh/Makefile.in
index 5d396273..89511983 100644
--- a/src/settings/plugins/ifcfg-rh/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -16,7 +16,17 @@
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -80,8 +90,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/ifcfg-rh
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -98,6 +106,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -228,6 +237,8 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -279,7 +290,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -314,6 +324,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -579,7 +590,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ifcfg-rh/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ifcfg-rh/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -668,14 +678,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -998,6 +1008,8 @@ uninstall-am: uninstall-dbusserviceDATA uninstall-pkglibLTLIBRARIES
 	tags tags-am uninstall uninstall-am uninstall-dbusserviceDATA \
 	uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 
 @GNOME_CODE_COVERAGE_RULES@
 
diff --git a/src/settings/plugins/ifcfg-rh/common.h b/src/settings/plugins/ifcfg-rh/common.h
index d78f3752..0ec355ee 100644
--- a/src/settings/plugins/ifcfg-rh/common.h
+++ b/src/settings/plugins/ifcfg-rh/common.h
@@ -26,7 +26,9 @@
 #define IFCFG_TAG "ifcfg-"
 #define KEYS_TAG "keys-"
 #define ROUTE_TAG "route-"
+#define RULE_TAG "rule-"
 #define ROUTE6_TAG "route6-"
+#define RULE6_TAG "rule6-"
 
 #define BAK_TAG ".bak"
 #define TILDE_TAG "~"
@@ -39,7 +41,7 @@
 #define IFCFG_DIR SYSCONFDIR"/sysconfig/network-scripts"
 
 #define IFCFG_PLUGIN_NAME "ifcfg-rh"
-#define IFCFG_PLUGIN_INFO "(c) 2007 - 2013 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
+#define IFCFG_PLUGIN_INFO "(c) 2007 - 2015 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
 
 #define TYPE_ETHERNET   "Ethernet"
 #define TYPE_WIRELESS   "Wireless"
diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
index 7596cbd5..94d22258 100644
--- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
+++ b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
@@ -33,6 +33,8 @@
 #include <nm-setting-pppoe.h>
 #include <nm-setting-wireless-security.h>
 #include <nm-setting-8021x.h>
+#include <nm-platform.h>
+#include <nm-logging.h>
 
 #include "common.h"
 #include "nm-config.h"
@@ -49,7 +51,6 @@ G_DEFINE_TYPE (NMIfcfgConnection, nm_ifcfg_connection, NM_TYPE_SETTINGS_CONNECTI
 typedef struct {
 	gulong ih_event_id;
 
-	char *path;
 	int file_wd;
 
 	char *keyfile;
@@ -63,6 +64,9 @@ typedef struct {
 
 	char *unmanaged_spec;
 	char *unrecognized_spec;
+
+	gulong devtimeout_link_changed_handler;
+	guint devtimeout_timeout_id;
 } NMIfcfgConnectionPrivate;
 
 enum {
@@ -80,6 +84,101 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
+static gboolean
+devtimeout_ready (gpointer user_data)
+{
+	NMIfcfgConnection *self = user_data;
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
+
+	priv->devtimeout_timeout_id = 0;
+	nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), TRUE);
+	return FALSE;
+}
+
+static void
+link_changed (NMPlatform *platform, int ifindex, NMPlatformLink *link,
+              NMPlatformSignalChangeType change_type, NMPlatformReason reason,
+              NMConnection *self)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
+	const char *ifname;
+
+	ifname = nm_connection_get_interface_name (self);
+	if (g_strcmp0 (link->name, ifname) != 0)
+		return;
+
+	/* Shouldn't happen, but... */
+	if (change_type == NM_PLATFORM_SIGNAL_REMOVED)
+		return;
+
+	nm_log_info (LOGD_SETTINGS, "Device %s appeared; connection '%s' now ready",
+	             ifname, nm_connection_get_id (self));
+
+	g_signal_handler_disconnect (platform, priv->devtimeout_link_changed_handler);
+	priv->devtimeout_link_changed_handler = 0;
+	g_source_remove (priv->devtimeout_timeout_id);
+
+	/* Don't declare the connection ready right away, since NMManager may not have
+	 * started processing the device yet.
+	 */
+	priv->devtimeout_timeout_id = g_idle_add (devtimeout_ready, self);
+}
+
+static gboolean
+devtimeout_expired (gpointer user_data)
+{
+	NMIfcfgConnection *self = user_data;
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
+
+	nm_log_info (LOGD_SETTINGS, "Device for connection '%s' did not appear before timeout",
+	             nm_connection_get_id (NM_CONNECTION (self)));
+
+	g_signal_handler_disconnect (nm_platform_get (), priv->devtimeout_link_changed_handler);
+	priv->devtimeout_link_changed_handler = 0;
+	priv->devtimeout_timeout_id = 0;
+
+	nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), TRUE);
+	return FALSE;
+}
+
+static void
+nm_ifcfg_connection_check_devtimeout (NMIfcfgConnection *self)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
+	NMSettingConnection *s_con;
+	const char *ifname;
+	const char *filename;
+	guint devtimeout;
+
+	s_con = nm_connection_get_setting_connection (NM_CONNECTION (self));
+
+	if (!nm_setting_connection_get_autoconnect (s_con))
+		return;
+	ifname = nm_setting_connection_get_interface_name (s_con);
+	if (!ifname)
+		return;
+	filename = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (self));
+	if (!filename)
+		return;
+	devtimeout = devtimeout_from_file (filename);
+	if (!devtimeout)
+		return;
+
+	if (nm_platform_link_get_ifindex (ifname) != 0)
+		return;
+
+	/* ONBOOT=yes, DEVICE and DEVTIMEOUT are set, but device is not present */
+	nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), FALSE);
+
+	nm_log_info (LOGD_SETTINGS, "Waiting %u seconds for %s to appear for connection '%s'",
+	             devtimeout, ifname, nm_connection_get_id (NM_CONNECTION (self)));
+
+	priv->devtimeout_link_changed_handler =
+		g_signal_connect (nm_platform_get (), NM_PLATFORM_SIGNAL_LINK_CHANGED,
+		                  G_CALLBACK (link_changed), self);
+	priv->devtimeout_timeout_id = g_timeout_add_seconds (devtimeout, devtimeout_expired, self);
+}
+
 static void
 files_changed_cb (NMInotifyHelper *ih,
                   struct inotify_event *evt,
@@ -102,8 +201,7 @@ files_changed_cb (NMInotifyHelper *ih,
 NMIfcfgConnection *
 nm_ifcfg_connection_new (NMConnection *source,
                          const char *full_path,
-                         GError **error,
-                         gboolean *ignore_error)
+                         GError **error)
 {
 	GObject *object;
 	NMConnection *tmp;
@@ -117,18 +215,9 @@ nm_ifcfg_connection_new (NMConnection *source,
 	if (source)
 		tmp = g_object_ref (source);
 	else {
-		char *keyfile = NULL, *routefile = NULL, *route6file = NULL;
-
-		tmp = connection_from_file (full_path, NULL, NULL,
+		tmp = connection_from_file (full_path,
 		                            &unhandled_spec,
-		                            &keyfile,
-		                            &routefile,
-		                            &route6file,
-		                            error,
-		                            ignore_error);
-		g_free (keyfile);
-		g_free (routefile);
-		g_free (route6file);
+		                            error);
 		if (!tmp)
 			return NULL;
 
@@ -142,6 +231,7 @@ nm_ifcfg_connection_new (NMConnection *source,
 		unrecognized_spec = unhandled_spec + strlen ("unrecognized:");
 
 	object = (GObject *) g_object_new (NM_TYPE_IFCFG_CONNECTION,
+	                                   NM_SETTINGS_CONNECTION_FILENAME, full_path,
 	                                   NM_IFCFG_CONNECTION_UNMANAGED_SPEC, unmanaged_spec,
 	                                   NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, unrecognized_spec,
 	                                   NULL);
@@ -149,11 +239,10 @@ nm_ifcfg_connection_new (NMConnection *source,
 	if (nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
 	                                             tmp,
 	                                             update_unsaved,
-	                                             error)) {
-		/* Set the path and start monitoring */
-		if (full_path)
-			nm_ifcfg_connection_set_path (NM_IFCFG_CONNECTION (object), full_path);
-	} else
+	                                             NULL,
+	                                             error))
+		nm_ifcfg_connection_check_devtimeout (NM_IFCFG_CONNECTION (object));
+	else
 		g_clear_object (&object);
 
 	g_object_unref (tmp);
@@ -161,14 +250,6 @@ nm_ifcfg_connection_new (NMConnection *source,
 	return (NMIfcfgConnection *) object;
 }
 
-const char *
-nm_ifcfg_connection_get_path (NMIfcfgConnection *self)
-{
-	g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL);
-
-	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->path;
-}
-
 static void
 path_watch_stop (NMIfcfgConnection *self)
 {
@@ -209,17 +290,21 @@ path_watch_stop (NMIfcfgConnection *self)
 	}
 }
 
-void
-nm_ifcfg_connection_set_path (NMIfcfgConnection *self, const char *ifcfg_path)
+static void
+filename_changed (GObject *object,
+                  GParamSpec *pspec,
+                  gpointer user_data)
 {
+	NMIfcfgConnection *self = NM_IFCFG_CONNECTION (object);
 	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
-
-	g_return_if_fail (ifcfg_path != NULL);
+	const char *ifcfg_path;
 
 	path_watch_stop (self);
-	g_free (priv->path);
 
-	priv->path = g_strdup (ifcfg_path);
+	ifcfg_path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (self));
+	if (!ifcfg_path)
+		return;
+
 	priv->keyfile = utils_get_keys_path (ifcfg_path);
 	priv->routefile = utils_get_route_path (ifcfg_path);
 	priv->route6file = utils_get_route6_path (ifcfg_path);
@@ -252,6 +337,28 @@ nm_ifcfg_connection_get_unrecognized_spec (NMIfcfgConnection *self)
 }
 
 static void
+replace_and_commit (NMSettingsConnection *connection,
+                    NMConnection *new_connection,
+                    NMSettingsConnectionCommitFunc callback,
+                    gpointer user_data)
+{
+	const char *filename;
+	GError *error = NULL;
+
+	filename = nm_settings_connection_get_filename (connection);
+	if (filename && utils_has_complex_routes (filename)) {
+		if (callback) {
+			error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+			                             "Cannot modify a connection that has an associated 'rule-' or 'rule6-' file");
+			callback (connection, error, user_data);
+			g_clear_error (&error);
+		}
+	}
+
+	NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->replace_and_commit (connection, new_connection, callback, user_data);
+}
+
+static void
 commit_changes (NMSettingsConnection *connection,
                 NMSettingsConnectionCommitFunc callback,
                 gpointer user_data)
@@ -261,16 +368,15 @@ commit_changes (NMSettingsConnection *connection,
 	NMConnection *reread;
 	gboolean same = FALSE, success = FALSE;
 	char *ifcfg_path = NULL;
+	const char *filename;
 
 	/* To ensure we don't rewrite files that are only changed from other
 	 * processes on-disk, read the existing connection back in and only rewrite
 	 * it if it's really changed.
 	 */
-	if (priv->path) {
-		reread = connection_from_file (priv->path, NULL, NULL,
-		                               NULL, NULL, NULL, NULL,
-		                               &error, NULL);
-		g_clear_error (&error);
+	filename = nm_settings_connection_get_filename (connection);
+	if (filename) {
+		reread = connection_from_file (filename, NULL, NULL);
 		if (reread) {
 			same = nm_connection_compare (NM_CONNECTION (connection),
 			                              reread,
@@ -288,7 +394,7 @@ commit_changes (NMSettingsConnection *connection,
 
 		success = writer_update_connection (NM_CONNECTION (connection),
 		                                    IFCFG_DIR,
-		                                    priv->path,
+		                                    filename,
 		                                    priv->keyfile,
 		                                    &error);
 	} else {
@@ -297,7 +403,7 @@ commit_changes (NMSettingsConnection *connection,
 		                                 &ifcfg_path,
 		                                 &error);
 		if (success) {
-			nm_ifcfg_connection_set_path (NM_IFCFG_CONNECTION (connection), ifcfg_path);
+			nm_settings_connection_set_filename (connection, ifcfg_path);
 			g_free (ifcfg_path);
 		}
 	}
@@ -318,14 +424,15 @@ do_delete (NMSettingsConnection *connection,
 	       gpointer user_data)
 {
 	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection);
+	const char *filename;
 
-	if (priv->path) {
-		g_unlink (priv->path);
+	filename = nm_settings_connection_get_filename (connection);
+	if (filename) {
+		g_unlink (filename);
 		if (priv->keyfile)
 			g_unlink (priv->keyfile);
 		if (priv->routefile)
 			g_unlink (priv->routefile);
-
 		if (priv->route6file)
 			g_unlink (priv->route6file);
 	}
@@ -338,6 +445,8 @@ do_delete (NMSettingsConnection *connection,
 static void
 nm_ifcfg_connection_init (NMIfcfgConnection *connection)
 {
+	g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_FILENAME,
+	                  G_CALLBACK (filename_changed), NULL);
 }
 
 static void
@@ -381,17 +490,21 @@ get_property (GObject *object, guint prop_id,
 static void
 dispose (GObject *object)
 {
-	path_watch_stop (NM_IFCFG_CONNECTION (object));
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
 
-	G_OBJECT_CLASS (nm_ifcfg_connection_parent_class)->dispose (object);
-}
+	path_watch_stop (NM_IFCFG_CONNECTION (object));
 
-static void
-finalize (GObject *object)
-{
-	g_free (NM_IFCFG_CONNECTION_GET_PRIVATE (object)->path);
+	if (priv->devtimeout_link_changed_handler) {
+		g_signal_handler_disconnect (nm_platform_get (),
+		                             priv->devtimeout_link_changed_handler);
+		priv->devtimeout_link_changed_handler = 0;
+	}
+	if (priv->devtimeout_timeout_id) {
+		g_source_remove (priv->devtimeout_timeout_id);
+		priv->devtimeout_timeout_id = 0;
+	}
 
-	G_OBJECT_CLASS (nm_ifcfg_connection_parent_class)->finalize (object);
+	G_OBJECT_CLASS (nm_ifcfg_connection_parent_class)->dispose (object);
 }
 
 static void
@@ -406,8 +519,8 @@ nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class)
 	object_class->set_property = set_property;
 	object_class->get_property = get_property;
 	object_class->dispose      = dispose;
-	object_class->finalize     = finalize;
 	settings_class->delete = do_delete;
+	settings_class->replace_and_commit = replace_and_commit;
 	settings_class->commit_changes = commit_changes;
 
 	/* Properties */
diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.h b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.h
index 37eacaf0..328e58f5 100644
--- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.h
+++ b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.h
@@ -48,13 +48,7 @@ GType nm_ifcfg_connection_get_type (void);
 
 NMIfcfgConnection *nm_ifcfg_connection_new (NMConnection *source,
                                             const char *full_path,
-                                            GError **error,
-                                            gboolean *ignore_error);
-
-const char *nm_ifcfg_connection_get_path (NMIfcfgConnection *self);
-
-void        nm_ifcfg_connection_set_path (NMIfcfgConnection *self,
-                                          const char *ifcfg_path);
+                                            GError **error);
 
 const char *nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self);
 const char *nm_ifcfg_connection_get_unrecognized_spec (NMIfcfgConnection *self);
diff --git a/src/settings/plugins/ifcfg-rh/plugin.c b/src/settings/plugins/ifcfg-rh/plugin.c
index 2dced56b..b7efa864 100644
--- a/src/settings/plugins/ifcfg-rh/plugin.c
+++ b/src/settings/plugins/ifcfg-rh/plugin.c
@@ -58,10 +58,31 @@
 #include "reader.h"
 #include "writer.h"
 #include "utils.h"
+#include "gsystem-local-alloc.h"
 
 #define DBUS_SERVICE_NAME "com.redhat.ifcfgrh1"
 #define DBUS_OBJECT_PATH "/com/redhat/ifcfgrh1"
 
+
+#define _LOG_DEFAULT_DOMAIN  LOGD_SETTINGS
+
+#define _LOG(level, domain, ...) \
+    G_STMT_START { \
+        nm_log ((level), (domain), \
+                "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+                "ifcfg-rh: " \
+                _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+    } G_STMT_END
+
+#define _LOGT(...)      _LOG (LOGL_TRACE, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+#define _LOGD(...)      _LOG (LOGL_DEBUG, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+#define _LOGI(...)      _LOG (LOGL_INFO,  _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+#define _LOGW(...)      _LOG (LOGL_WARN,  _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+#define _LOGE(...)      _LOG (LOGL_ERR,   _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+
+#define ERR_GET_MSG(err) (((err) && (err)->message) ? (err)->message : "(unknown)")
+
+
 static gboolean impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin,
                                                 const char *in_ifcfg,
                                                 const char **out_uuid,
@@ -70,10 +91,13 @@ static gboolean impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin,
 
 #include "nm-ifcfg-rh-glue.h"
 
-static void connection_new_or_changed (SCPluginIfcfg *plugin,
-                                       const char *path,
-                                       NMIfcfgConnection *existing,
-                                       char **out_old_path);
+static NMIfcfgConnection *update_connection (SCPluginIfcfg *plugin,
+                                             NMConnection *source,
+                                             const char *full_path,
+                                             NMIfcfgConnection *connection,
+                                             gboolean protect_existing_connection,
+                                             GHashTable *protected_connections,
+                                             GError **error);
 
 static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
 
@@ -104,13 +128,22 @@ typedef struct {
 static void
 connection_ifcfg_changed (NMIfcfgConnection *connection, gpointer user_data)
 {
-	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
+	SCPluginIfcfg *self = SC_PLUGIN_IFCFG (user_data);
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
 	const char *path;
 
-	path = nm_ifcfg_connection_get_path (connection);
+	path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection));
 	g_return_if_fail (path != NULL);
 
-	connection_new_or_changed (plugin, path, connection, NULL);
+
+	if (!priv->ifcfg_monitor) {
+		_LOGD ("connection_ifcfg_changed("NM_IFCFG_CONNECTION_LOG_FMTD"): %s", NM_IFCFG_CONNECTION_LOG_ARGD (connection), "ignore event");
+		return;
+	}
+
+	_LOGD ("connection_ifcfg_changed("NM_IFCFG_CONNECTION_LOG_FMTD"): %s", NM_IFCFG_CONNECTION_LOG_ARGD (connection), "reload");
+
+	update_connection (self, NULL, path, connection, TRUE, NULL, NULL);
 }
 
 static void
@@ -120,69 +153,6 @@ connection_removed_cb (NMSettingsConnection *obj, gpointer user_data)
 	                     nm_connection_get_uuid (NM_CONNECTION (obj)));
 }
 
-static NMIfcfgConnection *
-_internal_new_connection (SCPluginIfcfg *self,
-                          const char *path,
-                          NMConnection *source,
-                          GError **error)
-{
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
-	NMIfcfgConnection *connection;
-	const char *cid;
-	GError *local = NULL;
-	gboolean ignore_error = FALSE;
-
-	if (!source)
-		nm_log_info (LOGD_SETTINGS, "parsing %s ... ", path);
-
-	connection = nm_ifcfg_connection_new (source, path, &local, &ignore_error);
-	if (!connection) {
-		if (!ignore_error)
-			nm_log_warn (LOGD_SETTINGS, "    %s", (local && local->message) ? local->message : "(unknown)");
-		if (local)
-			g_propagate_error (error, local);
-		else
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "(unknown)");
-		return NULL;
-	}
-
-	cid = nm_connection_get_id (NM_CONNECTION (connection));
-	g_assert (cid);
-
-	g_hash_table_insert (priv->connections,
-	                     g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection))),
-	                     connection);
-	nm_log_info (LOGD_SETTINGS, "    read connection '%s'", cid);
-	g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED,
-	                  G_CALLBACK (connection_removed_cb),
-	                  self);
-
-	if (nm_ifcfg_connection_get_unmanaged_spec (connection)) {
-		const char *spec;
-		const char *device_id;
-
-		spec = nm_ifcfg_connection_get_unmanaged_spec (connection);
-		device_id = strchr (spec, ':');
-		if (device_id)
-			device_id++;
-		else
-			device_id = spec;
-		nm_log_warn (LOGD_SETTINGS, "    Ignoring connection '%s' / device '%s' due to NM_CONTROLLED=no.",
-		             cid, device_id);
-	} else if (nm_ifcfg_connection_get_unrecognized_spec (connection)) {
-		nm_log_warn (LOGD_SETTINGS, "    Ignoring connection '%s' of unrecognized type.", cid);
-	}
-
-	/* watch changes of ifcfg hardlinks */
-	g_signal_connect (G_OBJECT (connection), "ifcfg-changed",
-	                  G_CALLBACK (connection_ifcfg_changed), self);
-
-	return connection;
-}
-
-/* Monitoring */
-
 static void
 remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection)
 {
@@ -192,6 +162,8 @@ remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection)
 	g_return_if_fail (self != NULL);
 	g_return_if_fail (connection != NULL);
 
+	_LOGI ("remove "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection));
+
 	unmanaged = !!nm_ifcfg_connection_get_unmanaged_spec (connection);
 	unrecognized = !!nm_ifcfg_connection_get_unrecognized_spec (connection);
 
@@ -212,160 +184,233 @@ find_by_path (SCPluginIfcfg *self, const char *path)
 {
 	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
 	GHashTableIter iter;
-	NMIfcfgConnection *candidate = NULL;
+	NMSettingsConnection *candidate = NULL;
 
 	g_return_val_if_fail (path != NULL, NULL);
 
 	g_hash_table_iter_init (&iter, priv->connections);
 	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) {
-		if (g_strcmp0 (path, nm_ifcfg_connection_get_path (candidate)) == 0)
-			return candidate;
+		if (g_strcmp0 (path, nm_settings_connection_get_filename (candidate)) == 0)
+			return NM_IFCFG_CONNECTION (candidate);
 	}
 	return NULL;
 }
 
 static NMIfcfgConnection *
-find_by_uuid_from_path (SCPluginIfcfg *self, const char *path)
+update_connection (SCPluginIfcfg *self,
+                   NMConnection *source,
+                   const char *full_path,
+                   NMIfcfgConnection *connection,
+                   gboolean protect_existing_connection,
+                   GHashTable *protected_connections,
+                   GError **error)
 {
 	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
-	char *uuid;
-
-	g_return_val_if_fail (path != NULL, NULL);
+	NMIfcfgConnection *connection_new;
+	NMIfcfgConnection *connection_by_uuid;
+	GError *local = NULL;
+	const char *new_unmanaged = NULL, *old_unmanaged = NULL;
+	const char *new_unrecognized = NULL, *old_unrecognized = NULL;
+	gboolean unmanaged_changed = FALSE, unrecognized_changed = FALSE;
+	const char *uuid;
 
-	uuid = uuid_from_file (path);
-	if (uuid)
-		return g_hash_table_lookup (priv->connections, uuid);
-	else
+	g_return_val_if_fail (!source || NM_IS_CONNECTION (source), NULL);
+	g_return_val_if_fail (full_path || source, NULL);
+
+	if (full_path)
+		_LOGD ("loading from file \"%s\"...", full_path);
+
+	/* Create a NMIfcfgConnection instance, either by reading from @full_path or
+	 * based on @source. */
+	connection_new = nm_ifcfg_connection_new (source, full_path, error);
+	if (!connection_new) {
+		/* Unexpected failure. Probably the file is invalid? */
+		if (   connection
+		    && !protect_existing_connection
+		    && (!protected_connections || !g_hash_table_contains (protected_connections, connection)))
+			remove_connection (self, connection);
 		return NULL;
-}
+	}
 
-static void
-connection_new_or_changed (SCPluginIfcfg *self,
-                           const char *path,
-                           NMIfcfgConnection *existing,
-                           char **out_old_path)
-{
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
-	NMIfcfgConnection *new;
-	GError *error = NULL;
-	gboolean ignore_error = FALSE;
-	const char *new_unmanaged = NULL, *old_unmanaged = NULL;
-	const char *new_unrecognized = NULL, *old_unrecognized = NULL;
-	gboolean unmanaged_changed, unrecognized_changed;
+	uuid = nm_connection_get_uuid (NM_CONNECTION (connection_new));
+	connection_by_uuid = g_hash_table_lookup (priv->connections, uuid);
 
-	g_return_if_fail (self != NULL);
-	g_return_if_fail (path != NULL);
+	if (   connection
+	    && connection != connection_by_uuid) {
 
-	if (out_old_path)
-		*out_old_path = NULL;
-
-	if (!existing) {
-		/* See if it's a rename */
-		existing = find_by_uuid_from_path (self, path);
-		if (existing) {
-			const char *old_path = nm_ifcfg_connection_get_path (existing);
-			nm_log_info (LOGD_SETTINGS, "renaming %s -> %s", old_path, path);
-			if (out_old_path)
-				*out_old_path = g_strdup (old_path);
-			nm_ifcfg_connection_set_path (existing, path);
-		}
-	}
+		if (   (protect_existing_connection && connection_by_uuid != NULL)
+		    || (protected_connections && g_hash_table_contains (protected_connections, connection))) {
+			NMIfcfgConnection *conflicting = (protect_existing_connection && connection_by_uuid != NULL) ? connection_by_uuid : connection;
 
-	if (!existing) {
-		/* New connection */
-		new = _internal_new_connection (self, path, NULL, NULL);
-		if (new) {
-			if (nm_ifcfg_connection_get_unmanaged_spec (new))
-				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
-			else if (nm_ifcfg_connection_get_unrecognized_spec (new))
-				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
+			if (source)
+				_LOGW ("cannot update protected connection "NM_IFCFG_CONNECTION_LOG_FMT" due to conflicting UUID %s", NM_IFCFG_CONNECTION_LOG_ARG (conflicting), uuid);
 			else
-				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new);
+				_LOGW ("cannot load %s due to conflicting UUID for "NM_IFCFG_CONNECTION_LOG_FMT, full_path, NM_IFCFG_CONNECTION_LOG_ARG (conflicting));
+			g_object_unref (connection_new);
+			g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+			                     "Cannot update protected connection due to conflicting UUID");
+			return NULL;
 		}
-		return;
-	}
-
-	new = (NMIfcfgConnection *) nm_ifcfg_connection_new (NULL, path, &error, &ignore_error);
-	if (!new) {
-		/* errors reading connection; remove it */
-		if (!ignore_error)
-			nm_log_warn (LOGD_SETTINGS, "    %s", (error && error->message) ? error->message : "(unknown)");
-		g_clear_error (&error);
 
-		nm_log_info (LOGD_SETTINGS, "removed %s.", path);
-		remove_connection (self, existing);
-		return;
+		/* The new connection has a different UUID then the original one that we
+		 * are about to update. Remove @connection. */
+		remove_connection (self, connection);
 	}
 
-	/* Successfully read connection changes */
+	/* Check if the found connection with the same UUID is not protected from updating. */
+	if (   connection_by_uuid
+	    && (   (!connection && protect_existing_connection)
+	        || (protected_connections && g_hash_table_contains (protected_connections, connection_by_uuid)))) {
+		if (source)
+			_LOGW ("cannot update connection due to conflicting UUID for "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_by_uuid));
+		else
+			_LOGW ("cannot load %s due to conflicting UUID for "NM_IFCFG_CONNECTION_LOG_FMT, full_path, NM_IFCFG_CONNECTION_LOG_ARG (connection_by_uuid));
+		g_object_unref (connection_new);
+		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+		                      "Skip updating protected connection during reload");
+		return NULL;
+	}
 
-	old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (existing));
-	new_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (new));
+	/* Evaluate unmanaged/unrecognized flags. */
+	if (connection_by_uuid)
+		old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (connection_by_uuid);
+	new_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (connection_new);
 	unmanaged_changed = g_strcmp0 (old_unmanaged, new_unmanaged);
 
-	old_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (NM_IFCFG_CONNECTION (existing));
-	new_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (NM_IFCFG_CONNECTION (new));
+	if (connection_by_uuid)
+		old_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (connection_by_uuid);
+	new_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (connection_new);
 	unrecognized_changed = g_strcmp0 (old_unrecognized, new_unrecognized);
 
-	if (   !unmanaged_changed
-	    && !unrecognized_changed
-	    && nm_connection_compare (NM_CONNECTION (existing),
-	                              NM_CONNECTION (new),
-	                              NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
-	                                  NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
-		g_object_unref (new);
-		return;
-	}
+	if (connection_by_uuid) {
+		const char *old_path;
+
+		old_path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid));
+
+		if (   !unmanaged_changed
+		    && !unrecognized_changed
+		    && nm_connection_compare (NM_CONNECTION (connection_by_uuid),
+		                              NM_CONNECTION (connection_new),
+		                              NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
+		                              NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
+			if (old_path && g_strcmp0 (old_path, full_path) != 0)
+				_LOGI ("rename \"%s\" to "NM_IFCFG_CONNECTION_LOG_FMT" without other changes", nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid)), NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
+		} else {
+
+			/*******************************************************
+			 * UPDATE
+			 *******************************************************/
+
+			if (source)
+				_LOGI ("update "NM_IFCFG_CONNECTION_LOG_FMT" from %s", NM_IFCFG_CONNECTION_LOG_ARG (connection_new), NM_IFCFG_CONNECTION_LOG_PATH (old_path));
+			else if (!g_strcmp0 (old_path, nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_new))))
+				_LOGI ("update "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
+			else if (old_path)
+				_LOGI ("rename \"%s\" to "NM_IFCFG_CONNECTION_LOG_FMT, old_path, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
+			else
+				_LOGI ("update and persist "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
+
+			g_object_set (connection_by_uuid,
+			              NM_IFCFG_CONNECTION_UNMANAGED_SPEC, new_unmanaged,
+			              NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, new_unrecognized,
+			              NULL);
+
+			if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection_by_uuid),
+			                                              NM_CONNECTION (connection_new),
+			                                              FALSE,  /* don't set Unsaved */
+			                                              "ifcfg-update",
+			                                              &local)) {
+				/* Shouldn't ever get here as 'connection_new' was verified by the reader already
+				 * and the UUID did not change. */
+				g_assert_not_reached ();
+			}
+			g_assert_no_error (local);
+
+			if (new_unmanaged || new_unrecognized) {
+				if (!old_unmanaged && !old_unrecognized) {
+					g_object_ref (connection_by_uuid);
+					/* Unexport the connection by telling the settings service it's
+					 * been removed.
+					 */
+					nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection_by_uuid));
+					/* Remove the path so that claim_connection() doesn't complain later when
+					 * interface gets managed and connection is re-added. */
+					nm_connection_set_path (NM_CONNECTION (connection_by_uuid), NULL);
+
+					/* signal_remove() will end up removing the connection from our hash,
+					 * so add it back now.
+					 */
+					g_hash_table_insert (priv->connections,
+					                     g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection_by_uuid))),
+					                     connection_by_uuid);
+				}
+			} else {
+				if (old_unmanaged /* && !new_unmanaged */) {
+					_LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" and its device because NM_CONTROLLED was true.",
+					       NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
+					g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_by_uuid);
+				} else if (old_unrecognized /* && !new_unrecognized */) {
+					_LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" because it is now a recognized type.",
+					       NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
+					g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_by_uuid);
+				}
+			}
 
-	nm_log_info (LOGD_SETTINGS, "updating %s", path);
-	g_object_set (existing,
-	              NM_IFCFG_CONNECTION_UNMANAGED_SPEC, new_unmanaged,
-	              NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, new_unrecognized,
-	              NULL);
-
-	if (new_unmanaged || new_unrecognized) {
-		if (!old_unmanaged && !old_unrecognized) {
-			g_object_ref (existing);
-			/* Unexport the connection by telling the settings service it's
-			 * been removed.
-			 */
-			nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (existing));
-			/* Remove the path so that claim_connection() doesn't complain later when
-			 * interface gets managed and connection is re-added. */
-			nm_connection_set_path (NM_CONNECTION (existing), NULL);
-
-			/* signal_remove() will end up removing the connection from our hash,
-			 * so add it back now.
-			 */
-			g_hash_table_insert (priv->connections,
-			                     g_strdup (nm_connection_get_uuid (NM_CONNECTION (existing))),
-			                     existing);
+			if (unmanaged_changed)
+				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
+			if (unrecognized_changed)
+				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
 		}
+		nm_settings_connection_set_filename (NM_SETTINGS_CONNECTION (connection_by_uuid), full_path);
+		g_object_unref (connection_new);
+		return connection_by_uuid;
 	} else {
-		const char *cid = nm_connection_get_id (NM_CONNECTION (new));
-
-		if (old_unmanaged /* && !new_unmanaged */) {
-			nm_log_info (LOGD_SETTINGS, "Managing connection '%s' and its device because NM_CONTROLLED was true.", cid);
-			g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, existing);
-		} else if (old_unrecognized /* && !new_unrecognized */) {
-			nm_log_info (LOGD_SETTINGS, "Managing connection '%s' because it is now a recognized type.", cid);
-			g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, existing);
-		}
 
-		if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (existing),
-		                                              NM_CONNECTION (new),
-		                                              FALSE,  /* don't set Unsaved */
-		                                              &error)) {
-			/* Shouldn't ever get here as 'new' was verified by the reader already */
-			g_assert_no_error (error);
+		/*******************************************************
+		 * ADD
+		 *******************************************************/
+
+		if (source)
+			_LOGI ("add connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
+		else
+			_LOGI ("new connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
+		g_hash_table_insert (priv->connections, g_strdup (uuid), connection_new);
+
+		g_signal_connect (connection_new, NM_SETTINGS_CONNECTION_REMOVED,
+		                  G_CALLBACK (connection_removed_cb),
+		                  self);
+
+		if (nm_ifcfg_connection_get_unmanaged_spec (connection_new)) {
+			const char *spec;
+			const char *device_id;
+
+			spec = nm_ifcfg_connection_get_unmanaged_spec (connection_new);
+			device_id = strchr (spec, ':');
+			if (device_id)
+				device_id++;
+			else
+				device_id = spec;
+			_LOGW ("Ignoring connection "NM_IFCFG_CONNECTION_LOG_FMT" / device '%s' due to NM_CONTROLLED=no.",
+			       NM_IFCFG_CONNECTION_LOG_ARG (connection_new), device_id);
+		} else if (nm_ifcfg_connection_get_unrecognized_spec (connection_new))
+			_LOGW ("Ignoring connection "NM_IFCFG_CONNECTION_LOG_FMT" of unrecognized type.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
+
+		/* watch changes of ifcfg hardlinks */
+		g_signal_connect (G_OBJECT (connection_new), "ifcfg-changed",
+		                  G_CALLBACK (connection_ifcfg_changed), self);
+
+		if (!source) {
+			/* Only raise the signal if we were called without source, i.e. if we read the connection from file.
+			 * Otherwise, we were called by add_connection() which does not expect the signal. */
+			if (nm_ifcfg_connection_get_unmanaged_spec (connection_new))
+				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
+			else if (nm_ifcfg_connection_get_unrecognized_spec (connection_new))
+				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
+			else
+				g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_new);
 		}
+		return connection_new;
 	}
-	g_object_unref (new);
-
-	if (unmanaged_changed)
-		g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
-	if (unrecognized_changed)
-		g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
 }
 
 static void
@@ -385,6 +430,8 @@ ifcfg_dir_changed (GFileMonitor *monitor,
 		return;
 	}
 
+	_LOGD ("ifcfg_dir_changed(%s) = %d", path, event_type);
+
 	base = g_file_get_basename (file);
 	if (utils_is_ifcfg_alias_file (base, NULL)) {
 		/* Alias file changed. Get the base ifcfg file from it */
@@ -397,14 +444,13 @@ ifcfg_dir_changed (GFileMonitor *monitor,
 		connection = find_by_path (plugin, ifcfg_path);
 		switch (event_type) {
 		case G_FILE_MONITOR_EVENT_DELETED:
-			nm_log_info (LOGD_SETTINGS, "removed %s.", ifcfg_path);
 			if (connection)
 				remove_connection (plugin, connection);
 			break;
 		case G_FILE_MONITOR_EVENT_CREATED:
 		case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
 			/* Update or new */
-			connection_new_or_changed (plugin, ifcfg_path, connection, NULL);
+			update_connection (plugin, NULL, ifcfg_path, connection, TRUE, NULL, NULL);
 			break;
 		default:
 			break;
@@ -433,6 +479,43 @@ setup_ifcfg_monitoring (SCPluginIfcfg *plugin)
 	}
 }
 
+static GHashTable *
+_paths_from_connections (GHashTable *connections)
+{
+	GHashTableIter iter;
+	NMIfcfgConnection *connection;
+	GHashTable *paths = g_hash_table_new (g_str_hash, g_str_equal);
+
+	g_hash_table_iter_init (&iter, connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) {
+		const char *path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection));
+
+		if (path)
+			g_hash_table_add (paths, (void *) path);
+	}
+	return paths;
+}
+
+static int
+_sort_paths (const char **f1, const char **f2, GHashTable *paths)
+{
+	struct stat st;
+	gboolean c1, c2;
+	gint64 m1, m2;
+
+	c1 = !!g_hash_table_contains (paths, *f1);
+	c2 = !!g_hash_table_contains (paths, *f2);
+	if (c1 != c2)
+		return c1 ? -1 : 1;
+
+	m1 = stat (*f1, &st) == 0 ? (gint64) st.st_mtime : G_MININT64;
+	m2 = stat (*f2, &st) == 0 ? (gint64) st.st_mtime : G_MININT64;
+	if (m1 != m2)
+		return m1 > m2 ? -1 : 1;
+
+	return strcmp (*f1, *f2);
+}
+
 static void
 read_connections (SCPluginIfcfg *plugin)
 {
@@ -440,28 +523,26 @@ read_connections (SCPluginIfcfg *plugin)
 	GDir *dir;
 	GError *err = NULL;
 	const char *item;
-	GHashTable *oldconns;
+	GHashTable *alive_connections;
 	GHashTableIter iter;
-	gpointer key, value;
 	NMIfcfgConnection *connection;
+	GPtrArray *dead_connections = NULL;
+	guint i;
+	GPtrArray *filenames;
+	GHashTable *paths;
 
 	dir = g_dir_open (IFCFG_DIR, 0, &err);
 	if (!dir) {
-		nm_log_warn (LOGD_SETTINGS, "Could not read directory '%s': %s", IFCFG_DIR, err->message);
+		_LOGW ("Could not read directory '%s': %s", IFCFG_DIR, err->message);
 		g_error_free (err);
 		return;
 	}
 
-	oldconns = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-	g_hash_table_iter_init (&iter, priv->connections);
-	while (g_hash_table_iter_next (&iter, NULL, &value)) {
-		const char *ifcfg_path = nm_ifcfg_connection_get_path (value);
-		if (ifcfg_path)
-			g_hash_table_insert (oldconns, g_strdup (ifcfg_path), value);
-	}
+	alive_connections = g_hash_table_new (NULL, NULL);
 
+	filenames = g_ptr_array_new_with_free_func (g_free);
 	while ((item = g_dir_read_name (dir))) {
-		char *full_path, *old_path;
+		char *full_path;
 
 		if (utils_should_ignore_file (item, TRUE))
 			continue;
@@ -470,31 +551,45 @@ read_connections (SCPluginIfcfg *plugin)
 
 		full_path = g_build_filename (IFCFG_DIR, item, NULL);
 		if (!utils_get_ifcfg_name (full_path, TRUE))
-			goto next;
+			g_free (full_path);
+		else
+			g_ptr_array_add (filenames, full_path);
+	}
+	g_dir_close (dir);
 
-		connection = g_hash_table_lookup (oldconns, full_path);
-		g_hash_table_remove (oldconns, full_path);
-		connection_new_or_changed (plugin, full_path, connection, &old_path);
+	/* While reloading, we don't replace connections that we already loaded while
+	 * iterating over the files.
+	 *
+	 * To have sensible, reproducible behavior, sort the paths by last modification
+	 * time prefering older files.
+	 */
+	paths = _paths_from_connections (priv->connections);
+	g_ptr_array_sort_with_data (filenames, (GCompareDataFunc) _sort_paths, paths);
+	g_hash_table_destroy (paths);
+
+	for (i = 0; i < filenames->len; i++) {
+		connection = update_connection (plugin, NULL, filenames->pdata[i], NULL, FALSE, alive_connections, NULL);
+		if (connection)
+			g_hash_table_add (alive_connections, connection);
+	}
+	g_ptr_array_free (filenames, TRUE);
 
-		if (old_path) {
-			g_hash_table_remove (oldconns, old_path);
-			g_free (old_path);
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) {
+		if (   !g_hash_table_contains (alive_connections, connection)
+		    && nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection))) {
+			if (!dead_connections)
+				dead_connections = g_ptr_array_new ();
+			g_ptr_array_add (dead_connections, connection);
 		}
-
-	next:
-		g_free (full_path);
 	}
+	g_hash_table_destroy (alive_connections);
 
-	g_dir_close (dir);
-
-	g_hash_table_iter_init (&iter, oldconns);
-	while (g_hash_table_iter_next (&iter, &key, &value)) {
-		nm_log_info (LOGD_SETTINGS, "removed %s.", (char *)key);
-		g_hash_table_iter_remove (&iter);
-		remove_connection (plugin, value);
+	if (dead_connections) {
+		for (i = 0; i < dead_connections->len; i++)
+			remove_connection (plugin, dead_connections->pdata[i]);
+		g_ptr_array_free (dead_connections, TRUE);
 	}
-
-	g_hash_table_destroy (oldconns);
 }
 
 static GSList *
@@ -540,7 +635,7 @@ load_connection (NMSystemConfigInterface *config,
 		return FALSE;
 
 	connection = find_by_path (plugin, filename);
-	connection_new_or_changed (plugin, filename, connection, NULL);
+	update_connection (plugin, NULL, filename, connection, TRUE, NULL, NULL);
 	if (!connection)
 		connection = find_by_path (plugin, filename);
 
@@ -605,8 +700,7 @@ add_connection (NMSystemConfigInterface *config,
                 GError **error)
 {
 	SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config);
-	NMIfcfgConnection *added = NULL;
-	char *path = NULL;
+	gs_free char *path = NULL;
 
 	/* Ensure we reject attempts to add the connection long before we're
 	 * asked to write it to disk.
@@ -618,10 +712,7 @@ add_connection (NMSystemConfigInterface *config,
 		if (!writer_new_connection (connection, IFCFG_DIR, &path, error))
 			return NULL;
 	}
-
-	added = _internal_new_connection (self, path, connection, error);
-	g_free (path);
-	return (NMSettingsConnection *) added;
+	return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error));
 }
 
 #define SC_NETWORK_FILE "/etc/sysconfig/network"
@@ -641,7 +732,7 @@ plugin_get_hostname (SCPluginIfcfg *plugin)
 
 	network = svOpenFile (SC_NETWORK_FILE, NULL);
 	if (!network) {
-		nm_log_warn (LOGD_SETTINGS, "Could not get hostname: failed to read " SC_NETWORK_FILE);
+		_LOGW ("Could not get hostname: failed to read " SC_NETWORK_FILE);
 		return NULL;
 	}
 
@@ -693,7 +784,7 @@ plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname)
 #endif
 
 	if (!ret) {
-		nm_log_warn (LOGD_SETTINGS, "Could not save hostname: failed to create/open " HOSTNAME_FILE);
+		_LOGW ("Could not save hostname: failed to create/open " HOSTNAME_FILE);
 		g_free (hostname_eol);
 		return FALSE;
 	}
@@ -862,7 +953,7 @@ sc_plugin_ifcfg_init (SCPluginIfcfg *plugin)
 
 	priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
 	if (!priv->bus) {
-		nm_log_warn (LOGD_SETTINGS, "Couldn't connect to D-Bus: %s", error->message);
+		_LOGW ("Couldn't connect to D-Bus: %s", error->message);
 		g_clear_error (&error);
 	} else {
 		DBusConnection *tmp;
@@ -883,10 +974,10 @@ sc_plugin_ifcfg_init (SCPluginIfcfg *plugin)
 		                        G_TYPE_INVALID,
 		                        G_TYPE_UINT, &result,
 		                        G_TYPE_INVALID)) {
-			nm_log_warn (LOGD_SETTINGS, "Couldn't acquire D-Bus service: %s", error->message);
+			_LOGW ("Couldn't acquire D-Bus service: %s", error->message);
 			g_clear_error (&error);
 		} else if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
-			nm_log_warn (LOGD_SETTINGS, "Couldn't acquire ifcfgrh1 D-Bus service (already taken)");
+			_LOGW ("Couldn't acquire ifcfgrh1 D-Bus service (already taken)");
 		} else
 			success = TRUE;
 	}
@@ -1048,7 +1139,7 @@ nm_system_config_factory (void)
 			dbus_g_connection_register_g_object (priv->bus,
 			                                     DBUS_OBJECT_PATH,
 			                                     G_OBJECT (singleton));
-		nm_log_info (LOGD_SETTINGS, "Acquired D-Bus service %s", DBUS_SERVICE_NAME);
+		_LOGI ("Acquired D-Bus service %s", DBUS_SERVICE_NAME);
 	} else
 		g_object_ref (singleton);
 
diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c
index 145a0a39..41439f61 100644
--- a/src/settings/plugins/ifcfg-rh/reader.c
+++ b/src/settings/plugins/ifcfg-rh/reader.c
@@ -56,6 +56,7 @@
 #include "nm-posix-signals.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
+#include "gsystem-local-alloc.h"
 
 #include "common.h"
 #include "shvar.h"
@@ -292,9 +293,11 @@ get_numbered_tag (char *tag_name, int which)
 }
 
 static gboolean
-is_any_ip4_address_defined (shvarFile *ifcfg)
+is_any_ip4_address_defined (shvarFile *ifcfg, int *idx)
 {
-	int i;
+	int i, ignore, *ret_idx;;
+
+	ret_idx = idx ? idx : &ignore;
 
 	for (i = -1; i <= 2; i++) {
 		char *tag;
@@ -305,6 +308,7 @@ is_any_ip4_address_defined (shvarFile *ifcfg)
 		g_free (tag);
 		if (value) {
 			g_free (value);
+			*ret_idx = i;
 			return TRUE;
 		}
 
@@ -313,6 +317,7 @@ is_any_ip4_address_defined (shvarFile *ifcfg)
 		g_free(tag);
 		if (value) {
 			g_free (value);
+			*ret_idx = i;
 			return TRUE;
 		}
 
@@ -321,6 +326,7 @@ is_any_ip4_address_defined (shvarFile *ifcfg)
 		g_free(tag);
 		if (value) {
 			g_free (value);
+			*ret_idx = i;
 			return TRUE;
 		}
 	}
@@ -534,8 +540,6 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
 	char **lines = NULL, **iter;
 	GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
 	GMatchInfo *match_info;
-	NMIPRoute *route = NULL;
-	char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL;
 	gint64 prefix_int, metric_int;
 	gboolean success = FALSE;
 
@@ -567,6 +571,9 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
 	/* Iterate through file lines */
 	lines = g_strsplit_set (contents, "\n\r", -1);
 	for (iter = lines; iter && *iter; iter++) {
+		gs_free char *next_hop = NULL, *dest = NULL;
+		char *prefix, *metric;
+		NMIPRoute *route;
 
 		/* Skip empty lines */
 		if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
@@ -586,11 +593,10 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
 		}
 		dest = g_match_info_fetch (match_info, 1);
 		if (!strcmp (dest, "default"))
-			strcpy (dest, "0.0.0.0");
+			strcpy (dest,  "0.0.0.0");
 		if (!nm_utils_ipaddr_valid (AF_INET, dest)) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Invalid IP4 route destination address '%s'", dest);
-			g_free (dest);
 			g_match_info_free (match_info);
 			goto error;
 		}
@@ -605,7 +611,6 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
 			if (errno || prefix_int <= 0 || prefix_int > 32) {
 				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 				             "Invalid IP4 route destination prefix '%s'", prefix);
-				g_free (dest);
 				g_free (prefix);
 				goto error;
 			}
@@ -621,13 +626,10 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
 				             "Invalid IP4 route gateway address '%s'",
 				             next_hop);
 				g_match_info_free (match_info);
-				g_free (dest);
-				g_free (next_hop);
 				goto error;
 			}
 		} else {
 			/* we don't make distinction between missing GATEWAY IP and 0.0.0.0 */
-			next_hop = NULL;
 		}
 		g_match_info_free (match_info);
 
@@ -642,8 +644,6 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
 				g_match_info_free (match_info);
 				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 				             "Invalid IP4 route metric '%s'", metric);
-				g_free (dest);
-				g_free (next_hop);
 				g_free (metric);
 				goto error;
 			}
@@ -652,13 +652,11 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
 		g_match_info_free (match_info);
 
 		route = nm_ip_route_new (AF_INET, dest, prefix_int, next_hop, metric_int, error);
-		if (!route) {
-			g_free (dest);
-			g_free (next_hop);
+		if (!route)
 			goto error;
-		}
 		if (!nm_setting_ip_config_add_route (s_ip4, route))
 			PARSE_WARNING ("duplicate IP4 route");
+		nm_ip_route_unref (route);
 	}
 
 	success = TRUE;
@@ -666,8 +664,6 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
 error:
 	g_free (contents);
 	g_strfreev (lines);
-	if (route)
-		nm_ip_route_unref (route);
 	g_regex_unref (regex_to1);
 	g_regex_unref (regex_to2);
 	g_regex_unref (regex_via);
@@ -743,7 +739,6 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error
 	char **lines = NULL, **iter;
 	GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
 	GMatchInfo *match_info;
-	NMIPRoute *route = NULL;
 	char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL;
 	gint64 prefix_int, metric_int;
 	gboolean success = FALSE;
@@ -776,6 +771,7 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error
 	/* Iterate through file lines */
 	lines = g_strsplit_set (contents, "\n\r", -1);
 	for (iter = lines; iter && *iter; iter++) {
+		NMIPRoute *route;
 
 		/* Skip empty lines */
 		if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
@@ -865,6 +861,7 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error
 			goto error;
 		if (!nm_setting_ip_config_add_route (s_ip6, route))
 			PARSE_WARNING ("duplicate IP6 route");
+		nm_ip_route_unref (route);
 	}
 
 	success = TRUE;
@@ -872,8 +869,6 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error
 error:
 	g_free (contents);
 	g_strfreev (lines);
-	if (route)
-		nm_ip_route_unref (route);
 	g_regex_unref (regex_to1);
 	g_regex_unref (regex_to2);
 	g_regex_unref (regex_via);
@@ -892,7 +887,7 @@ make_ip4_setting (shvarFile *ifcfg,
 	char *value = NULL;
 	char *route_path = NULL;
 	char *method;
-	char *gateway = NULL;
+	gs_free char *gateway = NULL;
 	gint32 i;
 	shvarFile *network_ifcfg;
 	shvarFile *route_ifcfg;
@@ -930,7 +925,7 @@ make_ip4_setting (shvarFile *ifcfg,
 	value = svGetValue (ifcfg, "BOOTPROTO", FALSE);
 
 	if (!value || !*value || !g_ascii_strcasecmp (value, "none")) {
-		if (is_any_ip4_address_defined (ifcfg))
+		if (is_any_ip4_address_defined (ifcfg, NULL))
 			method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
 		else
 			method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
@@ -946,11 +941,25 @@ make_ip4_setting (shvarFile *ifcfg,
 		              NULL);
 		return NM_SETTING (s_ip4);
 	} else if (!g_ascii_strcasecmp (value, "shared")) {
+		int idx;
+
 		g_free (value);
 		g_object_set (s_ip4,
 		              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED,
 		              NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
 		              NULL);
+		/* 1 IP address is allowed for shared connections. Read it. */
+		if (is_any_ip4_address_defined (ifcfg, &idx)) {
+			NMIPAddress *addr = NULL;
+
+			if (!read_full_ip4_address (ifcfg, network_file, idx, NULL, &addr, NULL, error))
+				goto done;
+			if (!read_ip4_address (ifcfg, "GATEWAY", &gateway, error))
+				goto done;
+			(void) nm_setting_ip_config_add_address (s_ip4, addr);
+			nm_ip_address_unref (addr);
+			g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
+		}
 		return NM_SETTING (s_ip4);
 	} else {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -966,6 +975,8 @@ make_ip4_setting (shvarFile *ifcfg,
 	              NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "PEERROUTES", TRUE),
 	              NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
 	              NM_SETTING_IP_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", FALSE),
+	              NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV4_ROUTE_METRIC", 10,
+	                                                                  -1, G_MAXUINT32, -1),
 	              NULL);
 
 	if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
@@ -997,6 +1008,8 @@ make_ip4_setting (shvarFile *ifcfg,
 	for (i = -1; i < 256; i++) {
 		NMIPAddress *addr = NULL;
 
+		/* gateway will only be set if still unset. Hence, we don't leak gateway
+		 * here by calling read_full_ip4_address() repeatedly */
 		if (!read_full_ip4_address (ifcfg, network_file, i, NULL, &addr, &gateway, error))
 			goto done;
 
@@ -1075,14 +1088,10 @@ make_ip4_setting (shvarFile *ifcfg,
 
 	/* Static routes  - route-<name> file */
 	route_path = utils_get_route_path (ifcfg->fileName);
-	if (!route_path) {
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Could not get route file path for '%s'", ifcfg->fileName);
-		goto done;
-	}
 
-	/* First test new/legacy syntax */
-	if (utils_has_route_file_new_syntax (route_path)) {
+	if (utils_has_complex_routes (route_path)) {
+		PARSE_WARNING ("'rule-' or 'rule6-' file is present; you will need to use a dispatcher script to apply these routes");
+	} else if (utils_has_route_file_new_syntax (route_path)) {
 		/* Parse route file in new syntax */
 		route_ifcfg = utils_get_route_ifcfg (ifcfg->fileName, FALSE);
 		if (route_ifcfg) {
@@ -1107,6 +1116,7 @@ make_ip4_setting (shvarFile *ifcfg,
 		if (!read_route_file_legacy (route_path, s_ip4, error))
 			goto done;
 	}
+	g_free (route_path);
 
 	/* Legacy value NM used for a while but is incorrect (rh #459370) */
 	if (!nm_setting_ip_config_get_num_dns_searches (s_ip4)) {
@@ -1132,7 +1142,6 @@ make_ip4_setting (shvarFile *ifcfg,
 	return NM_SETTING (s_ip4);
 
 done:
-	g_free (gateway);
 	g_free (route_path);
 	g_object_unref (s_ip4);
 	return NULL;
@@ -1362,6 +1371,8 @@ make_ip6_setting (shvarFile *ifcfg,
 	              NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "IPV6_PEERROUTES", TRUE),
 	              NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
 	              NM_SETTING_IP_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV6_FAILURE_FATAL", FALSE),
+	              NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV6_ROUTE_METRIC", 10,
+	                                                                  -1, G_MAXUINT32, -1),
 	              NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val,
 	              NULL);
 
@@ -1467,18 +1478,15 @@ make_ip6_setting (shvarFile *ifcfg,
 
 	/* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIPConfig */
 
-	/* Read static routes from route6-<interface> file */
-	route6_path = utils_get_route6_path (ifcfg->fileName);
-	if (!route6_path) {
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Could not get route6 file path for '%s'", ifcfg->fileName);
-		goto error;
-	}
+	if (!utils_has_complex_routes (ifcfg->fileName)) {
+		/* Read static routes from route6-<interface> file */
+		route6_path = utils_get_route6_path (ifcfg->fileName);
+		if (!read_route6_file (route6_path, s_ip6, error))
+			goto error;
 
-	if (!read_route6_file (route6_path, s_ip6, error))
-		goto error;
+		g_free (route6_path);
+	}
 
-	g_free (route6_path);
 	return NM_SETTING (s_ip6);
 
 error:
@@ -3061,7 +3069,8 @@ make_wpa_setting (shvarFile *ifcfg,
 			if (psk) {
 				g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL);
 				g_free (psk);
-			}
+			} else if (error)
+				goto error;
 		}
 
 		if (adhoc)
@@ -3174,6 +3183,8 @@ make_wireless_security_setting (shvarFile *ifcfg,
 {
 	NMSetting *wsec;
 
+	g_return_val_if_fail (error && !*error, NULL);
+
 	if (!adhoc) {
 		wsec = make_leap_setting (ifcfg, file, error);
 		if (wsec)
@@ -3425,11 +3436,11 @@ wireless_connection_from_ifcfg (const char *file,
 	char *printable_ssid = NULL;
 	const char *mode;
 	gboolean adhoc = FALSE;
+	GError *local = NULL;
 
 	g_return_val_if_fail (file != NULL, NULL);
 	g_return_val_if_fail (ifcfg != NULL, NULL);
-	g_return_val_if_fail (error != NULL, NULL);
-	g_return_val_if_fail (*error == NULL, NULL);
+	g_return_val_if_fail (!error || !*error, NULL);
 
 	connection = nm_simple_connection_new ();
 
@@ -3453,10 +3464,11 @@ wireless_connection_from_ifcfg (const char *file,
 		adhoc = TRUE;
 
 	/* Wireless security */
-	security_setting = make_wireless_security_setting (ifcfg, file, ssid, adhoc, &s_8021x, error);
-	if (*error) {
+	security_setting = make_wireless_security_setting (ifcfg, file, ssid, adhoc, &s_8021x, &local);
+	if (local) {
 		g_free (printable_ssid);
 		g_object_unref (connection);
+		g_propagate_error (error, local);
 		return NULL;
 	}
 	if (security_setting) {
@@ -3838,7 +3850,8 @@ handle_bond_option (NMSettingBond *s_bond,
 	}
 
 	if (!nm_setting_bond_add_option (s_bond, key, sanitized ? sanitized : value))
-		PARSE_WARNING ("invalid bonding option '%s'", key);
+		PARSE_WARNING ("invalid bonding option '%s' = %s",
+		               key, sanitized ? sanitized : value);
 	g_free (sanitized);
 }
 
@@ -4443,6 +4456,7 @@ make_vlan_setting (shvarFile *ifcfg,
 		goto error;
 	}
 	g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
+	g_clear_pointer (&parent, g_free);
 
 	if (svTrueValue (ifcfg, "REORDER_HDR", FALSE))
 		vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS;
@@ -4461,6 +4475,8 @@ make_vlan_setting (shvarFile *ifcfg,
 	parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP);
 	parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP);
 
+	g_free (iface_name);
+
 	return (NMSetting *) s_vlan;
 
 error:
@@ -4624,32 +4640,24 @@ check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6)
 	}
 }
 
-NMConnection *
-connection_from_file (const char *filename,
-                      const char *network_file,  /* for unit tests only */
-                      const char *test_type,     /* for unit tests only */
-                      char **out_unhandled,
-                      char **out_keyfile,
-                      char **out_routefile,
-                      char **out_route6file,
-                      GError **error,
-                      gboolean *out_ignore_error)
+static NMConnection *
+connection_from_file_full (const char *filename,
+                           const char *network_file,  /* for unit tests only */
+                           const char *test_type,     /* for unit tests only */
+                           char **out_unhandled,
+                           GError **error,
+                           gboolean *out_ignore_error)
 {
 	NMConnection *connection = NULL;
 	shvarFile *parsed;
-	char *type, *devtype, *bootproto;
+	gs_free char *type = NULL;
+	char *devtype, *bootproto;
 	NMSetting *s_ip4, *s_ip6, *s_port, *s_dcb = NULL;
 	const char *ifcfg_name = NULL;
 
 	g_return_val_if_fail (filename != NULL, NULL);
 	if (out_unhandled)
 		g_return_val_if_fail (*out_unhandled == NULL, NULL);
-	if (out_keyfile)
-		g_return_val_if_fail (*out_keyfile == NULL, NULL);
-	if (out_routefile)
-		g_return_val_if_fail (*out_routefile == NULL, NULL);
-	if (out_route6file)
-		g_return_val_if_fail (*out_route6file == NULL, NULL);
 
 	/* Non-NULL only for unit tests; normally use /etc/sysconfig/network */
 	if (!network_file)
@@ -4685,8 +4693,7 @@ connection_from_file (const char *filename,
 		g_free (bootproto);
 		goto done;
 	}
-
-	type = NULL;
+	g_free (bootproto);
 
 	devtype = svGetValue (parsed, "DEVICETYPE", FALSE);
 	if (devtype) {
@@ -4775,7 +4782,6 @@ connection_from_file (const char *filename,
 			PARSE_WARNING ("connection type was unrecognized but device was not uniquely identified; device may be managed");
 		goto done;
 	}
-	g_free (type);
 
 	if (!connection)
 		goto done;
@@ -4827,15 +4833,64 @@ connection_from_file (const char *filename,
 		connection = NULL;
 	}
 
-	if (out_keyfile)
-		*out_keyfile = utils_get_keys_path (filename);
-	if (out_routefile)
-		*out_routefile = utils_get_route_path (filename);
-	if (out_route6file)
-		*out_route6file = utils_get_route6_path (filename);
-
 done:
 	svCloseFile (parsed);
 	return connection;
 }
 
+NMConnection *
+connection_from_file (const char *filename,
+                      char **out_unhandled,
+                      GError **error)
+{
+	gboolean ignore_error = FALSE;
+	NMConnection *conn;
+
+	conn = connection_from_file_full (filename, NULL, NULL,
+	                                  out_unhandled,
+	                                  error,
+	                                  &ignore_error);
+	if (error && *error && !ignore_error)
+		PARSE_WARNING ("%s", (*error)->message);
+	return conn;
+}
+
+NMConnection *
+connection_from_file_test (const char *filename,
+                           const char *network_file,
+                           const char *test_type,
+                           char **out_unhandled,
+                           GError **error)
+{
+	return connection_from_file_full (filename,
+	                                  network_file,
+	                                  test_type,
+	                                  out_unhandled,
+	                                  error,
+	                                  NULL);
+}
+
+guint
+devtimeout_from_file (const char *filename)
+{
+	shvarFile *ifcfg;
+	char *devtimeout_str;
+	guint devtimeout;
+
+	g_return_val_if_fail (filename != NULL, 0);
+
+	ifcfg = svOpenFile (filename, NULL);
+	if (!ifcfg)
+		return 0;
+
+	devtimeout_str = svGetValue (ifcfg, "DEVTIMEOUT", FALSE);
+	if (devtimeout_str) {
+		devtimeout = nm_utils_ascii_str_to_int64 (devtimeout_str, 10, 0, G_MAXUINT, 0);
+		g_free (devtimeout_str);
+	} else
+		devtimeout = 0;
+
+	svCloseFile (ifcfg);
+
+	return devtimeout;
+}
diff --git a/src/settings/plugins/ifcfg-rh/reader.h b/src/settings/plugins/ifcfg-rh/reader.h
index c23e5870..70e9ce4e 100644
--- a/src/settings/plugins/ifcfg-rh/reader.h
+++ b/src/settings/plugins/ifcfg-rh/reader.h
@@ -27,15 +27,18 @@
 #include "shvar.h"
 
 NMConnection *connection_from_file (const char *filename,
-                                    const char *network_file,  /* for unit tests only */
-                                    const char *test_type,     /* for unit tests only */
                                     char **out_unhandled,
-                                    char **out_keyfile,
-                                    char **out_routefile,
-                                    char **out_route6file,
-                                    GError **error,
-                                    gboolean *out_ignore_error);
+                                    GError **error);
 
 char *uuid_from_file (const char *filename);
 
+guint devtimeout_from_file (const char *filename);
+
+/* for test-ifcfg-rh */
+NMConnection *connection_from_file_test (const char *filename,
+                                         const char *network_file,
+                                         const char *test_type,
+                                         char **out_unhandled,
+                                         GError **error);
+
 #endif  /* __READER_H__ */
diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
index 6c9769b2..5f3d173b 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/settings/plugins/ifcfg-rh/shvar.c
@@ -372,10 +372,12 @@ svSetValue (shvarFile *s, const char *key, const char *value, gboolean verbatim)
 		if (oldval) {
 			/* delete line */
 			s->lineList = g_list_remove_link (s->lineList, s->current);
+			g_free (s->current->data);
 			g_list_free_1 (s->current);
 			s->modified = TRUE;
 		}
-		goto bail; /* do not need keyValue */
+		g_free (keyValue);
+		goto end;
 	}
 
 	if (!oldval) {
@@ -387,21 +389,19 @@ svSetValue (shvarFile *s, const char *key, const char *value, gboolean verbatim)
 
 	if (strcmp (oldval, newval) != 0) {
 		/* change line */
-		if (s->current)
+		if (s->current) {
+			g_free (s->current->data);
 			s->current->data = keyValue;
-		else
+		} else
 			s->lineList = g_list_append (s->lineList, keyValue);
 		s->modified = TRUE;
-	}
+	} else
+		g_free (keyValue);
 
  end:
 	g_free (newval);
 	g_free (oldval);
 	return;
-
- bail:
-	g_free (keyValue);
-	goto end;
 }
 
 /* Write the current contents iff modified.  Returns FALSE on error
diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/Makefile.am
index 5a17ed9b..a3f6a052 100644
--- a/src/settings/plugins/ifcfg-rh/tests/Makefile.am
+++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.am
@@ -47,6 +47,7 @@ test_ifcfg_rh_utils_SOURCES = \
 test_ifcfg_rh_utils_LDADD = \
 	$(top_builddir)/src/libNetworkManager.la
 
+@VALGRIND_RULES@
 TESTS = test-ifcfg-rh-utils test-ifcfg-rh
 
 endif
diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
index f34e759d..d3c838a7 100644
--- a/src/settings/plugins/ifcfg-rh/tests/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -83,8 +93,6 @@ host_triplet = @host@
 @ENABLE_TESTS_TRUE@TESTS = test-ifcfg-rh-utils$(EXEEXT) \
 @ENABLE_TESTS_TRUE@	test-ifcfg-rh$(EXEEXT)
 subdir = src/settings/plugins/ifcfg-rh/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -101,6 +109,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -226,6 +235,8 @@ am__tty_colors = { \
   fi; \
 }
 DIST_SUBDIRS = network-scripts
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -277,7 +288,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -312,6 +322,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -570,7 +581,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ifcfg-rh/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ifcfg-rh/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -624,14 +634,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -1073,9 +1083,13 @@ uninstall-am:
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_TESTS_TRUE@@GNOME_CODE_COVERAGE_RULES@
 
+@ENABLE_TESTS_TRUE@@VALGRIND_RULES@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am
index 8941da3a..a20a78d9 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am
@@ -9,10 +9,12 @@ EXTRA_DIST = \
 	ifcfg-test-wired-static-bootproto \
 	ifcfg-test-wired-dhcp \
 	ifcfg-test-wired-dhcp-plus-ip \
+	ifcfg-test-wired-shared-plus-ip \
 	ifcfg-test-wired-dhcp-send-hostname \
 	ifcfg-test-wired-dhcp6-only \
 	ifcfg-test-wired-global-gateway \
 	network-test-wired-global-gateway \
+	ifcfg-test-wired-obsolete-gateway-n \
 	ifcfg-test-wired-never-default \
 	network-test-wired-never-default \
 	ifcfg-test-wired-defroute-no \
@@ -106,6 +108,7 @@ EXTRA_DIST = \
 	ifcfg-test-bond-main \
 	ifcfg-test-bond-slave \
 	ifcfg-test-bond-slave-ib \
+	ifcfg-test-bond-mode-numeric \
 	ifcfg-test-dcb \
 	ifcfg-test-dcb-default-app-priorities \
 	ifcfg-test-dcb-bad-booleans \
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
index aac646f8..58798f77 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,7 +88,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/ifcfg-rh/tests/network-scripts
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -95,6 +104,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -119,6 +129,7 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -145,7 +156,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -180,6 +190,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -391,10 +402,12 @@ EXTRA_DIST = \
 	ifcfg-test-wired-static-bootproto \
 	ifcfg-test-wired-dhcp \
 	ifcfg-test-wired-dhcp-plus-ip \
+	ifcfg-test-wired-shared-plus-ip \
 	ifcfg-test-wired-dhcp-send-hostname \
 	ifcfg-test-wired-dhcp6-only \
 	ifcfg-test-wired-global-gateway \
 	network-test-wired-global-gateway \
+	ifcfg-test-wired-obsolete-gateway-n \
 	ifcfg-test-wired-never-default \
 	network-test-wired-never-default \
 	ifcfg-test-wired-defroute-no \
@@ -488,6 +501,7 @@ EXTRA_DIST = \
 	ifcfg-test-bond-main \
 	ifcfg-test-bond-slave \
 	ifcfg-test-bond-slave-ib \
+	ifcfg-test-bond-mode-numeric \
 	ifcfg-test-dcb \
 	ifcfg-test-dcb-default-app-priorities \
 	ifcfg-test-dcb-bad-booleans \
@@ -532,7 +546,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -712,6 +725,8 @@ uninstall-am:
 	mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
 	uninstall-am
 
+.PRECIOUS: Makefile
+
 
 dist-hook:
 	@for f in $(ALIAS_FILES); do \
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-mode-numeric b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-mode-numeric
new file mode 100644
index 00000000..9989f58b
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-mode-numeric
@@ -0,0 +1,5 @@
+DEVICE=bond0
+ONBOOT=no
+TYPE=Bond
+BOOTPROTO=dhcp
+BONDING_OPTS="mode=4 miimon=100"
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bridge-main b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bridge-main
index 8507628e..ee7a8dc6 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bridge-main
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bridge-main
@@ -3,6 +3,6 @@ ONBOOT=no
 TYPE=Bridge
 BOOTPROTO=dhcp
 STP=on
-DELAY=0
+DELAY=2
 BRIDGING_OPTS="priority=32744 hello_time=7 max_age=39 ageing_time=235352"
 MACADDR=00:16:41:11:22:33
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-open b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-open
index 48db45b2..b089103d 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-open
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-open
@@ -12,3 +12,5 @@ ONBOOT=yes
 USERCTL=yes
 PEERDNS=yes
 IPV6INIT=no
+IPV4_ROUTE_METRIC=104
+IPV6_ROUTE_METRIC=106
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp-plus-ip b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp-plus-ip
index f0c022a9..af254f9c 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp-plus-ip
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp-plus-ip
@@ -15,11 +15,11 @@ DNS3=1:2:3:4::a
 DNS4=1:2:3:4::b
 
 # additional IPs
-IPADDR0=1.2.3.4
-PREFIX0=24
-GATEWAY0=1.1.1.1
+IPADDR=1.2.3.4
+PREFIX=24
 IPADDR1=9.8.7.6
 PREFIX1=16
+GATEWAY=1.1.1.1
 
 IPV6ADDR="1001:abba::1234/56"
 IPV6ADDR_SECONDARIES="2001:abba::2234/64 3001:abba::3234/96"
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1
index cad0f6cf..1bc3d524 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1
@@ -5,8 +5,8 @@ HWADDR=00:11:22:33:44:ee
 BOOTPROTO=none
 IPADDR0=1.2.3.4
 PREFIX0=24
-GATEWAY0=1.1.1.1
 IPADDR1=9.8.7.6
 PREFIX1=16
 IPADDR2=3.3.3.3
 PREFIX2=8
+GATEWAY=1.1.1.1
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2
index ad9290a4..d7273e36 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2
@@ -5,10 +5,7 @@ HWADDR=00:11:22:33:44:ee
 BOOTPROTO=none
 IPADDR=1.2.3.4
 PREFIX=24
-GATEWAY=1.1.1.1
 IPADDR2=9.8.7.6
 PREFIX2=16
-GATEWAY2=5.5.5.5
 IPADDR3=3.3.3.3
 PREFIX3=8
-GATEWAY3=7.7.7.7
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-obsolete-gateway-n b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-obsolete-gateway-n
new file mode 100644
index 00000000..2190a995
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-obsolete-gateway-n
@@ -0,0 +1,13 @@
+# GATEWAY<N> is obsolete, but we read it for backwards compatibility
+
+TYPE=Ethernet
+DEVICE=eth0
+HWADDR=00:11:22:33:44:ee
+BOOTPROTO=none
+ONBOOT=yes
+
+# manual IP
+IPADDR1=1.2.3.4
+PREFIX1=24
+GATEWAY1=1.1.1.1
+
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-shared-plus-ip b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-shared-plus-ip
new file mode 100644
index 00000000..5098aef7
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-shared-plus-ip
@@ -0,0 +1,19 @@
+# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile)
+TYPE=Ethernet
+DEVICE=eth0
+HWADDR=00:11:22:33:44:ee
+BOOTPROTO=shared
+ONBOOT=no
+IPV6INIT=yes
+
+# additional IPs
+IPADDR=10.20.30.5
+PREFIX=24
+GATEWAY=1.1.1.1
+
+# these are ignored for shared method
+IPADDR1=6.7.8.9
+PREFIX1=16
+IPADDR2=3.3.3.3
+PREFIX2=24
+
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh-utils.c
index d82a3270..13f1126e 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh-utils.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh-utils.c
@@ -121,7 +121,7 @@ int main (int argc, char **argv)
 {
 	char *base;
 
-	nmtst_init (&argc, &argv, TRUE);
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
 
 	/* The tests */
 	test_get_ifcfg_name ("get-ifcfg-name-bad", "/foo/bar/adfasdfadf", FALSE, NULL);
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 4a6940d0..d2fb6867 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -194,8 +194,8 @@ test_read_basic (void)
 	guint64 expected_timestamp = 0;
 	gboolean success;
 
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-minimal",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-minimal",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -254,8 +254,8 @@ test_read_miscellaneous_variables (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*invalid MAC in HWADDR_BLACKLIST 'XX:aa:invalid'*");
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-misc-variables",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-misc-variables",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_test_assert_expected_messages ();
 	g_assert_no_error (error);
 	g_assert (connection);
@@ -304,8 +304,8 @@ test_read_variables_corner_cases (void)
 	guint64 expected_timestamp = 0;
 	gboolean success;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-variables-corner-cases-1",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-variables-corner-cases-1",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -350,10 +350,10 @@ test_read_unmanaged (void)
 	guint64 expected_timestamp = 0;
 	gboolean success;
 
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-nm-controlled",
-	                                   NULL, TYPE_ETHERNET,
-	                                   &unhandled_spec,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-nm-controlled",
+	                                        NULL, TYPE_ETHERNET,
+	                                        &unhandled_spec,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -377,16 +377,16 @@ test_read_unmanaged_unrecognized (void)
 {
 	NMConnection *connection;
 	NMSettingConnection *s_con;
-	char *unhandled_spec = NULL;
+	gs_free char *unhandled_spec = NULL;
 	GError *error = NULL;
 	const char *expected_id = "PigeonNet";
 	guint64 expected_timestamp = 0;
 	gboolean success;
 
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-nm-controlled-unrecognized",
-	                                   NULL, NULL,
-	                                   &unhandled_spec,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-nm-controlled-unrecognized",
+	                                        NULL, NULL,
+	                                        &unhandled_spec,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -408,16 +408,16 @@ test_read_unrecognized (void)
 {
 	NMConnection *connection;
 	NMSettingConnection *s_con;
-	char *unhandled_spec = NULL;
+	gs_free char *unhandled_spec = NULL;
 	GError *error = NULL;
 	const char *expected_id = "U Can't Touch This";
 	guint64 expected_timestamp = 0;
 	gboolean success;
 
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-unrecognized",
-	                                   NULL, NULL,
-	                                   &unhandled_spec,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-unrecognized",
+	                                        NULL, NULL,
+	                                        &unhandled_spec,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -452,8 +452,8 @@ test_read_wired_static (const char *file,
 	NMIPAddress *ip6_addr;
 	gboolean success;
 
-	connection = connection_from_file (file, NULL, TYPE_ETHERNET,
-	                                   &unmanaged, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (file, NULL, TYPE_ETHERNET,
+	                                        &unmanaged, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -527,7 +527,6 @@ test_read_wired_static (const char *file,
 		g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE);
 	}
 
-	g_free (unmanaged);
 	g_object_unref (connection);
 }
 
@@ -547,8 +546,8 @@ test_read_wired_static_no_prefix (gconstpointer user_data)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*missing PREFIX, assuming*");
-	connection = connection_from_file (file, NULL, TYPE_ETHERNET, NULL,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (file, NULL, TYPE_ETHERNET, NULL,
+	                                        &error);
 	g_test_assert_expected_messages ();
 	g_assert_no_error (error);
 	g_assert (connection);
@@ -584,10 +583,6 @@ test_read_wired_dhcp (void)
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *mac;
 	char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0xee };
@@ -595,15 +590,11 @@ test_read_wired_dhcp (void)
 	const char *expected_id = "System test-wired-dhcp";
 	const char *expected_dhcp_hostname = "foobar";
 
-	connection = connection_from_file (TEST_IFCFG_WIRED_DHCP,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_DHCP,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wired-dhcp-read", "failed to read %s: %s", TEST_IFCFG_WIRED_DHCP, error->message);
 
@@ -722,10 +713,6 @@ test_read_wired_dhcp (void)
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_DNS);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -740,9 +727,9 @@ test_read_wired_dhcp_plus_ip (void)
 	NMIPAddress *ip6_addr;
 	gboolean success;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-dhcp-plus-ip",
-	                                   NULL, TYPE_ETHERNET, NULL,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-dhcp-plus-ip",
+	                                        NULL, TYPE_ETHERNET, NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -807,6 +794,38 @@ test_read_wired_dhcp_plus_ip (void)
 }
 
 static void
+test_read_wired_shared_plus_ip (void)
+{
+	NMConnection *connection;
+	NMSettingIPConfig *s_ip4;
+	GError *error = NULL;
+	NMIPAddress *ip4_addr;
+
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-shared-plus-ip",
+	                                        NULL, TYPE_ETHERNET, NULL,
+	                                        &error);
+	nmtst_assert_connection_verifies_without_normalization (connection);
+
+	/* ===== IPv4 SETTING ===== */
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	g_assert (s_ip4);
+	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_SHARED);
+	g_assert (nm_setting_ip_config_get_may_fail (s_ip4));
+
+	/* IP addresses */
+	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 1);
+	ip4_addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	g_assert (ip4_addr);
+	g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 24);
+	g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "10.20.30.5");
+
+	/* Gateway */
+	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "1.1.1.1");
+
+	g_object_unref (connection);
+}
+
+static void
 test_read_wired_global_gateway (void)
 {
 	NMConnection *connection;
@@ -817,9 +836,9 @@ test_read_wired_global_gateway (void)
 	NMIPAddress *ip4_addr;
 	char *unmanaged = NULL;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-global-gateway",
-	                                   TEST_IFCFG_DIR"/network-scripts/network-test-wired-global-gateway",
-	                                   TYPE_ETHERNET, &unmanaged, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-global-gateway",
+	                                        TEST_IFCFG_DIR"/network-scripts/network-test-wired-global-gateway",
+	                                        TYPE_ETHERNET, &unmanaged, &error);
 	nmtst_assert_connection_verifies_without_normalization (connection);
 	g_assert (unmanaged == NULL);
 
@@ -850,6 +869,37 @@ test_read_wired_global_gateway (void)
 }
 
 static void
+test_read_wired_obsolete_gateway_n (void)
+{
+	NMConnection *connection;
+	NMSettingIPConfig *s_ip4;
+	GError *error = NULL;
+	NMIPAddress *ip4_addr;
+
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-obsolete-gateway-n",
+	                                        NULL, TYPE_ETHERNET, NULL,
+	                                        &error);
+	nmtst_assert_connection_verifies_without_normalization (connection);
+
+	/* ===== IPv4 SETTING ===== */
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	g_assert (s_ip4);
+	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+
+	/* IP addresses */
+	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 1);
+	ip4_addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	g_assert (ip4_addr);
+	g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 24);
+	g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "1.2.3.4");
+
+	/* Gateway */
+	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "1.1.1.1");
+
+	g_object_unref (connection);
+}
+
+static void
 test_read_wired_never_default (void)
 {
 	NMConnection *connection;
@@ -857,9 +907,9 @@ test_read_wired_never_default (void)
 	NMSettingIPConfig *s_ip6;
 	GError *error = NULL;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-never-default",
-	                                   TEST_IFCFG_DIR"/network-scripts/network-test-wired-never-default",
-	                                   TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-never-default",
+	                                        TEST_IFCFG_DIR"/network-scripts/network-test-wired-never-default",
+	                                        TYPE_ETHERNET, NULL, &error);
 	nmtst_assert_connection_verifies_without_normalization (connection);
 
 	/* ===== WIRED SETTING ===== */
@@ -892,23 +942,15 @@ test_read_wired_defroute_no (void)
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System test-wired-defroute-no";
 
-	connection = connection_from_file (TEST_IFCFG_WIRED_DEFROUTE_NO,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_DEFROUTE_NO,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wired-defroute-no-read", "failed to read %s: %s", TEST_IFCFG_WIRED_DEFROUTE_NO, error->message);
 
@@ -991,10 +1033,6 @@ test_read_wired_defroute_no (void)
 	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_NEVER_DEFAULT);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -1010,23 +1048,15 @@ test_read_wired_defroute_no_gatewaydev_yes (void)
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System test-wired-defroute-no-gatewaydev-yes";
 
-	connection = connection_from_file (TEST_IFCFG_WIRED_DEFROUTE_NO_GATEWAYDEV_YES,
-	                                   TEST_NETWORK_WIRED_DEFROUTE_NO_GATEWAYDEV_YES,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_DEFROUTE_NO_GATEWAYDEV_YES,
+	                                        TEST_NETWORK_WIRED_DEFROUTE_NO_GATEWAYDEV_YES,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wired-defroute-no-gatewaydev-yes-read",
 	        "failed to read %s: %s",
@@ -1117,10 +1147,6 @@ test_read_wired_defroute_no_gatewaydev_yes (void)
 	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_NEVER_DEFAULT);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -1134,8 +1160,8 @@ test_read_wired_static_routes (void)
 	GError *error = NULL;
 	NMIPRoute *ip4_route;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-static-routes",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-static-routes",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	nmtst_assert_connection_verifies_without_normalization (connection);
 
 	/* ===== CONNECTION SETTING ===== */
@@ -1182,24 +1208,16 @@ test_read_wired_static_routes_legacy (void)
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	NMIPRoute *ip4_route;
 	const char *expected_id = "System test-wired-static-routes-legacy";
 
-	connection = connection_from_file (TEST_IFCFG_WIRED_STATIC_ROUTES_LEGACY,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_STATIC_ROUTES_LEGACY,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 
 	ASSERT (connection != NULL,
 	        "wired-static-routes-legacy-read",
@@ -1291,10 +1309,6 @@ test_read_wired_static_routes_legacy (void)
 	g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "7.7.7.7");
 	g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -1306,23 +1320,15 @@ test_read_wired_ipv4_manual (const char *file, const char *expected_id)
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	NMIPAddress *ip4_addr;
 
-	connection = connection_from_file (file,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (file,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wired-ipv4-manual-read", "failed to read %s: %s", file, error->message);
 
@@ -1402,10 +1408,6 @@ test_read_wired_ipv4_manual (const char *file, const char *expected_id)
 	g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "3.3.3.3");
 	g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 8);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -1420,10 +1422,6 @@ test_read_wired_ipv6_manual (void)
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System test-wired-ipv6-manual";
@@ -1432,15 +1430,11 @@ test_read_wired_ipv6_manual (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*ignoring manual default route*");
-	connection = connection_from_file (TEST_IFCFG_WIRED_IPV6_MANUAL,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_IPV6_MANUAL,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	g_test_assert_expected_messages ();
 
 	ASSERT (connection != NULL,
@@ -1635,10 +1629,6 @@ test_read_wired_ipv6_manual (void)
 	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_DNS_SEARCH);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -1653,25 +1643,17 @@ test_read_wired_ipv6_only (void)
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System test-wired-ipv6-only";
 	NMIPAddress *ip6_addr;
 	const char *method;
 
-	connection = connection_from_file (TEST_IFCFG_WIRED_IPV6_ONLY,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_IPV6_ONLY,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wired-ipv6-only-read", "failed to read %s: %s", TEST_IFCFG_WIRED_IPV6_ONLY, error->message);
 
@@ -1773,10 +1755,6 @@ test_read_wired_ipv6_only (void)
 	g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip6, 1), ==, "ipsum.org");
 	g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip6, 2), ==, "dolor.edu");
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -1791,24 +1769,16 @@ test_read_wired_dhcp6_only (void)
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System test-wired-dhcp6-only";
 	const char *method;
 
-	connection = connection_from_file (TEST_IFCFG_WIRED_DHCP6_ONLY,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_DHCP6_ONLY,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wired-dhcp6-only-read", "failed to read %s: %s", TEST_IFCFG_WIRED_DHCP6_ONLY, error->message);
 
@@ -1878,10 +1848,6 @@ test_read_wired_dhcp6_only (void)
 	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_METHOD);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -1893,21 +1859,13 @@ test_read_onboot_no (void)
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
-	GError *error = NULL;
-
-	connection = connection_from_file (TEST_IFCFG_ONBOOT_NO,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	GError *error = NULL;
+
+	connection = connection_from_file_test (TEST_IFCFG_ONBOOT_NO,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "onboot-no-read", "failed to read %s: %s", TEST_IFCFG_ONBOOT_NO, error->message);
 
@@ -1932,10 +1890,6 @@ test_read_onboot_no (void)
 	        NM_SETTING_CONNECTION_SETTING_NAME,
 	        NM_SETTING_CONNECTION_AUTOCONNECT);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -1947,22 +1901,13 @@ test_read_noip (void)
 	NMConnection *connection;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
-	GError *error = NULL;
-
-	connection = connection_from_file (TEST_IFCFG_NOIP,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	GError *error = NULL;
+
+	connection = connection_from_file_test (TEST_IFCFG_NOIP,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	g_assert (connection);
 	g_assert (nm_connection_verify (connection, &error));
 	g_assert_no_error (error);
@@ -1977,10 +1922,6 @@ test_read_noip (void)
 	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE);
 	g_assert (nm_setting_ip_config_get_never_default (s_ip6) == FALSE);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -1996,10 +1937,6 @@ test_read_wired_8021x_peap_mschapv2 (void)
 	NMSetting8021x *s_8021x;
 	NMSetting8021x *tmp_8021x;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_identity = "David Smith";
@@ -2009,15 +1946,11 @@ test_read_wired_8021x_peap_mschapv2 (void)
 	const char *expected_ca_cert_path;
 	const char *read_ca_cert_path;
 
-	connection = connection_from_file (TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wired-8021x-peap-mschapv2-read", "failed to read %s: %s", TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2, error->message);
 
@@ -2176,10 +2109,6 @@ test_read_wired_8021x_peap_mschapv2 (void)
 
 	g_object_unref (tmp_8021x);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -2192,25 +2121,16 @@ test_read_wired_8021x_tls_secret_flags (const char *ifcfg, NMSettingSecretFlags
 	NMConnection *connection;
 	NMSettingWired *s_wired;
 	NMSetting8021x *s_8021x;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *expected_identity = "David Smith";
 	gboolean success = FALSE;
 	char *dirname, *tmp;
 
-	connection = connection_from_file (ifcfg,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (ifcfg,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 
@@ -2242,10 +2162,6 @@ test_read_wired_8021x_tls_secret_flags (const char *ifcfg, NMSettingSecretFlags
 
 	g_free (dirname);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -2260,9 +2176,9 @@ test_read_write_802_1X_subj_matches (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*missing IEEE_8021X_CA_CERT*peap*");
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-802-1X-subj-matches",
-	                                   NULL, TYPE_ETHERNET, NULL,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-802-1X-subj-matches",
+	                                        NULL, TYPE_ETHERNET, NULL,
+	                                        &error);
 	g_test_assert_expected_messages ();
 	g_assert_no_error (error);
 	g_assert (connection != NULL);
@@ -2295,8 +2211,8 @@ test_read_write_802_1X_subj_matches (void)
 	/* re-read the connection for comparison */
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*missing IEEE_8021X_CA_CERT*peap*");
-	reread = connection_from_file (written, NULL, TYPE_ETHERNET, NULL,
-	                               NULL, NULL, NULL, &error, NULL);
+	reread = connection_from_file_test (written, NULL, TYPE_ETHERNET, NULL,
+	                                    &error);
 	g_test_assert_expected_messages ();
 	unlink (written);
 	g_free (written);
@@ -2343,8 +2259,8 @@ test_read_802_1x_ttls_eapgtc (void)
 	 * NMSetting8021x::autheap property.
 	 */
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-802-1x-ttls-eapgtc",
-	                                   NULL, TYPE_WIRELESS, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-802-1x-ttls-eapgtc",
+	                                        NULL, TYPE_WIRELESS, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -2374,11 +2290,6 @@ test_read_wired_aliases_good (void)
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingIPConfig *s_ip4;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System aliasem0";
@@ -2388,15 +2299,11 @@ test_read_wired_aliases_good (void)
 	const char *expected_gateway = "192.168.1.1";
 	int i, j;
 
-	connection = connection_from_file (TEST_IFCFG_ALIASES_GOOD,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_ALIASES_GOOD,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "aliases-good-read", "failed to read %s: %s", TEST_IFCFG_ALIASES_GOOD, error->message);
 
@@ -2485,9 +2392,6 @@ test_read_wired_aliases_good (void)
 		        expected_address[i]);
 	}
 
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -2497,24 +2401,15 @@ test_read_wired_aliases_bad (const char *base, const char *expected_id)
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingIPConfig *s_ip4;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	NMIPAddress *ip4_addr;
 
-	connection = connection_from_file (base,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (base,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	g_test_assert_expected_messages ();
 	ASSERT (connection != NULL,
 	        "aliases-bad-read", "failed to read %s: %s", base, error->message);
@@ -2575,9 +2470,6 @@ test_read_wired_aliases_bad (const char *base, const char *expected_id)
 	/* Gateway */
 	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.1.1");
 
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -2610,12 +2502,7 @@ test_read_wifi_open (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
-	NMSettingIPConfig *s_ip4;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
+	NMSettingIPConfig *s_ip4, *s_ip6;
 	GError *error = NULL;
 	const char *tmp;
 	GBytes *ssid;
@@ -2627,15 +2514,11 @@ test_read_wifi_open (void)
 	const char *expected_mode = "infrastructure";
 	const guint32 expected_channel = 1;
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_OPEN,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_OPEN,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-open-read", "failed to read %s: %s", TEST_IFCFG_WIFI_OPEN, error->message);
 
@@ -2764,6 +2647,8 @@ test_read_wifi_open (void)
 	        TEST_IFCFG_WIFI_OPEN,
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME);
 
+	g_assert_cmpint (nm_setting_ip_config_get_route_metric (s_ip4), ==, 104);
+
 	/* Method */
 	tmp = nm_setting_ip_config_get_method (s_ip4);
 	ASSERT (strcmp (tmp, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0,
@@ -2772,10 +2657,10 @@ test_read_wifi_open (void)
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_METHOD);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	g_assert( s_ip6);
+	g_assert_cmpint (nm_setting_ip_config_get_route_metric (s_ip6), ==, 106);
+
 	g_object_unref (connection);
 }
 
@@ -2787,25 +2672,16 @@ test_read_wifi_open_auto (void)
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System blahblah (test-wifi-open-auto)";
 	const char *expected_mode = "infrastructure";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_OPEN_AUTO,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_OPEN_AUTO,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-open-auto-read", "failed to read %s: %s", TEST_IFCFG_WIFI_OPEN_AUTO, error->message);
 
@@ -2853,10 +2729,6 @@ test_read_wifi_open_auto (void)
 	        NM_SETTING_WIRELESS_SETTING_NAME,
 	        NM_SETTING_WIRELESS_MODE);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -2868,26 +2740,17 @@ test_read_wifi_open_ssid_hex (void)
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	GBytes *ssid;
 	const char *expected_id = "System blahblah (test-wifi-open-ssid-hex)";
 	const char *expected_ssid = "blahblah";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_OPEN_SSID_HEX,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_OPEN_SSID_HEX,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-open-ssid-hex-read", "failed to read %s: %s", TEST_IFCFG_WIFI_OPEN_SSID_HEX, error->message);
 
@@ -2941,10 +2804,6 @@ test_read_wifi_open_ssid_hex (void)
 	        NM_SETTING_WIRELESS_SETTING_NAME,
 	        NM_SETTING_WIRELESS_SSID);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -2952,29 +2811,16 @@ static void
 test_read_wifi_open_ssid_bad (const char *file, const char *test)
 {
 	NMConnection *connection;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
-	GError *error = NULL;
-
-	connection = connection_from_file (file,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	GError *error = NULL;
+
+	connection = connection_from_file_test (file,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection == NULL, test, "unexpected success reading %s", file);
 	g_clear_error (&error);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 }
 
 #define TEST_IFCFG_WIFI_OPEN_SSID_QUOTED TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open-ssid-quoted"
@@ -2985,26 +2831,17 @@ test_read_wifi_open_ssid_quoted (void)
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	GBytes *ssid;
 	const char *expected_id = "System foo\"bar\\ (test-wifi-open-ssid-quoted)";
 	const char *expected_ssid = "foo\"bar\\";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_OPEN_SSID_QUOTED,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_OPEN_SSID_QUOTED,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-open-ssid-quoted-read", "failed to read %s: %s", TEST_IFCFG_WIFI_OPEN_SSID_QUOTED, error->message);
 
@@ -3058,10 +2895,6 @@ test_read_wifi_open_ssid_quoted (void)
 	        NM_SETTING_WIRELESS_SETTING_NAME,
 	        NM_SETTING_WIRELESS_SSID);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -3075,11 +2908,6 @@ test_read_wifi_wep (void)
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
 	NMSettingIPConfig *s_ip4;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	GBytes *ssid;
@@ -3093,15 +2921,11 @@ test_read_wifi_wep (void)
 	const char *expected_wep_key0 = "0123456789abcdef0123456789";
 	NMWepKeyType key_type;
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WEP,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WEP,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wep-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WEP, error->message);
 
@@ -3316,10 +3140,6 @@ test_read_wifi_wep (void)
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_METHOD);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -3333,11 +3153,6 @@ test_read_wifi_wep_adhoc (void)
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
 	NMSettingIPConfig *s_ip4;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	GBytes *ssid;
@@ -3346,15 +3161,11 @@ test_read_wifi_wep_adhoc (void)
 	const char *expected_mode = "adhoc";
 	const char *expected_wep_key0 = "0123456789abcdef0123456789";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WEP_ADHOC,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WEP_ADHOC,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wep-adhoc-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WEP_ADHOC, error->message);
 
@@ -3556,10 +3367,6 @@ test_read_wifi_wep_adhoc (void)
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_DNS);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -3572,25 +3379,16 @@ test_read_wifi_wep_passphrase (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_wep_key0 = "foobar222blahblah";
 	NMWepKeyType key_type;
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WEP_PASSPHRASE,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WEP_PASSPHRASE,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wep-passphrase-read", "failed to read %s: %s",
 	        TEST_IFCFG_WIFI_WEP_PASSPHRASE, error->message);
@@ -3681,10 +3479,6 @@ test_read_wifi_wep_passphrase (void)
 	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 	        NM_SETTING_WIRELESS_SECURITY_WEP_KEY3);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -3697,25 +3491,16 @@ test_read_wifi_wep_40_ascii (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_wep_key0 = "Lorem";
 	NMWepKeyType key_type;
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WEP_40_ASCII,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WEP_40_ASCII,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wep-40-ascii-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WEP_40_ASCII, error->message);
 
@@ -3804,10 +3589,6 @@ test_read_wifi_wep_40_ascii (void)
 	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 	        NM_SETTING_WIRELESS_SECURITY_WEP_KEY3);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -3820,25 +3601,16 @@ test_read_wifi_wep_104_ascii (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_wep_key0 = "LoremIpsumSit";
 	NMWepKeyType key_type;
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WEP_104_ASCII,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WEP_104_ASCII,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wep-104-ascii-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WEP_104_ASCII, error->message);
 
@@ -3927,10 +3699,6 @@ test_read_wifi_wep_104_ascii (void)
 	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 	        NM_SETTING_WIRELESS_SECURITY_WEP_KEY3);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -3943,26 +3711,17 @@ test_read_wifi_leap (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System blahblah (test-wifi-leap)";
 	const char *expected_identity = "Bill Smith";
 	const char *expected_password = "foobarblah";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_LEAP,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_LEAP,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-leap-read", "failed to read %s: %s", TEST_IFCFG_WIFI_LEAP, error->message);
 
@@ -4052,10 +3811,6 @@ test_read_wifi_leap (void)
 	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 	        NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -4068,24 +3823,15 @@ test_read_wifi_leap_secret_flags (const char *file, NMSettingSecretFlags expecte
 	NMConnection *connection;
 	NMSettingWireless *s_wifi;
 	NMSettingWirelessSecurity *s_wsec;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *expected_identity = "Bill Smith";
 	gboolean success;
 
-	connection = connection_from_file (file,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (file,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 
@@ -4108,10 +3854,6 @@ test_read_wifi_leap_secret_flags (const char *file, NMSettingSecretFlags expecte
 	g_assert (nm_setting_wireless_security_get_leap_password_flags (s_wsec) == expected_flags);
 	g_assert (nm_setting_wireless_security_get_leap_password (s_wsec) == NULL);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -4125,11 +3867,6 @@ test_read_wifi_wpa_psk (void)
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
 	NMSettingIPConfig *s_ip4;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	GBytes *ssid;
@@ -4152,15 +3889,11 @@ test_read_wifi_wpa_psk (void)
 	gboolean found_proto_wpa = FALSE;
 	gboolean found_proto_rsn = FALSE;
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WPA_PSK,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wpa-psk-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WPA_PSK, error->message);
 
@@ -4409,10 +4142,6 @@ test_read_wifi_wpa_psk (void)
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_METHOD);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -4425,25 +4154,16 @@ test_read_wifi_wpa_psk_2 (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System ipsum (test-wifi-wpa-psk-2)";
 	const char *expected_psk = "They're really saying I love you. >>`<< \\";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_2,
-                                     NULL,
-                                     TYPE_WIRELESS,
-                                     &unmanaged,
-                                     &keyfile,
-                                     &routefile,
-                                     &route6file,
-                                     &error,
-                                     &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WPA_PSK_2,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wpa-psk-2-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WPA_PSK_2, error->message);
 
@@ -4500,10 +4220,6 @@ test_read_wifi_wpa_psk_2 (void)
 	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 	        NM_SETTING_WIRELESS_SECURITY_PSK);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -4516,25 +4232,16 @@ test_read_wifi_wpa_psk_unquoted (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System blahblah (test-wifi-wpa-psk-unquoted)";
 	const char *expected_psk = "54336845e2f3f321c4c7";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wpa-psk-unquoted-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED, error->message);
 
@@ -4591,10 +4298,6 @@ test_read_wifi_wpa_psk_unquoted (void)
 	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 	        NM_SETTING_WIRELESS_SECURITY_PSK);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -4604,34 +4307,21 @@ static void
 test_read_wifi_wpa_psk_unquoted2 (void)
 {
 	NMConnection *connection;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 
 	/* Ensure a quoted 64-character WPA passphrase will fail since passphrases
 	 * must be between 8 and 63 ASCII characters inclusive per the WPA spec.
 	 */
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED2,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED2,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection == NULL,
 	        "wifi-wpa-psk-unquoted-read", "unexpected success reading %s", TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED2);
 	g_clear_error (&error);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 }
 
 #define TEST_IFCFG_WIFI_WPA_PSK_ADHOC TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-wpa-psk-adhoc"
@@ -4644,11 +4334,6 @@ test_read_wifi_wpa_psk_adhoc (void)
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
 	NMSettingIPConfig *s_ip4;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System blahblah (test-wifi-wpa-psk-adhoc)";
@@ -4658,15 +4343,11 @@ test_read_wifi_wpa_psk_adhoc (void)
 	const char *expected_group = "ccmp";
 	const char *expected_proto = "wpa";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_ADHOC,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WPA_PSK_ADHOC,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wpa-psk-adhoc-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WPA_PSK_ADHOC, error->message);
 
@@ -4805,10 +4486,6 @@ test_read_wifi_wpa_psk_adhoc (void)
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_METHOD);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -4822,11 +4499,6 @@ test_read_wifi_wpa_psk_hex (void)
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
 	NMSettingIPConfig *s_ip4;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	GBytes *ssid;
@@ -4835,15 +4507,11 @@ test_read_wifi_wpa_psk_hex (void)
 	const char *expected_key_mgmt = "wpa-psk";
 	const char *expected_psk = "1da190379817bc360dda52e85c388c439a21ea5c7bf819c64e9da051807deae6";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_HEX,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WPA_PSK_HEX,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wpa-psk-hex-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WPA_PSK_HEX, error->message);
 
@@ -4947,10 +4615,6 @@ test_read_wifi_wpa_psk_hex (void)
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_METHOD);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -4967,24 +4631,16 @@ test_read_wifi_wpa_eap_tls (void)
 	NMSettingIPConfig *s_ip4;
 	NMSetting8021x *s_8021x;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp, *password;
 	const char *expected_identity = "Bill Smith";
 	const char *expected_privkey_password = "test1";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_EAP_TLS,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WPA_EAP_TLS,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wpa-eap-tls-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WPA_EAP_TLS, error->message);
 
@@ -5088,10 +4744,6 @@ test_read_wifi_wpa_eap_tls (void)
 	                    expected_privkey_password,
 	                    NM_SETTING_802_1X_PRIVATE_KEY);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -5107,24 +4759,16 @@ test_read_wifi_wpa_eap_ttls_tls (void)
 	NMSettingIPConfig *s_ip4;
 	NMSetting8021x *s_8021x;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp, *password;
 	const char *expected_identity = "Chuck Shumer";
 	const char *expected_privkey_password = "test1";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_EAP_TTLS_TLS,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WPA_EAP_TTLS_TLS,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wpa-eap-ttls-tls-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WPA_EAP_TTLS_TLS, error->message);
 
@@ -5247,10 +4891,6 @@ test_read_wifi_wpa_eap_ttls_tls (void)
 	        NM_SETTING_802_1X_SETTING_NAME,
 	        NM_SETTING_802_1X_IDENTITY);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -5263,22 +4903,14 @@ test_read_wifi_dynamic_wep_leap (void)
 	NMSettingWireless *s_wifi;
 	NMSettingWirelessSecurity *s_wsec;
 	NMSetting8021x *s_8021x;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE, success;
+	gboolean success;
 	GError *error = NULL;
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_DYNAMIC_WEP_LEAP,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_DYNAMIC_WEP_LEAP,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 
@@ -5319,10 +4951,6 @@ test_read_wifi_dynamic_wep_leap (void)
 	g_assert_cmpstr (nm_setting_802_1x_get_identity (s_8021x), ==, "bill smith");
 	g_assert_cmpstr (nm_setting_802_1x_get_password (s_8021x), ==, "foobar baz");
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -5338,25 +4966,17 @@ test_read_wifi_wep_eap_ttls_chap (void)
 	NMSettingIPConfig *s_ip4;
 	NMSetting8021x *s_8021x;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_password = "foobar baz";
 	const char *expected_identity = "David Smith";
 	const char *expected_key_mgmt = "ieee8021x";
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WEP_EAP_TTLS_CHAP,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WEP_EAP_TTLS_CHAP,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wep-eap-ttls-chap-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WEP_EAP_TTLS_CHAP, error->message);
 
@@ -5480,10 +5100,6 @@ test_read_wifi_wep_eap_ttls_chap (void)
 	        NM_SETTING_802_1X_SETTING_NAME,
 	        NM_SETTING_802_1X_PASSWORD);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -5496,8 +5112,8 @@ test_read_wifi_hidden (void)
 	gboolean success;
 	GError *error = NULL;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-hidden",
-	                                   NULL, TYPE_WIRELESS, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-hidden",
+	                                        NULL, TYPE_WIRELESS, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 
@@ -5584,8 +5200,8 @@ test_write_wifi_hidden (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile, NULL, TYPE_WIRELESS,
-	                               NULL, NULL, NULL, NULL, &error, NULL);
+	reread = connection_from_file_test (testfile, NULL, TYPE_WIRELESS,
+	                                    NULL, &error);
 	unlink (testfile);
 	g_assert_no_error (error);
 	g_assert (reread);
@@ -5610,8 +5226,8 @@ test_read_wifi_band_a (void)
 	gboolean success;
 	GError *error = NULL;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-band-a",
-	                                   NULL, TYPE_WIRELESS, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-band-a",
+	                                        NULL, TYPE_WIRELESS, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 
@@ -5698,8 +5314,8 @@ test_write_wifi_band_a (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile, NULL, TYPE_WIRELESS,
-	                               NULL, NULL, NULL, NULL, &error, NULL);
+	reread = connection_from_file_test (testfile, NULL, TYPE_WIRELESS,
+	                                    NULL, &error);
 	unlink (testfile);
 	g_assert_no_error (error);
 	g_assert (reread);
@@ -5721,10 +5337,11 @@ test_read_wifi_band_a_channel_mismatch (void)
 	NMConnection *connection;
 	GError *error = NULL;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-band-a-channel-mismatch",
-	                                   NULL, TYPE_WIRELESS, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-band-a-channel-mismatch",
+	                                        NULL, TYPE_WIRELESS, NULL, &error);
 	g_assert (connection == NULL);
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
+	g_clear_error (&error);
 }
 
 static void
@@ -5733,10 +5350,11 @@ test_read_wifi_band_bg_channel_mismatch (void)
 	NMConnection *connection;
 	GError *error = NULL;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-band-bg-channel-mismatch",
-	                                   NULL, TYPE_WIRELESS, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-band-bg-channel-mismatch",
+	                                        NULL, TYPE_WIRELESS, NULL, &error);
 	g_assert (connection == NULL);
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
+	g_clear_error (&error);
 }
 
 #define TEST_IFCFG_WIRED_QETH_STATIC TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-qeth-static"
@@ -5749,10 +5367,6 @@ test_read_wired_qeth_static (void)
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System test-wired-qeth-static";
@@ -5762,15 +5376,11 @@ test_read_wired_qeth_static (void)
 	const char *expected_channel2 = "0.0.0602";
 	const char * const *subchannels;
 
-	connection = connection_from_file (TEST_IFCFG_WIRED_QETH_STATIC,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_QETH_STATIC,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wired-qeth-static-read", "failed to read %s: %s", TEST_IFCFG_WIRED_QETH_STATIC, error->message);
 
@@ -5902,10 +5512,6 @@ test_read_wired_qeth_static (void)
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP_CONFIG_METHOD);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -5918,10 +5524,6 @@ test_read_wired_ctc_static (void)
 	NMSettingConnection *s_con;
 	NMSettingWired *s_wired;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System test-wired-ctc-static";
@@ -5930,15 +5532,11 @@ test_read_wired_ctc_static (void)
 	const char * const *subchannels;
 	gboolean success;
 
-	connection = connection_from_file (TEST_IFCFG_WIRED_CTC_STATIC,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIRED_CTC_STATIC,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        &unmanaged,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	
@@ -5974,10 +5572,6 @@ test_read_wired_ctc_static (void)
 	g_assert (tmp != NULL);
 	g_assert_cmpstr (tmp, ==, "0");
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -5990,25 +5584,16 @@ test_read_wifi_wep_no_keys (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
 	NMSettingWirelessSecurity *s_wsec;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System foobar (test-wifi-wep-no-keys)";
 	NMWepKeyType key_type;
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WEP_NO_KEYS,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WEP_NO_KEYS,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "wifi-wep-no-keys-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WEP_NO_KEYS, error->message);
 
@@ -6086,10 +5671,6 @@ test_read_wifi_wep_no_keys (void)
 	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 	        NM_SETTING_WIRELESS_SECURITY_WEP_KEY0);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -6100,24 +5681,16 @@ test_read_permissions (void)
 {
 	NMConnection *connection;
 	NMSettingConnection *s_con;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE, success;
+	gboolean success;
 	GError *error = NULL;
 	guint32 num;
 	const char *tmp;
 
-	connection = connection_from_file (TEST_IFCFG_PERMISSIONS,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_PERMISSIONS,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "permissions-read", "failed to read %s: %s", TEST_IFCFG_PERMISSIONS, error->message);
 
@@ -6159,10 +5732,6 @@ test_read_permissions (void)
 	ASSERT (strcmp (tmp, "johnny5") == 0,
 	        "permissions-verify-permissions", "unexpected permission #3");
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -6174,25 +5743,16 @@ test_read_wifi_wep_agent_keys (void)
 	NMConnection *connection;
 	NMSettingWireless *s_wifi;
 	NMSettingWirelessSecurity *s_wsec;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	NMWepKeyType key_type;
 	gboolean success;
 	NMSettingSecretFlags flags;
 
-	connection = connection_from_file (TEST_IFCFG_WIFI_WEP_AGENT_KEYS,
-	                                   NULL,
-	                                   TYPE_WIRELESS,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_WIFI_WEP_AGENT_KEYS,
+	                                        NULL,
+	                                        TYPE_WIRELESS,
+	                                        NULL,
+	                                        &error);
 	g_assert (connection != NULL);
 
 	success = nm_connection_verify (connection, &error);
@@ -6223,10 +5783,6 @@ test_read_wifi_wep_agent_keys (void)
 	flags = nm_setting_wireless_security_get_wep_key_flags (s_wsec);
 	g_assert (flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -6256,11 +5812,7 @@ test_write_wired_static (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
 	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -6294,6 +5846,7 @@ test_write_wired_static (void)
 	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
 	              NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
 	              NM_SETTING_IP_CONFIG_GATEWAY, "1.1.1.1",
+	              NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64) 204,
 	              NULL);
 
 	addr = nm_ip_address_new (AF_INET, "1.1.1.3", 24, &error);
@@ -6319,6 +5872,7 @@ test_write_wired_static (void)
 	g_object_set (s_ip6,
 	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
 	              NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
+	              NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64) 206,
 	              NULL);
 
 	/* Add addresses */
@@ -6378,15 +5932,11 @@ test_write_wired_static (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -6406,16 +5956,16 @@ test_write_wired_static (void)
 	nm_setting_ip_config_remove_dns_search (reread_s_ip4, 3);
 	nm_setting_ip_config_remove_dns_search (reread_s_ip4, 2);
 
+	g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip4), ==, 204);
+	g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip6), ==, 206);
+
 	ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
 	        "wired-static-write", "written and re-read connection weren't the same.");
 
-	if (route6file)
-		unlink (route6file);
+	route6file = utils_get_route6_path (testfile);
+	unlink (route6file);
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
 	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
@@ -6434,11 +5984,6 @@ test_write_wired_dhcp (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -6500,15 +6045,11 @@ test_write_wired_dhcp (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -6521,10 +6062,6 @@ test_write_wired_dhcp (void)
 	        "wired-dhcp-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -6537,9 +6074,9 @@ test_write_wired_dhcp_plus_ip (void)
 	GError *error = NULL;
 	gboolean success = FALSE;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-dhcp-plus-ip",
-	                                   NULL, TYPE_ETHERNET, NULL,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-dhcp-plus-ip",
+	                                        NULL, TYPE_ETHERNET, NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection != NULL);
 
@@ -6553,8 +6090,8 @@ test_write_wired_dhcp_plus_ip (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (written, NULL, TYPE_ETHERNET, NULL,
-	                               NULL, NULL, NULL, &error, NULL);
+	reread = connection_from_file_test (written, NULL, TYPE_ETHERNET, NULL,
+	                                    &error);
 	unlink (written);
 	g_free (written);
 
@@ -6583,9 +6120,9 @@ test_read_write_wired_dhcp_send_hostname (void)
 	GError *error = NULL;
 	gboolean success = FALSE;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-dhcp-send-hostname",
-	                                   NULL, TYPE_ETHERNET, NULL,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-dhcp-send-hostname",
+	                                        NULL, TYPE_ETHERNET, NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection != NULL);
 
@@ -6613,8 +6150,8 @@ test_read_write_wired_dhcp_send_hostname (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (written, NULL, TYPE_ETHERNET, NULL,
-	                               NULL, NULL, NULL, &error, NULL);
+	reread = connection_from_file_test (written, NULL, TYPE_ETHERNET, NULL,
+	                                    &error);
 	unlink (written);
 	g_free (written);
 
@@ -6657,11 +6194,7 @@ test_write_wired_static_ip6_only (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
 	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -6729,15 +6262,11 @@ test_write_wired_static_ip6_only (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -6749,13 +6278,7 @@ test_write_wired_static_ip6_only (void)
 	ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
 	        "wired-static-ip6-only-write", "written and re-read connection weren't the same.");
 
-	if (route6file)
-		unlink (route6file);
-
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
 	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
@@ -6786,7 +6309,6 @@ test_write_wired_static_ip6_only_gw (gconstpointer user_data)
 	GError *error = NULL;
 	char *testfile = NULL;
 	char *id = NULL;
-	gboolean ignore_error = FALSE;
 	char *written_ifcfg_gateway;
 	const char *gateway6 = user_data;
 
@@ -6854,13 +6376,11 @@ test_write_wired_static_ip6_only_gw (gconstpointer user_data)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               NULL, NULL,
-	                               NULL, NULL,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	g_assert_no_error (error);
 	g_assert (reread);
 	g_assert (nm_connection_verify (reread, &error));
@@ -6909,28 +6429,18 @@ test_read_write_static_routes_legacy (void)
 	NMSettingConnection *s_con;
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
-	char *unmanaged = NULL;
 	char *testfile = NULL;
-	char *keyfile = NULL;
-	char *keyfile2 = NULL;
-	char *routefile = NULL;
 	char *routefile2 = NULL;
-	char *route6file = NULL;
 	char *route6file2 = NULL;
-	gboolean ignore_error = FALSE;
 	gboolean success;
 	GError *error = NULL;
 	const char *tmp;
 
-	connection = connection_from_file (TEST_IFCFG_READ_WRITE_STATIC_ROUTES_LEGACY,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_READ_WRITE_STATIC_ROUTES_LEGACY,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "read-write-static-routes-legacy-read", "failed to read %s: %s",
 	        TEST_IFCFG_READ_WRITE_STATIC_ROUTES_LEGACY, error->message);
@@ -7011,17 +6521,15 @@ test_read_write_static_routes_legacy (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile2,
-	                               &routefile2,
-	                               &route6file2,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
+	routefile2 = utils_get_route_path (testfile);
 	unlink (routefile2);
+	route6file2 = utils_get_route6_path (testfile);
 	unlink (route6file2);
 
 	ASSERT (reread != NULL,
@@ -7037,12 +6545,7 @@ test_read_write_static_routes_legacy (void)
 	        "read-write-static-routes-legacy-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (keyfile2);
-	g_free (routefile);
 	g_free (routefile2);
-	g_free (route6file);
 	g_free (route6file2);
 	g_object_unref (connection);
 	g_object_unref (reread);
@@ -7069,11 +6572,7 @@ test_write_wired_static_routes (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
 	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -7164,22 +6663,17 @@ test_write_wired_static_routes (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
 	        "wired-static-routes-write-reread", "failed to read %s: %s", testfile, error->message);
 
-	ASSERT (routefile != NULL,
-	        "wired-static-routes-write-reread", "expected routefile for '%s'", testfile);
+	routefile = utils_get_route_path (testfile);
 	unlink (routefile);
 
 	ASSERT (nm_connection_verify (reread, &error),
@@ -7189,10 +6683,7 @@ test_write_wired_static_routes (void)
 	        "wired-static-routes-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
 	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -7211,11 +6702,7 @@ test_write_wired_dhcp_8021x_peap_mschapv2 (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -7295,22 +6782,17 @@ test_write_wired_dhcp_8021x_peap_mschapv2 (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
 	        "wired-dhcp-8021x-peap-mschapv2write-reread", "failed to read %s: %s", testfile, error->message);
 
-	ASSERT (keyfile != NULL,
-	        "wired-dhcp-8021x-peap-mschapv2write-reread", "expected keyfile for '%s'", testfile);
+	keyfile = utils_get_keys_path (testfile);
 	unlink (keyfile);
 
 	ASSERT (nm_connection_verify (reread, &error),
@@ -7320,10 +6802,7 @@ test_write_wired_dhcp_8021x_peap_mschapv2 (void)
 	        "wired-dhcp-8021x-peap-mschapv2write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -7365,11 +6844,7 @@ test_write_wired_8021x_tls (NMSetting8021xCKScheme scheme,
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
 	const char *pw;
 	char *tmp;
@@ -7479,17 +6954,13 @@ test_write_wired_8021x_tls (NMSetting8021xCKScheme scheme,
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
-	g_assert (keyfile != NULL);
+	keyfile = utils_get_keys_path (testfile);
 	unlink (keyfile);
 
 	g_assert (reread != NULL);
@@ -7555,10 +7026,7 @@ test_write_wired_8021x_tls (NMSetting8021xCKScheme scheme,
 	g_free (tmp);
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -7581,11 +7049,6 @@ test_write_wired_aliases (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	shvarFile *ifcfg;
 	int i, j;
 
@@ -7679,15 +7142,11 @@ test_write_wired_aliases (void)
 	        "wired-aliases-write", "saving failed to delete unused ifcfg-alias0:5");
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 	unlink (TEST_SCRATCH_ALIAS_BASE ":2");
 	unlink (TEST_SCRATCH_ALIAS_BASE ":3");
@@ -7743,9 +7202,6 @@ test_write_wired_aliases (void)
 	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "1.1.1.1");
 
 	g_free (testfile);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -7861,8 +7317,8 @@ test_write_gateway (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile, NULL, TYPE_WIRELESS,
-	                               NULL, NULL, NULL, NULL, &error, NULL);
+	reread = connection_from_file_test (testfile, NULL, TYPE_WIRELESS,
+	                                    NULL, &error);
 	unlink (testfile);
 	g_assert_no_error (error);
 	g_assert (reread);
@@ -7892,11 +7348,6 @@ test_write_wifi_open (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
 	const char *bssid = "11:22:33:44:55:66";
@@ -7973,15 +7424,11 @@ test_write_wifi_open (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	g_assert_no_error (error);
 
 	/* Now make sure that the ESSID item isn't double-quoted (rh #606518) */
@@ -8011,10 +7458,6 @@ test_write_wifi_open (void)
 	        "wifi-open-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -8032,11 +7475,6 @@ test_write_wifi_open_hex_ssid (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const unsigned char ssid_data[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd };
 
@@ -8103,15 +7541,11 @@ test_write_wifi_open_hex_ssid (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -8124,10 +7558,6 @@ test_write_wifi_open_hex_ssid (void)
 	        "wifi-open-hex-ssid-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -8146,11 +7576,7 @@ test_write_wifi_wep (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 	struct stat statbuf;
@@ -8232,27 +7658,20 @@ test_write_wifi_wep (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-wep-write-reread", "expected keyfile for '%s'", testfile);
-
+	keyfile = utils_get_keys_path (testfile);
 	ASSERT (stat (keyfile, &statbuf) == 0,
 	        "wifi-wep-write-reread", "couldn't stat() '%s'", keyfile);
 	ASSERT (S_ISREG (statbuf.st_mode),
 	        "wifi-wep-write-reread", "keyfile '%s' wasn't a normal file", keyfile);
 	ASSERT ((statbuf.st_mode & 0077) == 0,
 	        "wifi-wep-write-reread", "keyfile '%s' wasn't readable only by its owner", keyfile);
-
 	unlink (keyfile);
 
 	ASSERT (reread != NULL,
@@ -8265,10 +7684,7 @@ test_write_wifi_wep (void)
 	        "wifi-wep-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -8287,11 +7703,7 @@ test_write_wifi_wep_adhoc (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 	struct stat statbuf;
@@ -8379,27 +7791,20 @@ test_write_wifi_wep_adhoc (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-wep-adhoc-write-reread", "expected keyfile for '%s'", testfile);
-
+	keyfile = utils_get_keys_path (testfile);
 	ASSERT (stat (keyfile, &statbuf) == 0,
 	        "wifi-wep-adhoc-write-reread", "couldn't stat() '%s'", keyfile);
 	ASSERT (S_ISREG (statbuf.st_mode),
 	        "wifi-wep-adhoc-write-reread", "keyfile '%s' wasn't a normal file", keyfile);
 	ASSERT ((statbuf.st_mode & 0077) == 0,
 	        "wifi-wep-adhoc-write-reread", "keyfile '%s' wasn't readable only by its owner", keyfile);
-
 	unlink (keyfile);
 
 	ASSERT (reread != NULL,
@@ -8412,10 +7817,7 @@ test_write_wifi_wep_adhoc (void)
 	        "wifi-wep-adhoc-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -8434,11 +7836,7 @@ test_write_wifi_wep_passphrase (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 	struct stat statbuf;
@@ -8518,27 +7916,20 @@ test_write_wifi_wep_passphrase (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-wep-passphrase-write-reread", "expected keyfile for '%s'", testfile);
-
+	keyfile = utils_get_keys_path (testfile);
 	ASSERT (stat (keyfile, &statbuf) == 0,
 	        "wifi-wep-passphrase-write-reread", "couldn't stat() '%s'", keyfile);
 	ASSERT (S_ISREG (statbuf.st_mode),
 	        "wifi-wep-passphrase-write-reread", "keyfile '%s' wasn't a normal file", keyfile);
 	ASSERT ((statbuf.st_mode & 0077) == 0,
 	        "wifi-wep-passphrase-write-reread", "keyfile '%s' wasn't readable only by its owner", keyfile);
-
 	unlink (keyfile);
 
 	ASSERT (reread != NULL,
@@ -8551,10 +7942,7 @@ test_write_wifi_wep_passphrase (void)
 	        "wifi-wep-passphrase-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -8573,11 +7961,7 @@ test_write_wifi_wep_40_ascii (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah40";
 	struct stat statbuf;
@@ -8659,27 +8043,20 @@ test_write_wifi_wep_40_ascii (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-wep-40-ascii-write-reread", "expected keyfile for '%s'", testfile);
-
+	keyfile = utils_get_keys_path (testfile);
 	ASSERT (stat (keyfile, &statbuf) == 0,
 	        "wifi-wep-40-ascii-write-reread", "couldn't stat() '%s'", keyfile);
 	ASSERT (S_ISREG (statbuf.st_mode),
 	        "wifi-wep-40-ascii-write-reread", "keyfile '%s' wasn't a normal file", keyfile);
 	ASSERT ((statbuf.st_mode & 0077) == 0,
 	        "wifi-wep-40-ascii-write-reread", "keyfile '%s' wasn't readable only by its owner", keyfile);
-
 	unlink (keyfile);
 
 	ASSERT (reread != NULL,
@@ -8692,10 +8069,7 @@ test_write_wifi_wep_40_ascii (void)
 	        "wifi-wep-40-ascii-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -8714,11 +8088,7 @@ test_write_wifi_wep_104_ascii (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah104";
 	struct stat statbuf;
@@ -8800,27 +8170,20 @@ test_write_wifi_wep_104_ascii (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-wep-104-ascii-write-reread", "expected keyfile for '%s'", testfile);
-
+	keyfile = utils_get_keys_path (testfile);
 	ASSERT (stat (keyfile, &statbuf) == 0,
 	        "wifi-wep-104-ascii-write-reread", "couldn't stat() '%s'", keyfile);
 	ASSERT (S_ISREG (statbuf.st_mode),
 	        "wifi-wep-104-ascii-write-reread", "keyfile '%s' wasn't a normal file", keyfile);
 	ASSERT ((statbuf.st_mode & 0077) == 0,
 	        "wifi-wep-104-ascii-write-reread", "keyfile '%s' wasn't readable only by its owner", keyfile);
-
 	unlink (keyfile);
 
 	ASSERT (reread != NULL,
@@ -8833,10 +8196,7 @@ test_write_wifi_wep_104_ascii (void)
 	        "wifi-wep-104-ascii-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -8855,11 +8215,7 @@ test_write_wifi_leap (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 	struct stat statbuf;
@@ -8938,27 +8294,20 @@ test_write_wifi_leap (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-leap-write-reread", "expected keyfile for '%s'", testfile);
-
+	keyfile = utils_get_keys_path (testfile);
 	ASSERT (stat (keyfile, &statbuf) == 0,
 	        "wifi-leap-write-reread", "couldn't stat() '%s'", keyfile);
 	ASSERT (S_ISREG (statbuf.st_mode),
 	        "wifi-leap-write-reread", "keyfile '%s' wasn't a normal file", keyfile);
 	ASSERT ((statbuf.st_mode & 0077) == 0,
 	        "wifi-leap-write-reread", "keyfile '%s' wasn't readable only by its owner", keyfile);
-
 	unlink (keyfile);
 
 	ASSERT (reread != NULL,
@@ -8971,10 +8320,7 @@ test_write_wifi_leap (void)
 	        "wifi-leap-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -8993,11 +8339,7 @@ test_write_wifi_leap_secret_flags (NMSettingSecretFlags flags)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 
@@ -9075,21 +8417,17 @@ test_write_wifi_leap_secret_flags (NMSettingSecretFlags flags)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	g_assert_no_error (error);
 
 	/* No key should be written out since the secret is not system owned */
-	g_assert (keyfile);
+	keyfile = utils_get_keys_path (testfile);
 	g_assert (g_file_test (keyfile, G_FILE_TEST_EXISTS) == FALSE);
 
 	g_assert (reread);
@@ -9105,10 +8443,7 @@ test_write_wifi_leap_secret_flags (NMSettingSecretFlags flags)
 	g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -9132,11 +8467,7 @@ test_write_wifi_wpa_psk (const char *name,
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 
@@ -9229,22 +8560,17 @@ test_write_wifi_wpa_psk (const char *name,
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
-	tmp = g_strdup_printf ("%s-reread", test_name);
-	ASSERT (keyfile != NULL,
-	        tmp, "expected keyfile for '%s'", testfile);
+	keyfile = utils_get_keys_path (testfile);
 	unlink (keyfile);
 
+	tmp = g_strdup_printf ("%s-reread", test_name);
 	ASSERT (reread != NULL,
 	        tmp, "failed to read %s: %s", testfile, error->message);
 
@@ -9256,10 +8582,7 @@ test_write_wifi_wpa_psk (const char *name,
 	        test_name, "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -9278,11 +8601,7 @@ test_write_wifi_wpa_psk_adhoc (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 	NMIPAddress *addr;
@@ -9376,19 +8695,14 @@ test_write_wifi_wpa_psk_adhoc (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-wpa-psk-adhoc-write-reread", "expected keyfile for '%s'", testfile);
+	keyfile = utils_get_keys_path (testfile);
 	unlink (keyfile);
 
 	ASSERT (reread != NULL,
@@ -9401,10 +8715,7 @@ test_write_wifi_wpa_psk_adhoc (void)
 	        "wifi-wpa-psk-adhoc-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -9424,11 +8735,7 @@ test_write_wifi_wpa_eap_tls (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 
@@ -9540,19 +8847,14 @@ test_write_wifi_wpa_eap_tls (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-wpa-eap-tls-write-reread", "expected keyfile for '%s'", testfile);
+	keyfile = utils_get_keys_path (testfile);
 	unlink (keyfile);
 
 	ASSERT (reread != NULL,
@@ -9565,10 +8867,7 @@ test_write_wifi_wpa_eap_tls (void)
 	        "wifi-wpa-eap-tls-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -9588,11 +8887,7 @@ test_write_wifi_wpa_eap_ttls_tls (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 
@@ -9722,22 +9017,17 @@ test_write_wifi_wpa_eap_ttls_tls (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
 	        "wifi-wpa-eap-ttls-tls-write-reread", "failed to read %s: %s", testfile, error->message);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-wpa-eap-ttls-tls-write-reread", "expected keyfile for '%s'", testfile);
+	keyfile = utils_get_keys_path (testfile);
 	unlink (keyfile);
 
 	ASSERT (nm_connection_verify (reread, &error),
@@ -9747,10 +9037,7 @@ test_write_wifi_wpa_eap_ttls_tls (void)
 	        "wifi-wpa-eap-ttls-tls-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -9770,11 +9057,7 @@ test_write_wifi_wpa_eap_ttls_mschapv2 (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 
@@ -9876,22 +9159,17 @@ test_write_wifi_wpa_eap_ttls_mschapv2 (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
 	        "wifi-wpa-eap-ttls-mschapv2-write-reread", "failed to read %s: %s", testfile, error->message);
 
-	ASSERT (keyfile != NULL,
-	        "wifi-wpa-eap-ttls-mschapv2-write-reread", "expected keyfile for '%s'", testfile);
+	keyfile = utils_get_keys_path (testfile);
 	unlink (keyfile);
 
 	ASSERT (nm_connection_verify (reread, &error),
@@ -9901,10 +9179,7 @@ test_write_wifi_wpa_eap_ttls_mschapv2 (void)
 	        "wifi-wpa-eap-ttls-mschapv2-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -9923,11 +9198,7 @@ test_write_wifi_wpa_then_open (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 
@@ -10018,15 +9289,11 @@ test_write_wifi_wpa_then_open (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	g_assert_no_error (error);
 	g_assert (reread);
 
@@ -10036,18 +9303,13 @@ test_write_wifi_wpa_then_open (void)
 	success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
 	g_assert (success);
 
-	g_free (unmanaged);
-	unmanaged = NULL;
-	g_free (routefile);
-	routefile = NULL;
-	g_free (route6file);
-	route6file = NULL;
 	g_object_unref (reread);
 
 	/* Now change the connection to open and recheck */
 	nm_connection_remove_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
 
 	/* Write it back out */
+	keyfile = utils_get_keys_path (testfile);
 	success = writer_update_connection (connection,
 	                                    TEST_SCRATCH_DIR "/network-scripts/",
 	                                    testfile,
@@ -10064,22 +9326,18 @@ test_write_wifi_wpa_then_open (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read it for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 	g_assert_no_error (error);
 
 	g_assert (reread);
 
 	/* No keyfile since it's an open connection this time */
-	g_assert (keyfile);
+	keyfile = utils_get_keys_path (testfile);
 	g_assert (g_file_test (keyfile, G_FILE_TEST_EXISTS) == FALSE);
 
 	success = nm_connection_verify (reread, &error);
@@ -10090,10 +9348,7 @@ test_write_wifi_wpa_then_open (void)
 
 	unlink (testfile);
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (reread);
 
 	g_object_unref (connection);
@@ -10113,11 +9368,7 @@ test_write_wifi_wpa_then_wep_with_perms (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	char **perms;
 	const char *ssid_data = "SomeSSID";
@@ -10214,15 +9465,11 @@ test_write_wifi_wpa_then_wep_with_perms (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	g_assert_no_error (error);
 	g_assert (reread);
 
@@ -10232,12 +9479,6 @@ test_write_wifi_wpa_then_wep_with_perms (void)
 	success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
 	g_assert (success);
 
-	g_free (unmanaged);
-	unmanaged = NULL;
-	g_free (routefile);
-	routefile = NULL;
-	g_free (route6file);
-	route6file = NULL;
 	g_object_unref (reread);
 
 	/* Now change the connection to WEP and recheck */
@@ -10251,6 +9492,7 @@ test_write_wifi_wpa_then_wep_with_perms (void)
 	nm_setting_wireless_security_set_wep_key (s_wsec, 0, "abraka  dabra");
 
 	/* Write it back out */
+	keyfile = utils_get_keys_path (testfile);
 	success = writer_update_connection (connection,
 	                                    TEST_SCRATCH_DIR "/network-scripts/",
 	                                    testfile,
@@ -10266,15 +9508,11 @@ test_write_wifi_wpa_then_wep_with_perms (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read it for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	g_assert_no_error (error);
 
 	g_assert (reread);
@@ -10289,14 +9527,12 @@ test_write_wifi_wpa_then_wep_with_perms (void)
 	ASSERT (success,
 	        "test_write_wifi_wpa_then_wep_with_perms", "failed to compare connections");
 
+	keyfile = utils_get_keys_path (testfile);
 	unlink (keyfile);
 	unlink (testfile);
+	g_free (keyfile);
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (reread);
 
 	g_object_unref (connection);
@@ -10317,11 +9553,7 @@ test_write_wifi_dynamic_wep_leap (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
 	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GBytes *ssid;
 	const char *ssid_data = "blahblah";
 	shvarFile *ifcfg;
@@ -10409,18 +9641,15 @@ test_write_wifi_dynamic_wep_leap (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	g_assert_no_error (error);
 	g_assert (reread);
-	g_assert (keyfile);
+
+	keyfile = utils_get_keys_path (testfile);
 	unlink (keyfile);
 
 	success = nm_connection_verify (reread, &error);
@@ -10449,10 +9678,7 @@ test_write_wifi_dynamic_wep_leap (void)
 	unlink (testfile);
 
 	g_free (testfile);
-	g_free (unmanaged);
 	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -10471,11 +9697,7 @@ test_write_wired_qeth_dhcp (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
 	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -10546,15 +9768,11 @@ test_write_wired_qeth_dhcp (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -10566,13 +9784,7 @@ test_write_wired_qeth_dhcp (void)
 	ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
 	        "wired-qeth-dhcp-write", "written and re-read connection weren't the same.");
 
-	if (route6file)
-		unlink (route6file);
-
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
 	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
@@ -10592,11 +9804,7 @@ test_write_wired_ctc_dhcp (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
 	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	shvarFile *ifcfg;
 	char *tmp;
 
@@ -10680,15 +9888,11 @@ test_write_wired_ctc_dhcp (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	g_assert (reread);
@@ -10699,13 +9903,7 @@ test_write_wired_ctc_dhcp (void)
 	success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
 	g_assert (success);
 
-	if (route6file)
-		unlink (route6file);
-
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
 	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
@@ -10724,11 +9922,7 @@ test_write_permissions (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
 	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -10791,15 +9985,11 @@ test_write_permissions (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -10811,13 +10001,7 @@ test_write_permissions (void)
 	ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
 	        "permissions-write", "written and re-read connection weren't the same.");
 
-	if (route6file)
-		unlink (route6file);
-
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
 	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
@@ -10839,11 +10023,7 @@ test_write_wifi_wep_agent_keys (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
 	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 	g_assert (connection != NULL);
@@ -10919,15 +10099,11 @@ test_write_wifi_wep_agent_keys (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_WIRELESS,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_WIRELESS,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	g_assert_no_error (error);
@@ -10951,13 +10127,7 @@ test_write_wifi_wep_agent_keys (void)
 	success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
 	g_assert (success);
 
-	if (route6file)
-		unlink (route6file);
-
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
 	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
@@ -11031,6 +10201,7 @@ test_write_wired_pppoe (void)
 	        "wired-pppoe-write", "unexpected success writing connection to disk");
 
 	g_object_unref (connection);
+	g_clear_error (&error);
 }
 
 static void
@@ -11093,6 +10264,7 @@ test_write_vpn (void)
 	        "vpn-write", "unexpected success writing connection to disk");
 
 	g_object_unref (connection);
+	g_clear_error (&error);
 }
 
 static void
@@ -11175,6 +10347,7 @@ test_write_mobile_broadband (gboolean gsm)
 	        "mobile-broadband-write", "unexpected success writing connection to disk");
 
 	g_object_unref (connection);
+	g_clear_error (&error);
 }
 
 #define TEST_IFCFG_BRIDGE_MAIN TEST_IFCFG_DIR"/network-scripts/ifcfg-test-bridge-main"
@@ -11186,22 +10359,13 @@ test_read_bridge_main (void)
 	NMSettingBridge *s_bridge;
 	const char *mac;
 	char expected_mac_address[ETH_ALEN] = { 0x00, 0x16, 0x41, 0x11, 0x22, 0x33 };
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
-	GError *error = NULL;
-
-	connection = connection_from_file (TEST_IFCFG_BRIDGE_MAIN,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	GError *error = NULL;
+
+	connection = connection_from_file_test (TEST_IFCFG_BRIDGE_MAIN,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	g_assert (connection);
 	g_assert (nm_connection_verify (connection, &error));
 	g_assert_no_error (error);
@@ -11212,7 +10376,7 @@ test_read_bridge_main (void)
 
 	s_bridge = nm_connection_get_setting_bridge (connection);
 	g_assert (s_bridge);
-	g_assert_cmpuint (nm_setting_bridge_get_forward_delay (s_bridge), ==, 0);
+	g_assert_cmpuint (nm_setting_bridge_get_forward_delay (s_bridge), ==, 2);
 	g_assert (nm_setting_bridge_get_stp (s_bridge));
 	g_assert_cmpuint (nm_setting_bridge_get_priority (s_bridge), ==, 32744);
 	g_assert_cmpuint (nm_setting_bridge_get_hello_time (s_bridge), ==, 7);
@@ -11224,10 +10388,6 @@ test_read_bridge_main (void)
 	g_assert (mac);
 	g_assert (nm_utils_hwaddr_matches (mac, -1, expected_mac_address, ETH_ALEN));
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -11246,11 +10406,6 @@ test_write_bridge_main (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 	g_assert (connection);
@@ -11318,15 +10473,11 @@ test_write_bridge_main (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_BRIDGE,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_BRIDGE,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	g_assert (reread);
@@ -11335,10 +10486,6 @@ test_write_bridge_main (void)
 	g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -11351,23 +10498,14 @@ test_read_bridge_component (void)
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingBridgePort *s_port;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	gboolean success;
 
-	connection = connection_from_file (TEST_IFCFG_BRIDGE_COMPONENT,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_BRIDGE_COMPONENT,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	g_assert (connection);
 
 	success = nm_connection_verify (connection, &error);
@@ -11385,10 +10523,6 @@ test_read_bridge_component (void)
 	g_assert_cmpuint (nm_setting_bridge_port_get_priority (s_port), ==, 28);
 	g_assert_cmpuint (nm_setting_bridge_port_get_path_cost (s_port), ==, 100);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -11406,11 +10540,7 @@ test_write_bridge_component (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
 	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 	g_assert (connection);
@@ -11466,15 +10596,11 @@ test_write_bridge_component (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	g_assert (reread);
@@ -11484,13 +10610,7 @@ test_write_bridge_component (void)
 
 	g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
 
-	if (route6file)
-		unlink (route6file);
-
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
 	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
@@ -11501,22 +10621,13 @@ test_read_bridge_missing_stp (void)
 {
 	NMConnection *connection;
 	NMSettingBridge *s_bridge;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
-	GError *error = NULL;
-
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-bridge-missing-stp",
-	                                   NULL,
-	                                   TYPE_BRIDGE,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	GError *error = NULL;
+
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-bridge-missing-stp",
+	                                        NULL,
+	                                        TYPE_BRIDGE,
+	                                        NULL,
+	                                        &error);
 	g_assert (connection);
 	g_assert (nm_connection_verify (connection, &error));
 	g_assert_no_error (error);
@@ -11529,10 +10640,6 @@ test_read_bridge_missing_stp (void)
 	g_assert (s_bridge);
 	g_assert (nm_setting_bridge_get_stp (s_bridge) == FALSE);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -11542,31 +10649,18 @@ static void
 test_read_vlan_interface (void)
 {
 	NMConnection *connection;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	NMSettingVlan *s_vlan;
 	guint32 from = 0, to = 0;
 
-	connection = connection_from_file (TEST_IFCFG_VLAN_INTERFACE,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_VLAN_INTERFACE,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection != NULL);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 
 	g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "vlan43");
 
@@ -11613,30 +10707,17 @@ static void
 test_read_vlan_only_vlan_id (void)
 {
 	NMConnection *connection;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	NMSettingVlan *s_vlan;
 
-	connection = connection_from_file (TEST_IFCFG_VLAN_ONLY_VLANID,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_VLAN_ONLY_VLANID,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection != NULL);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 
 	g_assert (nm_connection_get_interface_name (connection) == NULL);
 
@@ -11655,30 +10736,17 @@ static void
 test_read_vlan_only_device (void)
 {
 	NMConnection *connection;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	NMSettingVlan *s_vlan;
 
-	connection = connection_from_file (TEST_IFCFG_VLAN_ONLY_DEVICE,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_VLAN_ONLY_DEVICE,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection != NULL);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 
 	g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "eth0.9");
 
@@ -11698,9 +10766,9 @@ test_read_vlan_physdev (void)
 	GError *error = NULL;
 	NMSettingVlan *s_vlan;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-physdev",
-	                                   NULL, TYPE_ETHERNET, NULL,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-physdev",
+	                                        NULL, TYPE_ETHERNET, NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	g_assert (nm_connection_verify (connection, &error));
@@ -11720,24 +10788,15 @@ static void
 test_write_vlan (void)
 {
 	NMConnection *connection;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
 	char *written = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	gboolean success = FALSE;
 
-	connection = connection_from_file (TEST_IFCFG_VLAN_INTERFACE,
-	                                   NULL,
-	                                   TYPE_VLAN,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_VLAN_INTERFACE,
+	                                        NULL,
+	                                        TYPE_VLAN,
+	                                        NULL,
+	                                        &error);
 	g_assert (connection != NULL);
 
 	success = writer_new_connection (connection,
@@ -11749,46 +10808,25 @@ test_write_vlan (void)
 	unlink (written);
 	g_free (written);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
+	g_object_unref (connection);
 }
 
 static void
 test_write_vlan_only_vlanid (void)
 {
 	NMConnection *connection, *reread;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
 	char *written = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	gboolean success = FALSE;
 
-	connection = connection_from_file (TEST_IFCFG_VLAN_ONLY_VLANID,
-	                                   NULL,
-	                                   TYPE_VLAN,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_VLAN_ONLY_VLANID,
+	                                        NULL,
+	                                        TYPE_VLAN,
+	                                        NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection != NULL);
 
-	g_free (unmanaged);
-	unmanaged = NULL;
-	g_free (keyfile);
-	keyfile = NULL;
-	g_free (routefile);
-	routefile = NULL;
-	g_free (route6file);
-	route6file = NULL;
-
 	success = writer_new_connection (connection,
 	                                 TEST_SCRATCH_DIR "/network-scripts/",
 	                                 &written,
@@ -11799,21 +10837,13 @@ test_write_vlan_only_vlanid (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (written,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (written,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (written);
 	g_free (written);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 
 	g_assert_no_error (error);
 	g_assert (reread != NULL);
@@ -11842,11 +10872,6 @@ test_write_ethernet_missing_ipv6 (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 	g_assert (connection);
@@ -11907,15 +10932,11 @@ test_write_ethernet_missing_ipv6 (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -11941,10 +10962,6 @@ test_write_ethernet_missing_ipv6 (void)
 	        "ethernet-missing-ipv6", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -11955,11 +10972,12 @@ test_read_ibft_ignored (void)
 	NMConnection *connection;
 	GError *error = NULL;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-ibft",
-	                                   NULL, TYPE_ETHERNET,
-	                                   NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-ibft",
+	                                        NULL, TYPE_ETHERNET,
+	                                        NULL, &error);
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
 	g_assert (connection == NULL);
+	g_clear_error (&error);
 }
 
 #define TEST_IFCFG_BOND_MAIN TEST_IFCFG_DIR"/network-scripts/ifcfg-test-bond-main"
@@ -11969,22 +10987,13 @@ test_read_bond_main (void)
 {
 	NMConnection *connection;
 	NMSettingBond *s_bond;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
-	GError *error = NULL;
-
-	connection = connection_from_file (TEST_IFCFG_BOND_MAIN,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	GError *error = NULL;
+
+	connection = connection_from_file_test (TEST_IFCFG_BOND_MAIN,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "bond-main-read", "unexpected failure reading %s", TEST_IFCFG_BOND_MAIN);
 
@@ -12007,10 +11016,6 @@ test_read_bond_main (void)
 	        "bond-main", "failed to verify %s: miimon=%s does not match 100",
 	        TEST_IFCFG_BOND_MAIN, nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON));
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -12029,11 +11034,6 @@ test_write_bond_main (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -12100,15 +11100,11 @@ test_write_bond_main (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_BOND,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_BOND,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -12121,10 +11117,6 @@ test_write_bond_main (void)
 	        "bond-main-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -12136,22 +11128,13 @@ test_read_bond_slave (void)
 {
 	NMConnection *connection;
 	NMSettingConnection *s_con;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
-	GError *error = NULL;
-
-	connection = connection_from_file (TEST_IFCFG_BOND_SLAVE,
-	                                   NULL,
-	                                   TYPE_ETHERNET,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	GError *error = NULL;
+
+	connection = connection_from_file_test (TEST_IFCFG_BOND_SLAVE,
+	                                        NULL,
+	                                        TYPE_ETHERNET,
+	                                        NULL,
+	                                        &error);
 	g_test_assert_expected_messages ();
 
 	ASSERT (connection != NULL,
@@ -12173,10 +11156,6 @@ test_read_bond_slave (void)
 	        "bond-slave-read", "failed to verify %s: slave-type is not bond",
 	        TEST_IFCFG_BOND_SLAVE);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -12193,11 +11172,7 @@ test_write_bond_slave (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
 	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -12245,15 +11220,11 @@ test_write_bond_slave (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -12265,13 +11236,7 @@ test_write_bond_slave (void)
 	ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
 	        "bond-slave-write", "written and re-read connection weren't the same.");
 
-	if (route6file)
-		unlink (route6file);
-
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
 	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
@@ -12285,24 +11250,16 @@ test_read_infiniband (void)
 	NMConnection *connection;
 	NMSettingInfiniband *s_infiniband;
 	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 	GError *error = NULL;
 	const char *mac;
 	char expected_mac_address[INFINIBAND_ALEN] = { 0x80, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22 };
 	const char *transport_mode;
 
-	connection = connection_from_file (TEST_IFCFG_INFINIBAND,
-	                                   NULL,
-	                                   TYPE_INFINIBAND,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	connection = connection_from_file_test (TEST_IFCFG_INFINIBAND,
+	                                        NULL,
+	                                        TYPE_INFINIBAND,
+	                                        &unmanaged,
+	                                        &error);
 	ASSERT (connection != NULL,
 	        "infiniband-read", "failed to read %s: %s", TEST_IFCFG_INFINIBAND, error->message);
 
@@ -12346,10 +11303,6 @@ test_read_infiniband (void)
 	        NM_SETTING_INFINIBAND_SETTING_NAME,
 	        NM_SETTING_INFINIBAND_TRANSPORT_MODE);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -12369,11 +11322,6 @@ test_write_infiniband (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -12443,15 +11391,11 @@ test_write_infiniband (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_INFINIBAND,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_INFINIBAND,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -12464,10 +11408,6 @@ test_write_infiniband (void)
 	        "infiniband-write", "written and re-read connection weren't the same.");
 
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
@@ -12479,22 +11419,13 @@ test_read_bond_slave_ib (void)
 {
 	NMConnection *connection;
 	NMSettingConnection *s_con;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
-	GError *error = NULL;
-
-	connection = connection_from_file (TEST_IFCFG_BOND_SLAVE_IB,
-	                                   NULL,
-	                                   NULL,
-	                                   &unmanaged,
-	                                   &keyfile,
-	                                   &routefile,
-	                                   &route6file,
-	                                   &error,
-	                                   &ignore_error);
+	GError *error = NULL;
+
+	connection = connection_from_file_test (TEST_IFCFG_BOND_SLAVE_IB,
+	                                        NULL,
+	                                        NULL,
+	                                        NULL,
+	                                        &error);
 	g_test_assert_expected_messages();
 
 	ASSERT (connection != NULL,
@@ -12516,10 +11447,6 @@ test_read_bond_slave_ib (void)
 	        "bond-slave-read-ib", "failed to verify %s: slave-type is not bond",
 	        TEST_IFCFG_BOND_SLAVE_IB);
 
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
 	g_object_unref (connection);
 }
 
@@ -12535,11 +11462,7 @@ test_write_bond_slave_ib (void)
 	gboolean success;
 	GError *error = NULL;
 	char *testfile = NULL;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
 	char *route6file = NULL;
-	gboolean ignore_error = FALSE;
 
 	connection = nm_simple_connection_new ();
 
@@ -12588,15 +11511,11 @@ test_write_bond_slave_ib (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               NULL,
-	                               &unmanaged,
-	                               &keyfile,
-	                               &routefile,
-	                               &route6file,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    NULL,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	ASSERT (reread != NULL,
@@ -12608,18 +11527,43 @@ test_write_bond_slave_ib (void)
 	ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
 	        "bond-slave-write-ib", "written and re-read connection weren't the same.");
 
-	if (route6file)
-		unlink (route6file);
-
 	g_free (testfile);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
 	g_free (route6file);
 	g_object_unref (connection);
 	g_object_unref (reread);
 }
 
+static void
+test_read_bond_opts_mode_numeric (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingBond *s_bond;
+	gboolean success;
+	GError *error = NULL;
+
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-bond-mode-numeric",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (connection);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "bond0");
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_BOND_SETTING_NAME);
+
+	s_bond = nm_connection_get_setting_bond (connection);
+	g_assert (s_bond);
+	g_assert_cmpstr (nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MODE), ==, "802.3ad");
+
+	g_object_unref (connection);
+}
+
 #define DCB_ALL_FLAGS (NM_SETTING_DCB_FLAG_ENABLE | \
                        NM_SETTING_DCB_FLAG_ADVERTISE | \
                        NM_SETTING_DCB_FLAG_WILLING)
@@ -12639,8 +11583,8 @@ test_read_dcb_basic (void)
 	guint expected_traffic_classes[8] = { 7, 6, 5, 4, 3, 2, 1, 0 };
 	gboolean expected_pfcs[8] = { TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE };
 
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -12698,7 +11642,7 @@ test_write_dcb_basic (void)
 	NMSettingDcb *s_dcb;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
-	gboolean success, ignore_error;
+	gboolean success;
 	guint i;
 	char *uuid, *testfile;
 	const guint group_ids[8] = { 4, 0xF, 6, 0xF, 1, 7, 3, 0xF };
@@ -12770,13 +11714,11 @@ test_write_dcb_basic (void)
 	g_assert (testfile);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               NULL, NULL,
-	                               NULL, NULL,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	g_assert_no_error (error);
@@ -12797,8 +11739,8 @@ test_read_dcb_default_app_priorities (void)
 	NMSettingDcb *s_dcb;
 	gboolean success;
 
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-default-app-priorities",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-default-app-priorities",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 	success = nm_connection_verify (connection, &error);
@@ -12828,13 +11770,14 @@ test_read_dcb_bad_booleans (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*invalid DCB_PG_STRICT value*not all 0s and 1s*");
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-booleans",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-booleans",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_test_assert_expected_messages ();
 
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
 	g_assert (strstr (error->message, "invalid boolean digit"));
 	g_assert (connection == NULL);
+	g_clear_error (&error);
 }
 
 static void
@@ -12845,13 +11788,14 @@ test_read_dcb_short_booleans (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*DCB_PG_STRICT value*8 characters*");
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-booleans",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-booleans",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_test_assert_expected_messages ();
 
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
 	g_assert (strstr (error->message, "boolean array must be 8 characters"));
 	g_assert (connection == NULL);
+	g_clear_error (&error);
 }
 
 static void
@@ -12862,13 +11806,14 @@ test_read_dcb_bad_uints (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*invalid DCB_PG_UP2TC value*not 0 - 7*");
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-uints",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-uints",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_test_assert_expected_messages ();
 
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
 	g_assert (strstr (error->message, "invalid uint digit"));
 	g_assert (connection == NULL);
+	g_clear_error (&error);
 }
 
 static void
@@ -12879,13 +11824,14 @@ test_read_dcb_short_uints (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*DCB_PG_UP2TC value*8 characters*");
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-uints",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-uints",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_test_assert_expected_messages ();
 
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
 	g_assert (strstr (error->message, "uint array must be 8 characters"));
 	g_assert (connection == NULL);
+	g_clear_error (&error);
 }
 
 static void
@@ -12896,13 +11842,14 @@ test_read_dcb_bad_percent (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*invalid DCB_PG_PCT percentage value*");
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-percent",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-percent",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_test_assert_expected_messages ();
 
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
 	g_assert (strstr (error->message, "invalid percent element"));
 	g_assert (connection == NULL);
+	g_clear_error (&error);
 }
 
 static void
@@ -12913,13 +11860,14 @@ test_read_dcb_short_percent (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*invalid DCB_PG_PCT percentage list value*");
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-percent",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-percent",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_test_assert_expected_messages ();
 
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
 	g_assert (strstr (error->message, "percent array must be 8 elements"));
 	g_assert (connection == NULL);
+	g_clear_error (&error);
 }
 
 static void
@@ -12930,13 +11878,14 @@ test_read_dcb_pgpct_not_100 (void)
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
 	                       "*DCB_PG_PCT percentages do not equal 100*");
-	connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-pgpct-not-100",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-pgpct-not-100",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_test_assert_expected_messages ();
 
 	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
 	g_assert (strstr (error->message, "invalid percentage sum"));
 	g_assert (connection == NULL);
+	g_clear_error (&error);
 }
 
 static void
@@ -12950,7 +11899,7 @@ test_read_fcoe_mode (gconstpointer user_data)
 	char *file;
 
 	file = g_strdup_printf (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-fcoe-%s", expected_mode);
-	connection = connection_from_file (file, NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (file, NULL, TYPE_ETHERNET, NULL, &error);
 	g_free (file);
 	g_assert_no_error (error);
 	g_assert (connection);
@@ -12978,7 +11927,7 @@ test_write_fcoe_mode (gconstpointer user_data)
 	NMSettingDcb *s_dcb;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
-	gboolean success, ignore_error;
+	gboolean success;
 	char *uuid, *testfile;
 
 	connection = nm_simple_connection_new ();
@@ -13040,13 +11989,11 @@ test_write_fcoe_mode (gconstpointer user_data)
 	}
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile,
-	                               NULL,
-	                               TYPE_ETHERNET,
-	                               NULL, NULL,
-	                               NULL, NULL,
-	                               &error,
-	                               &ignore_error);
+	reread = connection_from_file_test (testfile,
+	                                    NULL,
+	                                    TYPE_ETHERNET,
+	                                    NULL,
+	                                    &error);
 	unlink (testfile);
 
 	g_assert_no_error (error);
@@ -13069,8 +12016,8 @@ test_read_team_master (void)
 	GError *error = NULL;
 	const char *expected_config = "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }";
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 
@@ -13181,8 +12128,8 @@ test_write_team_master (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile, NULL, TYPE_ETHERNET,
-	                               NULL, NULL, NULL, NULL, &error, NULL);
+	reread = connection_from_file_test (testfile, NULL, TYPE_ETHERNET,
+	                                    NULL, &error);
 	unlink (testfile);
 	g_assert_no_error (error);
 	g_assert (reread);
@@ -13208,8 +12155,8 @@ test_read_team_port (void)
 	GError *error = NULL;
 	const char *expected_config = "{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }";
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 
@@ -13294,6 +12241,7 @@ test_write_team_port (void)
 	val = svGetValue (f, "TEAM_PORT_CONFIG", TRUE);
 	g_assert (val);
 	g_assert_cmpstr (val, ==, escaped_expected_config);
+	g_free (val);
 	val = svGetValue (f, "TEAM_MASTER", TRUE);
 	g_assert (val);
 	g_assert_cmpstr (val, ==, "team0");
@@ -13304,8 +12252,8 @@ test_write_team_port (void)
 	nm_connection_normalize (connection, NULL, NULL, NULL);
 
 	/* re-read the connection for comparison */
-	reread = connection_from_file (testfile, NULL, TYPE_ETHERNET,
-	                               NULL, NULL, NULL, NULL, &error, NULL);
+	reread = connection_from_file_test (testfile, NULL, TYPE_ETHERNET,
+	                                    NULL, &error);
 	unlink (testfile);
 	g_assert_no_error (error);
 	g_assert (reread);
@@ -13329,8 +12277,8 @@ test_read_team_port_empty_config (void)
 	gboolean success;
 	GError *error = NULL;
 
-	connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-empty-config",
-	                                   NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-empty-config",
+	                                        NULL, TYPE_ETHERNET, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 
@@ -13475,8 +12423,8 @@ test_read_vlan_trailing_spaces (void)
 	g_assert (strstr (contents, "DEVICE=\"vlan201\"  \n"));
 	g_free (contents);
 
-	connection = connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL,
-	                                   NULL, NULL, NULL, &error, NULL);
+	connection = connection_from_file_test (testfile, NULL, TYPE_ETHERNET, NULL,
+	                                        &error);
 	g_assert_no_error (error);
 	g_assert (connection != NULL);
 
@@ -13513,7 +12461,7 @@ NMTST_DEFINE ();
 
 int main (int argc, char **argv)
 {
-	nmtst_init_assert_logging (&argc, &argv);
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
 
 	g_test_add_func (TPATH "svUnescape", test_svUnescape);
 	g_test_add_func (TPATH "vlan-trailing-spaces", test_read_vlan_trailing_spaces);
@@ -13536,8 +12484,10 @@ int main (int argc, char **argv)
 	test_read_wired_static (TEST_IFCFG_WIRED_STATIC_BOOTPROTO, "System test-wired-static-bootproto", FALSE);
 	test_read_wired_dhcp ();
 	g_test_add_func (TPATH "dhcp-plus-ip", test_read_wired_dhcp_plus_ip);
+	g_test_add_func (TPATH "shared-plus-ip", test_read_wired_shared_plus_ip);
 	g_test_add_func (TPATH "dhcp-send-hostname", test_read_write_wired_dhcp_send_hostname);
 	g_test_add_func (TPATH "global-gateway", test_read_wired_global_gateway);
+	g_test_add_func (TPATH "obsolete-gateway-n", test_read_wired_obsolete_gateway_n);
 	g_test_add_func (TPATH "never-default", test_read_wired_never_default);
 	test_read_wired_defroute_no ();
 	test_read_wired_defroute_no_gatewaydev_yes ();
@@ -13706,6 +12656,7 @@ int main (int argc, char **argv)
 	test_write_bond_main ();
 	test_write_bond_slave ();
 	test_write_bond_slave_ib ();
+	g_test_add_func (TPATH "bond/bonding-opts-numeric-mode", test_read_bond_opts_mode_numeric);
 
 	/* bridging */
 	test_read_bridge_main ();
diff --git a/src/settings/plugins/ifcfg-rh/utils.c b/src/settings/plugins/ifcfg-rh/utils.c
index 5b9e9d79..4b7cb43d 100644
--- a/src/settings/plugins/ifcfg-rh/utils.c
+++ b/src/settings/plugins/ifcfg-rh/utils.c
@@ -356,6 +356,30 @@ gone:
 }
 
 gboolean
+utils_has_complex_routes (const char *filename)
+{
+	char *rules;
+
+	g_return_val_if_fail (filename != NULL, TRUE);
+
+	rules = utils_get_extra_path (filename, RULE_TAG);
+	if (g_file_test (rules, G_FILE_TEST_EXISTS)) {
+		g_free (rules);
+		return TRUE;
+	}
+	g_free (rules);
+
+	rules = utils_get_extra_path (filename, RULE6_TAG);
+	if (g_file_test (rules, G_FILE_TEST_EXISTS)) {
+		g_free (rules);
+		return TRUE;
+	}
+	g_free (rules);
+
+	return FALSE;
+}
+
+gboolean
 utils_ignore_ip_config (NMConnection *connection)
 {
 	NMSettingConnection *s_con;
diff --git a/src/settings/plugins/ifcfg-rh/utils.h b/src/settings/plugins/ifcfg-rh/utils.h
index 95af828b..445437c4 100644
--- a/src/settings/plugins/ifcfg-rh/utils.h
+++ b/src/settings/plugins/ifcfg-rh/utils.h
@@ -25,6 +25,13 @@
 #include <nm-connection.h>
 #include "shvar.h"
 #include "common.h"
+#include "nm-logging.h"
+
+#define NM_IFCFG_CONNECTION_LOG_PATH(path)  str_if_set (path,"in-memory")
+#define NM_IFCFG_CONNECTION_LOG_FMT         "%s (%s,\"%s\")"
+#define NM_IFCFG_CONNECTION_LOG_ARG(con)    NM_IFCFG_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con))
+#define NM_IFCFG_CONNECTION_LOG_FMTD        "%s (%s,\"%s\",%p)"
+#define NM_IFCFG_CONNECTION_LOG_ARGD(con)   NM_IFCFG_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)), (con)
 
 char *utils_single_quote_string (const char *str);
 
@@ -47,6 +54,7 @@ shvarFile *utils_get_route_ifcfg (const char *parent, gboolean should_create);
 shvarFile *utils_get_route6_ifcfg (const char *parent, gboolean should_create);
 
 gboolean utils_has_route_file_new_syntax (const char *filename);
+gboolean utils_has_complex_routes (const char *filename);
 
 gboolean utils_ignore_ip_config (NMConnection *connection);
 
diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c
index f4ffffd6..d2b0c970 100644
--- a/src/settings/plugins/ifcfg-rh/writer.c
+++ b/src/settings/plugins/ifcfg-rh/writer.c
@@ -44,6 +44,7 @@
 #include <nm-utils.h>
 
 #include "nm-logging.h"
+#include "gsystem-local-alloc.h"
 #include "common.h"
 #include "shvar.h"
 #include "reader.h"
@@ -695,9 +696,15 @@ write_wireless_security_setting (NMConnection *connection,
 				 * keys.
 				 */
 				key_type = nm_setting_wireless_security_get_wep_key_type (s_wsec);
+				if (key_type == NM_WEP_KEY_TYPE_UNKNOWN) {
+					if (nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_KEY))
+						key_type = NM_WEP_KEY_TYPE_KEY;
+					else if (nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_PASSPHRASE))
+						key_type = NM_WEP_KEY_TYPE_PASSPHRASE;
+				}
 				if (key_type == NM_WEP_KEY_TYPE_PASSPHRASE)
 					tmp = g_strdup_printf ("KEY_PASSPHRASE%d", i + 1);
-				else {
+				else if (key_type == NM_WEP_KEY_TYPE_KEY) {
 					tmp = g_strdup_printf ("KEY%d", i + 1);
 
 					/* Add 's:' prefix for ASCII keys */
@@ -705,7 +712,8 @@ write_wireless_security_setting (NMConnection *connection,
 						ascii_key = g_strdup_printf ("s:%s", key);
 						key = ascii_key;
 					}
-				}
+				} else
+					key = NULL;
 
 				set_secret (ifcfg,
 				            tmp,
@@ -1806,6 +1814,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	char *route_path = NULL;
 	gint32 j;
 	guint32 i, n, num;
+	gint64 route_metric;
 	GString *searches;
 	gboolean success = FALSE;
 	gboolean fake_ip4 = FALSE;
@@ -2015,6 +2024,11 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	            nm_setting_ip_config_get_may_fail (s_ip4) ? "no" : "yes",
 	            FALSE);
 
+	route_metric = nm_setting_ip_config_get_route_metric (s_ip4);
+	tmp = route_metric != -1 ? g_strdup_printf ("%"G_GINT64_FORMAT, route_metric) : NULL;
+	svSetValue (ifcfg, "IPV4_ROUTE_METRIC", tmp, FALSE);
+	g_free (tmp);
+
 	/* Static routes - route-<name> file */
 	route_path = utils_get_route_path (ifcfg->fileName);
 	if (!route_path) {
@@ -2105,13 +2119,16 @@ static void
 write_ip4_aliases (NMConnection *connection, char *base_ifcfg_path)
 {
 	NMSettingIPConfig *s_ip4;
-	char *base_ifcfg_dir, *base_ifcfg_name, *base_name;
+	gs_free char *base_ifcfg_dir = NULL, *base_ifcfg_name = NULL;
+	const char*base_name;
 	int i, num, base_ifcfg_name_len, base_name_len;
 	GDir *dir;
 
 	base_ifcfg_dir = g_path_get_dirname (base_ifcfg_path);
 	base_ifcfg_name = g_path_get_basename (base_ifcfg_path);
 	base_ifcfg_name_len = strlen (base_ifcfg_name);
+	if (!g_str_has_prefix (base_ifcfg_name, IFCFG_TAG))
+		g_return_if_reached ();
 	base_name = base_ifcfg_name + strlen (IFCFG_TAG);
 	base_name_len = strlen (base_name);
 
@@ -2183,9 +2200,6 @@ write_ip4_aliases (NMConnection *connection, char *base_ifcfg_path)
 		svWriteFile (ifcfg, 0644, NULL);
 		svCloseFile (ifcfg);
 	}
-
-	g_free (base_ifcfg_name);
-	g_free (base_ifcfg_dir);
 }
 
 static gboolean
@@ -2249,10 +2263,12 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	NMSettingIPConfig *s_ip4;
 	const char *value;
 	char *addr_key;
+	char *tmp;
 	guint32 i, num, num4;
 	GString *searches;
 	NMIPAddress *addr;
 	const char *dns;
+	gint64 route_metric;
 	GString *ip_str1, *ip_str2, *ip_ptr;
 	char *route6_path;
 
@@ -2266,6 +2282,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 		svSetValue (ifcfg, "IPV6_PEERDNS", "yes", FALSE);
 		svSetValue (ifcfg, "IPV6_PEERROUTES", "yes", FALSE);
 		svSetValue (ifcfg, "IPV6_FAILURE_FATAL", "no", FALSE);
+		svSetValue (ifcfg, "IPV6_ROUTE_METRIC", NULL, FALSE);
 		return TRUE;
 	}
 
@@ -2380,6 +2397,11 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	            nm_setting_ip_config_get_may_fail (s_ip6) ? "no" : "yes",
 	            FALSE);
 
+	route_metric = nm_setting_ip_config_get_route_metric (s_ip6);
+	tmp = route_metric != -1 ? g_strdup_printf ("%"G_GINT64_FORMAT, route_metric) : NULL;
+	svSetValue (ifcfg, "IPV6_ROUTE_METRIC", tmp, FALSE);
+	g_free (tmp);
+
 	/* IPv6 Privacy Extensions */
 	svSetValue (ifcfg, "IPV6_PRIVACY", NULL, FALSE);
 	svSetValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", NULL, FALSE);
@@ -2624,6 +2646,12 @@ writer_update_connection (NMConnection *connection,
                           const char *keyfile,
                           GError **error)
 {
+	if (utils_has_complex_routes (filename)) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+		             "Cannot modify a connection that has an associated 'rule-' or 'rule6-' file");
+		return FALSE;
+	}
+
 	return write_connection (connection, ifcfg_dir, filename, keyfile, NULL, error);
 }
 
diff --git a/src/settings/plugins/ifcfg-suse/Makefile.in b/src/settings/plugins/ifcfg-suse/Makefile.in
index 149faa3e..f7df30b4 100644
--- a/src/settings/plugins/ifcfg-suse/Makefile.in
+++ b/src/settings/plugins/ifcfg-suse/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/ifcfg-suse
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -203,6 +212,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -229,7 +240,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -264,6 +274,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -498,7 +509,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ifcfg-suse/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ifcfg-suse/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -568,14 +578,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -797,6 +807,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
 	uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/settings/plugins/ifnet/Makefile.in b/src/settings/plugins/ifnet/Makefile.in
index 11e9297f..cbedcd79 100644
--- a/src/settings/plugins/ifnet/Makefile.in
+++ b/src/settings/plugins/ifnet/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/ifnet
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -226,6 +235,8 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -277,7 +288,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -312,6 +322,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -562,7 +573,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ifnet/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ifnet/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -651,14 +661,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -954,6 +964,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 
 @GNOME_CODE_COVERAGE_RULES@
 	-DSBINDIR=\"$(sbindir)\"
diff --git a/src/settings/plugins/ifnet/net_parser.c b/src/settings/plugins/ifnet/net_parser.c
index 1cf46fbf..755767e2 100644
--- a/src/settings/plugins/ifnet/net_parser.c
+++ b/src/settings/plugins/ifnet/net_parser.c
@@ -396,7 +396,11 @@ ifnet_init (gchar * config_file)
 const char *
 ifnet_get_data (const char *conn_name, const char *key)
 {
-	GHashTable *conn = g_hash_table_lookup (conn_table, conn_name);
+	GHashTable *conn;
+
+	g_return_val_if_fail (conn_name && key, NULL);
+
+	conn = g_hash_table_lookup (conn_table, conn_name);
 
 	if (conn)
 		return g_hash_table_lookup (conn, key);
diff --git a/src/settings/plugins/ifnet/nm-ifnet-connection.c b/src/settings/plugins/ifnet/nm-ifnet-connection.c
index c84ad5ed..693e6532 100644
--- a/src/settings/plugins/ifnet/nm-ifnet-connection.c
+++ b/src/settings/plugins/ifnet/nm-ifnet-connection.c
@@ -82,6 +82,7 @@ nm_ifnet_connection_new (NMConnection *source, const char *conn_name)
 	nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
 	                                         tmp,
 	                                         update_unsaved,
+	                                         NULL,
 	                                         NULL);
 	g_object_unref (tmp);
 
diff --git a/src/settings/plugins/ifnet/plugin.c b/src/settings/plugins/ifnet/plugin.c
index 3eb1ed52..33711639 100644
--- a/src/settings/plugins/ifnet/plugin.c
+++ b/src/settings/plugins/ifnet/plugin.c
@@ -313,10 +313,13 @@ reload_connections (NMSystemConfigInterface *config)
 				if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (old),
 				                                              NM_CONNECTION (new),
 				                                              FALSE,  /* don't set Unsaved */
+				                                              "ifnet-update",
 				                                              &error)) {
-					/* Shouldn't ever get here as 'new' was verified by the reader already */
-					g_assert_no_error (error);
+					/* Shouldn't ever get here as 'new' was verified by the reader already
+					 * and the UUID did not change. */
+					g_assert_not_reached ();
 				}
+				g_assert_no_error (error);
 				nm_log_info (LOGD_SETTINGS, "Connection %s updated",
 				             nm_connection_get_id (NM_CONNECTION (new)));
 			}
@@ -393,7 +396,7 @@ check_unmanaged (gpointer key, gpointer data, gpointer user_data)
 
 	conn_name = nm_ifnet_connection_get_conn_name (connection);
 
-	if (is_managed (conn_name))
+	if (!conn_name || is_managed (conn_name))
 		return;
 
 	nm_log_info (LOGD_SETTINGS, "Checking unmanaged: %s", conn_name);
diff --git a/src/settings/plugins/ifnet/tests/Makefile.in b/src/settings/plugins/ifnet/tests/Makefile.in
index 8293c869..5b0dcc8d 100644
--- a/src/settings/plugins/ifnet/tests/Makefile.in
+++ b/src/settings/plugins/ifnet/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -80,8 +90,6 @@ build_triplet = @build@
 host_triplet = @host@
 @ENABLE_TESTS_TRUE@noinst_PROGRAMS = check_ifnet$(EXEEXT)
 subdir = src/settings/plugins/ifnet/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -98,6 +106,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -179,6 +188,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -205,7 +216,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -240,6 +250,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -492,7 +503,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ifnet/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ifnet/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -541,14 +551,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -824,6 +834,8 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_TESTS_TRUE@@GNOME_CODE_COVERAGE_RULES@
 
diff --git a/src/settings/plugins/ifnet/tests/test_all.c b/src/settings/plugins/ifnet/tests/test_all.c
index 9c399128..76ed0c7d 100644
--- a/src/settings/plugins/ifnet/tests/test_all.c
+++ b/src/settings/plugins/ifnet/tests/test_all.c
@@ -448,8 +448,7 @@ main (int argc, char **argv)
 
 	nm_linux_platform_setup ();
 
-	nmtst_init_assert_logging (&argc, &argv);
-	nm_logging_setup ("WARN", "DEFAULT", NULL, NULL);
+	nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT");
 
 	f = g_build_filename (argv[1], "net", NULL);
 	ifnet_init (f);
diff --git a/src/settings/plugins/ifupdown/Makefile.in b/src/settings/plugins/ifupdown/Makefile.in
index 44596e48..6d0da08c 100644
--- a/src/settings/plugins/ifupdown/Makefile.in
+++ b/src/settings/plugins/ifupdown/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/ifupdown
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -225,6 +234,8 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -276,7 +287,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -311,6 +321,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -557,7 +568,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ifupdown/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ifupdown/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -644,14 +654,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -947,6 +957,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-pkglibLTLIBRARIES
 
+.PRECIOUS: Makefile
+
 
 @GNOME_CODE_COVERAGE_RULES@
 
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.am b/src/settings/plugins/ifupdown/tests/Makefile.am
index 24cdd955..2e927db9 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.am
+++ b/src/settings/plugins/ifupdown/tests/Makefile.am
@@ -23,6 +23,8 @@ test_ifupdown_SOURCES = \
 test_ifupdown_LDADD = \
 	$(top_builddir)/src/libNetworkManager.la
 
+# TODO: enable valgrind for ifupdown. Currently it fails.
+#@VALGRIND_RULES@
 TESTS = test-ifupdown
 
 endif
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.in b/src/settings/plugins/ifupdown/tests/Makefile.in
index 6dedec00..d8c5b39e 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.in
+++ b/src/settings/plugins/ifupdown/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 @ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-ifupdown$(EXEEXT)
 @ENABLE_TESTS_TRUE@TESTS = test-ifupdown$(EXEEXT)
 subdir = src/settings/plugins/ifupdown/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -197,6 +206,8 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -223,7 +234,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -258,6 +268,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -501,7 +512,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/ifupdown/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/ifupdown/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -548,14 +558,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -895,6 +905,8 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in
index 8c0d11af..21c5577c 100644
--- a/src/settings/plugins/keyfile/Makefile.in
+++ b/src/settings/plugins/keyfile/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/keyfile
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -194,6 +203,8 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -245,7 +256,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -280,6 +290,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -538,7 +549,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/keyfile/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/keyfile/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -591,14 +601,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -892,6 +902,8 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @GNOME_CODE_COVERAGE_RULES@
 
diff --git a/src/settings/plugins/keyfile/common.h b/src/settings/plugins/keyfile/common.h
index db6569e5..7bde4bf3 100644
--- a/src/settings/plugins/keyfile/common.h
+++ b/src/settings/plugins/keyfile/common.h
@@ -24,7 +24,7 @@
 #include <glib.h>
 
 #define KEYFILE_PLUGIN_NAME "keyfile"
-#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2013 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
+#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2015 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
 
 #define KEYFILE_DIR NMCONFDIR "/system-connections"
 
diff --git a/src/settings/plugins/keyfile/nm-keyfile-connection.c b/src/settings/plugins/keyfile/nm-keyfile-connection.c
index c852f028..8fb94302 100644
--- a/src/settings/plugins/keyfile/nm-keyfile-connection.c
+++ b/src/settings/plugins/keyfile/nm-keyfile-connection.c
@@ -36,19 +36,12 @@
 
 G_DEFINE_TYPE (NMKeyfileConnection, nm_keyfile_connection, NM_TYPE_SETTINGS_CONNECTION)
 
-#define NM_KEYFILE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_KEYFILE_CONNECTION, NMKeyfileConnectionPrivate))
-
-typedef struct {
-	char *path;
-} NMKeyfileConnectionPrivate;
-
 NMKeyfileConnection *
 nm_keyfile_connection_new (NMConnection *source,
                            const char *full_path,
                            GError **error)
 {
 	GObject *object;
-	NMKeyfileConnectionPrivate *priv;
 	NMConnection *tmp;
 	const char *uuid;
 	gboolean update_unsaved = TRUE;
@@ -75,15 +68,15 @@ nm_keyfile_connection_new (NMConnection *source,
 		update_unsaved = FALSE;
 	}
 
-	object = (GObject *) g_object_new (NM_TYPE_KEYFILE_CONNECTION, NULL);
-
-	priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (object);
-	priv->path = g_strdup (full_path);
+	object = (GObject *) g_object_new (NM_TYPE_KEYFILE_CONNECTION,
+	                                   NM_SETTINGS_CONNECTION_FILENAME, full_path,
+	                                   NULL);
 
 	/* Update our settings with what was read from the file */
 	if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
 	                                              tmp,
 	                                              update_unsaved,
+	                                              NULL,
 	                                              error)) {
 		g_object_unref (object);
 		object = NULL;
@@ -93,38 +86,16 @@ nm_keyfile_connection_new (NMConnection *source,
 	return (NMKeyfileConnection *) object;
 }
 
-const char *
-nm_keyfile_connection_get_path (NMKeyfileConnection *self)
-{
-	g_return_val_if_fail (NM_IS_KEYFILE_CONNECTION (self), NULL);
-
-	return NM_KEYFILE_CONNECTION_GET_PRIVATE (self)->path;
-}
-
-void
-nm_keyfile_connection_set_path (NMKeyfileConnection *self, const char *path)
-{
-	NMKeyfileConnectionPrivate *priv;
-
-	g_return_if_fail (NM_IS_KEYFILE_CONNECTION (self));
-	g_return_if_fail (path != NULL);
-
-	priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (self);
-	g_free (priv->path);
-	priv->path = g_strdup (path);
-}
-
 static void
 commit_changes (NMSettingsConnection *connection,
                 NMSettingsConnectionCommitFunc callback,
                 gpointer user_data)
 {
-	NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (connection);
 	char *path = NULL;
 	GError *error = NULL;
 
 	if (!nm_keyfile_plugin_write_connection (NM_CONNECTION (connection),
-	                                         priv->path,
+	                                         nm_settings_connection_get_filename (connection),
 	                                         &path,
 	                                         &error)) {
 		callback (connection, error, user_data);
@@ -133,10 +104,8 @@ commit_changes (NMSettingsConnection *connection,
 	}
 
 	/* Update the filename if it changed */
-	if (path) {
-		g_free (priv->path);
-		priv->path = path;
-	}
+	if (path)
+		nm_settings_connection_set_filename (connection, path);
 
 	NM_SETTINGS_CONNECTION_CLASS (nm_keyfile_connection_parent_class)->commit_changes (connection,
 	                                                                                   callback,
@@ -148,10 +117,11 @@ do_delete (NMSettingsConnection *connection,
            NMSettingsConnectionDeleteFunc callback,
            gpointer user_data)
 {
-	NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (connection);
+	const char *path;
 
-	if (priv->path)
-		g_unlink (priv->path);
+	path = nm_settings_connection_get_filename (connection);
+	if (path)
+		g_unlink (path);
 
 	NM_SETTINGS_CONNECTION_CLASS (nm_keyfile_connection_parent_class)->delete (connection,
 	                                                                           callback,
@@ -166,23 +136,11 @@ nm_keyfile_connection_init (NMKeyfileConnection *connection)
 }
 
 static void
-finalize (GObject *object)
-{
-	g_free (NM_KEYFILE_CONNECTION_GET_PRIVATE (object)->path);
-
-	G_OBJECT_CLASS (nm_keyfile_connection_parent_class)->finalize (object);
-}
-
-static void
 nm_keyfile_connection_class_init (NMKeyfileConnectionClass *keyfile_connection_class)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (keyfile_connection_class);
 	NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (keyfile_connection_class);
 
-	g_type_class_add_private (keyfile_connection_class, sizeof (NMKeyfileConnectionPrivate));
-
 	/* Virtual methods */
-	object_class->finalize = finalize;
 	settings_class->commit_changes = commit_changes;
 	settings_class->delete = do_delete;
 }
diff --git a/src/settings/plugins/keyfile/nm-keyfile-connection.h b/src/settings/plugins/keyfile/nm-keyfile-connection.h
index 135bb49f..f6fa432b 100644
--- a/src/settings/plugins/keyfile/nm-keyfile-connection.h
+++ b/src/settings/plugins/keyfile/nm-keyfile-connection.h
@@ -47,9 +47,6 @@ NMKeyfileConnection *nm_keyfile_connection_new (NMConnection *source,
                                                 const char *filename,
                                                 GError **error);
 
-const char *nm_keyfile_connection_get_path (NMKeyfileConnection *self);
-void        nm_keyfile_connection_set_path (NMKeyfileConnection *self, const char *path);
-
 G_END_DECLS
 
 #endif /* __NETWORKMANAGER_KEYFILE_CONNECTION_H__ */
diff --git a/src/settings/plugins/keyfile/plugin.c b/src/settings/plugins/keyfile/plugin.c
index 371fa47a..fcdb3c3c 100644
--- a/src/settings/plugins/keyfile/plugin.c
+++ b/src/settings/plugins/keyfile/plugin.c
@@ -45,6 +45,7 @@
 #include "writer.h"
 #include "common.h"
 #include "utils.h"
+#include "gsystem-local-alloc.h"
 
 static char *plugin_get_hostname (SCPluginKeyfile *plugin);
 static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
@@ -87,7 +88,7 @@ remove_connection (SCPluginKeyfile *self, NMKeyfileConnection *connection)
 
 	g_return_if_fail (connection != NULL);
 
-	nm_log_info (LOGD_SETTINGS, "removed %s.", nm_keyfile_connection_get_path (connection));
+	nm_log_info (LOGD_SETTINGS, "keyfile: removed " NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection));
 
 	/* Removing from the hash table should drop the last reference */
 	g_object_ref (connection);
@@ -100,102 +101,182 @@ remove_connection (SCPluginKeyfile *self, NMKeyfileConnection *connection)
 	g_return_if_fail (removed);
 }
 
-static void
-update_connection (SCPluginKeyfile *self,
-                   NMKeyfileConnection *connection,
-                   const char *name)
-{
-	NMKeyfileConnection *tmp;
-	GError *error = NULL;
-
-	tmp = nm_keyfile_connection_new (NULL, name, &error);
-	if (!tmp) {
-		/* Error; remove the connection */
-		nm_log_warn (LOGD_SETTINGS, "    error in connection %s: %s", name,
-		             (error && error->message) ? error->message : "(unknown)");
-		g_clear_error (&error);
-		remove_connection (self, connection);
-		return;
-	}
-
-	if (!nm_connection_compare (NM_CONNECTION (connection),
-	                            NM_CONNECTION (tmp),
-	                            NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
-		                          NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
-		nm_log_info (LOGD_SETTINGS, "updating %s", name);
-		if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection),
-		                                              NM_CONNECTION (tmp),
-		                                              FALSE,  /* don't set Unsaved */
-		                                              &error)) {
-			/* Shouldn't ever get here as 'new' was verified by the reader already */
-			g_assert_no_error (error);
-		}
-	}
-	g_object_unref (tmp);
-}
-
 static NMKeyfileConnection *
 find_by_path (SCPluginKeyfile *self, const char *path)
 {
 	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
 	GHashTableIter iter;
-	NMKeyfileConnection *candidate = NULL;
+	NMSettingsConnection *candidate = NULL;
 
 	g_return_val_if_fail (path != NULL, NULL);
 
 	g_hash_table_iter_init (&iter, priv->connections);
 	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) {
-		if (g_strcmp0 (path, nm_keyfile_connection_get_path (candidate)) == 0)
-			return candidate;
+		if (g_strcmp0 (path, nm_settings_connection_get_filename (candidate)) == 0)
+			return NM_KEYFILE_CONNECTION (candidate);
 	}
 	return NULL;
 }
 
-static void
-new_connection (SCPluginKeyfile *self,
-                const char *name,
-                char **out_old_path)
+/* update_connection:
+ * @self: the plugin instance
+ * @source: if %NULL, this re-reads the connection from @full_path
+ *   and updates it. When passing @source, this adds a connection from
+ *   memory.
+ * @full_path: the filename of the keyfile to be loaded
+ * @connection: an existing connection that might be updated.
+ *   If given, @connection must be an existing connection that is currently
+ *   owned by the plugin.
+ * @protect_existing_connection: if %TRUE, and !@connection, we don't allow updating
+ *   an existing connection with the same UUID.
+ *   If %TRUE and @connection, allow updating only if the reload would modify
+ *   @connection (without changing its UUID) or if we would create a new connection.
+ *   In other words, if this paramter is %TRUE, we only allow creating a
+ *   new connection (with an unseen UUID) or updating the passed in @connection
+ *   (whereas the UUID cannot change).
+ *   Note, that this allows for @connection to be replaced by a new connection.
+ * @protected_connections: (allow-none): if given, we only update an
+ *   existing connection if it is not contained in this hash.
+ * @error: error in case of failure
+ *
+ * Loads a connection from file @full_path. This can both be used to
+ * load a connection initially or to update an existing connection.
+ *
+ * If you pass in an existing connection and the reloaded file happens
+ * to have a different UUID, the connection is deleted.
+ * Beware, that means that after the function, you have a dangling pointer
+ * if the returned connection is different from @connection.
+ *
+ * Returns: the updated connection.
+ * */
+static NMKeyfileConnection *
+update_connection (SCPluginKeyfile *self,
+                   NMConnection *source,
+                   const char *full_path,
+                   NMKeyfileConnection *connection,
+                   gboolean protect_existing_connection,
+                   GHashTable *protected_connections,
+                   GError **error)
 {
 	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
-	NMKeyfileConnection *tmp, *connection;
-	GError *error = NULL;
+	NMKeyfileConnection *connection_new;
+	NMKeyfileConnection *connection_by_uuid;
+	GError *local = NULL;
 	const char *uuid;
 
-	if (out_old_path)
-		*out_old_path = NULL;
+	g_return_val_if_fail (!source || NM_IS_CONNECTION (source), NULL);
+	g_return_val_if_fail (full_path || source, NULL);
 
-	tmp = nm_keyfile_connection_new (NULL, name, &error);
-	if (!tmp) {
-		nm_log_warn (LOGD_SETTINGS, "    error in connection %s: %s", name,
-		             (error && error->message) ? error->message : "(unknown)");
-		g_clear_error (&error);
-		return;
+	if (full_path)
+		nm_log_dbg (LOGD_SETTINGS, "keyfile: loading from file \"%s\"...", full_path);
+
+	connection_new = nm_keyfile_connection_new (source, full_path, &local);
+	if (!connection_new) {
+		/* Error; remove the connection */
+		if (source)
+			nm_log_warn (LOGD_SETTINGS, "keyfile: error creating connection %s: %s", nm_connection_get_uuid (source), local->message);
+		else
+			nm_log_warn (LOGD_SETTINGS, "keyfile: error loading connection from file %s: %s", full_path, local->message);
+		if (   connection
+		    && !protect_existing_connection
+		    && (!protected_connections || !g_hash_table_contains (protected_connections, connection)))
+			remove_connection (self, connection);
+		g_propagate_error (error, local);
+		return NULL;
+	}
+
+	uuid = nm_connection_get_uuid (NM_CONNECTION (connection_new));
+	connection_by_uuid = g_hash_table_lookup (priv->connections, uuid);
+
+	if (   connection
+	    && connection != connection_by_uuid) {
+
+		if (   (protect_existing_connection && connection_by_uuid != NULL)
+		    || (protected_connections && g_hash_table_contains (protected_connections, connection))) {
+			NMKeyfileConnection *conflicting = (protect_existing_connection && connection_by_uuid != NULL) ? connection_by_uuid : connection;
+
+			if (source)
+				nm_log_warn (LOGD_SETTINGS, "keyfile: cannot update protected "NM_KEYFILE_CONNECTION_LOG_FMT" connection due to conflicting UUID %s", NM_KEYFILE_CONNECTION_LOG_ARG (conflicting), uuid);
+			else
+				nm_log_warn (LOGD_SETTINGS, "keyfile: cannot load %s due to conflicting UUID for "NM_KEYFILE_CONNECTION_LOG_FMT, full_path, NM_KEYFILE_CONNECTION_LOG_ARG (conflicting));
+			g_object_unref (connection_new);
+			g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+			                      "Cannot update protected connection due to conflicting UUID");
+			return NULL;
+		}
+
+		/* The new connection has a different UUID then the original one.
+		 * Remove @connection. */
+		remove_connection (self, connection);
 	}
 
-	/* Connection renames will show as different paths but same UUID */
-	uuid = nm_connection_get_uuid (NM_CONNECTION (tmp));
-	connection = g_hash_table_lookup (priv->connections, uuid);
-	if (connection) {
-		nm_log_info (LOGD_SETTINGS, "rename %s -> %s", nm_keyfile_connection_get_path (connection), name);
-		if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection),
-		                                              NM_CONNECTION (tmp),
-		                                              FALSE,  /* don't set Unsaved */
-		                                              &error)) {
-			/* Shouldn't ever get here as 'tmp' was verified by the reader already */
-			g_assert_no_error (error);
+	if (   connection_by_uuid
+	    && (   (!connection && protect_existing_connection)
+	        || (protected_connections && g_hash_table_contains (protected_connections, connection_by_uuid)))) {
+		if (source)
+			nm_log_warn (LOGD_SETTINGS, "keyfile: cannot update connection due to conflicting UUID for "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_by_uuid));
+		else
+			nm_log_warn (LOGD_SETTINGS, "keyfile: cannot load %s due to conflicting UUID for "NM_KEYFILE_CONNECTION_LOG_FMT, full_path, NM_KEYFILE_CONNECTION_LOG_ARG (connection_by_uuid));
+		g_object_unref (connection_new);
+		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+		                      "Skip updating protected connection during reload");
+		return NULL;
+	}
+
+	if (connection_by_uuid) {
+		const char *old_path;
+
+		old_path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid));
+
+		if (nm_connection_compare (NM_CONNECTION (connection_by_uuid),
+		                           NM_CONNECTION (connection_new),
+		                           NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
+		                           NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
+			/* Nothing to do... except updating the path. */
+			if (old_path && g_strcmp0 (old_path, full_path) != 0)
+				nm_log_info (LOGD_SETTINGS, "keyfile: rename \"%s\" to "NM_KEYFILE_CONNECTION_LOG_FMT" without other changes", old_path, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+		} else {
+			/* An existing connection changed. */
+			if (source)
+				nm_log_info (LOGD_SETTINGS, "keyfile: update "NM_KEYFILE_CONNECTION_LOG_FMT" from %s", NM_KEYFILE_CONNECTION_LOG_ARG (connection_new), NM_KEYFILE_CONNECTION_LOG_PATH (old_path));
+			else if (!g_strcmp0 (old_path, nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_new))))
+				nm_log_info (LOGD_SETTINGS, "keyfile: update "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+			else if (old_path)
+				nm_log_info (LOGD_SETTINGS, "keyfile: rename \"%s\" to "NM_KEYFILE_CONNECTION_LOG_FMT, old_path, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+			else
+				nm_log_info (LOGD_SETTINGS, "keyfile: update and persist "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+
+			if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection_by_uuid),
+			                                              NM_CONNECTION (connection_new),
+			                                              FALSE,  /* don't set Unsaved */
+			                                              "keyfile-update",
+			                                              &local)) {
+				/* Shouldn't ever get here as 'connection_new' was verified by the reader already
+				 * and the UUID did not change. */
+				g_assert_not_reached ();
+			}
+			g_assert_no_error (local);
 		}
-		g_object_unref (tmp);
-		if (out_old_path)
-			*out_old_path = g_strdup (nm_keyfile_connection_get_path (connection));
-		nm_keyfile_connection_set_path (connection, name);
+		nm_settings_connection_set_filename (NM_SETTINGS_CONNECTION (connection_by_uuid), full_path);
+		g_object_unref (connection_new);
+		return connection_by_uuid;
 	} else {
-		nm_log_info (LOGD_SETTINGS, "new connection %s", name);
-		g_hash_table_insert (priv->connections, g_strdup (uuid), tmp);
-		g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, tmp);
+		if (source)
+			nm_log_info (LOGD_SETTINGS, "keyfile: add connection "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+		else
+			nm_log_info (LOGD_SETTINGS, "keyfile: new connection "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+		g_hash_table_insert (priv->connections, g_strdup (uuid), connection_new);
 
-		g_signal_connect (tmp, NM_SETTINGS_CONNECTION_REMOVED,
+		g_signal_connect (connection_new, NM_SETTINGS_CONNECTION_REMOVED,
 		                  G_CALLBACK (connection_removed_cb),
 		                  self);
+
+		if (!source) {
+			/* Only raise the signal if we were called without source, i.e. if we read the connection from file.
+			 * Otherwise, we were called by add_connection() which does not expect the signal. */
+			g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_new);
+		}
+		return connection_new;
 	}
 }
 
@@ -210,26 +291,28 @@ dir_changed (GFileMonitor *monitor,
 	SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config);
 	NMKeyfileConnection *connection;
 	char *full_path;
+	gboolean exists;
 
 	full_path = g_file_get_path (file);
 	if (nm_keyfile_plugin_utils_should_ignore_file (full_path)) {
 		g_free (full_path);
 		return;
 	}
+	exists = g_file_test (full_path, G_FILE_TEST_EXISTS);
+
+	nm_log_dbg (LOGD_SETTINGS, "dir_changed(%s) = %d; file %s", full_path, event_type, exists ? "exists" : "does not exist");
 
 	connection = find_by_path (self, full_path);
 
 	switch (event_type) {
 	case G_FILE_MONITOR_EVENT_DELETED:
-		if (connection)
+		if (!exists && connection)
 			remove_connection (SC_PLUGIN_KEYFILE (config), connection);
 		break;
 	case G_FILE_MONITOR_EVENT_CREATED:
 	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
-		if (connection)
-			update_connection (SC_PLUGIN_KEYFILE (config), connection, full_path);
-		else
-			new_connection (SC_PLUGIN_KEYFILE (config), full_path, NULL);
+		if (exists)
+			update_connection (SC_PLUGIN_KEYFILE (config), NULL, full_path, connection, TRUE, NULL, NULL);
 		break;
 	default:
 		break;
@@ -305,6 +388,43 @@ setup_monitoring (NMSystemConfigInterface *config)
 	}
 }
 
+static GHashTable *
+_paths_from_connections (GHashTable *connections)
+{
+	GHashTableIter iter;
+	NMKeyfileConnection *connection;
+	GHashTable *paths = g_hash_table_new (g_str_hash, g_str_equal);
+
+	g_hash_table_iter_init (&iter, connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) {
+		const char *path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection));
+
+		if (path)
+			g_hash_table_add (paths, (void *) path);
+	}
+	return paths;
+}
+
+static int
+_sort_paths (const char **f1, const char **f2, GHashTable *paths)
+{
+	struct stat st;
+	gboolean c1, c2;
+	gint64 m1, m2;
+
+	c1 = !!g_hash_table_contains (paths, *f1);
+	c2 = !!g_hash_table_contains (paths, *f2);
+	if (c1 != c2)
+		return c1 ? -1 : 1;
+
+	m1 = stat (*f1, &st) == 0 ? (gint64) st.st_mtime : G_MININT64;
+	m2 = stat (*f2, &st) == 0 ? (gint64) st.st_mtime : G_MININT64;
+	if (m1 != m2)
+		return m1 > m2 ? -1 : 1;
+
+	return strcmp (*f1, *f2);
+}
+
 static void
 read_connections (NMSystemConfigInterface *config)
 {
@@ -313,13 +433,17 @@ read_connections (NMSystemConfigInterface *config)
 	GDir *dir;
 	GError *error = NULL;
 	const char *item;
-	GHashTable *oldconns;
+	GHashTable *alive_connections;
 	GHashTableIter iter;
-	gpointer data;
+	NMKeyfileConnection *connection;
+	GPtrArray *dead_connections = NULL;
+	guint i;
+	GPtrArray *filenames;
+	GHashTable *paths;
 
 	dir = g_dir_open (KEYFILE_DIR, 0, &error);
 	if (!dir) {
-		nm_log_warn (LOGD_SETTINGS, "Cannot read directory '%s': (%d) %s",
+		nm_log_warn (LOGD_SETTINGS, "keyfile: cannot read directory '%s': (%d) %s",
 		             KEYFILE_DIR,
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -327,45 +451,49 @@ read_connections (NMSystemConfigInterface *config)
 		return;
 	}
 
-	oldconns = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-	g_hash_table_iter_init (&iter, priv->connections);
-	while (g_hash_table_iter_next (&iter, NULL, &data)) {
-		const char *con_path = nm_keyfile_connection_get_path (data);
-		if (con_path)
-			g_hash_table_insert (oldconns, g_strdup (con_path), data);
-	}
+	alive_connections = g_hash_table_new (NULL, NULL);
 
+	filenames = g_ptr_array_new_with_free_func (g_free);
 	while ((item = g_dir_read_name (dir))) {
-		NMKeyfileConnection *connection;
-		char *full_path, *old_path;
-
 		if (nm_keyfile_plugin_utils_should_ignore_file (item))
 			continue;
+		g_ptr_array_add (filenames, g_build_filename (KEYFILE_DIR, item, NULL));
+	}
+	g_dir_close (dir);
 
-		full_path = g_build_filename (KEYFILE_DIR, item, NULL);
+	/* While reloading, we don't replace connections that we already loaded while
+	 * iterating over the files.
+	 *
+	 * To have sensible, reproducible behavior, sort the paths by last modification
+	 * time prefering older files.
+	 */
+	paths = _paths_from_connections (priv->connections);
+	g_ptr_array_sort_with_data (filenames, (GCompareDataFunc) _sort_paths, paths);
+	g_hash_table_destroy (paths);
+
+	for (i = 0; i < filenames->len; i++) {
+		connection = update_connection (self, NULL, filenames->pdata[i], NULL, FALSE, alive_connections, NULL);
+		if (connection)
+			g_hash_table_add (alive_connections, connection);
+	}
+	g_ptr_array_free (filenames, TRUE);
 
-		connection = g_hash_table_lookup (oldconns, full_path);
-		if (connection) {
-			g_hash_table_remove (oldconns, full_path);
-			update_connection (self, connection, full_path);
-		} else {
-			new_connection (self, full_path, &old_path);
-			if (old_path) {
-				g_hash_table_remove (oldconns, old_path);
-				g_free (old_path);
-			}
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) {
+		if (   !g_hash_table_contains (alive_connections, connection)
+		    && nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection))) {
+			if (!dead_connections)
+				dead_connections = g_ptr_array_new ();
+			g_ptr_array_add (dead_connections, connection);
 		}
-
-		g_free (full_path);
 	}
-	g_dir_close (dir);
+	g_hash_table_destroy (alive_connections);
 
-	g_hash_table_iter_init (&iter, oldconns);
-	while (g_hash_table_iter_next (&iter, NULL, &data)) {
-		g_hash_table_iter_remove (&iter);
-		remove_connection (self, data);
+	if (dead_connections) {
+		for (i = 0; i < dead_connections->len; i++)
+			remove_connection (self, dead_connections->pdata[i]);
+		g_ptr_array_free (dead_connections, TRUE);
 	}
-	g_hash_table_destroy (oldconns);
 }
 
 /* Plugin */
@@ -399,13 +527,7 @@ load_connection (NMSystemConfigInterface *config,
 	if (nm_keyfile_plugin_utils_should_ignore_file (filename + dir_len + 1))
 		return FALSE;
 
-	connection = find_by_path (self, filename);
-	if (connection)
-		update_connection (self, connection, filename);
-	else {
-		new_connection (self, filename, NULL);
-		connection = find_by_path (self, filename);
-	}
+	connection = update_connection (self, NULL, filename, find_by_path (self, filename), TRUE, NULL, NULL);
 
 	return (connection != NULL);
 }
@@ -423,26 +545,13 @@ add_connection (NMSystemConfigInterface *config,
                 GError **error)
 {
 	SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config);
-	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
-	NMSettingsConnection *added = NULL;
-	char *path = NULL;
+	gs_free char *path = NULL;
 
 	if (save_to_disk) {
 		if (!nm_keyfile_plugin_write_connection (connection, NULL, &path, error))
 			return NULL;
 	}
-
-	added = (NMSettingsConnection *) nm_keyfile_connection_new (connection, path, error);
-	if (added) {
-		g_hash_table_insert (priv->connections,
-		                     g_strdup (nm_connection_get_uuid (NM_CONNECTION (added))),
-		                     added);
-		g_signal_connect (added, NM_SETTINGS_CONNECTION_REMOVED,
-		                  G_CALLBACK (connection_removed_cb),
-		                  self);
-	}
-	g_free (path);
-	return added;
+	return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error));
 }
 
 static gboolean
@@ -500,7 +609,7 @@ get_unmanaged_specs (NMSystemConfigInterface *config)
 			} else if (!strncmp (udis[i], "interface-name:", 15) && nm_utils_iface_valid_name (udis[i] + 15)) {
 				specs = g_slist_append (specs, udis[i]);
 			} else {
-				nm_log_warn (LOGD_SETTINGS, "Error in file '%s': invalid unmanaged-devices entry: '%s'", priv->conf_file, udis[i]);
+				nm_log_warn (LOGD_SETTINGS, "keyfile: error in file '%s': invalid unmanaged-devices entry: '%s'", priv->conf_file, udis[i]);
 				g_free (udis[i]);
 			}
 		}
@@ -510,7 +619,7 @@ get_unmanaged_specs (NMSystemConfigInterface *config)
 
  out:
 	if (error) {
-		nm_log_warn (LOGD_SETTINGS, "%s", error->message);
+		nm_log_warn (LOGD_SETTINGS, "keyfile: error getting unmanaged specs: %s", error->message);
 		g_error_free (error);
 	}
 	if (key_file)
@@ -538,7 +647,7 @@ plugin_get_hostname (SCPluginKeyfile *plugin)
 
  out:
 	if (error) {
-		nm_log_warn (LOGD_SETTINGS, "%s", error->message);
+		nm_log_warn (LOGD_SETTINGS, "keyfile: error getting hostname: %s", error->message);
 		g_error_free (error);
 	}
 	if (key_file)
@@ -585,7 +694,7 @@ plugin_set_hostname (SCPluginKeyfile *plugin, const char *hostname)
 
  out:
 	if (error) {
-		nm_log_warn (LOGD_SETTINGS, "%s", error->message);
+		nm_log_warn (LOGD_SETTINGS, "keyfile: error setting hostname: %s", error->message);
 		g_error_free (error);
 	}
 	g_free (data);
diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c
index 1d2ecdad..1f0953e0 100644
--- a/src/settings/plugins/keyfile/reader.c
+++ b/src/settings/plugins/keyfile/reader.c
@@ -870,6 +870,7 @@ parity_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const cha
 				int_val = 'X';
 			}
 		}
+		g_free (str_val);
 	}
 
 	if (!int_val)
diff --git a/src/settings/plugins/keyfile/tests/Makefile.am b/src/settings/plugins/keyfile/tests/Makefile.am
index 20b9820c..a79e20b5 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.am
+++ b/src/settings/plugins/keyfile/tests/Makefile.am
@@ -34,6 +34,7 @@ test_keyfile_LDADD = \
 	$(DBUS_LIBS) \
 	$(CODE_COVERAGE_LDFLAGS)
 
+@VALGRIND_RULES@
 TESTS = test-keyfile
 
 endif
diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in
index 8530bf8c..c4d12459 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 @ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-keyfile$(EXEEXT)
 @ENABLE_TESTS_TRUE@TESTS = test-keyfile$(EXEEXT)
 subdir = src/settings/plugins/keyfile/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -217,6 +226,8 @@ am__tty_colors = { \
   fi; \
 }
 DIST_SUBDIRS = keyfiles
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -268,7 +279,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -303,6 +313,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -548,7 +559,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/keyfile/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/keyfile/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -596,14 +606,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -1031,9 +1041,13 @@ uninstall-am:
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_TESTS_TRUE@@GNOME_CODE_COVERAGE_RULES@
 
+@ENABLE_TESTS_TRUE@@VALGRIND_RULES@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
index bc522b1b..f7a0c45e 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,7 +88,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/keyfile/tests/keyfiles
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -95,6 +104,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -119,6 +129,7 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -145,7 +156,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -180,6 +190,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -434,7 +445,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/keyfile/tests/keyfiles/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/keyfile/tests/keyfiles/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -611,6 +621,8 @@ uninstall-am:
 	mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
 	uninstall-am
 
+.PRECIOUS: Makefile
+
 
 check-local:
 	@for f in $(KEYFILES); do \
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main
index 7fbbfe22..3b9fcb28 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main
@@ -6,7 +6,7 @@ type=bridge
 [bridge]
 interface-name=br0
 stp=true
-forward-delay=0
+forward-delay=2
 priority=32744
 hello-time=7
 max-age=39
diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c
index 33e3863c..edece1b2 100644
--- a/src/settings/plugins/keyfile/tests/test-keyfile.c
+++ b/src/settings/plugins/keyfile/tests/test-keyfile.c
@@ -1515,6 +1515,7 @@ test_write_intlike_ssid (void)
 	g_assert_no_error (error);
 	g_assert (tmp);
 	g_assert_cmpstr (tmp, ==, "101");
+	g_free (tmp);
 
 	g_key_file_free (keyfile);
 
@@ -1601,6 +1602,7 @@ test_write_intlike_ssid_2 (void)
 	g_assert_no_error (error);
 	g_assert (tmp);
 	g_assert_cmpstr (tmp, ==, "11\\;12\\;13\\;");
+	g_free (tmp);
 
 	g_key_file_free (keyfile);
 
@@ -2511,6 +2513,7 @@ test_write_wired_8021x_tls_connection_path (void)
 	tmp2 = g_path_get_dirname (testfile);
 	if (g_strcmp0 (tmp2, TEST_KEYFILES_DIR) == 0)
 		relative = TRUE;
+	g_free (tmp2);
 
 	/* CA cert */
 	tmp = g_key_file_get_string (keyfile,
@@ -2564,10 +2567,22 @@ test_write_wired_8021x_tls_connection_blob (void)
 	char *new_priv_key;
 	const char *uuid;
 	GError *error = NULL;
+	GBytes *password_raw = NULL;
+#define PASSWORD_RAW "password-raw\0test"
 
 	connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_BLOB);
 	g_assert (connection != NULL);
 
+	s_8021x = nm_connection_get_setting_802_1x (connection);
+	g_assert (s_8021x);
+
+	password_raw = g_bytes_new (PASSWORD_RAW, STRLEN (PASSWORD_RAW));
+	g_object_set (s_8021x,
+	              NM_SETTING_802_1X_PASSWORD_RAW,
+	              password_raw,
+	              NULL);
+	g_bytes_unref (password_raw);
+
 	/* Write out the connection */
 	success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, geteuid (), getegid (), &testfile, &error);
 	if (!success) {
@@ -2610,6 +2625,11 @@ test_write_wired_8021x_tls_connection_blob (void)
 	g_assert (nm_setting_802_1x_get_client_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
 	g_assert (nm_setting_802_1x_get_private_key_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
 
+	password_raw = nm_setting_802_1x_get_password_raw (s_8021x);
+	g_assert (password_raw);
+	g_assert (g_bytes_get_size (password_raw) == STRLEN (PASSWORD_RAW));
+	g_assert (!memcmp (g_bytes_get_data (password_raw, NULL), PASSWORD_RAW, STRLEN (PASSWORD_RAW)));
+
 	unlink (testfile);
 	g_free (testfile);
 
@@ -2784,7 +2804,7 @@ test_read_bridge_main (void)
 	/* Bridge setting */
 	s_bridge = nm_connection_get_setting_bridge (connection);
 	g_assert (s_bridge);
-	g_assert_cmpuint (nm_setting_bridge_get_forward_delay (s_bridge), ==, 0);
+	g_assert_cmpuint (nm_setting_bridge_get_forward_delay (s_bridge), ==, 2);
 	g_assert_cmpuint (nm_setting_bridge_get_stp (s_bridge), ==, TRUE);
 	g_assert_cmpuint (nm_setting_bridge_get_priority (s_bridge), ==, 32744);
 	g_assert_cmpuint (nm_setting_bridge_get_hello_time (s_bridge), ==, 7);
@@ -3098,6 +3118,7 @@ test_write_new_wired_group_name (void)
 	unlink (testfile);
 	g_free (testfile);
 
+	g_key_file_unref (kf);
 	g_object_unref (reread);
 	g_object_unref (connection);
 }
@@ -3236,6 +3257,7 @@ test_write_new_wireless_group_names (void)
 	unlink (testfile);
 	g_free (testfile);
 
+	g_key_file_unref (kf);
 	g_object_unref (reread);
 	g_object_unref (connection);
 }
@@ -3548,7 +3570,7 @@ NMTST_DEFINE ();
 
 int main (int argc, char **argv)
 {
-	nmtst_init_assert_logging (&argc, &argv);
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
 
 	/* The tests */
 	g_test_add_func ("/keyfile/test_read_valid_wired_connection ", test_read_valid_wired_connection);
diff --git a/src/settings/plugins/keyfile/utils.h b/src/settings/plugins/keyfile/utils.h
index 1a7c2502..d1533671 100644
--- a/src/settings/plugins/keyfile/utils.h
+++ b/src/settings/plugins/keyfile/utils.h
@@ -23,6 +23,13 @@
 
 #include <glib.h>
 #include "common.h"
+#include "NetworkManagerUtils.h"
+
+#define NM_KEYFILE_CONNECTION_LOG_PATH(path)  str_if_set (path,"in-memory")
+#define NM_KEYFILE_CONNECTION_LOG_FMT         "%s (%s,\"%s\")"
+#define NM_KEYFILE_CONNECTION_LOG_ARG(con)    NM_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con))
+#define NM_KEYFILE_CONNECTION_LOG_FMTD        "%s (%s,\"%s\",%p)"
+#define NM_KEYFILE_CONNECTION_LOG_ARGD(con)   NM_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)), (con)
 
 gboolean nm_keyfile_plugin_utils_should_ignore_file (const char *filename);
 
diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c
index d342e3f7..7aa5bfb0 100644
--- a/src/settings/plugins/keyfile/writer.c
+++ b/src/settings/plugins/keyfile/writer.c
@@ -27,7 +27,6 @@
 #include <stdio.h>
 #include <errno.h>
 
-#include <dbus/dbus-glib.h>
 #include <nm-setting.h>
 #include <nm-setting-connection.h>
 #include <nm-setting-ip4-config.h>
@@ -42,7 +41,6 @@
 #include <string.h>
 #include <arpa/inet.h>
 
-#include "nm-dbus-glib-types.h"
 #include "nm-glib-compat.h"
 #include "nm-logging.h"
 #include "writer.h"
@@ -345,19 +343,24 @@ password_raw_writer (GKeyFile *file,
                      const GValue *value)
 {
 	const char *setting_name = nm_setting_get_name (setting);
-	GByteArray *array;
-	int i, *tmp_array;
+	GBytes *array;
+	int *tmp_array;
+	gsize i, len;
+	const char *data;
 
-	g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY));
+	g_return_if_fail (G_VALUE_HOLDS (value, G_TYPE_BYTES));
 
-	array = (GByteArray *) g_value_get_boxed (value);
-	if (!array || !array->len)
+	array = (GBytes *) g_value_get_boxed (value);
+	if (!array)
+		return;
+	data = g_bytes_get_data (array, &len);
+	if (!data || !len)
 		return;
 
-	tmp_array = g_new (gint, array->len);
-	for (i = 0; i < array->len; i++)
-		tmp_array[i] = (int) array->data[i];
-	nm_keyfile_plugin_kf_set_integer_list (file, setting_name, key, tmp_array, array->len);
+	tmp_array = g_new (gint, len);
+	for (i = 0; i < len; i++)
+		tmp_array[i] = (int) data[i];
+	nm_keyfile_plugin_kf_set_integer_list (file, setting_name, key, tmp_array, len);
 	g_free (tmp_array);
 }
 
@@ -813,13 +816,10 @@ _internal_write_connection (NMConnection *connection,
 	WriteInfo info;
 	GError *local_err = NULL;
 
-	if (out_path)
-		g_return_val_if_fail (*out_path == NULL, FALSE);
+	g_return_val_if_fail (!out_path || !*out_path, FALSE);
 
-	if (!nm_connection_verify (connection, error)) {
+	if (!nm_connection_verify (connection, error))
 		g_return_val_if_reached (FALSE);
-		return FALSE;
-	}
 
 	id = nm_connection_get_id (connection);
 	g_assert (id && *id);
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index 9ae87095..c60027ad 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -547,6 +547,13 @@ add_wep_key (NMSupplicantConfig *self,
 	if (!key || !key_len)
 		return TRUE;
 
+	if (wep_type == NM_WEP_KEY_TYPE_UNKNOWN) {
+		if (nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_KEY))
+			wep_type = NM_WEP_KEY_TYPE_KEY;
+		else if (nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_PASSPHRASE))
+			wep_type = NM_WEP_KEY_TYPE_PASSPHRASE;
+	}
+
 	if (   (wep_type == NM_WEP_KEY_TYPE_UNKNOWN)
 	    || (wep_type == NM_WEP_KEY_TYPE_KEY)) {
 		if ((key_len == 10) || (key_len == 26)) {
diff --git a/src/supplicant-manager/tests/Makefile.am b/src/supplicant-manager/tests/Makefile.am
index 452ccdc1..85268dcf 100644
--- a/src/supplicant-manager/tests/Makefile.am
+++ b/src/supplicant-manager/tests/Makefile.am
@@ -18,4 +18,5 @@ test_supplicant_config_SOURCES = \
 test_supplicant_config_LDADD = \
 	$(top_builddir)/src/libNetworkManager.la
 
+@VALGRIND_RULES@
 TESTS = test-supplicant-config
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index 567b6c77..50981a19 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 noinst_PROGRAMS = test-supplicant-config$(EXEEXT)
 TESTS = test-supplicant-config$(EXEEXT)
 subdir = src/supplicant-manager/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -194,6 +203,8 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -220,7 +231,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -255,6 +265,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -489,7 +500,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/supplicant-manager/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/supplicant-manager/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -534,14 +544,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -853,6 +863,10 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
+
+@VALGRIND_RULES@
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/supplicant-manager/tests/test-supplicant-config.c b/src/supplicant-manager/tests/test-supplicant-config.c
index 5aa3fa2d..5ffead40 100644
--- a/src/supplicant-manager/tests/test-supplicant-config.c
+++ b/src/supplicant-manager/tests/test-supplicant-config.c
@@ -111,7 +111,7 @@ test_wifi_open (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wifi;
 	NMSettingIPConfig *s_ip4;
-	NMSupplicantConfig *config;
+	gs_unref_object NMSupplicantConfig *config = NULL;
 	GHashTable *hash;
 	char *uuid;
 	gboolean success;
@@ -191,6 +191,7 @@ test_wifi_open (void)
 	validate_opt ("wifi-open", hash, "bssid", TYPE_KEYWORD, bssid_str, -1);
 	validate_opt ("wifi-open", hash, "key_mgmt", TYPE_KEYWORD, "NONE", -1);
 
+	g_hash_table_unref (hash);
 	g_object_unref (connection);
 }
 
@@ -206,7 +207,7 @@ test_wifi_wep_key (const char *detail,
 	NMSettingWireless *s_wifi;
 	NMSettingWirelessSecurity *s_wsec;
 	NMSettingIPConfig *s_ip4;
-	NMSupplicantConfig *config;
+	gs_unref_object NMSupplicantConfig *config = NULL;
 	GHashTable *hash;
 	char *uuid;
 	gboolean success;
@@ -305,6 +306,7 @@ test_wifi_wep_key (const char *detail,
 	validate_opt (detail, hash, "wep_tx_keyidx", TYPE_INT, GINT_TO_POINTER (0), -1);
 	validate_opt (detail, hash, "wep_key0", TYPE_BYTES, expected, expected_size);
 
+	g_hash_table_unref (hash);
 	g_object_unref (connection);
 }
 
@@ -343,7 +345,7 @@ test_wifi_wpa_psk (const char *detail,
 	NMSettingWireless *s_wifi;
 	NMSettingWirelessSecurity *s_wsec;
 	NMSettingIPConfig *s_ip4;
-	NMSupplicantConfig *config;
+	gs_unref_object NMSupplicantConfig *config = NULL;
 	GHashTable *hash;
 	char *uuid;
 	gboolean success;
@@ -454,6 +456,7 @@ test_wifi_wpa_psk (const char *detail,
 	validate_opt (detail, hash, "group", TYPE_KEYWORD, "TKIP CCMP", -1);
 	validate_opt (detail, hash, "psk", key_type, expected, expected_size);
 
+	g_hash_table_unref (hash);
 	g_object_unref (connection);
 }
 
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 65bc2199..a96d1ce9 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -86,6 +86,7 @@ EXTRA_DIST = test-secret-agent.py
 
 ###########################################
 
+@VALGRIND_RULES@
 TESTS = \
 	test-ip4-config \
 	test-ip6-config \
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index a5d5b3a8..61e757e7 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -87,8 +97,6 @@ TESTS = test-ip4-config$(EXEEXT) test-ip6-config$(EXEEXT) \
 	test-general$(EXEEXT) test-general-with-expect$(EXEEXT) \
 	test-wired-defname$(EXEEXT)
 subdir = src/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -105,6 +113,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -249,6 +258,8 @@ am__tty_colors = { \
   fi; \
 }
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -300,7 +311,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -335,6 +345,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -626,7 +637,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -701,14 +711,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -1095,6 +1105,12 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
+
+###########################################
+
+@VALGRIND_RULES@
 
 @ENABLE_TESTS_TRUE@check-local:
 @ENABLE_TESTS_TRUE@	@for t in bond bridge ethernet gre infiniband macvlan tun veth vlan vxlan; do \
diff --git a/src/tests/config/Makefile.am b/src/tests/config/Makefile.am
index 66009c87..42c6b9a1 100644
--- a/src/tests/config/Makefile.am
+++ b/src/tests/config/Makefile.am
@@ -23,6 +23,7 @@ test_config_SOURCES = \
 test_config_LDADD = \
 	$(top_builddir)/src/libNetworkManager.la
 
+@VALGRIND_RULES@
 TESTS = test-config
 
 EXTRA_DIST = \
diff --git a/src/tests/config/Makefile.in b/src/tests/config/Makefile.in
index 81fb0885..73ff9d48 100644
--- a/src/tests/config/Makefile.in
+++ b/src/tests/config/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 noinst_PROGRAMS = test-config$(EXEEXT)
 TESTS = test-config$(EXEEXT)
 subdir = src/tests/config
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -194,6 +203,8 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -220,7 +231,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -255,6 +265,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -500,7 +511,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tests/config/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/tests/config/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -546,14 +556,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -865,6 +875,10 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
+
+@VALGRIND_RULES@
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/tests/config/nm-test-device.c b/src/tests/config/nm-test-device.c
index 63067b25..512085e9 100644
--- a/src/tests/config/nm-test-device.c
+++ b/src/tests/config/nm-test-device.c
@@ -61,12 +61,6 @@ dispose (GObject *object)
 	g_object_class->dispose (object);
 }
 
-static void
-finalize (GObject *object)
-{
-	g_object_class->finalize (object);
-}
-
 static guint32
 get_generic_capabilities (NMDevice *device)
 {
@@ -84,7 +78,6 @@ nm_test_device_class_init (NMTestDeviceClass *klass)
 	object_class->constructor = constructor;
 	object_class->constructed = constructed;
 	object_class->dispose = dispose;
-	object_class->finalize = finalize;
 
 	device_class->get_generic_capabilities = get_generic_capabilities;
 }
diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c
index 808fc670..e027eab8 100644
--- a/src/tests/config/test-config.c
+++ b/src/tests/config/test-config.c
@@ -27,6 +27,10 @@
 #include <nm-config.h>
 #include "nm-test-device.h"
 #include "nm-fake-platform.h"
+#include "nm-logging.h"
+#include "nm-dbus-manager.h"
+
+#include "nm-test-utils.h"
 
 static void
 setup_config (const char *config_file, const char *config_dir, ...)
@@ -108,7 +112,7 @@ static void
 test_config_non_existent (void)
 {
 	NMConfig *config;
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 
 	setup_config (SRCDIR "/no-such-file", "/no/such/dir", NULL);
 	config = nm_config_new (&error);
@@ -120,7 +124,7 @@ static void
 test_config_parse_error (void)
 {
 	NMConfig *config;
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 
 	setup_config (SRCDIR "/bad.conf", "/no/such/dir", NULL);
 	config = nm_config_new (&error);
@@ -270,7 +274,7 @@ static void
 test_config_confdir_parse_error (void)
 {
 	NMConfig *config;
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 
 	/* Using SRCDIR as the conf dir will pick up bad.conf */
 	setup_config (SRCDIR "/NetworkManager.conf", SRCDIR, NULL);
@@ -279,14 +283,19 @@ test_config_confdir_parse_error (void)
 	g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
 }
 
+NMTST_DEFINE ();
+
 int
 main (int argc, char **argv)
 {
-#if !GLIB_CHECK_VERSION (2, 35, 0)
-	g_type_init ();
-#endif
-
-	g_test_init (&argc, &argv, NULL);
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
+
+	/* Initialize the DBus manager singleton explicitly, because it is accessed by
+	 * the class initializer of NMDevice (used by the NMTestDevice stub).
+	 * This way, we skip calling nm_dbus_manager_init_bus() which would
+	 * either fail and/or cause unexpected actions in the test.
+	 * */
+	nm_dbus_manager_setup (g_object_new (NM_TYPE_DBUS_MANAGER, NULL));
 
 	nm_fake_platform_setup ();
 
diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c
index f5010dae..4a0627c9 100644
--- a/src/tests/test-general-with-expect.c
+++ b/src/tests/test-general-with-expect.c
@@ -333,16 +333,42 @@ test_nm_utils_kill_child (void)
 
 /*******************************************/
 
+static void
+test_nm_ethernet_address_is_valid ()
+{
+	g_assert (!nm_ethernet_address_is_valid (NULL, -1));
+	g_assert (!nm_ethernet_address_is_valid (NULL, ETH_ALEN));
+
+	g_assert (!nm_ethernet_address_is_valid ("FF:FF:FF:FF:FF:FF", -1));
+	g_assert (!nm_ethernet_address_is_valid ("00:00:00:00:00:00", -1));
+	g_assert (!nm_ethernet_address_is_valid ("44:44:44:44:44:44", -1));
+	g_assert (!nm_ethernet_address_is_valid ("00:30:b4:00:00:00", -1));
+
+	g_assert (!nm_ethernet_address_is_valid ("", -1));
+	g_assert (!nm_ethernet_address_is_valid ("1", -1));
+	g_assert (!nm_ethernet_address_is_valid ("2", -1));
+
+	g_assert (!nm_ethernet_address_is_valid (((guint8[8]) { 0x00,0x30,0xb4,0x00,0x00,0x00 }), ETH_ALEN));
+	g_assert ( nm_ethernet_address_is_valid (((guint8[8]) { 0x00,0x30,0xb4,0x00,0x00,0x01 }), ETH_ALEN));
+
+	/* some Broad cast addresses (with MSB of first octet set). */
+	g_assert (!nm_ethernet_address_is_valid ("57:44:44:44:44:44", -1));
+	g_assert ( nm_ethernet_address_is_valid ("56:44:44:44:44:44", -1));
+	g_assert (!nm_ethernet_address_is_valid (((guint8[8]) { 0x03,0x30,0xb4,0x00,0x00,0x00 }), ETH_ALEN));
+	g_assert ( nm_ethernet_address_is_valid (((guint8[8]) { 0x02,0x30,0xb4,0x00,0x00,0x01 }), ETH_ALEN));
+}
+
+/*******************************************/
+
 NMTST_DEFINE ();
 
 int
 main (int argc, char **argv)
 {
-	nmtst_init_assert_logging (&argc, &argv);
-
-	nm_logging_setup ("DEBUG", "DEFAULT", NULL, NULL);
+	nmtst_init_assert_logging (&argc, &argv, "DEBUG", "DEFAULT");
 
 	g_test_add_func ("/general/nm_utils_kill_child", test_nm_utils_kill_child);
+	g_test_add_func ("/general/nm_ethernet_address_is_valid", test_nm_ethernet_address_is_valid);
 
 	return g_test_run ();
 }
diff --git a/src/tests/test-wired-defname.c b/src/tests/test-wired-defname.c
index a05588b8..b2933de0 100644
--- a/src/tests/test-wired-defname.c
+++ b/src/tests/test-wired-defname.c
@@ -26,6 +26,7 @@
 #include <nm-simple-connection.h>
 #include <nm-setting-connection.h>
 #include "nm-device-ethernet-utils.h"
+#include "gsystem-local-alloc.h"
 
 static NMConnection *
 _new_connection (const char *id)
@@ -45,7 +46,7 @@ _new_connection (const char *id)
 static void
 test_defname_no_connections (void)
 {
-	char *name;
+	gs_free char *name = NULL;
 
 	name = nm_device_ethernet_utils_get_default_wired_name (NULL);
 	g_assert_cmpstr (name, ==, "Wired connection 1");
@@ -57,7 +58,7 @@ static void
 test_defname_no_conflict (void)
 {
 	GSList *list = NULL;
-	char *name;
+	gs_free char *name = NULL;
 
 	list = g_slist_append (list, _new_connection ("asdfasdfasdfadf"));
 	list = g_slist_append (list, _new_connection ("work wifi"));
@@ -75,7 +76,7 @@ static void
 test_defname_conflict (void)
 {
 	GSList *list = NULL;
-	char *name;
+	gs_free char *name = NULL;
 
 	list = g_slist_append (list, _new_connection ("asdfasdfasdfadf"));
 	list = g_slist_append (list, _new_connection ("Wired connection 1"));
@@ -93,7 +94,7 @@ static void
 test_defname_multiple_conflicts (void)
 {
 	GSList *list = NULL;
-	char *name;
+	gs_free char *name = NULL;
 
 	list = g_slist_append (list, _new_connection ("random gsm connection"));
 	list = g_slist_append (list, _new_connection ("home wifi"));